From 2b5ff82d7bad9ea64c2170222be21beb505e82ce Mon Sep 17 00:00:00 2001 From: mpoke Date: Thu, 11 Jan 2024 14:13:21 +0100 Subject: [PATCH 001/110] cleanup ./changelog entries --- .changelog/epilogue.md | 198 +----------------- .../consumer/1146-pending-packets.md | 2 - .../consumer/1150-revert-wire-breaking.md | 2 - .../consumer/1244-validate-transfer.md | 2 - .../bug-fixes/consumer/1262-fee-pool-addr.md | 2 - .../bug-fixes/consumer/1295-migration.md | 2 - .../v3.2.0/dependencies/1196-bump-ibc.md | 3 - .../v3.2.0/dependencies/1258-bump-ibc.md | 3 - .../v3.2.0/dependencies/1258-bump-sdk.md | 3 - .../v3.2.0/dependencies/1259-bump-sdk.md | 3 - .../consumer/1024-jail-throttling-v2.md | 2 - .../consumer/1164-provider-info-query.md | 4 - .../provider/1076-export-timestamps.md | 2 - .../features/provider/1280-reward-denoms.md | 3 - .../improvements/1244-consumer-unbonding.md | 2 - .../consumer/1037-optimize-storage.md | 2 - .../v3.2.0/state-breaking/1196-bump-ibc.md | 3 - .../state-breaking/1244-consumer-unbonding.md | 2 - .../v3.2.0/state-breaking/1258-bump-ibc.md | 3 - .../v3.2.0/state-breaking/1258-bump-sdk.md | 3 - .../v3.2.0/state-breaking/1259-bump-sdk.md | 3 - .../consumer/1024-jail-throttling-v2.md | 2 - .../consumer/1037-optimize-storage.md | 2 - .../consumer/1146-pending-packets.md | 2 - .../consumer/1150-revert-wire-breaking.md | 2 - .../consumer/1244-validate-transfer.md | 2 - .../consumer/1262-fee-pool-addr.md | 2 - .../state-breaking/consumer/1295-migration.md | 2 - .../provider/1280-reward-denoms.md | 3 - .changelog/v3.2.0/summary.md | 1 - ...ic-verification-of-equivocation-feature.md | 2 - .../v3.3.0/dependencies/1373-bump-ibc.md | 3 - .../v3.3.0/features/1336-quint-model.md | 2 - .../1339-check-key-assignment-in-use.md | 3 - ...1340-cryptographic-equivocation-feature.md | 4 - .../improvements/1324-consumer-genesis.md | 16 -- .../v3.3.0/improvements/1350-cleanup-types.md | 3 - .../provider/1503-query-key-assignment.md | 1 - .../state-breaking/1324-consumer-genesis.md | 2 - .../state-breaking/1460-msg-validation.md | 3 - .../1339-check-key-assignment-in-use.md | 3 - ...1340-cryptographic-equivocation-feature.md | 4 - .changelog/v3.3.0/summary.md | 1 - 43 files changed, 2 insertions(+), 312 deletions(-) delete mode 100644 .changelog/v3.2.0/bug-fixes/consumer/1146-pending-packets.md delete mode 100644 .changelog/v3.2.0/bug-fixes/consumer/1150-revert-wire-breaking.md delete mode 100644 .changelog/v3.2.0/bug-fixes/consumer/1244-validate-transfer.md delete mode 100644 .changelog/v3.2.0/bug-fixes/consumer/1262-fee-pool-addr.md delete mode 100644 .changelog/v3.2.0/bug-fixes/consumer/1295-migration.md delete mode 100644 .changelog/v3.2.0/dependencies/1196-bump-ibc.md delete mode 100644 .changelog/v3.2.0/dependencies/1258-bump-ibc.md delete mode 100644 .changelog/v3.2.0/dependencies/1258-bump-sdk.md delete mode 100644 .changelog/v3.2.0/dependencies/1259-bump-sdk.md delete mode 100644 .changelog/v3.2.0/features/consumer/1024-jail-throttling-v2.md delete mode 100644 .changelog/v3.2.0/features/consumer/1164-provider-info-query.md delete mode 100644 .changelog/v3.2.0/features/provider/1076-export-timestamps.md delete mode 100644 .changelog/v3.2.0/features/provider/1280-reward-denoms.md delete mode 100644 .changelog/v3.2.0/improvements/1244-consumer-unbonding.md delete mode 100644 .changelog/v3.2.0/improvements/consumer/1037-optimize-storage.md delete mode 100644 .changelog/v3.2.0/state-breaking/1196-bump-ibc.md delete mode 100644 .changelog/v3.2.0/state-breaking/1244-consumer-unbonding.md delete mode 100644 .changelog/v3.2.0/state-breaking/1258-bump-ibc.md delete mode 100644 .changelog/v3.2.0/state-breaking/1258-bump-sdk.md delete mode 100644 .changelog/v3.2.0/state-breaking/1259-bump-sdk.md delete mode 100644 .changelog/v3.2.0/state-breaking/consumer/1024-jail-throttling-v2.md delete mode 100644 .changelog/v3.2.0/state-breaking/consumer/1037-optimize-storage.md delete mode 100644 .changelog/v3.2.0/state-breaking/consumer/1146-pending-packets.md delete mode 100644 .changelog/v3.2.0/state-breaking/consumer/1150-revert-wire-breaking.md delete mode 100644 .changelog/v3.2.0/state-breaking/consumer/1244-validate-transfer.md delete mode 100644 .changelog/v3.2.0/state-breaking/consumer/1262-fee-pool-addr.md delete mode 100644 .changelog/v3.2.0/state-breaking/consumer/1295-migration.md delete mode 100644 .changelog/v3.2.0/state-breaking/provider/1280-reward-denoms.md delete mode 100644 .changelog/v3.2.0/summary.md delete mode 100644 .changelog/v3.3.0/api-breaking/provider/1340-add-cryptographic-verification-of-equivocation-feature.md delete mode 100644 .changelog/v3.3.0/dependencies/1373-bump-ibc.md delete mode 100644 .changelog/v3.3.0/features/1336-quint-model.md delete mode 100644 .changelog/v3.3.0/features/provider/1339-check-key-assignment-in-use.md delete mode 100644 .changelog/v3.3.0/features/provider/1340-cryptographic-equivocation-feature.md delete mode 100644 .changelog/v3.3.0/improvements/1324-consumer-genesis.md delete mode 100644 .changelog/v3.3.0/improvements/1350-cleanup-types.md delete mode 100644 .changelog/v3.3.0/improvements/provider/1503-query-key-assignment.md delete mode 100644 .changelog/v3.3.0/state-breaking/1324-consumer-genesis.md delete mode 100644 .changelog/v3.3.0/state-breaking/1460-msg-validation.md delete mode 100644 .changelog/v3.3.0/state-breaking/provider/1339-check-key-assignment-in-use.md delete mode 100644 .changelog/v3.3.0/state-breaking/provider/1340-cryptographic-equivocation-feature.md delete mode 100644 .changelog/v3.3.0/summary.md diff --git a/.changelog/epilogue.md b/.changelog/epilogue.md index 88987ef0a0..15e2568e25 100644 --- a/.changelog/epilogue.md +++ b/.changelog/epilogue.md @@ -1,197 +1,3 @@ -## v3.1.0 +## Previous Versions -Date July 11th, 2023 - -A minor upgrade to v3.0.0, which removes the panic in the consumer ccv module which would occur in an emergency scenario where the ccv channel is closed. This release also fixes how a distribution related event is emitted, and bumps cometbft. - -* (feat) [#1127](https://github.com/cosmos/interchain-security/pull/1127) Remove consumer panic when ccv channel is closed -* (fix) [#720](https://github.com/cosmos/interchain-security/issues/720) Fix the attribute `AttributeDistributionTotal` value in `FeeDistribution` event emit. -* (deps) [#1119](https://github.com/cosmos/interchain-security/pull/1119) bump cometbft from `v0.37.1` to `0.37.2`. - -## v3.0.0 - -Date: June 21st, 2023 - -Interchain Security v3 uses SDK 0.47 and IBC 7. - -* (fix) [#1093](https://github.com/cosmos/interchain-security/pull/1093) Make SlashPacketData backward compatible when sending data over the wire -* (deps) [#1019](https://github.com/cosmos/interchain-security/pull/1019) Bump multiple dependencies. - * Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to [v0.47.3](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.3). - * Bump [ibc-go](https://github.com/cosmos/ibc-go) to [v7.1.0](https://github.com/cosmos/ibc-go/releases/tag/v7.1.0). - * Bump [CometBFT](https://github.com/cometbft/cometbft) to [v0.37.1](https://github.com/cometbft/cometbft/releases/tag/v0.37.1). -* `[x/ccv/provider]` (fix) [#945](https://github.com/cosmos/interchain-security/issues/945) Refactor `AfterUnbondingInitiated` to not panic when `PutUnbondingOnHold` returns error. -* `[x/ccv/provider]` (fix) [#977](https://github.com/cosmos/interchain-security/pull/977) Avoids panicking the provider when an unbonding delegation was removed through a `CancelUnbondingDelegation` message. -* `[x/ccv/democracy]` (feat) [#1019](https://github.com/cosmos/interchain-security/pull/1019) Whitelisting non-legacy params in the "democracy module" require the entire module to be whitelisted. - -## v2.4.0-lsm - -*November 20, 2023* - -* (fix) [#1439](https://github.com/cosmos/interchain-security/pull/1439) Fix unmarshaling for the CLI consumer double vote cmd. -* (feat!) [#1435](https://github.com/cosmos/interchain-security/pull/1435) Add height-base filter for consumer equivocation evidence. - -## v2.3.0-provider-lsm - -*November 15, 2023* - -❗ *This release is deprecated and should not be used in production.* - -* (fix!) [#1422](https://github.com/cosmos/interchain-security/pull/1422) Fix the misbehaviour handling by verifying the signatures of byzantine validators. - -## v2.2.0-provider-lsm - -❗ *This release is deprecated and should not be used in production.* - -### Cryptographic verification of equivocation -* New feature enabling the provider chain to verify equivocation evidence on its own instead of trusting consumer chains, see [EPIC](https://github.com/cosmos/interchain-security/issues/732). - -## v2.1.0-provider-lsm - -Date: September 15th, 2023 - -* (feature!) [#1280](https://github.com/cosmos/interchain-security/pull/1280) provider proposal for changing reward denoms - -## v2.0.0-lsm - -Date: August 18th, 2023 - -* (deps!) [#1120](https://github.com/cosmos/interchain-security/pull/1120) Bump [Cosmos SDK](https://github.com/cosmos/cosmos-sdk) to [v0.45.16-ics-lsm](https://github.com/cosmos/cosmos-sdk/tree/v0.45.16-ics-lsm). This requires adapting ICS to support this SDK release. Changes are state breaking. -* (fix) [#720](https://github.com/cosmos/interchain-security/issues/720) Fix the attribute `AttributeDistributionTotal` value in `FeeDistribution` event emit. - -## v2.0.0 - -Date: June 1st, 2023 - -Unlike prior releases, the ICS `v2.0.0` release will be based on the main branch. `v2.0.0` will contain all the accumulated PRs from the various releases below, along with other PRs that were merged, but not released to production. After `v2.0.0`, we plan to revamp release practices, and how we modularize the repo for consumer/provider. - -Upgrading a provider from `v1.1.0-multiden` to `v2.0.0` will require state migrations. See [migration.go](https://github.com/cosmos/interchain-security/blob/v2.0.0/x/ccv/provider/keeper/migration.go). - -Upgrading a consumer from `v1.2.0-multiden` to `v2.0.0` will NOT require state migrations. - -Some PRs from v2.0.0 may reappear from other releases below. This is due to the fact that ICS v1.1.0 deviates from the commit ordering of the main branch, and other releases thereafter are based on v1.1.0. - -### High level changes included in v2.0.0 - -* MVP for standalone to consumer changeover, see [EPIC](https://github.com/cosmos/interchain-security/issues/756) -* MVP for soft opt out, see [EPIC](https://github.com/cosmos/interchain-security/issues/851) -* Various fixes, critical and non-critical -* Docs updates which should not affect production code - -## Notable PRs included in v2.0.0 - -* (feat!) Add DistributionTransmissionChannel to ConsumerAdditionProposal [#965](https://github.com/cosmos/interchain-security/pull/965) -* (feat/fix) limit vsc matured packets handled per endblocker [#1004](https://github.com/cosmos/interchain-security/pull/1004) -* (fix) consumer key prefix order to avoid complex migrations [#963](https://github.com/cosmos/interchain-security/pull/963) and [#991](https://github.com/cosmos/interchain-security/pull/991). The latter PR is the proper fix. -* (feat) v1->v2 migrations to accommodate a bugfix having to do with store keys, introduce new params, and deal with consumer genesis state schema changes [#975](https://github.com/cosmos/interchain-security/pull/975) and [#997](https://github.com/cosmos/interchain-security/pull/997) -* (deps) Bump github.com/cosmos/ibc-go/v4 from 4.4.0 to 4.4.2 [#982](https://github.com/cosmos/interchain-security/pull/982) -* (fix) partially revert key assignment type safety PR [#980](https://github.com/cosmos/interchain-security/pull/980) -* (fix) Remove panics on failure to send IBC packets [#876](https://github.com/cosmos/interchain-security/pull/876) -* (fix) Prevent denom DOS [#931](https://github.com/cosmos/interchain-security/pull/931) -* (fix) multisig for assigning consumer key, use json [#916](https://github.com/cosmos/interchain-security/pull/916) -* (deps) Bump github.com/cosmos/ibc-go/v4 from 4.3.0 to 4.4.0 [#902](https://github.com/cosmos/interchain-security/pull/902) -* (feat) Add warnings when provider unbonding is shorter than consumer unbonding [#858](https://github.com/cosmos/interchain-security/pull/858) -* (chore) use go 1.19 [#899](https://github.com/cosmos/interchain-security/pull/899), [#840](https://github.com/cosmos/interchain-security/pull/840) -* (feat) Standalone to consumer changeover - recycle existing transfer channel [#832](https://github.com/cosmos/interchain-security/pull/832) -* (deps) Bump IBC [862](https://github.com/cosmos/interchain-security/pull/862) -* (testing) Add tests for soft opt out [#857](https://github.com/cosmos/interchain-security/pull/857) -* (feat) Standalone to consumer changeover - staking functionalities [#794](https://github.com/cosmos/interchain-security/pull/794) -* (fix) prevent provider from sending VSCPackets with multiple updates for the same validator [#850](https://github.com/cosmos/interchain-security/pull/850) -* (feat) Soft opt out [#833](https://github.com/cosmos/interchain-security/issues/833) -* (fix) Correctly handle VSC packet with duplicate val updates on consumer [#846](https://github.com/cosmos/interchain-security/pull/846) -* (deps) bump sdk to v0.45.15.ics [#805](https://github.com/cosmos/interchain-security/pull/805) -* (refactor) Remove spm module [#812](https://github.com/cosmos/interchain-security/pull/812) -* (feat) Standalone to consumer changeover part 1 [#757](https://github.com/cosmos/interchain-security/pull/757) -* (chore) Swap names of e2e and integration tests [#681](https://github.com/cosmos/interchain-security/pull/681) -* (fix) fix StopConsumerChain not running in cachedContext [#802](https://github.com/cosmos/interchain-security/pull/802). Also in earlier releases with different commit order! -* (docs) Introduce docs website [#759](https://github.com/cosmos/interchain-security/pull/759) -* (fix) Serialize correct byte prefix for SlashLogKey [#786](https://github.com/cosmos/interchain-security/pull/786) -* (feature) Improve keeper field validation [#766](https://github.com/cosmos/interchain-security/pull/766) -* (docs) Contributing guidelines [#744](https://github.com/cosmos/interchain-security/pull/744) -* (refactor) Key assignment type safety [#725](https://github.com/cosmos/interchain-security/pull/725) -* (fix) Update protos and fix deps [#752](https://github.com/cosmos/interchain-security/pull/752) -* (api) Add consumer QueryParams [#746](https://github.com/cosmos/interchain-security/pull/746) -* (feature) New validation for keeper fields [#740](https://github.com/cosmos/interchain-security/pull/740) - -## v1.2.0-multiden - -The first release candidate for a fix built on top of v1.2.0, intended for consumers. This release adds a list of denoms on the consumer that are allowed to be sent to the provider as rewards. This prevents a potential DOS attack that was discovered during the audit of Replicated Security performed by Oak Security and funded by the Cosmos Hub community through Proposal 687. In an effort to move quickly, this release also includes a multisig fix that is effective only for provider. It shouldn't affect the consumer module. - -Note PRs were made in a private security repo. - -[full diff](https://github.com/cosmos/interchain-security/compare/v1.2.0...v1.2.0-multiden-rc0) - -## v1.1.0-multiden - -This release combines two fixes on top of v1.1.0, that we judged were urgent to get onto the Cosmos Hub before the launch of the first ICS consumer chain. This is an emergency release intended for providers. - -The first fix is to enable the use of multisigs and Ledger devices when assigning keys for consumer chains. The second is to prevent a possible DOS vector involving the reward distribution system. - -Note PRs were made in a private security repo. - -[full diff](https://github.com/cosmos/interchain-security/compare/v1.1.0...release/v1.1.0-multiden) - -### Multisig fix - -On April 25th (a week and a half ago), we began receiving reports that validators using multisigs and Ledger devices were getting errors reading Error: unable to resolve type URL /interchain_security.ccv.provider.v1.MsgAssignConsumerKey: tx parse error when attempting to assign consensus keys for consumer chains. - -We quickly narrowed the problem down to issues having to do with using the PubKey type directly in the MsgAssignConsumerKey transaction, and Amino (a deprecated serialization library still used in Ledger devices and multisigs) not being able to handle this. We attempted to fix this with the assistance of the Cosmos-SDK team, but after making no headway for a few days, we decided to simply use a JSON representation of the PubKey in the transaction. This is how it is usually represented anyway. We have verified that this fixes the problem. - -### Distribution fix - -The ICS distribution system works by allowing consumer chains to send rewards to a module address on the provider called the FeePoolAddress. From here they are automatically distributed to all validators and delegators through the distribution system that already exists to distribute staking rewards. The FeePoolAddress is usually blocked so that no tokens can be sent to it, but to enable ICS distribution we had to unblock it. - -We recently realized that unblocking the FeePoolAddress could enable an attacker to send a huge number of different denoms into the distribution system. The distribution system would then attempt to distribute them all, leading to out of memory errors. Fixing a similar attack vector that existed in the distribution system before ICS led us to this realization. - -To fix this problem, we have re-blocked the FeePoolAddress and created a new address called the ConsumerRewardsPool. Consumer chains now send rewards to this new address. There is also a new transaction type called RegisterConsumerRewardDenom. This transaction allows people to register denoms to be used as rewards from consumer chains. It costs 10 Atoms to run this transaction.The Atoms are transferred to the community pool. Only denoms registered with this command are then transferred to the FeePoolAddress and distributed out to delegators and validators. - -## v1.2.1 - -* (fix) Remove SPM [#812](https://github.com/cosmos/interchain-security/pull/812) -* (refactor) Key assignment type safety [#725](https://github.com/cosmos/interchain-security/pull/725) - -## v1.2.0 - -Date: April 13th, 2023 - -* (feat) Soft opt-out [#833](https://github.com/cosmos/interchain-security/pull/833) -* (fix) Correctly handle VSC packet with duplicate val updates on consumer [#846](https://github.com/cosmos/interchain-security/pull/846) -* (chore) bump: sdk v0.45.15-ics [#805](https://github.com/cosmos/interchain-security/pull/805) -* (api) add interchain security consumer QueryParams [#746](https://github.com/cosmos/interchain-security/pull/746) - -## v1.1.1 - -* (fix) Remove SPM [#812](https://github.com/cosmos/interchain-security/pull/812) -* (refactor) Key assignment type safety [#725](https://github.com/cosmos/interchain-security/pull/725) - -## v1.1.0 - -Date: March 24th, 2023 - -* (fix) StopConsumerChain not running in cachedContext [#802](https://github.com/cosmos/interchain-security/pull/802) - -## v1.0.0 - -Date: February 6th, 2023 - -This is the first version of Interchain Security (ICS), also known as _Replicated Security_ (RS). -Replicated Security is a feature which will allow a chain -- referred to as the _provider_ -- to share security with other chains -- referred to as _consumers_. -This means that the provider's validator set will be granted the right to validate consumer chains. -The communication between the provider and the consumer chains is done through the IBC protocol over a unique, ordered channel (one for each consumer chain). Thus, RS is an IBC application. - -### Features / sub-protocols - -RS consist of the following core features: - -- **Channel Initialization**: Enables the provider to add new consumer chains. This process is governance-gated, i.e., to add a new consumer chain, a `ConsumerAdditionProposal` governance proposal must be sent to the provider and it must receive the necessary votes. -- **Validator Set Update**: Enables the provider to - (1) update the consumers on the voting power granted to validators (based on the changes in the active validator set on the provider chain), - and (2) ensure the timely completion of unbonding operations (e.g., undelegations). -- **Consumer Initiated Slashing**: Enables the provider to jail validators for downtime infractions on the consumer chains. -- **Reward Distribution**: Enables the consumers to transfer to the provider (over IBC) a portion of their block rewards as payment for the security provided. Once transferred, these rewards are distributed on the provider using the protocol in the [distribution module of Cosmos SDK](https://docs.cosmos.network/v0.45/modules/distribution/). -- **Consumer Chain Removal**: Enables the provider to remove a consumer either after a `ConsumerRemovalProposal` passes governance or after one of the timeout periods elapses -- `InitTimeoutPeriod`, `VscTimeoutPeriod`, `IBCTimeoutPeriod`. -- **Social Slashing**: Equivocation offenses (double signing etc.) on consumer chains are logged, and then can be used in a governance proposal to slash the validators responsible. - -In addition, RS has the following features: - -- **Key Assignment**: Enables validator operators to use different consensus keys for each consumer chain validator node that they operate. -- **Jail Throttling**: Enables the provider to slow down a "worst case scenario" attack where a malicious consumer binary attempts to jail a significant amount (> 2/3) of the voting power, effectively taking control of the provider. \ No newline at end of file +[CHANGELOG of previous versions](https://github.com/cosmos/interchain-security/blob/main/CHANGELOG.md) \ No newline at end of file diff --git a/.changelog/v3.2.0/bug-fixes/consumer/1146-pending-packets.md b/.changelog/v3.2.0/bug-fixes/consumer/1146-pending-packets.md deleted file mode 100644 index 0bab707fec..0000000000 --- a/.changelog/v3.2.0/bug-fixes/consumer/1146-pending-packets.md +++ /dev/null @@ -1,2 +0,0 @@ -- Fix deletion of pending packets that may cause duplicate sends - ([\#1146](https://github.com/cosmos/interchain-security/pull/1146)) \ No newline at end of file diff --git a/.changelog/v3.2.0/bug-fixes/consumer/1150-revert-wire-breaking.md b/.changelog/v3.2.0/bug-fixes/consumer/1150-revert-wire-breaking.md deleted file mode 100644 index 067448e770..0000000000 --- a/.changelog/v3.2.0/bug-fixes/consumer/1150-revert-wire-breaking.md +++ /dev/null @@ -1,2 +0,0 @@ -- Remove `idx` field from the `ccv.ConsumerPacketData` type as this would break the - wire ([\#1150](https://github.com/cosmos/interchain-security/pull/1150)) \ No newline at end of file diff --git a/.changelog/v3.2.0/bug-fixes/consumer/1244-validate-transfer.md b/.changelog/v3.2.0/bug-fixes/consumer/1244-validate-transfer.md deleted file mode 100644 index 2d94c79c75..0000000000 --- a/.changelog/v3.2.0/bug-fixes/consumer/1244-validate-transfer.md +++ /dev/null @@ -1,2 +0,0 @@ -- Validate token transfer messages before calling `Transfer()`. - ([\#1244](https://github.com/cosmos/interchain-security/pull/1244)) \ No newline at end of file diff --git a/.changelog/v3.2.0/bug-fixes/consumer/1262-fee-pool-addr.md b/.changelog/v3.2.0/bug-fixes/consumer/1262-fee-pool-addr.md deleted file mode 100644 index bbb54db2e3..0000000000 --- a/.changelog/v3.2.0/bug-fixes/consumer/1262-fee-pool-addr.md +++ /dev/null @@ -1,2 +0,0 @@ -- Remove incorrect address validation on `ProviderFeePoolAddrStr` param. - ([\#1262](https://github.com/cosmos/interchain-security/pull/1262)) \ No newline at end of file diff --git a/.changelog/v3.2.0/bug-fixes/consumer/1295-migration.md b/.changelog/v3.2.0/bug-fixes/consumer/1295-migration.md deleted file mode 100644 index 739b08dc39..0000000000 --- a/.changelog/v3.2.0/bug-fixes/consumer/1295-migration.md +++ /dev/null @@ -1,2 +0,0 @@ -- Increment consumer consensus version and register consumer migration. - ([\#1295](https://github.com/cosmos/interchain-security/pull/1295)) \ No newline at end of file diff --git a/.changelog/v3.2.0/dependencies/1196-bump-ibc.md b/.changelog/v3.2.0/dependencies/1196-bump-ibc.md deleted file mode 100644 index fcf4450150..0000000000 --- a/.changelog/v3.2.0/dependencies/1196-bump-ibc.md +++ /dev/null @@ -1,3 +0,0 @@ -- Bump [ibc-go](https://github.com/cosmos/ibc-go) to - [v7.2.0](https://github.com/cosmos/ibc-go/releases/tag/v7.2.0). - ([\#1196](https://github.com/cosmos/interchain-security/pull/1196)) \ No newline at end of file diff --git a/.changelog/v3.2.0/dependencies/1258-bump-ibc.md b/.changelog/v3.2.0/dependencies/1258-bump-ibc.md deleted file mode 100644 index 68c6e2b104..0000000000 --- a/.changelog/v3.2.0/dependencies/1258-bump-ibc.md +++ /dev/null @@ -1,3 +0,0 @@ -- Bump [ibc-go](https://github.com/cosmos/ibc-go) to - [v7.3.0](https://github.com/cosmos/ibc-go/releases/tag/v7.3.0). - ([\#1258](https://github.com/cosmos/interchain-security/pull/1258)) \ No newline at end of file diff --git a/.changelog/v3.2.0/dependencies/1258-bump-sdk.md b/.changelog/v3.2.0/dependencies/1258-bump-sdk.md deleted file mode 100644 index 7344fac97e..0000000000 --- a/.changelog/v3.2.0/dependencies/1258-bump-sdk.md +++ /dev/null @@ -1,3 +0,0 @@ -- Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to - [v0.47.4](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.4). - ([\#1258](https://github.com/cosmos/interchain-security/pull/1258)) \ No newline at end of file diff --git a/.changelog/v3.2.0/dependencies/1259-bump-sdk.md b/.changelog/v3.2.0/dependencies/1259-bump-sdk.md deleted file mode 100644 index 247c623b7d..0000000000 --- a/.changelog/v3.2.0/dependencies/1259-bump-sdk.md +++ /dev/null @@ -1,3 +0,0 @@ -- Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to - [v0.47.5](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.5). - ([\#1259](https://github.com/cosmos/interchain-security/pull/1259)) \ No newline at end of file diff --git a/.changelog/v3.2.0/features/consumer/1024-jail-throttling-v2.md b/.changelog/v3.2.0/features/consumer/1024-jail-throttling-v2.md deleted file mode 100644 index 7570facb34..0000000000 --- a/.changelog/v3.2.0/features/consumer/1024-jail-throttling-v2.md +++ /dev/null @@ -1,2 +0,0 @@ -- Add the consumer-side changes for jail throttling with retries (cf. ADR 008). - ([\#1024](https://github.com/cosmos/interchain-security/pull/1024)) \ No newline at end of file diff --git a/.changelog/v3.2.0/features/consumer/1164-provider-info-query.md b/.changelog/v3.2.0/features/consumer/1164-provider-info-query.md deleted file mode 100644 index fc1d27b964..0000000000 --- a/.changelog/v3.2.0/features/consumer/1164-provider-info-query.md +++ /dev/null @@ -1,4 +0,0 @@ -- Introduce the gRPC query `/interchain_security/ccv/consumer/provider- - info` and CLI command `interchain-security-cd q ccvconsumer - provider-info` to retrieve provider info from the consumer chain. - ([\#1164](https://github.com/cosmos/interchain-security/pull/1164)) \ No newline at end of file diff --git a/.changelog/v3.2.0/features/provider/1076-export-timestamps.md b/.changelog/v3.2.0/features/provider/1076-export-timestamps.md deleted file mode 100644 index f2a8608f8b..0000000000 --- a/.changelog/v3.2.0/features/provider/1076-export-timestamps.md +++ /dev/null @@ -1,2 +0,0 @@ -- Add `InitTimeoutTimestamps` and `ExportedVscSendTimestamps` to exported - genesis. ([\#1076](https://github.com/cosmos/interchain-security/pull/1076)) \ No newline at end of file diff --git a/.changelog/v3.2.0/features/provider/1280-reward-denoms.md b/.changelog/v3.2.0/features/provider/1280-reward-denoms.md deleted file mode 100644 index c1f3659a44..0000000000 --- a/.changelog/v3.2.0/features/provider/1280-reward-denoms.md +++ /dev/null @@ -1,3 +0,0 @@ -- Add a governance proposal for setting on the provider the denominations for - rewards from consumer chains. - ([\#1280](https://github.com/cosmos/interchain-security/pull/1280)) \ No newline at end of file diff --git a/.changelog/v3.2.0/improvements/1244-consumer-unbonding.md b/.changelog/v3.2.0/improvements/1244-consumer-unbonding.md deleted file mode 100644 index 4a8504e4ce..0000000000 --- a/.changelog/v3.2.0/improvements/1244-consumer-unbonding.md +++ /dev/null @@ -1,2 +0,0 @@ -- Update the default consumer unbonding period to 2 weeks. - ([\#1244](https://github.com/cosmos/interchain-security/pull/1244)) \ No newline at end of file diff --git a/.changelog/v3.2.0/improvements/consumer/1037-optimize-storage.md b/.changelog/v3.2.0/improvements/consumer/1037-optimize-storage.md deleted file mode 100644 index 726906420b..0000000000 --- a/.changelog/v3.2.0/improvements/consumer/1037-optimize-storage.md +++ /dev/null @@ -1,2 +0,0 @@ -- Optimize pending packets storage on consumer, with migration. - ([\#1037](https://github.com/cosmos/interchain-security/pull/1037)) \ No newline at end of file diff --git a/.changelog/v3.2.0/state-breaking/1196-bump-ibc.md b/.changelog/v3.2.0/state-breaking/1196-bump-ibc.md deleted file mode 100644 index fcf4450150..0000000000 --- a/.changelog/v3.2.0/state-breaking/1196-bump-ibc.md +++ /dev/null @@ -1,3 +0,0 @@ -- Bump [ibc-go](https://github.com/cosmos/ibc-go) to - [v7.2.0](https://github.com/cosmos/ibc-go/releases/tag/v7.2.0). - ([\#1196](https://github.com/cosmos/interchain-security/pull/1196)) \ No newline at end of file diff --git a/.changelog/v3.2.0/state-breaking/1244-consumer-unbonding.md b/.changelog/v3.2.0/state-breaking/1244-consumer-unbonding.md deleted file mode 100644 index 4a8504e4ce..0000000000 --- a/.changelog/v3.2.0/state-breaking/1244-consumer-unbonding.md +++ /dev/null @@ -1,2 +0,0 @@ -- Update the default consumer unbonding period to 2 weeks. - ([\#1244](https://github.com/cosmos/interchain-security/pull/1244)) \ No newline at end of file diff --git a/.changelog/v3.2.0/state-breaking/1258-bump-ibc.md b/.changelog/v3.2.0/state-breaking/1258-bump-ibc.md deleted file mode 100644 index 68c6e2b104..0000000000 --- a/.changelog/v3.2.0/state-breaking/1258-bump-ibc.md +++ /dev/null @@ -1,3 +0,0 @@ -- Bump [ibc-go](https://github.com/cosmos/ibc-go) to - [v7.3.0](https://github.com/cosmos/ibc-go/releases/tag/v7.3.0). - ([\#1258](https://github.com/cosmos/interchain-security/pull/1258)) \ No newline at end of file diff --git a/.changelog/v3.2.0/state-breaking/1258-bump-sdk.md b/.changelog/v3.2.0/state-breaking/1258-bump-sdk.md deleted file mode 100644 index 7344fac97e..0000000000 --- a/.changelog/v3.2.0/state-breaking/1258-bump-sdk.md +++ /dev/null @@ -1,3 +0,0 @@ -- Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to - [v0.47.4](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.4). - ([\#1258](https://github.com/cosmos/interchain-security/pull/1258)) \ No newline at end of file diff --git a/.changelog/v3.2.0/state-breaking/1259-bump-sdk.md b/.changelog/v3.2.0/state-breaking/1259-bump-sdk.md deleted file mode 100644 index 247c623b7d..0000000000 --- a/.changelog/v3.2.0/state-breaking/1259-bump-sdk.md +++ /dev/null @@ -1,3 +0,0 @@ -- Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to - [v0.47.5](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.5). - ([\#1259](https://github.com/cosmos/interchain-security/pull/1259)) \ No newline at end of file diff --git a/.changelog/v3.2.0/state-breaking/consumer/1024-jail-throttling-v2.md b/.changelog/v3.2.0/state-breaking/consumer/1024-jail-throttling-v2.md deleted file mode 100644 index 7570facb34..0000000000 --- a/.changelog/v3.2.0/state-breaking/consumer/1024-jail-throttling-v2.md +++ /dev/null @@ -1,2 +0,0 @@ -- Add the consumer-side changes for jail throttling with retries (cf. ADR 008). - ([\#1024](https://github.com/cosmos/interchain-security/pull/1024)) \ No newline at end of file diff --git a/.changelog/v3.2.0/state-breaking/consumer/1037-optimize-storage.md b/.changelog/v3.2.0/state-breaking/consumer/1037-optimize-storage.md deleted file mode 100644 index 726906420b..0000000000 --- a/.changelog/v3.2.0/state-breaking/consumer/1037-optimize-storage.md +++ /dev/null @@ -1,2 +0,0 @@ -- Optimize pending packets storage on consumer, with migration. - ([\#1037](https://github.com/cosmos/interchain-security/pull/1037)) \ No newline at end of file diff --git a/.changelog/v3.2.0/state-breaking/consumer/1146-pending-packets.md b/.changelog/v3.2.0/state-breaking/consumer/1146-pending-packets.md deleted file mode 100644 index a10d75a505..0000000000 --- a/.changelog/v3.2.0/state-breaking/consumer/1146-pending-packets.md +++ /dev/null @@ -1,2 +0,0 @@ -- Fix deletion of pending packets that may cause duplicate sends - ([\#1146](https://github.com/cosmos/interchain-security/pull/1146)) \ No newline at end of file diff --git a/.changelog/v3.2.0/state-breaking/consumer/1150-revert-wire-breaking.md b/.changelog/v3.2.0/state-breaking/consumer/1150-revert-wire-breaking.md deleted file mode 100644 index 067448e770..0000000000 --- a/.changelog/v3.2.0/state-breaking/consumer/1150-revert-wire-breaking.md +++ /dev/null @@ -1,2 +0,0 @@ -- Remove `idx` field from the `ccv.ConsumerPacketData` type as this would break the - wire ([\#1150](https://github.com/cosmos/interchain-security/pull/1150)) \ No newline at end of file diff --git a/.changelog/v3.2.0/state-breaking/consumer/1244-validate-transfer.md b/.changelog/v3.2.0/state-breaking/consumer/1244-validate-transfer.md deleted file mode 100644 index 2d94c79c75..0000000000 --- a/.changelog/v3.2.0/state-breaking/consumer/1244-validate-transfer.md +++ /dev/null @@ -1,2 +0,0 @@ -- Validate token transfer messages before calling `Transfer()`. - ([\#1244](https://github.com/cosmos/interchain-security/pull/1244)) \ No newline at end of file diff --git a/.changelog/v3.2.0/state-breaking/consumer/1262-fee-pool-addr.md b/.changelog/v3.2.0/state-breaking/consumer/1262-fee-pool-addr.md deleted file mode 100644 index bbb54db2e3..0000000000 --- a/.changelog/v3.2.0/state-breaking/consumer/1262-fee-pool-addr.md +++ /dev/null @@ -1,2 +0,0 @@ -- Remove incorrect address validation on `ProviderFeePoolAddrStr` param. - ([\#1262](https://github.com/cosmos/interchain-security/pull/1262)) \ No newline at end of file diff --git a/.changelog/v3.2.0/state-breaking/consumer/1295-migration.md b/.changelog/v3.2.0/state-breaking/consumer/1295-migration.md deleted file mode 100644 index 739b08dc39..0000000000 --- a/.changelog/v3.2.0/state-breaking/consumer/1295-migration.md +++ /dev/null @@ -1,2 +0,0 @@ -- Increment consumer consensus version and register consumer migration. - ([\#1295](https://github.com/cosmos/interchain-security/pull/1295)) \ No newline at end of file diff --git a/.changelog/v3.2.0/state-breaking/provider/1280-reward-denoms.md b/.changelog/v3.2.0/state-breaking/provider/1280-reward-denoms.md deleted file mode 100644 index c1f3659a44..0000000000 --- a/.changelog/v3.2.0/state-breaking/provider/1280-reward-denoms.md +++ /dev/null @@ -1,3 +0,0 @@ -- Add a governance proposal for setting on the provider the denominations for - rewards from consumer chains. - ([\#1280](https://github.com/cosmos/interchain-security/pull/1280)) \ No newline at end of file diff --git a/.changelog/v3.2.0/summary.md b/.changelog/v3.2.0/summary.md deleted file mode 100644 index e7b2c7d6d4..0000000000 --- a/.changelog/v3.2.0/summary.md +++ /dev/null @@ -1 +0,0 @@ -*November 24, 2023* diff --git a/.changelog/v3.3.0/api-breaking/provider/1340-add-cryptographic-verification-of-equivocation-feature.md b/.changelog/v3.3.0/api-breaking/provider/1340-add-cryptographic-verification-of-equivocation-feature.md deleted file mode 100644 index c50662be72..0000000000 --- a/.changelog/v3.3.0/api-breaking/provider/1340-add-cryptographic-verification-of-equivocation-feature.md +++ /dev/null @@ -1,2 +0,0 @@ -- Deprecate equivocation proposals. -([\#1340](https://github.com/cosmos/interchain-security/pull/1340)) \ No newline at end of file diff --git a/.changelog/v3.3.0/dependencies/1373-bump-ibc.md b/.changelog/v3.3.0/dependencies/1373-bump-ibc.md deleted file mode 100644 index efe4e0c286..0000000000 --- a/.changelog/v3.3.0/dependencies/1373-bump-ibc.md +++ /dev/null @@ -1,3 +0,0 @@ -- Bump [ibc-go](https://github.com/cosmos/ibc-go) to - [v7.3.1](https://github.com/cosmos/ibc-go/releases/tag/v7.3.1). - ([\#1373](https://github.com/cosmos/interchain-security/pull/1373)) \ No newline at end of file diff --git a/.changelog/v3.3.0/features/1336-quint-model.md b/.changelog/v3.3.0/features/1336-quint-model.md deleted file mode 100644 index 96c4562b32..0000000000 --- a/.changelog/v3.3.0/features/1336-quint-model.md +++ /dev/null @@ -1,2 +0,0 @@ -- Add Quint model of Replicated Security. - ([\#1336](https://github.com/cosmos/interchain-security/pull/1336)) \ No newline at end of file diff --git a/.changelog/v3.3.0/features/provider/1339-check-key-assignment-in-use.md b/.changelog/v3.3.0/features/provider/1339-check-key-assignment-in-use.md deleted file mode 100644 index 9f274f7bb4..0000000000 --- a/.changelog/v3.3.0/features/provider/1339-check-key-assignment-in-use.md +++ /dev/null @@ -1,3 +0,0 @@ -- Update how consumer-assigned keys are checked when a validator is - created on the provider. - ([\#1339](https://github.com/cosmos/interchain-security/pull/1339)) \ No newline at end of file diff --git a/.changelog/v3.3.0/features/provider/1340-cryptographic-equivocation-feature.md b/.changelog/v3.3.0/features/provider/1340-cryptographic-equivocation-feature.md deleted file mode 100644 index 5437fba186..0000000000 --- a/.changelog/v3.3.0/features/provider/1340-cryptographic-equivocation-feature.md +++ /dev/null @@ -1,4 +0,0 @@ -- Introduce the cryptographic verification of equivocation feature to the provider - (cf. [ADR-005](docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md) - & [ADR-013](docs/docs/adrs/adr-013-equivocation-slashing.md)). - ([\#1340](https://github.com/cosmos/interchain-security/pull/1340)) \ No newline at end of file diff --git a/.changelog/v3.3.0/improvements/1324-consumer-genesis.md b/.changelog/v3.3.0/improvements/1324-consumer-genesis.md deleted file mode 100644 index a727be8341..0000000000 --- a/.changelog/v3.3.0/improvements/1324-consumer-genesis.md +++ /dev/null @@ -1,16 +0,0 @@ -- Split out consumer genesis state to reduce shared data between provider and - consumer. ([\#1324](https://github.com/cosmos/interchain-security/pull/1324)) - - Note: This breaks json format used by augmenting Genesis files of consumer - chains with consumer genesis content exported from provider chain. Consumer - Genesis content exported from a provider chain using major version 1, 2 or 3 - of the provider module needs to be transformed with the transformation command - introduced by this PR: - ``` - Transform the consumer genesis file from a provider version v1, v2 or v3 to a version supported by this consumer. Result is printed to STDOUT. - - Example: - $ transform /path/to/ccv_consumer_genesis.json - - Usage: - interchain-security-cd genesis transform [genesis-file] [flags] - ``` \ No newline at end of file diff --git a/.changelog/v3.3.0/improvements/1350-cleanup-types.md b/.changelog/v3.3.0/improvements/1350-cleanup-types.md deleted file mode 100644 index 6e26fc3992..0000000000 --- a/.changelog/v3.3.0/improvements/1350-cleanup-types.md +++ /dev/null @@ -1,3 +0,0 @@ -- Refactor shared events, codecs and errors assign to - consumer and provider dedicated types where possible. - ([\#1350](https://github.com/cosmos/interchain-security/pull/1350)) \ No newline at end of file diff --git a/.changelog/v3.3.0/improvements/provider/1503-query-key-assignment.md b/.changelog/v3.3.0/improvements/provider/1503-query-key-assignment.md deleted file mode 100644 index 62b505ec01..0000000000 --- a/.changelog/v3.3.0/improvements/provider/1503-query-key-assignment.md +++ /dev/null @@ -1 +0,0 @@ -- Add `QueryAllPairsValConAddrByConsumerChainID` method to get list of all pairs `valConsensus` address by `Consummer chainID`. ([\#1503](https://github.com/cosmos/interchain-security/pull/1503)) \ No newline at end of file diff --git a/.changelog/v3.3.0/state-breaking/1324-consumer-genesis.md b/.changelog/v3.3.0/state-breaking/1324-consumer-genesis.md deleted file mode 100644 index b47f7199fd..0000000000 --- a/.changelog/v3.3.0/state-breaking/1324-consumer-genesis.md +++ /dev/null @@ -1,2 +0,0 @@ -- Split out consumer genesis state to reduce shared data between provider and - consumer. ([\#1324](https://github.com/cosmos/interchain-security/pull/1324)) \ No newline at end of file diff --git a/.changelog/v3.3.0/state-breaking/1460-msg-validation.md b/.changelog/v3.3.0/state-breaking/1460-msg-validation.md deleted file mode 100644 index 46d18bd4c9..0000000000 --- a/.changelog/v3.3.0/state-breaking/1460-msg-validation.md +++ /dev/null @@ -1,3 +0,0 @@ -- Improve validation of IBC packet data and provider messages. Also, - enable the provider to validate consumer packets before handling them. - ([\#1460](https://github.com/cosmos/interchain-security/pull/1460)) \ No newline at end of file diff --git a/.changelog/v3.3.0/state-breaking/provider/1339-check-key-assignment-in-use.md b/.changelog/v3.3.0/state-breaking/provider/1339-check-key-assignment-in-use.md deleted file mode 100644 index 2890582ba8..0000000000 --- a/.changelog/v3.3.0/state-breaking/provider/1339-check-key-assignment-in-use.md +++ /dev/null @@ -1,3 +0,0 @@ -- Change the states by adding a consumer key for each chain that is - not yet registered meaning for which the gov proposal has not passed. - ([\#1339](https://github.com/cosmos/interchain-security/pull/1339)) \ No newline at end of file diff --git a/.changelog/v3.3.0/state-breaking/provider/1340-cryptographic-equivocation-feature.md b/.changelog/v3.3.0/state-breaking/provider/1340-cryptographic-equivocation-feature.md deleted file mode 100644 index 5437fba186..0000000000 --- a/.changelog/v3.3.0/state-breaking/provider/1340-cryptographic-equivocation-feature.md +++ /dev/null @@ -1,4 +0,0 @@ -- Introduce the cryptographic verification of equivocation feature to the provider - (cf. [ADR-005](docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md) - & [ADR-013](docs/docs/adrs/adr-013-equivocation-slashing.md)). - ([\#1340](https://github.com/cosmos/interchain-security/pull/1340)) \ No newline at end of file diff --git a/.changelog/v3.3.0/summary.md b/.changelog/v3.3.0/summary.md deleted file mode 100644 index e556c0f0ca..0000000000 --- a/.changelog/v3.3.0/summary.md +++ /dev/null @@ -1 +0,0 @@ -*January 5, 2024* From 9991d43b3f357f0352819eda6e56c6b6fc033d39 Mon Sep 17 00:00:00 2001 From: Marius Poke Date: Thu, 11 Jan 2024 15:40:13 +0100 Subject: [PATCH 002/110] docs: changelog and release notes for v4.0.0 (#1564) * add v4.0.0 section to changelog * add release notes --- .changelog/unreleased/.gitkeep | 0 .../unreleased/dependencies/1663-bump-sdk.md | 3 - CHANGELOG.md | 363 ++---------------- RELEASE_NOTES.md | 36 +- 4 files changed, 34 insertions(+), 368 deletions(-) create mode 100644 .changelog/unreleased/.gitkeep delete mode 100644 .changelog/unreleased/dependencies/1663-bump-sdk.md diff --git a/.changelog/unreleased/.gitkeep b/.changelog/unreleased/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/.changelog/unreleased/dependencies/1663-bump-sdk.md b/.changelog/unreleased/dependencies/1663-bump-sdk.md deleted file mode 100644 index a4d2a6bd9c..0000000000 --- a/.changelog/unreleased/dependencies/1663-bump-sdk.md +++ /dev/null @@ -1,3 +0,0 @@ -- Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to - [v0.47.10](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.10). - ([\#1663](https://github.com/cosmos/interchain-security/pull/1663)) \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d46f32447..eb6be888e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,366 +56,55 @@ ## v3.3.0 -*January 5, 2024* +*January 11, 2024* ### API BREAKING -- [Provider](x/ccv/provider) - - Deprecate equivocation proposals. - ([\#1340](https://github.com/cosmos/interchain-security/pull/1340)) - -### DEPENDENCIES - -- Bump [ibc-go](https://github.com/cosmos/ibc-go) to - [v7.3.1](https://github.com/cosmos/ibc-go/releases/tag/v7.3.1). - ([\#1373](https://github.com/cosmos/interchain-security/pull/1373)) - -### FEATURES - -- General - - Add Quint model of Replicated Security. - ([\#1336](https://github.com/cosmos/interchain-security/pull/1336)) -- [Provider](x/ccv/provider) - - Update how consumer-assigned keys are checked when a validator is - created on the provider. - ([\#1339](https://github.com/cosmos/interchain-security/pull/1339)) - - Introduce the cryptographic verification of equivocation feature to the provider - (cf. [ADR-005](docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md) - & [ADR-013](docs/docs/adrs/adr-013-equivocation-slashing.md)). - ([\#1340](https://github.com/cosmos/interchain-security/pull/1340)) - -### IMPROVEMENTS - -- General - - Split out consumer genesis state to reduce shared data between provider and - consumer. ([\#1324](https://github.com/cosmos/interchain-security/pull/1324)) - - Note: This breaks json format used by augmenting Genesis files of consumer - chains with consumer genesis content exported from provider chain. Consumer - Genesis content exported from a provider chain using major version 1, 2 or 3 - of the provider module needs to be transformed with the transformation command - introduced by this PR: - ``` - Transform the consumer genesis file from a provider version v1, v2 or v3 to a version supported by this consumer. Result is printed to STDOUT. - - Example: - $ transform /path/to/ccv_consumer_genesis.json - - Usage: - interchain-security-cd genesis transform [genesis-file] [flags] - ``` - - Refactor shared events, codecs and errors assign to - consumer and provider dedicated types where possible. - ([\#1350](https://github.com/cosmos/interchain-security/pull/1350)) -- [Provider](x/ccv/provider) - - Add `QueryAllPairsValConAddrByConsumerChainID` method to get list of all pairs `valConsensus` address by `Consummer chainID`. ([\#1503](https://github.com/cosmos/interchain-security/pull/1503)) +- [Consumer](x/ccv/consumer) + - Fix a bug in consmer genesis file transform CLI command. + ([\#1458](https://github.com/cosmos/interchain-security/pull/1458)) -### STATE BREAKING +### BUG FIXES - General - - Split out consumer genesis state to reduce shared data between provider and - consumer. ([\#1324](https://github.com/cosmos/interchain-security/pull/1324)) + - Fix a bug in consmer genesis file transform CLI command. + ([\#1458](https://github.com/cosmos/interchain-security/pull/1458)) - Improve validation of IBC packet data and provider messages. Also, enable the provider to validate consumer packets before handling them. ([\#1460](https://github.com/cosmos/interchain-security/pull/1460)) -- [Provider](x/ccv/provider) - - Change the states by adding a consumer key for each chain that is - not yet registered meaning for which the gov proposal has not passed. - ([\#1339](https://github.com/cosmos/interchain-security/pull/1339)) - - Introduce the cryptographic verification of equivocation feature to the provider - (cf. [ADR-005](docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md) - & [ADR-013](docs/docs/adrs/adr-013-equivocation-slashing.md)). - ([\#1340](https://github.com/cosmos/interchain-security/pull/1340)) - -## v3.2.0 - -*November 24, 2023* - -### BUG FIXES - - [Consumer](x/ccv/consumer) - - Fix deletion of pending packets that may cause duplicate sends - ([\#1146](https://github.com/cosmos/interchain-security/pull/1146)) - - Remove `idx` field from the `ccv.ConsumerPacketData` type as this would break the - wire ([\#1150](https://github.com/cosmos/interchain-security/pull/1150)) - - Validate token transfer messages before calling `Transfer()`. - ([\#1244](https://github.com/cosmos/interchain-security/pull/1244)) - - Remove incorrect address validation on `ProviderFeePoolAddrStr` param. - ([\#1262](https://github.com/cosmos/interchain-security/pull/1262)) - - Increment consumer consensus version and register consumer migration. - ([\#1295](https://github.com/cosmos/interchain-security/pull/1295)) + - Avoid jailing validators immediately once they can no longer opt-out from + validating consumer chains. + ([\#1549](https://github.com/cosmos/interchain-security/pull/1549)) ### DEPENDENCIES -- Bump [ibc-go](https://github.com/cosmos/ibc-go) to - [v7.2.0](https://github.com/cosmos/ibc-go/releases/tag/v7.2.0). - ([\#1196](https://github.com/cosmos/interchain-security/pull/1196)) -- Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to - [v0.47.4](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.4). - ([\#1258](https://github.com/cosmos/interchain-security/pull/1258)) -- Bump [ibc-go](https://github.com/cosmos/ibc-go) to - [v7.3.0](https://github.com/cosmos/ibc-go/releases/tag/v7.3.0). - ([\#1258](https://github.com/cosmos/interchain-security/pull/1258)) +- Bump Golang to v1.21 + ([\#1557](https://github.com/cosmos/interchain-security/pull/1557)) - Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to - [v0.47.5](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.5). - ([\#1259](https://github.com/cosmos/interchain-security/pull/1259)) + [v0.47.7](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.7). + ([\#1558](https://github.com/cosmos/interchain-security/pull/1558)) +- Bump [CometBFT](https://github.com/cometbft/cometbft) to + [v0.37.4](https://github.com/cometbft/cometbft/releases/tag/v0.37.4). + ([\#1558](https://github.com/cosmos/interchain-security/pull/1558)) ### FEATURES -- [Consumer](x/ccv/consumer) - - Add the consumer-side changes for jail throttling with retries (cf. ADR 008). - ([\#1024](https://github.com/cosmos/interchain-security/pull/1024)) - - Introduce the gRPC query `/interchain_security/ccv/consumer/provider- - info` and CLI command `interchain-security-cd q ccvconsumer - provider-info` to retrieve provider info from the consumer chain. - ([\#1164](https://github.com/cosmos/interchain-security/pull/1164)) - [Provider](x/ccv/provider) - - Add `InitTimeoutTimestamps` and `ExportedVscSendTimestamps` to exported - genesis. ([\#1076](https://github.com/cosmos/interchain-security/pull/1076)) - - Add a governance proposal for setting on the provider the denominations for - rewards from consumer chains. - ([\#1280](https://github.com/cosmos/interchain-security/pull/1280)) - -### IMPROVEMENTS - -- General - - Update the default consumer unbonding period to 2 weeks. - ([\#1244](https://github.com/cosmos/interchain-security/pull/1244)) -- [Consumer](x/ccv/consumer) - - Optimize pending packets storage on consumer, with migration. - ([\#1037](https://github.com/cosmos/interchain-security/pull/1037)) + - Add the provider-side changes for jail throttling with retries (cf. ADR 008). + ([\#1321](https://github.com/cosmos/interchain-security/pull/1321)) ### STATE BREAKING -- General - - Bump [ibc-go](https://github.com/cosmos/ibc-go) to - [v7.2.0](https://github.com/cosmos/ibc-go/releases/tag/v7.2.0). - ([\#1196](https://github.com/cosmos/interchain-security/pull/1196)) - - Update the default consumer unbonding period to 2 weeks. - ([\#1244](https://github.com/cosmos/interchain-security/pull/1244)) - - Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to - [v0.47.4](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.4). - ([\#1258](https://github.com/cosmos/interchain-security/pull/1258)) - - Bump [ibc-go](https://github.com/cosmos/ibc-go) to - [v7.3.0](https://github.com/cosmos/ibc-go/releases/tag/v7.3.0). - ([\#1258](https://github.com/cosmos/interchain-security/pull/1258)) - - Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to - [v0.47.5](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.5). - ([\#1259](https://github.com/cosmos/interchain-security/pull/1259)) - [Consumer](x/ccv/consumer) - - Add the consumer-side changes for jail throttling with retries (cf. ADR 008). - ([\#1024](https://github.com/cosmos/interchain-security/pull/1024)) - - Optimize pending packets storage on consumer, with migration. - ([\#1037](https://github.com/cosmos/interchain-security/pull/1037)) - - Fix deletion of pending packets that may cause duplicate sends - ([\#1146](https://github.com/cosmos/interchain-security/pull/1146)) - - Remove `idx` field from the `ccv.ConsumerPacketData` type as this would break the - wire ([\#1150](https://github.com/cosmos/interchain-security/pull/1150)) - - Validate token transfer messages before calling `Transfer()`. - ([\#1244](https://github.com/cosmos/interchain-security/pull/1244)) - - Remove incorrect address validation on `ProviderFeePoolAddrStr` param. - ([\#1262](https://github.com/cosmos/interchain-security/pull/1262)) - - Increment consumer consensus version and register consumer migration. - ([\#1295](https://github.com/cosmos/interchain-security/pull/1295)) + - Avoid jailing validators immediately once they can no longer opt-out from + validating consumer chains. + ([\#1549](https://github.com/cosmos/interchain-security/pull/1549)) - [Provider](x/ccv/provider) - - Add a governance proposal for setting on the provider the denominations for - rewards from consumer chains. - ([\#1280](https://github.com/cosmos/interchain-security/pull/1280)) - -## v3.1.0 - -Date July 11th, 2023 - -A minor upgrade to v3.0.0, which removes the panic in the consumer ccv module which would occur in an emergency scenario where the ccv channel is closed. This release also fixes how a distribution related event is emitted, and bumps cometbft. - -* (feat) [#1127](https://github.com/cosmos/interchain-security/pull/1127) Remove consumer panic when ccv channel is closed -* (fix) [#720](https://github.com/cosmos/interchain-security/issues/720) Fix the attribute `AttributeDistributionTotal` value in `FeeDistribution` event emit. -* (deps) [#1119](https://github.com/cosmos/interchain-security/pull/1119) bump cometbft from `v0.37.1` to `0.37.2`. - -## v3.0.0 - -Date: June 21st, 2023 - -Interchain Security v3 uses SDK 0.47 and IBC 7. - -* (fix) [#1093](https://github.com/cosmos/interchain-security/pull/1093) Make SlashPacketData backward compatible when sending data over the wire -* (deps) [#1019](https://github.com/cosmos/interchain-security/pull/1019) Bump multiple dependencies. - * Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to [v0.47.3](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.3). - * Bump [ibc-go](https://github.com/cosmos/ibc-go) to [v7.1.0](https://github.com/cosmos/ibc-go/releases/tag/v7.1.0). - * Bump [CometBFT](https://github.com/cometbft/cometbft) to [v0.37.1](https://github.com/cometbft/cometbft/releases/tag/v0.37.1). -* `[x/ccv/provider]` (fix) [#945](https://github.com/cosmos/interchain-security/issues/945) Refactor `AfterUnbondingInitiated` to not panic when `PutUnbondingOnHold` returns error. -* `[x/ccv/provider]` (fix) [#977](https://github.com/cosmos/interchain-security/pull/977) Avoids panicking the provider when an unbonding delegation was removed through a `CancelUnbondingDelegation` message. -* `[x/ccv/democracy]` (feat) [#1019](https://github.com/cosmos/interchain-security/pull/1019) Whitelisting non-legacy params in the "democracy module" require the entire module to be whitelisted. - -## v2.4.0-lsm - -*November 20, 2023* - -* (fix) [#1439](https://github.com/cosmos/interchain-security/pull/1439) Fix unmarshaling for the CLI consumer double vote cmd. -* (feat!) [#1435](https://github.com/cosmos/interchain-security/pull/1435) Add height-base filter for consumer equivocation evidence. - -## v2.3.0-provider-lsm - -*November 15, 2023* - -❗ *This release is deprecated and should not be used in production.* - -* (fix!) [#1422](https://github.com/cosmos/interchain-security/pull/1422) Fix the misbehaviour handling by verifying the signatures of byzantine validators. - -## v2.2.0-provider-lsm - -❗ *This release is deprecated and should not be used in production.* - -### Cryptographic verification of equivocation -* New feature enabling the provider chain to verify equivocation evidence on its own instead of trusting consumer chains, see [EPIC](https://github.com/cosmos/interchain-security/issues/732). - -## v2.1.0-provider-lsm - -Date: September 15th, 2023 - -* (feature!) [#1280](https://github.com/cosmos/interchain-security/pull/1280) provider proposal for changing reward denoms - -## v2.0.0-lsm - -Date: August 18th, 2023 - -* (deps!) [#1120](https://github.com/cosmos/interchain-security/pull/1120) Bump [Cosmos SDK](https://github.com/cosmos/cosmos-sdk) to [v0.45.16-ics-lsm](https://github.com/cosmos/cosmos-sdk/tree/v0.45.16-ics-lsm). This requires adapting ICS to support this SDK release. Changes are state breaking. -* (fix) [#720](https://github.com/cosmos/interchain-security/issues/720) Fix the attribute `AttributeDistributionTotal` value in `FeeDistribution` event emit. - -## v2.0.0 - -Date: June 1st, 2023 - -Unlike prior releases, the ICS `v2.0.0` release will be based on the main branch. `v2.0.0` will contain all the accumulated PRs from the various releases below, along with other PRs that were merged, but not released to production. After `v2.0.0`, we plan to revamp release practices, and how we modularize the repo for consumer/provider. - -Upgrading a provider from `v1.1.0-multiden` to `v2.0.0` will require state migrations. See [migration.go](https://github.com/cosmos/interchain-security/blob/v2.0.0/x/ccv/provider/keeper/migration.go). - -Upgrading a consumer from `v1.2.0-multiden` to `v2.0.0` will NOT require state migrations. - -Some PRs from v2.0.0 may reappear from other releases below. This is due to the fact that ICS v1.1.0 deviates from the commit ordering of the main branch, and other releases thereafter are based on v1.1.0. - -### High level changes included in v2.0.0 - -* MVP for standalone to consumer changeover, see [EPIC](https://github.com/cosmos/interchain-security/issues/756) -* MVP for soft opt out, see [EPIC](https://github.com/cosmos/interchain-security/issues/851) -* Various fixes, critical and non-critical -* Docs updates which should not affect production code - -## Notable PRs included in v2.0.0 - -* (feat!) Add DistributionTransmissionChannel to ConsumerAdditionProposal [#965](https://github.com/cosmos/interchain-security/pull/965) -* (feat/fix) limit vsc matured packets handled per endblocker [#1004](https://github.com/cosmos/interchain-security/pull/1004) -* (fix) consumer key prefix order to avoid complex migrations [#963](https://github.com/cosmos/interchain-security/pull/963) and [#991](https://github.com/cosmos/interchain-security/pull/991). The latter PR is the proper fix. -* (feat) v1->v2 migrations to accommodate a bugfix having to do with store keys, introduce new params, and deal with consumer genesis state schema changes [#975](https://github.com/cosmos/interchain-security/pull/975) and [#997](https://github.com/cosmos/interchain-security/pull/997) -* (deps) Bump github.com/cosmos/ibc-go/v4 from 4.4.0 to 4.4.2 [#982](https://github.com/cosmos/interchain-security/pull/982) -* (fix) partially revert key assignment type safety PR [#980](https://github.com/cosmos/interchain-security/pull/980) -* (fix) Remove panics on failure to send IBC packets [#876](https://github.com/cosmos/interchain-security/pull/876) -* (fix) Prevent denom DOS [#931](https://github.com/cosmos/interchain-security/pull/931) -* (fix) multisig for assigning consumer key, use json [#916](https://github.com/cosmos/interchain-security/pull/916) -* (deps) Bump github.com/cosmos/ibc-go/v4 from 4.3.0 to 4.4.0 [#902](https://github.com/cosmos/interchain-security/pull/902) -* (feat) Add warnings when provider unbonding is shorter than consumer unbonding [#858](https://github.com/cosmos/interchain-security/pull/858) -* (chore) use go 1.19 [#899](https://github.com/cosmos/interchain-security/pull/899), [#840](https://github.com/cosmos/interchain-security/pull/840) -* (feat) Standalone to consumer changeover - recycle existing transfer channel [#832](https://github.com/cosmos/interchain-security/pull/832) -* (deps) Bump IBC [862](https://github.com/cosmos/interchain-security/pull/862) -* (testing) Add tests for soft opt out [#857](https://github.com/cosmos/interchain-security/pull/857) -* (feat) Standalone to consumer changeover - staking functionalities [#794](https://github.com/cosmos/interchain-security/pull/794) -* (fix) prevent provider from sending VSCPackets with multiple updates for the same validator [#850](https://github.com/cosmos/interchain-security/pull/850) -* (feat) Soft opt out [#833](https://github.com/cosmos/interchain-security/issues/833) -* (fix) Correctly handle VSC packet with duplicate val updates on consumer [#846](https://github.com/cosmos/interchain-security/pull/846) -* (deps) bump sdk to v0.45.15.ics [#805](https://github.com/cosmos/interchain-security/pull/805) -* (refactor) Remove spm module [#812](https://github.com/cosmos/interchain-security/pull/812) -* (feat) Standalone to consumer changeover part 1 [#757](https://github.com/cosmos/interchain-security/pull/757) -* (chore) Swap names of e2e and integration tests [#681](https://github.com/cosmos/interchain-security/pull/681) -* (fix) fix StopConsumerChain not running in cachedContext [#802](https://github.com/cosmos/interchain-security/pull/802). Also in earlier releases with different commit order! -* (docs) Introduce docs website [#759](https://github.com/cosmos/interchain-security/pull/759) -* (fix) Serialize correct byte prefix for SlashLogKey [#786](https://github.com/cosmos/interchain-security/pull/786) -* (feature) Improve keeper field validation [#766](https://github.com/cosmos/interchain-security/pull/766) -* (docs) Contributing guidelines [#744](https://github.com/cosmos/interchain-security/pull/744) -* (refactor) Key assignment type safety [#725](https://github.com/cosmos/interchain-security/pull/725) -* (fix) Update protos and fix deps [#752](https://github.com/cosmos/interchain-security/pull/752) -* (api) Add consumer QueryParams [#746](https://github.com/cosmos/interchain-security/pull/746) -* (feature) New validation for keeper fields [#740](https://github.com/cosmos/interchain-security/pull/740) - -## v1.2.0-multiden - -The first release candidate for a fix built on top of v1.2.0, intended for consumers. This release adds a list of denoms on the consumer that are allowed to be sent to the provider as rewards. This prevents a potential DOS attack that was discovered during the audit of Replicated Security performed by Oak Security and funded by the Cosmos Hub community through Proposal 687. In an effort to move quickly, this release also includes a multisig fix that is effective only for provider. It shouldn't affect the consumer module. - -Note PRs were made in a private security repo. - -[full diff](https://github.com/cosmos/interchain-security/compare/v1.2.0...v1.2.0-multiden-rc0) - -## v1.1.0-multiden - -This release combines two fixes on top of v1.1.0, that we judged were urgent to get onto the Cosmos Hub before the launch of the first ICS consumer chain. This is an emergency release intended for providers. - -The first fix is to enable the use of multisigs and Ledger devices when assigning keys for consumer chains. The second is to prevent a possible DOS vector involving the reward distribution system. - -Note PRs were made in a private security repo. - -[full diff](https://github.com/cosmos/interchain-security/compare/v1.1.0...release/v1.1.0-multiden) - -### Multisig fix - -On April 25th (a week and a half ago), we began receiving reports that validators using multisigs and Ledger devices were getting errors reading Error: unable to resolve type URL /interchain_security.ccv.provider.v1.MsgAssignConsumerKey: tx parse error when attempting to assign consensus keys for consumer chains. - -We quickly narrowed the problem down to issues having to do with using the PubKey type directly in the MsgAssignConsumerKey transaction, and Amino (a deprecated serialization library still used in Ledger devices and multisigs) not being able to handle this. We attempted to fix this with the assistance of the Cosmos-SDK team, but after making no headway for a few days, we decided to simply use a JSON representation of the PubKey in the transaction. This is how it is usually represented anyway. We have verified that this fixes the problem. - -### Distribution fix - -The ICS distribution system works by allowing consumer chains to send rewards to a module address on the provider called the FeePoolAddress. From here they are automatically distributed to all validators and delegators through the distribution system that already exists to distribute staking rewards. The FeePoolAddress is usually blocked so that no tokens can be sent to it, but to enable ICS distribution we had to unblock it. - -We recently realized that unblocking the FeePoolAddress could enable an attacker to send a huge number of different denoms into the distribution system. The distribution system would then attempt to distribute them all, leading to out of memory errors. Fixing a similar attack vector that existed in the distribution system before ICS led us to this realization. - -To fix this problem, we have re-blocked the FeePoolAddress and created a new address called the ConsumerRewardsPool. Consumer chains now send rewards to this new address. There is also a new transaction type called RegisterConsumerRewardDenom. This transaction allows people to register denoms to be used as rewards from consumer chains. It costs 10 Atoms to run this transaction.The Atoms are transferred to the community pool. Only denoms registered with this command are then transferred to the FeePoolAddress and distributed out to delegators and validators. - -## v1.2.1 - -* (fix) Remove SPM [#812](https://github.com/cosmos/interchain-security/pull/812) -* (refactor) Key assignment type safety [#725](https://github.com/cosmos/interchain-security/pull/725) - -## v1.2.0 - -Date: April 13th, 2023 - -* (feat) Soft opt-out [#833](https://github.com/cosmos/interchain-security/pull/833) -* (fix) Correctly handle VSC packet with duplicate val updates on consumer [#846](https://github.com/cosmos/interchain-security/pull/846) -* (chore) bump: sdk v0.45.15-ics [#805](https://github.com/cosmos/interchain-security/pull/805) -* (api) add interchain security consumer QueryParams [#746](https://github.com/cosmos/interchain-security/pull/746) - -## v1.1.1 - -* (fix) Remove SPM [#812](https://github.com/cosmos/interchain-security/pull/812) -* (refactor) Key assignment type safety [#725](https://github.com/cosmos/interchain-security/pull/725) - -## v1.1.0 - -Date: March 24th, 2023 - -* (fix) StopConsumerChain not running in cachedContext [#802](https://github.com/cosmos/interchain-security/pull/802) - -## v1.0.0 - -Date: February 6th, 2023 - -This is the first version of Interchain Security (ICS), also known as _Replicated Security_ (RS). -Replicated Security is a feature which will allow a chain -- referred to as the _provider_ -- to share security with other chains -- referred to as _consumers_. -This means that the provider's validator set will be granted the right to validate consumer chains. -The communication between the provider and the consumer chains is done through the IBC protocol over a unique, ordered channel (one for each consumer chain). Thus, RS is an IBC application. - -### Features / sub-protocols - -RS consist of the following core features: - -- **Channel Initialization**: Enables the provider to add new consumer chains. This process is governance-gated, i.e., to add a new consumer chain, a `ConsumerAdditionProposal` governance proposal must be sent to the provider and it must receive the necessary votes. -- **Validator Set Update**: Enables the provider to - (1) update the consumers on the voting power granted to validators (based on the changes in the active validator set on the provider chain), - and (2) ensure the timely completion of unbonding operations (e.g., undelegations). -- **Consumer Initiated Slashing**: Enables the provider to jail validators for downtime infractions on the consumer chains. -- **Reward Distribution**: Enables the consumers to transfer to the provider (over IBC) a portion of their block rewards as payment for the security provided. Once transferred, these rewards are distributed on the provider using the protocol in the [distribution module of Cosmos SDK](https://docs.cosmos.network/v0.45/modules/distribution/). -- **Consumer Chain Removal**: Enables the provider to remove a consumer either after a `ConsumerRemovalProposal` passes governance or after one of the timeout periods elapses -- `InitTimeoutPeriod`, `VscTimeoutPeriod`, `IBCTimeoutPeriod`. -- **Social Slashing**: Equivocation offenses (double signing etc.) on consumer chains are logged, and then can be used in a governance proposal to slash the validators responsible. + - Add the provider-side changes for jail throttling with retries (cf. ADR 008). + ([\#1321](https://github.com/cosmos/interchain-security/pull/1321)) -In addition, RS has the following features: +## Previous Versions -- **Key Assignment**: Enables validator operators to use different consensus keys for each consumer chain validator node that they operate. -- **Jail Throttling**: Enables the provider to slow down a "worst case scenario" attack where a malicious consumer binary attempts to jail a significant amount (> 2/3) of the voting power, effectively taking control of the provider. +[CHANGELOG of previous versions](https://github.com/cosmos/interchain-security/blob/main/CHANGELOG.md) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 5d5ad1eb62..f833594abe 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,37 +1,17 @@ - - -# Replicated Security Release Notes - - -❗ ***Note this release is ONLY relevant to *** +# Replicated Security v4.0.0 Release Notes ## 📝 Changelog -** REMOVE THE LINE BELOW TO ENABLE THE MARKDOWN LINK CHECKER FOR RELEASE ** - - -Check out the [changelog](https://github.com/cosmos/interchain-security/blob//CHANGELOG.md) for a list of relevant changes or [compare all changes](https://github.com/cosmos/interchain-security/compare/release/...) from last release. +Check out the [changelog](https://github.com/cosmos/interchain-security/blob/v4.0.0/CHANGELOG.md) for a list of relevant changes or [compare all changes](https://github.com/cosmos/interchain-security/compare/v3.3.0...v4.0.0) from last release. -Refer to the [upgrading guide](https://github.com/cosmos/interchain-security/blob/release//UPGRADING.md) when migrating from `` to ``. +Refer to the [upgrading guide](https://github.com/cosmos/interchain-security/blob/release/v4.0.x/UPGRADING.md) when migrating +from a version `>= v3.1.x` to `v4.0.x`. -** REMOVE THE LINE BELOW TO ENABLE THE MARKDOWN LINK CHECKER FOR RELEASE ** - ## 🚀 Highlights - +This release introduces the following noteworthy changes: -## ❤️ Contributors - -* Informal Systems ([@informalinc](https://twitter.com/informalinc)) - +- It sets the minimum required version of Go to `1.21`. +- It adds the provider-side changes for jail throttling with retries and, as a result, it fully enables the jail throttling with retries feature (cf. [ADR 008](https://github.com/cosmos/interchain-security/blob/release/v3.2.x/docs/docs/adrs/adr-008-throttle-retries.md)). +- Fixes a bug in the soft opt-out protocol -- it avoids jailing validators immediately once they can no longer opt-out from validating consumer chains. -This list is non-exhaustive and ordered alphabetically. -Thank you to everyone who contributed to this release! From 04a669cff30952d71961c973e75f532943414356 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Fri, 19 Jan 2024 19:25:23 +0100 Subject: [PATCH 003/110] fix!: Validation of SlashAcks fails due to marshaling to Bech32 (backport #1570) (#1577) fix!: Validation of SlashAcks fails due to marshaling to Bech32 (#1570) * add different Bech32Prefix for consumer and provider * separate app encoding and params * remove ConsumerValPubKey from ValidatorConfig * update addresses in tests * make SlashAcks consistent across chains * add comments for clarity * Regenerate traces * Fix argument order * set bech32prefix for provider to cosmos * add changelog entries * add consumer-double-downtime e2e test * update nightly-e2e workflow * fix typo * add consumer-double-downtime to testConfigs * remove changes on provider * skip invalid SlashAcks * seal the config * clear the outstanding downtime flag for new vals * add info on upgrading to v4.0.0 * fix upgrade handler * fix changeover e2e test * Update tests/e2e/config.go Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * Update tests/e2e/config.go Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * add AccountPrefix to ChainConfig * fix docstrings * update AccountAddressPrefix in app.go * fix consumer-misb e2e test --------- Co-authored-by: Philip Offtermatt Co-authored-by: Simon Noetzlin Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> (cherry picked from commit 86046926502f7b0ba795bebcdd1fdc97ac776573) Co-authored-by: Marius Poke --- .changelog/unreleased/state-breaking/1570-slashack-bech32.md | 2 ++ .changelog/v4.0.0/bug-fixes/1570-slashack-bech32.md | 2 ++ 2 files changed, 4 insertions(+) create mode 100644 .changelog/unreleased/state-breaking/1570-slashack-bech32.md create mode 100644 .changelog/v4.0.0/bug-fixes/1570-slashack-bech32.md diff --git a/.changelog/unreleased/state-breaking/1570-slashack-bech32.md b/.changelog/unreleased/state-breaking/1570-slashack-bech32.md new file mode 100644 index 0000000000..a0e9fe9262 --- /dev/null +++ b/.changelog/unreleased/state-breaking/1570-slashack-bech32.md @@ -0,0 +1,2 @@ +- Fix the validation of VSCPackets to not fail due to marshaling to string using Bech32. + ([\#1570](https://github.com/cosmos/interchain-security/pull/1570)) \ No newline at end of file diff --git a/.changelog/v4.0.0/bug-fixes/1570-slashack-bech32.md b/.changelog/v4.0.0/bug-fixes/1570-slashack-bech32.md new file mode 100644 index 0000000000..a0e9fe9262 --- /dev/null +++ b/.changelog/v4.0.0/bug-fixes/1570-slashack-bech32.md @@ -0,0 +1,2 @@ +- Fix the validation of VSCPackets to not fail due to marshaling to string using Bech32. + ([\#1570](https://github.com/cosmos/interchain-security/pull/1570)) \ No newline at end of file From e7e586ee3a7c8eaab21dcda970192a7d9d148f53 Mon Sep 17 00:00:00 2001 From: Marius Poke Date: Mon, 22 Jan 2024 09:39:42 +0100 Subject: [PATCH 004/110] docs: update changelog for v4.0.0 (#1578) update changelog --- .changelog/unreleased/state-breaking/1570-slashack-bech32.md | 2 -- .changelog/v4.0.0/bug-fixes/1570-slashack-bech32.md | 2 -- 2 files changed, 4 deletions(-) delete mode 100644 .changelog/unreleased/state-breaking/1570-slashack-bech32.md delete mode 100644 .changelog/v4.0.0/bug-fixes/1570-slashack-bech32.md diff --git a/.changelog/unreleased/state-breaking/1570-slashack-bech32.md b/.changelog/unreleased/state-breaking/1570-slashack-bech32.md deleted file mode 100644 index a0e9fe9262..0000000000 --- a/.changelog/unreleased/state-breaking/1570-slashack-bech32.md +++ /dev/null @@ -1,2 +0,0 @@ -- Fix the validation of VSCPackets to not fail due to marshaling to string using Bech32. - ([\#1570](https://github.com/cosmos/interchain-security/pull/1570)) \ No newline at end of file diff --git a/.changelog/v4.0.0/bug-fixes/1570-slashack-bech32.md b/.changelog/v4.0.0/bug-fixes/1570-slashack-bech32.md deleted file mode 100644 index a0e9fe9262..0000000000 --- a/.changelog/v4.0.0/bug-fixes/1570-slashack-bech32.md +++ /dev/null @@ -1,2 +0,0 @@ -- Fix the validation of VSCPackets to not fail due to marshaling to string using Bech32. - ([\#1570](https://github.com/cosmos/interchain-security/pull/1570)) \ No newline at end of file From 5aa1c50a7c8b887a7f0f6e6f439b89c27fce0239 Mon Sep 17 00:00:00 2001 From: Marius Poke Date: Mon, 22 Jan 2024 09:54:28 +0100 Subject: [PATCH 005/110] docs: prepare for v4.0.0 (#1581) * unclog build * update release notes * update release date --- CHANGELOG.md | 4 ++++ RELEASE_NOTES.md | 1 + 2 files changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb6be888e9..2c88c0c722 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -76,6 +76,8 @@ - Avoid jailing validators immediately once they can no longer opt-out from validating consumer chains. ([\#1549](https://github.com/cosmos/interchain-security/pull/1549)) + - Fix the validation of VSCPackets to not fail due to marshaling to string using Bech32. + ([\#1570](https://github.com/cosmos/interchain-security/pull/1570)) ### DEPENDENCIES @@ -100,6 +102,8 @@ - Avoid jailing validators immediately once they can no longer opt-out from validating consumer chains. ([\#1549](https://github.com/cosmos/interchain-security/pull/1549)) + - Fix the validation of VSCPackets to not fail due to marshaling to string using Bech32. + ([\#1570](https://github.com/cosmos/interchain-security/pull/1570)) - [Provider](x/ccv/provider) - Add the provider-side changes for jail throttling with retries (cf. ADR 008). ([\#1321](https://github.com/cosmos/interchain-security/pull/1321)) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index f833594abe..913cb9faef 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -14,4 +14,5 @@ This release introduces the following noteworthy changes: - It sets the minimum required version of Go to `1.21`. - It adds the provider-side changes for jail throttling with retries and, as a result, it fully enables the jail throttling with retries feature (cf. [ADR 008](https://github.com/cosmos/interchain-security/blob/release/v3.2.x/docs/docs/adrs/adr-008-throttle-retries.md)). - Fixes a bug in the soft opt-out protocol -- it avoids jailing validators immediately once they can no longer opt-out from validating consumer chains. +- Fixes a bug the validation of VSCPackets caused by marshaling to string using Bech32. From 1f1d3bda696eaa2781f98dcfc215d8fdef4eb740 Mon Sep 17 00:00:00 2001 From: insumity Date: Mon, 5 Feb 2024 09:27:26 +0100 Subject: [PATCH 006/110] feat!: enable Opt In and Top N chains through gov proposals (#1615) * init commit * added test * fixed tests * added changelog entry and comment * Update x/ccv/provider/keeper/proposal_test.go Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * Update .changelog/unreleased/features/1587-enable-opt-in-chains-through-gov-proposals.md Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * Update proto/interchain_security/ccv/provider/v1/provider.proto Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * Update proto/interchain_security/ccv/provider/v1/provider.proto Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * Update proto/interchain_security/ccv/provider/v1/provider.proto Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * Update proto/interchain_security/ccv/provider/v1/provider.proto Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * Update x/ccv/provider/keeper/keeper.go Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * changed to tabular test --------- Co-authored-by: insumity Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> --- ...ble-opt-in-chains-through-gov-proposals.md | 2 + .../ccv/provider/v1/provider.proto | 5 + testutil/keeper/unit_test_helpers.go | 1 + x/ccv/provider/client/proposal_handler.go | 6 +- x/ccv/provider/keeper/keeper.go | 48 ++++ x/ccv/provider/keeper/keeper_test.go | 31 +++ x/ccv/provider/keeper/proposal.go | 7 + x/ccv/provider/keeper/proposal_test.go | 18 ++ x/ccv/provider/proposal_handler_test.go | 1 + x/ccv/provider/types/keys.go | 8 + x/ccv/provider/types/keys_test.go | 1 + x/ccv/provider/types/proposal.go | 8 + x/ccv/provider/types/proposal_test.go | 44 ++- x/ccv/provider/types/provider.pb.go | 251 ++++++++++-------- 14 files changed, 306 insertions(+), 125 deletions(-) create mode 100644 .changelog/unreleased/features/1587-enable-opt-in-chains-through-gov-proposals.md diff --git a/.changelog/unreleased/features/1587-enable-opt-in-chains-through-gov-proposals.md b/.changelog/unreleased/features/1587-enable-opt-in-chains-through-gov-proposals.md new file mode 100644 index 0000000000..57f16adc9b --- /dev/null +++ b/.changelog/unreleased/features/1587-enable-opt-in-chains-through-gov-proposals.md @@ -0,0 +1,2 @@ +- Enable Opt In and Top N chains through gov proposals. + ([\#1587](https://github.com/cosmos/interchain-security/pull/1587)) \ No newline at end of file diff --git a/proto/interchain_security/ccv/provider/v1/provider.proto b/proto/interchain_security/ccv/provider/v1/provider.proto index 4da89022e8..9d815a1768 100644 --- a/proto/interchain_security/ccv/provider/v1/provider.proto +++ b/proto/interchain_security/ccv/provider/v1/provider.proto @@ -83,6 +83,11 @@ message ConsumerAdditionProposal { // chain. it is most relevant for chains performing a sovereign to consumer // changeover in order to maintain the existing ibc transfer channel string distribution_transmission_channel = 14; + // Corresponds to the percentage of validators that have to validate the chain under the Top N case. + // For example, 53 corresponds to a Top 53% chain, meaning that the top 53% provider validators by voting power + // have to validate the proposed consumer chain. top_N can either be 0 or any value in [50, 100]. + // A chain can join with top_N == 0 as an Opt In chain, or with top_N ∈ [50, 100] as a Top N chain. + uint32 top_N = 15; } // ConsumerRemovalProposal is a governance proposal on the provider chain to diff --git a/testutil/keeper/unit_test_helpers.go b/testutil/keeper/unit_test_helpers.go index ff3df99763..05bef232e3 100644 --- a/testutil/keeper/unit_test_helpers.go +++ b/testutil/keeper/unit_test_helpers.go @@ -271,6 +271,7 @@ func GetTestConsumerAdditionProp() *providertypes.ConsumerAdditionProposal { types.DefaultCCVTimeoutPeriod, types.DefaultTransferTimeoutPeriod, types.DefaultConsumerUnbondingPeriod, + 0, ).(*providertypes.ConsumerAdditionProposal) return prop diff --git a/x/ccv/provider/client/proposal_handler.go b/x/ccv/provider/client/proposal_handler.go index fa74bb953e..9b5674f4c7 100644 --- a/x/ccv/provider/client/proposal_handler.go +++ b/x/ccv/provider/client/proposal_handler.go @@ -64,7 +64,8 @@ Where proposal.json contains: "transfer_timeout_period": 3600000000000, "ccv_timeout_period": 2419200000000000, "unbonding_period": 1728000000000000, - "deposit": "10000stake" + "deposit": "10000stake", + "top_n": 0, } `, RunE: func(cmd *cobra.Command, args []string) error { @@ -86,7 +87,7 @@ Where proposal.json contains: proposal.GenesisHash, proposal.BinaryHash, proposal.SpawnTime, proposal.ConsumerRedistributionFraction, proposal.BlocksPerDistributionTransmission, proposal.DistributionTransmissionChannel, proposal.HistoricalEntries, - proposal.CcvTimeoutPeriod, proposal.TransferTimeoutPeriod, proposal.UnbondingPeriod) + proposal.CcvTimeoutPeriod, proposal.TransferTimeoutPeriod, proposal.UnbondingPeriod, proposal.TopN) from := clientCtx.GetFromAddress() @@ -241,6 +242,7 @@ type ConsumerAdditionProposalJSON struct { UnbondingPeriod time.Duration `json:"unbonding_period"` Deposit string `json:"deposit"` + TopN uint32 `json:"top_N"` } type ConsumerAdditionProposalReq struct { diff --git a/x/ccv/provider/keeper/keeper.go b/x/ccv/provider/keeper/keeper.go index 510d957c5d..1a7fe69ee5 100644 --- a/x/ccv/provider/keeper/keeper.go +++ b/x/ccv/provider/keeper/keeper.go @@ -1136,3 +1136,51 @@ func (k Keeper) GetAllRegisteredAndProposedChainIDs(ctx sdk.Context) []string { return allConsumerChains } + +// SetTopN stores the N value associated to chain with `chainID` +func (k Keeper) SetTopN( + ctx sdk.Context, + chainID string, + N uint32, +) { + store := ctx.KVStore(k.storeKey) + + buf := make([]byte, 4) + binary.BigEndian.PutUint32(buf, N) + + store.Set(types.TopNKey(chainID), buf) +} + +// DeleteTopN removes the N value associated to chain with `chainID` +func (k Keeper) DeleteTopN( + ctx sdk.Context, + chainID string, +) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.TopNKey(chainID)) +} + +// GetTopN returns (N, true) if chain `chainID` has a top N associated, and (0, false) otherwise. +func (k Keeper) GetTopN( + ctx sdk.Context, + chainID string, +) (uint32, bool) { + store := ctx.KVStore(k.storeKey) + buf := store.Get(types.TopNKey(chainID)) + if buf == nil { + return 0, false + } + return binary.BigEndian.Uint32(buf), true +} + +// IsTopN returns true if chain with `chainID` is a Top N chain (i.e., enforces at least one validator to validate chain `chainID`) +func (k Keeper) IsTopN(ctx sdk.Context, chainID string) bool { + topN, found := k.GetTopN(ctx, chainID) + return found && topN > 0 +} + +// IsOptIn returns true if chain with `chainID` is an Opt In chain (i.e., no validator is forced to validate chain `chainID`) +func (k Keeper) IsOptIn(ctx sdk.Context, chainID string) bool { + topN, found := k.GetTopN(ctx, chainID) + return !found || topN == 0 +} diff --git a/x/ccv/provider/keeper/keeper_test.go b/x/ccv/provider/keeper/keeper_test.go index 9c9d421fd9..4dc73b7f9e 100644 --- a/x/ccv/provider/keeper/keeper_test.go +++ b/x/ccv/provider/keeper/keeper_test.go @@ -628,3 +628,34 @@ func TestGetAllProposedConsumerChainIDs(t *testing.T) { } } } + +// TestTopN tests `SetTopN`, `GetTopN`, `IsTopN`, and `IsOptIn` methods +func TestTopN(t *testing.T) { + providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + tests := []struct { + chainID string + N uint32 + isOptIn bool + }{ + {chainID: "TopNChain1", N: 50, isOptIn: false}, + {chainID: "TopNChain2", N: 100, isOptIn: false}, + {chainID: "OptInChain", N: 0, isOptIn: true}, + } + + for _, test := range tests { + providerKeeper.SetTopN(ctx, test.chainID, test.N) + topN, found := providerKeeper.GetTopN(ctx, test.chainID) + require.Equal(t, test.N, topN) + require.True(t, found) + + if test.isOptIn { + require.True(t, providerKeeper.IsOptIn(ctx, test.chainID)) + require.False(t, providerKeeper.IsTopN(ctx, test.chainID)) + } else { + require.False(t, providerKeeper.IsOptIn(ctx, test.chainID)) + require.True(t, providerKeeper.IsTopN(ctx, test.chainID)) + } + } +} diff --git a/x/ccv/provider/keeper/proposal.go b/x/ccv/provider/keeper/proposal.go index b0e2845502..f1af329d60 100644 --- a/x/ccv/provider/keeper/proposal.go +++ b/x/ccv/provider/keeper/proposal.go @@ -214,6 +214,8 @@ func (k Keeper) StopConsumerChain(ctx sdk.Context, chainID string, closeChan boo k.DeleteUnbondingOpIndex(ctx, chainID, unbondingOpsIndex.VscId) } + k.DeleteTopN(ctx, chainID) + k.Logger(ctx).Info("consumer chain removed from provider", "chainID", chainID) return nil @@ -373,6 +375,11 @@ func (k Keeper) BeginBlockInit(ctx sdk.Context) { ctx.Logger().Info("consumer client could not be created: %w", err) continue } + + // Only set Top N at the moment a chain starts. If we were to do this earlier (e.g., during the proposal), + // then someone could create a bogus ConsumerAdditionProposal to override the Top N for a specific chain. + k.SetTopN(ctx, prop.ChainId, prop.Top_N) + // The cached context is created with a new EventManager so we merge the event // into the original context ctx.EventManager().EmitEvents(cachedCtx.EventManager().Events()) diff --git a/x/ccv/provider/keeper/proposal_test.go b/x/ccv/provider/keeper/proposal_test.go index fc1c7a4344..8de4282474 100644 --- a/x/ccv/provider/keeper/proposal_test.go +++ b/x/ccv/provider/keeper/proposal_test.go @@ -64,6 +64,7 @@ func TestHandleConsumerAdditionProposal(t *testing.T) { 100000000000, 100000000000, 100000000000, + 0, ).(*providertypes.ConsumerAdditionProposal), blockTime: now, expAppendProp: true, @@ -89,6 +90,7 @@ func TestHandleConsumerAdditionProposal(t *testing.T) { 100000000000, 100000000000, 100000000000, + 0, ).(*providertypes.ConsumerAdditionProposal), blockTime: now, expAppendProp: false, @@ -552,6 +554,10 @@ func TestStopConsumerChain(t *testing.T) { require.Error(t, err) } else { require.NoError(t, err) + + // in case the chain was successfully stopped, it should not contain a Top N associated to it + _, found := providerKeeper.GetTopN(ctx, "chainID") + require.False(t, found) } testkeeper.TestProviderStateIsCleanedAfterConsumerChainIsStopped(t, ctx, providerKeeper, "chainID", "channelID") @@ -924,6 +930,7 @@ func TestBeginBlockInit(t *testing.T) { 100000000000, 100000000000, 100000000000, + 67, ).(*providertypes.ConsumerAdditionProposal), providertypes.NewConsumerAdditionProposal( "title", "spawn time passed", "chain2", clienttypes.NewHeight(3, 4), []byte{}, []byte{}, @@ -935,6 +942,7 @@ func TestBeginBlockInit(t *testing.T) { 100000000000, 100000000000, 100000000000, + 0, ).(*providertypes.ConsumerAdditionProposal), providertypes.NewConsumerAdditionProposal( "title", "spawn time not passed", "chain3", clienttypes.NewHeight(3, 4), []byte{}, []byte{}, @@ -946,6 +954,7 @@ func TestBeginBlockInit(t *testing.T) { 100000000000, 100000000000, 100000000000, + 0, ).(*providertypes.ConsumerAdditionProposal), providertypes.NewConsumerAdditionProposal( "title", "invalid proposal: chain id already exists", "chain2", clienttypes.NewHeight(4, 5), []byte{}, []byte{}, @@ -957,6 +966,7 @@ func TestBeginBlockInit(t *testing.T) { 100000000000, 100000000000, 100000000000, + 0, ).(*providertypes.ConsumerAdditionProposal), } @@ -989,6 +999,13 @@ func TestBeginBlockInit(t *testing.T) { _, found = providerKeeper.GetPendingConsumerAdditionProp( ctx, pendingProps[3].SpawnTime, pendingProps[3].ChainId) require.False(t, found) + + // test that Top N is set correctly + require.True(t, providerKeeper.IsTopN(ctx, "chain1")) + topN, found := providerKeeper.GetTopN(ctx, "chain1") + require.Equal(t, uint32(67), topN) + + require.True(t, providerKeeper.IsOptIn(ctx, "chain2")) } // TestBeginBlockCCR tests BeginBlockCCR against the spec. @@ -1058,6 +1075,7 @@ func TestBeginBlockCCR(t *testing.T) { // // Test execution // + providerKeeper.BeginBlockCCR(ctx) // Only the 3rd (final) proposal is still stored as pending diff --git a/x/ccv/provider/proposal_handler_test.go b/x/ccv/provider/proposal_handler_test.go index 65e84ac661..30c1793360 100644 --- a/x/ccv/provider/proposal_handler_test.go +++ b/x/ccv/provider/proposal_handler_test.go @@ -44,6 +44,7 @@ func TestProviderProposalHandler(t *testing.T) { 100000000000, 100000000000, 100000000000, + 0, ), blockTime: hourFromNow, // ctx blocktime is after proposal's spawn time expValidConsumerAddition: true, diff --git a/x/ccv/provider/types/keys.go b/x/ccv/provider/types/keys.go index e9222ade98..125ad4a473 100644 --- a/x/ccv/provider/types/keys.go +++ b/x/ccv/provider/types/keys.go @@ -150,6 +150,9 @@ const ( // ConsumerValidatorBytePrefix is the byte prefix used when storing for each consumer chain all the consumer validators in this epoch ConsumerValidatorBytePrefix + // TopNBytePrefix is the byte prefix storing the mapping from a consumer chain to the N value of this chain, + // that corresponds to the N% of the top validators that have to validate this consumer chain + TopNBytePrefix // NOTE: DO NOT ADD NEW BYTE PREFIXES HERE WITHOUT ADDING THEM TO getAllKeyPrefixes() IN keys_test.go ) @@ -522,6 +525,11 @@ func ConsumerValidatorKey(chainID string, providerAddr []byte) []byte { return append(prefix, providerAddr...) } +// TopNKey returns the key of consumer chain `chainID` +func TopNKey(chainID string) []byte { + return ChainIdWithLenKey(TopNBytePrefix, chainID) +} + // // End of generic helpers section // diff --git a/x/ccv/provider/types/keys_test.go b/x/ccv/provider/types/keys_test.go index 02faa9a640..da2dbbea31 100644 --- a/x/ccv/provider/types/keys_test.go +++ b/x/ccv/provider/types/keys_test.go @@ -57,6 +57,7 @@ func getAllKeyPrefixes() []byte { providertypes.EquivocationEvidenceMinHeightBytePrefix, providertypes.ProposedConsumerChainByteKey, providertypes.ConsumerValidatorBytePrefix, + providertypes.TopNBytePrefix, } } diff --git a/x/ccv/provider/types/proposal.go b/x/ccv/provider/types/proposal.go index 93cadfd14e..10f3a88865 100644 --- a/x/ccv/provider/types/proposal.go +++ b/x/ccv/provider/types/proposal.go @@ -49,6 +49,7 @@ func NewConsumerAdditionProposal(title, description, chainID string, ccvTimeoutPeriod time.Duration, transferTimeoutPeriod time.Duration, unbondingPeriod time.Duration, + topN uint32, ) govv1beta1.Content { return &ConsumerAdditionProposal{ Title: title, @@ -65,6 +66,7 @@ func NewConsumerAdditionProposal(title, description, chainID string, CcvTimeoutPeriod: ccvTimeoutPeriod, TransferTimeoutPeriod: transferTimeoutPeriod, UnbondingPeriod: unbondingPeriod, + Top_N: topN, } } @@ -135,6 +137,12 @@ func (cccp *ConsumerAdditionProposal) ValidateBasic() error { return errorsmod.Wrap(ErrInvalidConsumerAdditionProposal, "unbonding period cannot be zero") } + // Top N corresponds to the top N% of validators that have to validate the consumer chain and can only be 0 (for an + // Opt In chain) or in the range [50, 100] (for a Top N chain). + if cccp.Top_N != 0 && cccp.Top_N < 50 || cccp.Top_N > 100 { + return errorsmod.Wrap(ErrInvalidConsumerAdditionProposal, "Top N can either be 0 or in the range [50, 100]") + } + return nil } diff --git a/x/ccv/provider/types/proposal_test.go b/x/ccv/provider/types/proposal_test.go index 72fcfe8436..13e7edb11e 100644 --- a/x/ccv/provider/types/proposal_test.go +++ b/x/ccv/provider/types/proposal_test.go @@ -36,6 +36,7 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { 100000000000, 100000000000, 100000000000, + 0, ), true, }, @@ -48,7 +49,8 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { 10000, 100000000000, 100000000000, - 100000000000), + 100000000000, + 0), true, }, { @@ -60,7 +62,8 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { 10000, 100000000000, 100000000000, - 100000000000), + 100000000000, + 0), false, }, { @@ -72,7 +75,8 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { 10000, 100000000000, 100000000000, - 100000000000), + 100000000000, + 0), false, }, { @@ -104,7 +108,8 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { 10000, 100000000000, 100000000000, - 100000000000), + 100000000000, + 0), false, }, { @@ -116,7 +121,8 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { 10000, 100000000000, 100000000000, - 100000000000), + 100000000000, + 0), false, }, { @@ -128,7 +134,8 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { 10000, 100000000000, 100000000000, - 100000000000), + 100000000000, + 0), false, }, { @@ -140,7 +147,8 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { 10000, 100000000000, 100000000000, - 100000000000), + 100000000000, + 0), false, }, { @@ -152,7 +160,8 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { 100000000000, 10000, 100000000000, - 100000000000), + 100000000000, + 0), false, }, { @@ -164,7 +173,8 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { 10000, 100000000000, 100000000000, - 100000000000), + 100000000000, + 0), false, }, { @@ -176,7 +186,8 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { -2, 100000000000, 100000000000, - 100000000000), + 100000000000, + 0), false, }, { @@ -188,7 +199,8 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { 10000, 0, 100000000000, - 100000000000), + 100000000000, + 0), false, }, { @@ -200,7 +212,8 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { 10000, 100000000000, 0, - 100000000000), + 100000000000, + 0), false, }, { @@ -212,6 +225,7 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { 10000, 100000000000, 100000000000, + 0, 0), false, }, @@ -236,7 +250,8 @@ func TestMarshalConsumerAdditionProposal(t *testing.T) { 10000, 100000000000, 100000000000, - 100000000000) + 100000000000, + 0) cccp, ok := content.(*types.ConsumerAdditionProposal) require.True(t, ok) @@ -278,7 +293,8 @@ func TestConsumerAdditionProposalString(t *testing.T) { 500000, 100000000000, 10000000000, - 100000000000) + 100000000000, + 0) expect := fmt.Sprintf(`CreateConsumerChain Proposal Title: title diff --git a/x/ccv/provider/types/provider.pb.go b/x/ccv/provider/types/provider.pb.go index 819154b75d..2ef5f607d0 100644 --- a/x/ccv/provider/types/provider.pb.go +++ b/x/ccv/provider/types/provider.pb.go @@ -90,6 +90,11 @@ type ConsumerAdditionProposal struct { // chain. it is most relevant for chains performing a sovereign to consumer // changeover in order to maintain the existing ibc transfer channel DistributionTransmissionChannel string `protobuf:"bytes,14,opt,name=distribution_transmission_channel,json=distributionTransmissionChannel,proto3" json:"distribution_transmission_channel,omitempty"` + // Corresponds to the percentage of validators that have to validate the chain under the Top N case. + // For example, 53 corresponds to a Top 53% chain, meaning that the top 53% provider validators by voting power + // have to validate the proposed consumer chain. top_N can either be 0 or any value in [50, 100]. + // A chain can join with top_N == 0 as an Opt In chain, or with top_N ∈ [50, 100] as a Top N chain. + Top_N uint32 `protobuf:"varint,15,opt,name=top_N,json=topN,proto3" json:"top_N,omitempty"` } func (m *ConsumerAdditionProposal) Reset() { *m = ConsumerAdditionProposal{} } @@ -1395,7 +1400,7 @@ func (m *ConsumerAddrsToPrune) GetConsumerAddrs() *AddressList { } // ConsumerValidator is used to facilitate epoch-based transitions. It contains relevant info for -// a validator that is opted in, in an epoch, on a consumer chain. +// a validator that is expected to validate on a consumer chain during an epoch. type ConsumerValidator struct { // validator's consensus address on the provider chain ProviderConsAddr []byte `protobuf:"bytes,1,opt,name=provider_cons_addr,json=providerConsAddr,proto3" json:"provider_cons_addr,omitempty"` @@ -1490,117 +1495,118 @@ func init() { } var fileDescriptor_f22ec409a72b7b72 = []byte{ - // 1755 bytes of a gzipped FileDescriptorProto + // 1776 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0x4f, 0x6f, 0x1b, 0xc7, - 0x15, 0xd7, 0x92, 0x94, 0x2c, 0x3e, 0x4a, 0x94, 0xb4, 0x52, 0xe2, 0x95, 0xab, 0x52, 0xf2, 0xa6, - 0x49, 0x55, 0xa4, 0x59, 0x56, 0x4a, 0x0b, 0x04, 0x46, 0x83, 0x40, 0xa2, 0x9c, 0x58, 0x56, 0x12, + 0x15, 0xd7, 0x8a, 0x94, 0x2c, 0x3e, 0x4a, 0x94, 0xb4, 0x52, 0xe2, 0x95, 0xab, 0x52, 0xf4, 0xa6, + 0x49, 0x55, 0xa4, 0x59, 0x56, 0x4a, 0x0b, 0x04, 0x46, 0x83, 0x40, 0xa2, 0x9c, 0x58, 0x56, 0x62, 0x2b, 0x2b, 0x55, 0x46, 0xdb, 0xc3, 0x62, 0x38, 0x3b, 0x26, 0x07, 0x5a, 0xee, 0xac, 0x67, 0x66, 0xd7, 0xe1, 0xa5, 0xe7, 0x1e, 0xd3, 0x5b, 0xd0, 0x4b, 0xd3, 0x02, 0x3d, 0xf7, 0x6b, 0xe4, 0x98, - 0x63, 0x4f, 0x49, 0x61, 0x1f, 0xfb, 0x25, 0x8a, 0x99, 0xfd, 0x4b, 0x4a, 0x72, 0x69, 0xb8, 0xbd, - 0xcd, 0xbe, 0x79, 0xef, 0xf7, 0xfe, 0xbf, 0x37, 0x24, 0xec, 0xd3, 0x50, 0x12, 0x8e, 0x87, 0x88, - 0x86, 0x9e, 0x20, 0x38, 0xe6, 0x54, 0x8e, 0xbb, 0x18, 0x27, 0xdd, 0x88, 0xb3, 0x84, 0xfa, 0x84, - 0x77, 0x93, 0xbd, 0xe2, 0xec, 0x44, 0x9c, 0x49, 0x66, 0xbe, 0x75, 0x8d, 0x8c, 0x83, 0x71, 0xe2, - 0x14, 0x7c, 0xc9, 0xde, 0x9d, 0xb7, 0x6f, 0x02, 0x4e, 0xf6, 0xba, 0xcf, 0x28, 0x27, 0x29, 0xd6, - 0x9d, 0x8d, 0x01, 0x1b, 0x30, 0x7d, 0xec, 0xaa, 0x53, 0x46, 0xdd, 0x1e, 0x30, 0x36, 0x08, 0x48, - 0x57, 0x7f, 0xf5, 0xe3, 0x27, 0x5d, 0x49, 0x47, 0x44, 0x48, 0x34, 0x8a, 0x32, 0x86, 0xce, 0x34, - 0x83, 0x1f, 0x73, 0x24, 0x29, 0x0b, 0x73, 0x00, 0xda, 0xc7, 0x5d, 0xcc, 0x38, 0xe9, 0xe2, 0x80, - 0x92, 0x50, 0x2a, 0xad, 0xe9, 0x29, 0x63, 0xe8, 0x2a, 0x86, 0x80, 0x0e, 0x86, 0x32, 0x25, 0x8b, - 0xae, 0x24, 0xa1, 0x4f, 0xf8, 0x88, 0xa6, 0xcc, 0xe5, 0x57, 0x26, 0xb0, 0x55, 0xb9, 0xc7, 0x7c, - 0x1c, 0x49, 0xd6, 0xbd, 0x24, 0x63, 0x91, 0xdd, 0xbe, 0x83, 0x99, 0x18, 0x31, 0xd1, 0x25, 0xca, - 0xff, 0x10, 0x93, 0x6e, 0xb2, 0xd7, 0x27, 0x12, 0xed, 0x15, 0x84, 0xdc, 0xee, 0x8c, 0xaf, 0x8f, - 0x44, 0xc9, 0x83, 0x19, 0xcd, 0xec, 0xb6, 0x7f, 0x58, 0x00, 0xab, 0xc7, 0x42, 0x11, 0x8f, 0x08, - 0x3f, 0xf0, 0x7d, 0xaa, 0x5c, 0x3a, 0xe5, 0x2c, 0x62, 0x02, 0x05, 0xe6, 0x06, 0xcc, 0x4b, 0x2a, - 0x03, 0x62, 0x19, 0x3b, 0xc6, 0x6e, 0xd3, 0x4d, 0x3f, 0xcc, 0x1d, 0x68, 0xf9, 0x44, 0x60, 0x4e, - 0x23, 0xc5, 0x6c, 0xd5, 0xf4, 0x5d, 0x95, 0x64, 0x6e, 0xc2, 0x62, 0x9a, 0x07, 0xea, 0x5b, 0x75, - 0x7d, 0x7d, 0x4b, 0x7f, 0x1f, 0xfb, 0xe6, 0x27, 0xd0, 0xa6, 0x21, 0x95, 0x14, 0x05, 0xde, 0x90, - 0xa8, 0x68, 0x58, 0x8d, 0x1d, 0x63, 0xb7, 0xb5, 0x7f, 0xc7, 0xa1, 0x7d, 0xec, 0xa8, 0x00, 0x3a, - 0x59, 0xd8, 0x92, 0x3d, 0xe7, 0x81, 0xe6, 0x38, 0x6c, 0x7c, 0xfb, 0xfd, 0xf6, 0x9c, 0xbb, 0x9c, - 0xc9, 0xa5, 0x44, 0xf3, 0x2e, 0x2c, 0x0d, 0x48, 0x48, 0x04, 0x15, 0xde, 0x10, 0x89, 0xa1, 0x35, - 0xbf, 0x63, 0xec, 0x2e, 0xb9, 0xad, 0x8c, 0xf6, 0x00, 0x89, 0xa1, 0xb9, 0x0d, 0xad, 0x3e, 0x0d, - 0x11, 0x1f, 0xa7, 0x1c, 0x0b, 0x9a, 0x03, 0x52, 0x92, 0x66, 0xe8, 0x01, 0x88, 0x08, 0x3d, 0x0b, - 0x3d, 0x95, 0x6d, 0xeb, 0x56, 0x66, 0x48, 0x9a, 0x69, 0x27, 0xcf, 0xb4, 0x73, 0x9e, 0x97, 0xc2, - 0xe1, 0xa2, 0x32, 0xe4, 0xab, 0x1f, 0xb6, 0x0d, 0xb7, 0xa9, 0xe5, 0xd4, 0x8d, 0xf9, 0x39, 0xac, - 0xc6, 0x61, 0x9f, 0x85, 0x3e, 0x0d, 0x07, 0x5e, 0x44, 0x38, 0x65, 0xbe, 0xb5, 0xa8, 0xa1, 0x36, - 0xaf, 0x40, 0x1d, 0x65, 0x45, 0x93, 0x22, 0x7d, 0xad, 0x90, 0x56, 0x0a, 0xe1, 0x53, 0x2d, 0x6b, - 0x7e, 0x01, 0x26, 0xc6, 0x89, 0x36, 0x89, 0xc5, 0x32, 0x47, 0x6c, 0xce, 0x8e, 0xb8, 0x8a, 0x71, - 0x72, 0x9e, 0x4a, 0x67, 0x90, 0xbf, 0x87, 0xdb, 0x92, 0xa3, 0x50, 0x3c, 0x21, 0x7c, 0x1a, 0x17, - 0x66, 0xc7, 0x7d, 0x23, 0xc7, 0x98, 0x04, 0x7f, 0x00, 0x3b, 0x38, 0x2b, 0x20, 0x8f, 0x13, 0x9f, - 0x0a, 0xc9, 0x69, 0x3f, 0x56, 0xb2, 0xde, 0x13, 0x8e, 0xb0, 0xae, 0x91, 0x96, 0x2e, 0x82, 0x4e, - 0xce, 0xe7, 0x4e, 0xb0, 0x7d, 0x9c, 0x71, 0x99, 0x8f, 0xe0, 0x27, 0xfd, 0x80, 0xe1, 0x4b, 0xa1, - 0x8c, 0xf3, 0x26, 0x90, 0xb4, 0xea, 0x11, 0x15, 0x42, 0xa1, 0x2d, 0xed, 0x18, 0xbb, 0x75, 0xf7, - 0x6e, 0xca, 0x7b, 0x4a, 0xf8, 0x51, 0x85, 0xf3, 0xbc, 0xc2, 0x68, 0xbe, 0x07, 0xe6, 0x90, 0x0a, - 0xc9, 0x38, 0xc5, 0x28, 0xf0, 0x48, 0x28, 0x39, 0x25, 0xc2, 0x5a, 0xd6, 0xe2, 0x6b, 0xe5, 0xcd, - 0xfd, 0xf4, 0xc2, 0x7c, 0x08, 0x77, 0x6f, 0x54, 0xea, 0xe1, 0x21, 0x0a, 0x43, 0x12, 0x58, 0x6d, - 0xed, 0xca, 0xb6, 0x7f, 0x83, 0xce, 0x5e, 0xca, 0x76, 0x6f, 0xf1, 0x8f, 0xdf, 0x6c, 0xcf, 0x7d, - 0xfd, 0xcd, 0xf6, 0x9c, 0xfd, 0x0f, 0x03, 0x6e, 0xf7, 0x0a, 0xc7, 0x47, 0x2c, 0x41, 0xc1, 0xff, - 0xb3, 0xc1, 0x0e, 0xa0, 0x29, 0x24, 0x8b, 0xd2, 0x92, 0x6e, 0xbc, 0x42, 0x49, 0x2f, 0x2a, 0x31, - 0x75, 0x61, 0xff, 0xc5, 0x80, 0x8d, 0xfb, 0x4f, 0x63, 0x9a, 0x30, 0x8c, 0xfe, 0x27, 0xf3, 0xe0, - 0x04, 0x96, 0x49, 0x05, 0x4f, 0x58, 0xf5, 0x9d, 0xfa, 0x6e, 0x6b, 0xff, 0x6d, 0x27, 0x1d, 0x4e, - 0x4e, 0x31, 0xb3, 0xb2, 0x01, 0xe5, 0x54, 0xb5, 0xbb, 0x93, 0xb2, 0xf7, 0x6a, 0x96, 0x61, 0xff, - 0xcd, 0x80, 0x3b, 0x2a, 0xd2, 0x03, 0xe2, 0x92, 0x67, 0x88, 0xfb, 0x47, 0x24, 0x64, 0x23, 0xf1, - 0xda, 0x76, 0xda, 0xb0, 0xec, 0x6b, 0x24, 0x4f, 0x32, 0x0f, 0xf9, 0xbe, 0xb6, 0x53, 0xf3, 0x28, - 0xe2, 0x39, 0x3b, 0xf0, 0x7d, 0x73, 0x17, 0x56, 0x4b, 0x1e, 0xae, 0xf2, 0xa9, 0xc2, 0xac, 0xd8, - 0xda, 0x39, 0x9b, 0xce, 0x32, 0xb1, 0xff, 0x6d, 0xc0, 0xea, 0x27, 0x01, 0xeb, 0xa3, 0xe0, 0x2c, - 0x40, 0x62, 0xa8, 0xaa, 0x6c, 0xac, 0xd2, 0xc3, 0x49, 0xd6, 0xde, 0xda, 0xbc, 0x99, 0xd3, 0xa3, - 0xc4, 0xf4, 0xc0, 0xf9, 0x08, 0xd6, 0x8a, 0x86, 0x2b, 0xaa, 0x40, 0x7b, 0x73, 0xb8, 0xfe, 0xfc, - 0xfb, 0xed, 0x95, 0xbc, 0xd8, 0x7a, 0xba, 0x22, 0x8e, 0xdc, 0x15, 0x3c, 0x41, 0xf0, 0xcd, 0x0e, - 0xb4, 0x68, 0x1f, 0x7b, 0x82, 0x3c, 0xf5, 0xc2, 0x78, 0xa4, 0x0b, 0xa8, 0xe1, 0x36, 0x69, 0x1f, - 0x9f, 0x91, 0xa7, 0x9f, 0xc7, 0x23, 0xf3, 0x7d, 0x78, 0x33, 0x5f, 0xac, 0x5e, 0x82, 0x02, 0x4f, - 0xc9, 0xab, 0x70, 0x70, 0x5d, 0x4f, 0x4b, 0xee, 0x7a, 0x7e, 0x7b, 0x81, 0x02, 0xa5, 0xec, 0xc0, - 0xf7, 0xb9, 0xfd, 0x62, 0x1e, 0x16, 0x4e, 0x11, 0x47, 0x23, 0x61, 0x9e, 0xc3, 0x8a, 0x24, 0xa3, - 0x28, 0x40, 0x92, 0x78, 0xe9, 0x30, 0xcf, 0x3c, 0x7d, 0x57, 0x0f, 0xf9, 0xea, 0x12, 0x74, 0x2a, - 0x6b, 0x2f, 0xd9, 0x73, 0x7a, 0x9a, 0x7a, 0x26, 0x91, 0x24, 0x6e, 0x3b, 0xc7, 0x48, 0x89, 0xe6, - 0x07, 0x60, 0x49, 0x1e, 0x0b, 0x59, 0x8e, 0xd9, 0x72, 0xbe, 0xa4, 0xb9, 0x7c, 0x33, 0xbf, 0x4f, - 0x27, 0x53, 0x31, 0x57, 0xae, 0x9f, 0xa8, 0xf5, 0xd7, 0x99, 0xa8, 0x67, 0xb0, 0xae, 0xd6, 0xd1, - 0x34, 0x66, 0x63, 0x76, 0xcc, 0x35, 0x25, 0x3f, 0x09, 0xfa, 0x05, 0x98, 0x89, 0xc0, 0xd3, 0x98, - 0xf3, 0xaf, 0x60, 0x67, 0x22, 0xf0, 0x24, 0xa4, 0x0f, 0x5b, 0x42, 0x15, 0x9f, 0x37, 0x22, 0x52, - 0xcf, 0xe7, 0x28, 0x20, 0x21, 0x15, 0xc3, 0x1c, 0x7c, 0x61, 0x76, 0xf0, 0x4d, 0x0d, 0xf4, 0x99, - 0xc2, 0x71, 0x73, 0x98, 0x4c, 0x4b, 0x0f, 0x3a, 0xd7, 0x6b, 0x29, 0x12, 0x74, 0x4b, 0x27, 0xe8, - 0x47, 0xd7, 0x40, 0x14, 0x59, 0x12, 0xf0, 0x4e, 0x65, 0x8f, 0xa8, 0xae, 0xf6, 0x74, 0x43, 0x79, - 0x9c, 0x0c, 0xd4, 0xb0, 0x45, 0xe9, 0x4a, 0x21, 0xa4, 0xd8, 0x85, 0xd9, 0xf4, 0x50, 0x4f, 0x9b, - 0x62, 0x72, 0xf4, 0x18, 0x0d, 0xb3, 0x07, 0x83, 0x5d, 0xae, 0x9b, 0x62, 0x46, 0xb8, 0x15, 0xac, - 0x8f, 0x09, 0x51, 0xdd, 0x5c, 0x59, 0x39, 0x24, 0x62, 0x78, 0xa8, 0x57, 0x62, 0xdd, 0x6d, 0x17, - 0xeb, 0xe5, 0xbe, 0xa2, 0x3e, 0x6c, 0x2c, 0x2e, 0xae, 0x36, 0xed, 0x9f, 0x41, 0x53, 0x37, 0xf3, - 0x01, 0xbe, 0x14, 0xe6, 0x16, 0x34, 0x55, 0x57, 0x10, 0x21, 0x88, 0xb0, 0x0c, 0x3d, 0x03, 0x4a, - 0x82, 0x2d, 0x61, 0xf3, 0xa6, 0x87, 0x95, 0x30, 0x1f, 0xc3, 0xad, 0x88, 0xe8, 0xad, 0xaf, 0x05, - 0x5b, 0xfb, 0x1f, 0x3a, 0x33, 0xbc, 0x71, 0x9d, 0x9b, 0x00, 0xdd, 0x1c, 0xcd, 0xe6, 0xe5, 0x73, - 0x6e, 0x6a, 0xd9, 0x08, 0xf3, 0x62, 0x5a, 0xe9, 0xaf, 0x5f, 0x49, 0xe9, 0x14, 0x5e, 0xa9, 0xf3, - 0x5d, 0x68, 0x1d, 0xa4, 0x6e, 0x7f, 0x4a, 0x85, 0xbc, 0x1a, 0x96, 0xa5, 0x6a, 0x58, 0x1e, 0x42, - 0x3b, 0xdb, 0x91, 0xe7, 0x4c, 0x0f, 0x24, 0xf3, 0xc7, 0x00, 0xd9, 0x72, 0x55, 0x83, 0x2c, 0x1d, - 0xd9, 0xcd, 0x8c, 0x72, 0xec, 0x4f, 0xec, 0xba, 0xda, 0xc4, 0xae, 0xb3, 0x5d, 0x58, 0xb9, 0x10, - 0xf8, 0x37, 0xf9, 0x03, 0xea, 0x51, 0x24, 0xcc, 0x37, 0x60, 0x41, 0xf5, 0x50, 0x06, 0xd4, 0x70, - 0xe7, 0x13, 0x81, 0x8f, 0xf5, 0xd4, 0x2e, 0x1f, 0x69, 0x2c, 0xf2, 0xa8, 0x2f, 0xac, 0xda, 0x4e, - 0x7d, 0xb7, 0xe1, 0xb6, 0xe3, 0x52, 0xfc, 0xd8, 0x17, 0xf6, 0x6f, 0xa1, 0x55, 0x01, 0x34, 0xdb, - 0x50, 0x2b, 0xb0, 0x6a, 0xd4, 0x37, 0xef, 0xc1, 0x66, 0x09, 0x34, 0x39, 0x86, 0x53, 0xc4, 0xa6, - 0x7b, 0xbb, 0x60, 0x98, 0x98, 0xc4, 0xc2, 0x7e, 0x04, 0x1b, 0xc7, 0x65, 0xd3, 0x17, 0x43, 0x7e, - 0xc2, 0x43, 0x63, 0x72, 0x9b, 0x6f, 0x41, 0xb3, 0xf8, 0x25, 0xa2, 0xbd, 0x6f, 0xb8, 0x25, 0xc1, - 0x1e, 0xc1, 0xea, 0x85, 0xc0, 0x67, 0x24, 0xf4, 0x4b, 0xb0, 0x1b, 0x02, 0x70, 0x38, 0x0d, 0x34, - 0xf3, 0x4b, 0xb7, 0x54, 0xc7, 0x60, 0xf3, 0x02, 0x05, 0xd4, 0x47, 0x92, 0xf1, 0x33, 0x22, 0xd3, - 0x05, 0x7c, 0x8a, 0xf0, 0x25, 0x91, 0xc2, 0x74, 0xa1, 0x11, 0x50, 0x21, 0xb3, 0xca, 0xfa, 0xe0, - 0xc6, 0xca, 0x4a, 0xf6, 0x9c, 0x9b, 0x40, 0x8e, 0x90, 0x44, 0x59, 0xef, 0x6a, 0x2c, 0xfb, 0xa7, - 0xb0, 0xfe, 0x19, 0x92, 0x31, 0x27, 0xfe, 0x44, 0x8e, 0x57, 0xa1, 0xae, 0xf2, 0x67, 0xe8, 0xfc, - 0xa9, 0xa3, 0x7a, 0x0f, 0x58, 0xf7, 0xbf, 0x8c, 0x18, 0x97, 0xc4, 0xbf, 0x12, 0x91, 0x97, 0x84, - 0xf7, 0x12, 0xd6, 0x55, 0xb0, 0x04, 0x09, 0x7d, 0xaf, 0xf0, 0x33, 0xcd, 0x63, 0x6b, 0xff, 0x57, - 0x33, 0x75, 0xc7, 0xb4, 0xba, 0xcc, 0x81, 0xb5, 0x64, 0x8a, 0x2e, 0xec, 0x3f, 0x19, 0x60, 0x9d, - 0x90, 0xf1, 0x81, 0x10, 0x74, 0x10, 0x8e, 0x48, 0x28, 0xd5, 0x0c, 0x44, 0x98, 0xa8, 0xa3, 0xf9, - 0x16, 0x2c, 0x17, 0x3b, 0x57, 0xaf, 0x5a, 0x43, 0xaf, 0xda, 0xa5, 0x9c, 0xa8, 0x1a, 0xcc, 0xbc, - 0x07, 0x10, 0x71, 0x92, 0x78, 0xd8, 0xbb, 0x24, 0xe3, 0x2c, 0x8b, 0x5b, 0xd5, 0x15, 0x9a, 0xfe, - 0x4e, 0x74, 0x4e, 0xe3, 0x7e, 0x40, 0xf1, 0x09, 0x19, 0xbb, 0x8b, 0x8a, 0xbf, 0x77, 0x42, 0xc6, - 0xea, 0x4d, 0x14, 0xb1, 0x67, 0x84, 0xeb, 0xbd, 0x57, 0x77, 0xd3, 0x0f, 0xfb, 0xcf, 0x06, 0xdc, - 0x2e, 0xd2, 0x91, 0x97, 0xeb, 0x69, 0xdc, 0x57, 0x12, 0x2f, 0x89, 0xdb, 0x15, 0x6b, 0x6b, 0xd7, - 0x58, 0xfb, 0x11, 0x2c, 0x15, 0x0d, 0xa2, 0xec, 0xad, 0xcf, 0x60, 0x6f, 0x2b, 0x97, 0x38, 0x21, - 0x63, 0xfb, 0x0f, 0x15, 0xdb, 0x0e, 0xc7, 0x95, 0xd9, 0xc7, 0xff, 0x8b, 0x6d, 0x85, 0xda, 0xaa, - 0x6d, 0xb8, 0x2a, 0x7f, 0xc5, 0x81, 0xfa, 0x55, 0x07, 0xec, 0xbf, 0x1a, 0xb0, 0x51, 0xd5, 0x2a, - 0xce, 0xd9, 0x29, 0x8f, 0x43, 0xf2, 0x32, 0xed, 0x65, 0xfb, 0xd5, 0xaa, 0xed, 0xf7, 0x18, 0xda, - 0x13, 0x46, 0x89, 0x2c, 0x1a, 0xbf, 0x98, 0xa9, 0xc6, 0x2a, 0xd3, 0xd5, 0x5d, 0xae, 0xfa, 0x21, - 0xec, 0xbf, 0x1b, 0xb0, 0x96, 0xdb, 0x58, 0x04, 0xcb, 0xfc, 0x39, 0x98, 0x85, 0x7b, 0xe5, 0xeb, - 0x2d, 0x2d, 0xa9, 0xd5, 0xfc, 0x26, 0x7f, 0xba, 0x95, 0xa5, 0x51, 0xab, 0x94, 0x86, 0xf9, 0x29, - 0xac, 0x17, 0x26, 0x47, 0x3a, 0x41, 0x33, 0x67, 0xb1, 0x78, 0x9f, 0x16, 0xa4, 0xc3, 0xc7, 0xdf, - 0x3e, 0xef, 0x18, 0xdf, 0x3d, 0xef, 0x18, 0xff, 0x7a, 0xde, 0x31, 0xbe, 0x7a, 0xd1, 0x99, 0xfb, - 0xee, 0x45, 0x67, 0xee, 0x9f, 0x2f, 0x3a, 0x73, 0xbf, 0xfb, 0x70, 0x40, 0xe5, 0x30, 0xee, 0x3b, - 0x98, 0x8d, 0xba, 0xd9, 0x9f, 0x15, 0x65, 0x4c, 0xde, 0x2b, 0xfe, 0xc9, 0x49, 0x7e, 0xd9, 0xfd, - 0x72, 0xf2, 0x7f, 0x22, 0x39, 0x8e, 0x88, 0xe8, 0x2f, 0xe8, 0xe9, 0xf5, 0xfe, 0x7f, 0x02, 0x00, - 0x00, 0xff, 0xff, 0x0a, 0xef, 0x81, 0x2b, 0x58, 0x12, 0x00, 0x00, + 0x63, 0x4f, 0x69, 0x61, 0x1f, 0x7b, 0xed, 0x07, 0x28, 0x66, 0xf6, 0x2f, 0x29, 0xc9, 0xa5, 0x91, + 0xf6, 0xb6, 0x7c, 0xf3, 0xde, 0xef, 0xbd, 0x79, 0x7f, 0x7e, 0x6f, 0x24, 0xd8, 0xa7, 0xa1, 0x24, + 0x1c, 0x0f, 0x11, 0x0d, 0x3d, 0x41, 0x70, 0xcc, 0xa9, 0x1c, 0x77, 0x31, 0x4e, 0xba, 0x11, 0x67, + 0x09, 0xf5, 0x09, 0xef, 0x26, 0x7b, 0xc5, 0xb7, 0x13, 0x71, 0x26, 0x99, 0xf9, 0xd6, 0x35, 0x36, + 0x0e, 0xc6, 0x89, 0x53, 0xe8, 0x25, 0x7b, 0x77, 0xde, 0xbe, 0x09, 0x38, 0xd9, 0xeb, 0x3e, 0xa7, + 0x9c, 0xa4, 0x58, 0x77, 0x36, 0x07, 0x6c, 0xc0, 0xf4, 0x67, 0x57, 0x7d, 0x65, 0xd2, 0x9d, 0x01, + 0x63, 0x83, 0x80, 0x74, 0xf5, 0xaf, 0x7e, 0xfc, 0xb4, 0x2b, 0xe9, 0x88, 0x08, 0x89, 0x46, 0x51, + 0xa6, 0xd0, 0x9e, 0x56, 0xf0, 0x63, 0x8e, 0x24, 0x65, 0x61, 0x0e, 0x40, 0xfb, 0xb8, 0x8b, 0x19, + 0x27, 0x5d, 0x1c, 0x50, 0x12, 0x4a, 0xe5, 0x35, 0xfd, 0xca, 0x14, 0xba, 0x4a, 0x21, 0xa0, 0x83, + 0xa1, 0x4c, 0xc5, 0xa2, 0x2b, 0x49, 0xe8, 0x13, 0x3e, 0xa2, 0xa9, 0x72, 0xf9, 0x2b, 0x33, 0xd8, + 0xae, 0x9c, 0x63, 0x3e, 0x8e, 0x24, 0xeb, 0x5e, 0x92, 0xb1, 0xc8, 0x4e, 0xdf, 0xc1, 0x4c, 0x8c, + 0x98, 0xe8, 0x12, 0x75, 0xff, 0x10, 0x93, 0x6e, 0xb2, 0xd7, 0x27, 0x12, 0xed, 0x15, 0x82, 0x3c, + 0xee, 0x4c, 0xaf, 0x8f, 0x44, 0xa9, 0x83, 0x19, 0xcd, 0xe2, 0xb6, 0xff, 0xbd, 0x08, 0x56, 0x8f, + 0x85, 0x22, 0x1e, 0x11, 0x7e, 0xe0, 0xfb, 0x54, 0x5d, 0xe9, 0x94, 0xb3, 0x88, 0x09, 0x14, 0x98, + 0x9b, 0xb0, 0x20, 0xa9, 0x0c, 0x88, 0x65, 0x74, 0x8c, 0xdd, 0x86, 0x9b, 0xfe, 0x30, 0x3b, 0xd0, + 0xf4, 0x89, 0xc0, 0x9c, 0x46, 0x4a, 0xd9, 0x9a, 0xd7, 0x67, 0x55, 0x91, 0xb9, 0x05, 0x4b, 0x69, + 0x1d, 0xa8, 0x6f, 0xd5, 0xf4, 0xf1, 0x2d, 0xfd, 0xfb, 0xd8, 0x37, 0x3f, 0x81, 0x16, 0x0d, 0xa9, + 0xa4, 0x28, 0xf0, 0x86, 0x44, 0x65, 0xc3, 0xaa, 0x77, 0x8c, 0xdd, 0xe6, 0xfe, 0x1d, 0x87, 0xf6, + 0xb1, 0xa3, 0x12, 0xe8, 0x64, 0x69, 0x4b, 0xf6, 0x9c, 0x07, 0x5a, 0xe3, 0xb0, 0xfe, 0xcd, 0x77, + 0x3b, 0x73, 0xee, 0x4a, 0x66, 0x97, 0x0a, 0xcd, 0xbb, 0xb0, 0x3c, 0x20, 0x21, 0x11, 0x54, 0x78, + 0x43, 0x24, 0x86, 0xd6, 0x42, 0xc7, 0xd8, 0x5d, 0x76, 0x9b, 0x99, 0xec, 0x01, 0x12, 0x43, 0x73, + 0x07, 0x9a, 0x7d, 0x1a, 0x22, 0x3e, 0x4e, 0x35, 0x16, 0xb5, 0x06, 0xa4, 0x22, 0xad, 0xd0, 0x03, + 0x10, 0x11, 0x7a, 0x1e, 0x7a, 0xaa, 0xda, 0xd6, 0xad, 0x2c, 0x90, 0xb4, 0xd2, 0x4e, 0x5e, 0x69, + 0xe7, 0x3c, 0x6f, 0x85, 0xc3, 0x25, 0x15, 0xc8, 0x97, 0xff, 0xd8, 0x31, 0xdc, 0x86, 0xb6, 0x53, + 0x27, 0xe6, 0x23, 0x58, 0x8b, 0xc3, 0x3e, 0x0b, 0x7d, 0x1a, 0x0e, 0xbc, 0x88, 0x70, 0xca, 0x7c, + 0x6b, 0x49, 0x43, 0x6d, 0x5d, 0x81, 0x3a, 0xca, 0x9a, 0x26, 0x45, 0xfa, 0x4a, 0x21, 0xad, 0x16, + 0xc6, 0xa7, 0xda, 0xd6, 0xfc, 0x1c, 0x4c, 0x8c, 0x13, 0x1d, 0x12, 0x8b, 0x65, 0x8e, 0xd8, 0x98, + 0x1d, 0x71, 0x0d, 0xe3, 0xe4, 0x3c, 0xb5, 0xce, 0x20, 0x7f, 0x0b, 0xb7, 0x25, 0x47, 0xa1, 0x78, + 0x4a, 0xf8, 0x34, 0x2e, 0xcc, 0x8e, 0xfb, 0x46, 0x8e, 0x31, 0x09, 0xfe, 0x00, 0x3a, 0x38, 0x6b, + 0x20, 0x8f, 0x13, 0x9f, 0x0a, 0xc9, 0x69, 0x3f, 0x56, 0xb6, 0xde, 0x53, 0x8e, 0xb0, 0xee, 0x91, + 0xa6, 0x6e, 0x82, 0x76, 0xae, 0xe7, 0x4e, 0xa8, 0x7d, 0x9c, 0x69, 0x99, 0x8f, 0xe1, 0x47, 0xfd, + 0x80, 0xe1, 0x4b, 0xa1, 0x82, 0xf3, 0x26, 0x90, 0xb4, 0xeb, 0x11, 0x15, 0x42, 0xa1, 0x2d, 0x77, + 0x8c, 0xdd, 0x9a, 0x7b, 0x37, 0xd5, 0x3d, 0x25, 0xfc, 0xa8, 0xa2, 0x79, 0x5e, 0x51, 0x34, 0xdf, + 0x03, 0x73, 0x48, 0x85, 0x64, 0x9c, 0x62, 0x14, 0x78, 0x24, 0x94, 0x9c, 0x12, 0x61, 0xad, 0x68, + 0xf3, 0xf5, 0xf2, 0xe4, 0x7e, 0x7a, 0x60, 0x3e, 0x84, 0xbb, 0x37, 0x3a, 0xf5, 0xf0, 0x10, 0x85, + 0x21, 0x09, 0xac, 0x96, 0xbe, 0xca, 0x8e, 0x7f, 0x83, 0xcf, 0x5e, 0xaa, 0x66, 0x6e, 0xc0, 0x82, + 0x64, 0x91, 0xf7, 0xc8, 0x5a, 0xed, 0x18, 0xbb, 0x2b, 0x6e, 0x5d, 0xb2, 0xe8, 0xd1, 0xbd, 0xa5, + 0xdf, 0x7f, 0xbd, 0x33, 0xf7, 0xd5, 0xd7, 0x3b, 0x73, 0xf6, 0xdf, 0x0c, 0xb8, 0xdd, 0x2b, 0xb2, + 0x31, 0x62, 0x09, 0x0a, 0xfe, 0x9f, 0x53, 0x77, 0x00, 0x0d, 0xa1, 0xc2, 0xd1, 0x7d, 0x5e, 0x7f, + 0x8d, 0x3e, 0x5f, 0x52, 0x66, 0xea, 0xc0, 0xfe, 0x93, 0x01, 0x9b, 0xf7, 0x9f, 0xc5, 0x34, 0x61, + 0x18, 0xfd, 0x4f, 0x48, 0xe2, 0x04, 0x56, 0x48, 0x05, 0x4f, 0x58, 0xb5, 0x4e, 0x6d, 0xb7, 0xb9, + 0xff, 0xb6, 0x93, 0x32, 0x96, 0x53, 0x10, 0x59, 0xc6, 0x5a, 0x4e, 0xd5, 0xbb, 0x3b, 0x69, 0x7b, + 0x6f, 0xde, 0x32, 0xec, 0xbf, 0x18, 0x70, 0x47, 0xa5, 0x7f, 0x40, 0x5c, 0xf2, 0x1c, 0x71, 0xff, + 0x88, 0x84, 0x6c, 0x24, 0xbe, 0x77, 0x9c, 0x36, 0xac, 0xf8, 0x1a, 0xc9, 0x93, 0xcc, 0x43, 0xbe, + 0xaf, 0xe3, 0xd4, 0x3a, 0x4a, 0x78, 0xce, 0x0e, 0x7c, 0xdf, 0xdc, 0x85, 0xb5, 0x52, 0x87, 0xab, + 0x7a, 0xaa, 0x34, 0x2b, 0xb5, 0x56, 0xae, 0xa6, 0xab, 0x4c, 0xec, 0x7f, 0x19, 0xb0, 0xf6, 0x49, + 0xc0, 0xfa, 0x28, 0x38, 0x0b, 0x90, 0x18, 0xaa, 0xd6, 0x1b, 0xab, 0xf2, 0x70, 0x92, 0xcd, 0xbc, + 0x0e, 0x6f, 0xe6, 0xf2, 0x28, 0x33, 0xcd, 0x42, 0x1f, 0xc1, 0x7a, 0x31, 0x85, 0x45, 0x17, 0xe8, + 0xdb, 0x1c, 0x6e, 0xbc, 0xf8, 0x6e, 0x67, 0x35, 0x6f, 0xb6, 0x9e, 0xee, 0x88, 0x23, 0x77, 0x15, + 0x4f, 0x08, 0x7c, 0xb3, 0x0d, 0x4d, 0xda, 0xc7, 0x9e, 0x20, 0xcf, 0xbc, 0x30, 0x1e, 0xe9, 0x06, + 0xaa, 0xbb, 0x0d, 0xda, 0xc7, 0x67, 0xe4, 0xd9, 0xa3, 0x78, 0x64, 0xbe, 0x0f, 0x6f, 0xe6, 0xdb, + 0xd6, 0x4b, 0x50, 0xe0, 0x29, 0x7b, 0x95, 0x0e, 0xae, 0xfb, 0x69, 0xd9, 0xdd, 0xc8, 0x4f, 0x2f, + 0x50, 0xa0, 0x9c, 0x1d, 0xf8, 0x3e, 0xb7, 0x5f, 0x2e, 0xc0, 0xe2, 0x29, 0xe2, 0x68, 0x24, 0xcc, + 0x73, 0x58, 0x95, 0x64, 0x14, 0x05, 0x48, 0x12, 0x2f, 0x65, 0xf8, 0xec, 0xa6, 0xef, 0x6a, 0xe6, + 0xaf, 0x6e, 0x46, 0xa7, 0xb2, 0x0b, 0x93, 0x3d, 0xa7, 0xa7, 0xa5, 0x67, 0x12, 0x49, 0xe2, 0xb6, + 0x72, 0x8c, 0x54, 0x68, 0x7e, 0x00, 0x96, 0xe4, 0xb1, 0x90, 0x25, 0xf7, 0x96, 0xa4, 0x93, 0xd6, + 0xf2, 0xcd, 0xfc, 0x3c, 0xa5, 0xab, 0x82, 0x6c, 0xae, 0xa7, 0xd9, 0xda, 0xf7, 0xa1, 0xd9, 0x33, + 0xd8, 0x50, 0x3b, 0x6a, 0x1a, 0xb3, 0x3e, 0x3b, 0xe6, 0xba, 0xb2, 0x9f, 0x04, 0xfd, 0x1c, 0xcc, + 0x44, 0xe0, 0x69, 0xcc, 0x85, 0xd7, 0x88, 0x33, 0x11, 0x78, 0x12, 0xd2, 0x87, 0x6d, 0xa1, 0x9a, + 0xcf, 0x1b, 0x11, 0xa9, 0x49, 0x3b, 0x0a, 0x48, 0x48, 0xc5, 0x30, 0x07, 0x5f, 0x9c, 0x1d, 0x7c, + 0x4b, 0x03, 0x7d, 0xa6, 0x70, 0xdc, 0x1c, 0x26, 0xf3, 0xd2, 0x83, 0xf6, 0xf5, 0x5e, 0x8a, 0x02, + 0xdd, 0xd2, 0x05, 0xfa, 0xc1, 0x35, 0x10, 0x45, 0x95, 0x04, 0xbc, 0x53, 0x59, 0x2e, 0x6a, 0xaa, + 0x3d, 0x3d, 0x50, 0x1e, 0x27, 0x03, 0xc5, 0xc0, 0x28, 0xdd, 0x33, 0x84, 0x14, 0x0b, 0x32, 0x63, + 0x0f, 0xf5, 0xde, 0x29, 0x98, 0xa3, 0xc7, 0x68, 0x98, 0xbd, 0x22, 0xec, 0x72, 0x07, 0x15, 0x1c, + 0xe1, 0x56, 0xb0, 0x3e, 0x26, 0x44, 0x4d, 0x73, 0x65, 0x0f, 0x91, 0x88, 0xe1, 0xa1, 0xde, 0x93, + 0x35, 0xb7, 0x55, 0xec, 0x9c, 0xfb, 0x4a, 0xfa, 0xb0, 0xbe, 0xb4, 0xb4, 0xd6, 0xb0, 0x7f, 0x02, + 0x0d, 0x3d, 0xcc, 0x07, 0xf8, 0x52, 0x98, 0xdb, 0xd0, 0x50, 0x53, 0x41, 0x84, 0x20, 0xc2, 0x32, + 0x34, 0x07, 0x94, 0x02, 0x5b, 0xc2, 0xd6, 0x4d, 0xaf, 0x2d, 0x61, 0x3e, 0x81, 0x5b, 0x11, 0xd1, + 0x4f, 0x01, 0x6d, 0xd8, 0xdc, 0xff, 0xd0, 0x99, 0xe1, 0xe1, 0xeb, 0xdc, 0x04, 0xe8, 0xe6, 0x68, + 0x36, 0x2f, 0xdf, 0x78, 0x53, 0xcb, 0x46, 0x98, 0x17, 0xd3, 0x4e, 0x7f, 0xf9, 0x5a, 0x4e, 0xa7, + 0xf0, 0x4a, 0x9f, 0xef, 0x42, 0xf3, 0x20, 0xbd, 0xf6, 0xa7, 0x54, 0xc8, 0xab, 0x69, 0x59, 0xae, + 0xa6, 0xe5, 0x21, 0xb4, 0xb2, 0xc5, 0x79, 0xce, 0x34, 0x21, 0x99, 0x3f, 0x04, 0xc8, 0x36, 0xae, + 0x22, 0xb2, 0x94, 0xb2, 0x1b, 0x99, 0xe4, 0xd8, 0x9f, 0xd8, 0x75, 0xf3, 0x13, 0xbb, 0xce, 0x76, + 0x61, 0xf5, 0x42, 0xe0, 0x5f, 0xe5, 0xaf, 0xaa, 0xc7, 0x91, 0x30, 0xdf, 0x80, 0x45, 0x35, 0x43, + 0x19, 0x50, 0xdd, 0x5d, 0x48, 0x04, 0x3e, 0xd6, 0xac, 0x5d, 0xbe, 0xdc, 0x58, 0xe4, 0x51, 0x5f, + 0x58, 0xf3, 0x9d, 0xda, 0x6e, 0xdd, 0x6d, 0xc5, 0xa5, 0xf9, 0xb1, 0x2f, 0xec, 0x5f, 0x43, 0xb3, + 0x02, 0x68, 0xb6, 0x60, 0xbe, 0xc0, 0x9a, 0xa7, 0xbe, 0x79, 0x0f, 0xb6, 0x4a, 0xa0, 0x49, 0x1a, + 0x4e, 0x11, 0x1b, 0xee, 0xed, 0x42, 0x61, 0x82, 0x89, 0x85, 0xfd, 0x18, 0x36, 0x8f, 0xcb, 0xa1, + 0x2f, 0x48, 0x7e, 0xe2, 0x86, 0xc6, 0xe4, 0x36, 0xdf, 0x86, 0x46, 0xf1, 0xe7, 0x89, 0xbe, 0x7d, + 0xdd, 0x2d, 0x05, 0xf6, 0x08, 0xd6, 0x2e, 0x04, 0x3e, 0x23, 0xa1, 0x5f, 0x82, 0xdd, 0x90, 0x80, + 0xc3, 0x69, 0xa0, 0x99, 0x9f, 0xbf, 0xa5, 0x3b, 0x06, 0x5b, 0x17, 0x28, 0xa0, 0x3e, 0x92, 0x8c, + 0x9f, 0x11, 0x99, 0x2e, 0xe0, 0x53, 0x84, 0x2f, 0x89, 0x14, 0xa6, 0x0b, 0xf5, 0x80, 0x0a, 0x99, + 0x75, 0xd6, 0x07, 0x37, 0x76, 0x56, 0xb2, 0xe7, 0xdc, 0x04, 0x72, 0x84, 0x24, 0xca, 0x66, 0x57, + 0x63, 0xd9, 0x3f, 0x86, 0x8d, 0xcf, 0x90, 0x8c, 0x39, 0xf1, 0x27, 0x6a, 0xbc, 0x06, 0x35, 0x55, + 0x3f, 0x43, 0xd7, 0x4f, 0x7d, 0xaa, 0xf7, 0x80, 0x75, 0xff, 0x8b, 0x88, 0x71, 0x49, 0xfc, 0x2b, + 0x19, 0x79, 0x45, 0x7a, 0x2f, 0x61, 0x43, 0x25, 0x4b, 0x90, 0xd0, 0xf7, 0x8a, 0x7b, 0xa6, 0x75, + 0x6c, 0xee, 0xff, 0x62, 0xa6, 0xe9, 0x98, 0x76, 0x97, 0x5d, 0x60, 0x3d, 0x99, 0x92, 0x0b, 0xfb, + 0x0f, 0x06, 0x58, 0x27, 0x64, 0x7c, 0x20, 0x04, 0x1d, 0x84, 0x23, 0x12, 0x4a, 0xc5, 0x81, 0x08, + 0x13, 0xf5, 0x69, 0xbe, 0x05, 0x2b, 0xc5, 0xce, 0xd5, 0xab, 0xd6, 0xd0, 0xab, 0x76, 0x39, 0x17, + 0xaa, 0x01, 0x33, 0xef, 0x01, 0x44, 0x9c, 0x24, 0x1e, 0xf6, 0x2e, 0xc9, 0x38, 0xab, 0xe2, 0x76, + 0x75, 0x85, 0xa6, 0x7f, 0x3c, 0x3a, 0xa7, 0x71, 0x3f, 0xa0, 0xf8, 0x84, 0x8c, 0xdd, 0x25, 0xa5, + 0xdf, 0x3b, 0x21, 0x63, 0xf5, 0x26, 0x8a, 0xd8, 0x73, 0xc2, 0xf5, 0xde, 0xab, 0xb9, 0xe9, 0x0f, + 0xfb, 0x8f, 0x06, 0xdc, 0x2e, 0xca, 0x91, 0xb7, 0xeb, 0x69, 0xdc, 0x57, 0x16, 0xaf, 0xc8, 0xdb, + 0x95, 0x68, 0xe7, 0xaf, 0x89, 0xf6, 0x23, 0x58, 0x2e, 0x06, 0x44, 0xc5, 0x5b, 0x9b, 0x21, 0xde, + 0x66, 0x6e, 0x71, 0x42, 0xc6, 0xf6, 0xef, 0x2a, 0xb1, 0x1d, 0x8e, 0x2b, 0xdc, 0xc7, 0xff, 0x4b, + 0x6c, 0x85, 0xdb, 0x6a, 0x6c, 0xb8, 0x6a, 0x7f, 0xe5, 0x02, 0xb5, 0xab, 0x17, 0xb0, 0xff, 0x6c, + 0xc0, 0x66, 0xd5, 0xab, 0x38, 0x67, 0xa7, 0x3c, 0x0e, 0xc9, 0xab, 0xbc, 0x97, 0xe3, 0x37, 0x5f, + 0x1d, 0xbf, 0x27, 0xd0, 0x9a, 0x08, 0x4a, 0x64, 0xd9, 0xf8, 0xd9, 0x4c, 0x3d, 0x56, 0x61, 0x57, + 0x77, 0xa5, 0x7a, 0x0f, 0x61, 0xff, 0xd5, 0x80, 0xf5, 0x3c, 0xc6, 0x22, 0x59, 0xe6, 0x4f, 0xc1, + 0x2c, 0xae, 0x57, 0xbe, 0xde, 0xd2, 0x96, 0x5a, 0xcb, 0x4f, 0xf2, 0xa7, 0x5b, 0xd9, 0x1a, 0xf3, + 0x95, 0xd6, 0x30, 0x3f, 0x85, 0x8d, 0x22, 0xe4, 0x48, 0x17, 0x68, 0xe6, 0x2a, 0x16, 0xef, 0xd3, + 0x42, 0x74, 0xf8, 0xe4, 0x9b, 0x17, 0x6d, 0xe3, 0xdb, 0x17, 0x6d, 0xe3, 0x9f, 0x2f, 0xda, 0xc6, + 0x97, 0x2f, 0xdb, 0x73, 0xdf, 0xbe, 0x6c, 0xcf, 0xfd, 0xfd, 0x65, 0x7b, 0xee, 0x37, 0x1f, 0x0e, + 0xa8, 0x1c, 0xc6, 0x7d, 0x07, 0xb3, 0x51, 0x37, 0xfb, 0x0f, 0x46, 0x99, 0x93, 0xf7, 0x8a, 0x7f, + 0xef, 0x24, 0x3f, 0xef, 0x7e, 0x31, 0xf9, 0xcf, 0x23, 0x39, 0x8e, 0x88, 0xe8, 0x2f, 0x6a, 0xf6, + 0x7a, 0xff, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xc4, 0xae, 0x39, 0x65, 0x6d, 0x12, 0x00, 0x00, } func (m *ConsumerAdditionProposal) Marshal() (dAtA []byte, err error) { @@ -1623,6 +1629,11 @@ func (m *ConsumerAdditionProposal) MarshalToSizedBuffer(dAtA []byte) (int, error _ = i var l int _ = l + if m.Top_N != 0 { + i = encodeVarintProvider(dAtA, i, uint64(m.Top_N)) + i-- + dAtA[i] = 0x78 + } if len(m.DistributionTransmissionChannel) > 0 { i -= len(m.DistributionTransmissionChannel) copy(dAtA[i:], m.DistributionTransmissionChannel) @@ -2777,6 +2788,9 @@ func (m *ConsumerAdditionProposal) Size() (n int) { if l > 0 { n += 1 + l + sovProvider(uint64(l)) } + if m.Top_N != 0 { + n += 1 + sovProvider(uint64(m.Top_N)) + } return n } @@ -3673,6 +3687,25 @@ func (m *ConsumerAdditionProposal) Unmarshal(dAtA []byte) error { } m.DistributionTransmissionChannel = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 15: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Top_N", wireType) + } + m.Top_N = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProvider + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Top_N |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipProvider(dAtA[iNdEx:]) From 6693dd354cbc3b5ae9ad1718581f0eebe1e95433 Mon Sep 17 00:00:00 2001 From: insumity Date: Wed, 7 Feb 2024 11:35:28 +0100 Subject: [PATCH 007/110] feat!: introduce MsgOptIn and MsgOptOut (#1620) * init commit * cleaning up * changed cons to val address * Revert "changed cons to val address" This reverts commit a32e8829fee3cbbe50e363a0aa91ad62117a8a1d. * Update x/ccv/provider/keeper/keeper.go Co-authored-by: Simon Noetzlin * took into account comments * added key assignment * add contraint such that opt out only works if the chain is running --------- Co-authored-by: insumity Co-authored-by: Simon Noetzlin --- .../ccv/provider/v1/tx.proto | 28 + x/ccv/provider/client/cli/tx.go | 87 ++ x/ccv/provider/keeper/keeper.go | 141 ++- x/ccv/provider/keeper/keeper_test.go | 191 +++- x/ccv/provider/keeper/key_assignment.go | 48 + x/ccv/provider/keeper/msg_server.go | 101 +- x/ccv/provider/keeper/partial_set_security.go | 69 ++ .../keeper/partial_set_security_test.go | 111 +++ x/ccv/provider/types/codec.go | 8 + x/ccv/provider/types/keys.go | 30 + x/ccv/provider/types/keys_test.go | 3 + x/ccv/provider/types/msg.go | 113 +++ x/ccv/provider/types/tx.pb.go | 875 +++++++++++++++++- x/ccv/types/events.go | 2 + 14 files changed, 1717 insertions(+), 90 deletions(-) create mode 100644 x/ccv/provider/keeper/partial_set_security.go create mode 100644 x/ccv/provider/keeper/partial_set_security_test.go diff --git a/proto/interchain_security/ccv/provider/v1/tx.proto b/proto/interchain_security/ccv/provider/v1/tx.proto index 3294807015..51003bdf05 100644 --- a/proto/interchain_security/ccv/provider/v1/tx.proto +++ b/proto/interchain_security/ccv/provider/v1/tx.proto @@ -15,6 +15,8 @@ service Msg { rpc AssignConsumerKey(MsgAssignConsumerKey) returns (MsgAssignConsumerKeyResponse); rpc SubmitConsumerMisbehaviour(MsgSubmitConsumerMisbehaviour) returns (MsgSubmitConsumerMisbehaviourResponse); rpc SubmitConsumerDoubleVoting(MsgSubmitConsumerDoubleVoting) returns (MsgSubmitConsumerDoubleVotingResponse); + rpc OptIn(MsgOptIn) returns (MsgOptInResponse); + rpc OptOut(MsgOptOut) returns (MsgOptOutResponse); } message MsgAssignConsumerKey { @@ -61,3 +63,29 @@ message MsgSubmitConsumerDoubleVoting { } message MsgSubmitConsumerDoubleVotingResponse {} + +message MsgOptIn { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + // the chain id of the consumer chain to opt in to + string chain_id = 1; + // the validator address on the provider + string provider_addr = 2 [ (gogoproto.moretags) = "yaml:\"address\"" ]; + // (optional) the consensus public key to use on the consumer in json string format corresponding to proto-any, + // for example `{"@type":"/cosmos.crypto.ed25519.PubKey","key":"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is="}` + // we can set `consumer_key = ""` if we do not consider the `consumer_key` + string consumer_key = 3; +} + +message MsgOptInResponse {} + +message MsgOptOut { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + // the chain id of the consumer chain to opt out from + string chain_id = 1; + // the validator address on the provider + string provider_addr = 2 [ (gogoproto.moretags) = "yaml:\"address\"" ]; +} + +message MsgOptOutResponse {} \ No newline at end of file diff --git a/x/ccv/provider/client/cli/tx.go b/x/ccv/provider/client/cli/tx.go index 379e55a792..2d55b602dd 100644 --- a/x/ccv/provider/client/cli/tx.go +++ b/x/ccv/provider/client/cli/tx.go @@ -34,6 +34,8 @@ func GetTxCmd() *cobra.Command { cmd.AddCommand(NewAssignConsumerKeyCmd()) cmd.AddCommand(NewSubmitConsumerMisbehaviourCmd()) cmd.AddCommand(NewSubmitConsumerDoubleVotingCmd()) + cmd.AddCommand(NewOptInCmd()) + cmd.AddCommand(NewOptOutCmd()) return cmd } @@ -202,3 +204,88 @@ Example: return cmd } + +func NewOptInCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "opt-in [consumer-chain-id] [consumer-pubkey]", + Short: "opts in validator to the consumer chain, and if given uses the " + + "provided consensus public key for this consumer chain", + Args: cobra.RangeArgs(1, 2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + txf, err := tx.NewFactoryCLI(clientCtx, cmd.Flags()) + if err != nil { + return err + } + txf = txf.WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever) + + providerValAddr := clientCtx.GetFromAddress() + + var consumerPubKey string + if len(args) == 2 { + // consumer public key was provided + consumerPubKey = args[1] + } else { + consumerPubKey = "" + } + msg, err := types.NewMsgOptIn(args[0], sdk.ValAddress(providerValAddr), consumerPubKey) + + if err != nil { + return err + } + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + _ = cmd.MarkFlagRequired(flags.FlagFrom) + + return cmd +} + +func NewOptOutCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "opt-out [consumer-chain-id]", + Short: "opts out validator from this consumer chain", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + txf, err := tx.NewFactoryCLI(clientCtx, cmd.Flags()) + if err != nil { + return err + } + txf = txf.WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever) + + providerValAddr := clientCtx.GetFromAddress() + + msg, err := types.NewMsgOptOut(args[0], sdk.ValAddress(providerValAddr)) + if err != nil { + return err + } + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + _ = cmd.MarkFlagRequired(flags.FlagFrom) + + return cmd +} diff --git a/x/ccv/provider/keeper/keeper.go b/x/ccv/provider/keeper/keeper.go index 1a7fe69ee5..ea052ec5fd 100644 --- a/x/ccv/provider/keeper/keeper.go +++ b/x/ccv/provider/keeper/keeper.go @@ -1160,7 +1160,7 @@ func (k Keeper) DeleteTopN( store.Delete(types.TopNKey(chainID)) } -// GetTopN returns (N, true) if chain `chainID` has a top N associated, and (0, false) otherwise. +// GetTopN returns (N, true) if chain `chainID` has a top N associated, and (0, false) otherwise. func (k Keeper) GetTopN( ctx sdk.Context, chainID string, @@ -1184,3 +1184,142 @@ func (k Keeper) IsOptIn(ctx sdk.Context, chainID string) bool { topN, found := k.GetTopN(ctx, chainID) return !found || topN == 0 } + +func (k Keeper) SetOptedIn( + ctx sdk.Context, + chainID string, + providerAddr types.ProviderConsAddress, + blockHeight uint64, +) { + store := ctx.KVStore(k.storeKey) + + // validator is considered opted in + blockHeightBytes := make([]byte, 8) + binary.BigEndian.PutUint64(blockHeightBytes, blockHeight) + + store.Set(types.OptedInKey(chainID, providerAddr), blockHeightBytes) +} + +func (k Keeper) DeleteOptedIn( + ctx sdk.Context, + chainID string, + providerAddr types.ProviderConsAddress, +) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.OptedInKey(chainID, providerAddr)) +} + +func (k Keeper) IsOptedIn( + ctx sdk.Context, + chainID string, + providerAddr types.ProviderConsAddress, +) bool { + store := ctx.KVStore(k.storeKey) + return store.Get(types.OptedInKey(chainID, providerAddr)) != nil +} + +func (k Keeper) GetOptedIn( + ctx sdk.Context, + chainID string) (optedInValidators []OptedInValidator) { + store := ctx.KVStore(k.storeKey) + key := types.ChainIdWithLenKey(types.OptedInBytePrefix, chainID) + iterator := sdk.KVStorePrefixIterator(store, key) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + optedInValidators = append(optedInValidators, OptedInValidator{ + ProviderAddr: types.NewProviderConsAddress(iterator.Key()[len(key):]), + BlockHeight: binary.BigEndian.Uint64(iterator.Value()), + }) + } + + return optedInValidators +} + +func (k Keeper) SetToBeOptedIn( + ctx sdk.Context, + chainID string, + providerAddr types.ProviderConsAddress, +) { + store := ctx.KVStore(k.storeKey) + store.Set(types.ToBeOptedInKey(chainID, providerAddr), []byte{}) +} + +func (k Keeper) DeleteToBeOptedIn( + ctx sdk.Context, + chainID string, + providerAddr types.ProviderConsAddress, +) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.ToBeOptedInKey(chainID, providerAddr)) +} + +func (k Keeper) IsToBeOptedIn( + ctx sdk.Context, + chainID string, + providerAddr types.ProviderConsAddress, +) bool { + store := ctx.KVStore(k.storeKey) + return store.Get(types.ToBeOptedInKey(chainID, providerAddr)) != nil +} + +func (k Keeper) GetToBeOptedIn( + ctx sdk.Context, + chainID string) (addresses []types.ProviderConsAddress) { + + store := ctx.KVStore(k.storeKey) + key := types.ChainIdWithLenKey(types.ToBeOptedInBytePrefix, chainID) + iterator := sdk.KVStorePrefixIterator(store, key) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + providerAddr := types.NewProviderConsAddress(iterator.Key()[len(key):]) + addresses = append(addresses, providerAddr) + } + + return addresses +} + +func (k Keeper) SetToBeOptedOut( + ctx sdk.Context, + chainID string, + providerAddr types.ProviderConsAddress, +) { + store := ctx.KVStore(k.storeKey) + store.Set(types.ToBeOptedOutKey(chainID, providerAddr), []byte{}) +} + +func (k Keeper) DeleteToBeOptedOut( + ctx sdk.Context, + chainID string, + providerAddr types.ProviderConsAddress, +) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.ToBeOptedOutKey(chainID, providerAddr)) +} + +func (k Keeper) IsToBeOptedOut( + ctx sdk.Context, + chainID string, + providerAddr types.ProviderConsAddress, +) bool { + store := ctx.KVStore(k.storeKey) + return store.Get(types.ToBeOptedOutKey(chainID, providerAddr)) != nil +} + +func (k Keeper) GetToBeOptedOut( + ctx sdk.Context, + chainID string) (addresses []types.ProviderConsAddress) { + + store := ctx.KVStore(k.storeKey) + key := types.ChainIdWithLenKey(types.ToBeOptedOutBytePrefix, chainID) + iterator := sdk.KVStorePrefixIterator(store, key) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + providerAddr := types.NewProviderConsAddress(iterator.Key()[len(key):]) + addresses = append(addresses, providerAddr) + } + + return addresses +} diff --git a/x/ccv/provider/keeper/keeper_test.go b/x/ccv/provider/keeper/keeper_test.go index 4dc73b7f9e..6eb28675ba 100644 --- a/x/ccv/provider/keeper/keeper_test.go +++ b/x/ccv/provider/keeper/keeper_test.go @@ -1,7 +1,9 @@ package keeper_test import ( + "bytes" "fmt" + "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" "sort" "testing" "time" @@ -629,7 +631,7 @@ func TestGetAllProposedConsumerChainIDs(t *testing.T) { } } -// TestTopN tests `SetTopN`, `GetTopN`, `IsTopN`, and `IsOptIn` methods +// TestTopN tests the `SetTopN`, `GetTopN`, `IsTopN`, and `IsOptIn` methods func TestTopN(t *testing.T) { providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() @@ -659,3 +661,190 @@ func TestTopN(t *testing.T) { } } } + +func TestGetOptedIn(t *testing.T) { + providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + expectedOptedInValidators := []keeper.OptedInValidator{ + { + ProviderAddr: types.NewProviderConsAddress([]byte("providerAddr1")), + BlockHeight: 1, + }, + { + ProviderAddr: types.NewProviderConsAddress([]byte("providerAddr2")), + BlockHeight: 2, + }, + { + ProviderAddr: types.NewProviderConsAddress([]byte("providerAddr3")), + BlockHeight: 3, + }, + } + + for _, expectedOptedInValidator := range expectedOptedInValidators { + providerKeeper.SetOptedIn(ctx, "chainID", + expectedOptedInValidator.ProviderAddr, expectedOptedInValidator.BlockHeight) + } + + actualOptedInValidators := providerKeeper.GetOptedIn(ctx, "chainID") + + // sort validators first to be able to compare + sortOptedInValidators := func(optedInValidators []keeper.OptedInValidator) { + sort.Slice(optedInValidators, func(i int, j int) bool { + a := optedInValidators[i] + b := optedInValidators[j] + return a.BlockHeight < b.BlockHeight || + (a.BlockHeight == b.BlockHeight && bytes.Compare(a.ProviderAddr.ToSdkConsAddr(), b.ProviderAddr.ToSdkConsAddr()) < 0) + }) + } + sortOptedInValidators(expectedOptedInValidators) + sortOptedInValidators(actualOptedInValidators) + require.Equal(t, expectedOptedInValidators, actualOptedInValidators) +} + +// TestOptedIn tests the `SetOptedIn`, `IsOptedIn`, and `RemoveOptedIn` methods +func TestOptedIn(t *testing.T) { + providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + optedInValidator := keeper.OptedInValidator{ + ProviderAddr: types.NewProviderConsAddress([]byte("providerAddr")), + BlockHeight: 1, + } + + require.False(t, providerKeeper.IsOptedIn(ctx, "chainID", optedInValidator.ProviderAddr)) + providerKeeper.SetOptedIn(ctx, "chainID", optedInValidator.ProviderAddr, optedInValidator.BlockHeight) + require.True(t, providerKeeper.IsOptedIn(ctx, "chainID", optedInValidator.ProviderAddr)) + providerKeeper.DeleteOptedIn(ctx, "chainID", optedInValidator.ProviderAddr) + require.False(t, providerKeeper.IsOptedIn(ctx, "chainID", optedInValidator.ProviderAddr)) +} + +func TestGetToBeOptedIn(t *testing.T) { + providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + expectedAddresses := []types.ProviderConsAddress{ + types.NewProviderConsAddress([]byte("providerAddr1")), + types.NewProviderConsAddress([]byte("providerAddr2")), + types.NewProviderConsAddress([]byte("providerAddr3"))} + + for _, addr := range expectedAddresses { + providerKeeper.SetToBeOptedIn(ctx, "chainID", addr) + } + + actualAddresses := providerKeeper.GetToBeOptedIn(ctx, "chainID") + + // sort addresses first to be able to compare + sortAddresses := func(addresses []types.ProviderConsAddress) { + sort.Slice(addresses, func(i int, j int) bool { + a := addresses[i] + b := addresses[j] + return bytes.Compare(a.Address.Bytes(), b.Address.Bytes()) < 0 + }) + } + sortAddresses(expectedAddresses) + sortAddresses(actualAddresses) + require.Equal(t, expectedAddresses, actualAddresses) + + for _, addr := range expectedAddresses { + require.True(t, providerKeeper.IsToBeOptedIn(ctx, "chainID", addr)) + providerKeeper.DeleteToBeOptedIn(ctx, "chainID", addr) + require.False(t, providerKeeper.IsToBeOptedIn(ctx, "chainID", addr)) + } +} + +func TestBeOptedIn(t *testing.T) { + providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + expectedAddresses := []types.ProviderConsAddress{ + types.NewProviderConsAddress([]byte("providerAddr1")), + types.NewProviderConsAddress([]byte("providerAddr2")), + types.NewProviderConsAddress([]byte("providerAddr3"))} + + for _, addr := range expectedAddresses { + providerKeeper.SetToBeOptedIn(ctx, "chainID", addr) + } + + actualAddresses := providerKeeper.GetToBeOptedIn(ctx, "chainID") + + // sort addresses first to be able to compare + sortAddresses := func(addresses []types.ProviderConsAddress) { + sort.Slice(addresses, func(i int, j int) bool { + a := addresses[i] + b := addresses[j] + return bytes.Compare(a.Address.Bytes(), b.Address.Bytes()) < 0 + }) + } + sortAddresses(expectedAddresses) + sortAddresses(actualAddresses) + require.Equal(t, expectedAddresses, actualAddresses) + + for _, addr := range expectedAddresses { + require.True(t, providerKeeper.IsToBeOptedIn(ctx, "chainID", addr)) + providerKeeper.DeleteToBeOptedIn(ctx, "chainID", addr) + require.False(t, providerKeeper.IsToBeOptedIn(ctx, "chainID", addr)) + } +} + +// TestToBeOptedIn tests the `SetToBeOptedIn`, `IsToBeOptedIn`, and `DeleteToBeOptedIn` methods +func TestToBeOptedIn(t *testing.T) { + providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + providerAddr := types.NewProviderConsAddress([]byte("providerAddr1")) + + require.False(t, providerKeeper.IsToBeOptedIn(ctx, "chainID", providerAddr)) + providerKeeper.SetToBeOptedIn(ctx, "chainID", providerAddr) + require.True(t, providerKeeper.IsToBeOptedIn(ctx, "chainID", providerAddr)) + providerKeeper.DeleteToBeOptedIn(ctx, "chainID", providerAddr) + require.False(t, providerKeeper.IsToBeOptedIn(ctx, "chainID", providerAddr)) +} + +func TestGetToBeOptedOut(t *testing.T) { + providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + expectedAddresses := []types.ProviderConsAddress{ + types.NewProviderConsAddress([]byte("providerAddr1")), + types.NewProviderConsAddress([]byte("providerAddr2")), + types.NewProviderConsAddress([]byte("providerAddr3"))} + + for _, addr := range expectedAddresses { + providerKeeper.SetToBeOptedOut(ctx, "chainID", addr) + } + + actualAddresses := providerKeeper.GetToBeOptedOut(ctx, "chainID") + + // sort addresses first to be able to compare + sortAddresses := func(addresses []types.ProviderConsAddress) { + sort.Slice(addresses, func(i int, j int) bool { + a := addresses[i] + b := addresses[j] + return bytes.Compare(a.Address.Bytes(), b.Address.Bytes()) < 0 + }) + } + sortAddresses(expectedAddresses) + sortAddresses(actualAddresses) + require.Equal(t, expectedAddresses, actualAddresses) + + for _, addr := range expectedAddresses { + require.True(t, providerKeeper.IsToBeOptedOut(ctx, "chainID", addr)) + providerKeeper.DeleteToBeOptedOut(ctx, "chainID", addr) + require.False(t, providerKeeper.IsToBeOptedOut(ctx, "chainID", addr)) + } +} + +// TestToBeOptedOut tests the `SetToBeOptedOut`, `IsToBeOptedOut`, and `DeleteToBeOptedOut` methods +func TestToBeOptedOut(t *testing.T) { + providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + providerAddr := types.NewProviderConsAddress([]byte("providerAddr1")) + + require.False(t, providerKeeper.IsToBeOptedOut(ctx, "chainID", providerAddr)) + providerKeeper.SetToBeOptedOut(ctx, "chainID", providerAddr) + require.True(t, providerKeeper.IsToBeOptedOut(ctx, "chainID", providerAddr)) + providerKeeper.DeleteToBeOptedOut(ctx, "chainID", providerAddr) + require.False(t, providerKeeper.IsToBeOptedOut(ctx, "chainID", providerAddr)) +} diff --git a/x/ccv/provider/keeper/key_assignment.go b/x/ccv/provider/keeper/key_assignment.go index 89dbcfda4e..983b92cb26 100644 --- a/x/ccv/provider/keeper/key_assignment.go +++ b/x/ccv/provider/keeper/key_assignment.go @@ -1,6 +1,7 @@ package keeper import ( + "encoding/base64" "fmt" errorsmod "cosmossdk.io/errors" @@ -14,6 +15,53 @@ import ( ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" ) +// ParseConsumerKey parses the ED25519 PubKey`consumerKey` from a JSON string +// and constructs its corresponding `tmprotocrypto.PublicKey` +func (k Keeper) ParseConsumerKey(consumerKey string) (tmprotocrypto.PublicKey, error) { + // parse consumer key as long as it's in the right format + pkType, keyStr, err := types.ParseConsumerKeyFromJson(consumerKey) + if err != nil { + return tmprotocrypto.PublicKey{}, err + } + + // Note: the correct way to decide if a key type is supported is to check the + // consensus params. However this functionality was disabled in https://github.com/cosmos/interchain-security/pull/916 + // as a quick way to get ed25519 working, avoiding amino/proto-any marshalling issues. + + // make sure the consumer key type is supported + // cp := ctx.ConsensusParams() + // if cp != nil && cp.Validator != nil { + // if !tmstrings.StringInSlice(pkType, cp.Validator.PubKeyTypes) { + // return nil, errorsmod.Wrapf( + // stakingtypes.ErrValidatorPubKeyTypeNotSupported, + // "got: %s, expected one of: %s", pkType, cp.Validator.PubKeyTypes, + // ) + // } + // } + + // For now, only accept ed25519. + // TODO: decide what types should be supported. + if pkType != "/cosmos.crypto.ed25519.PubKey" { + return tmprotocrypto.PublicKey{}, errorsmod.Wrapf( + stakingtypes.ErrValidatorPubKeyTypeNotSupported, + "got: %s, expected: %s", pkType, "/cosmos.crypto.ed25519.PubKey", + ) + } + + pubKeyBytes, err := base64.StdEncoding.DecodeString(keyStr) + if err != nil { + return tmprotocrypto.PublicKey{}, err + } + + consumerTMPublicKey := tmprotocrypto.PublicKey{ + Sum: &tmprotocrypto.PublicKey_Ed25519{ + Ed25519: pubKeyBytes, + }, + } + + return consumerTMPublicKey, nil +} + // GetValidatorConsumerPubKey returns a validator's public key assigned for a consumer chain func (k Keeper) GetValidatorConsumerPubKey( ctx sdk.Context, diff --git a/x/ccv/provider/keeper/msg_server.go b/x/ccv/provider/keeper/msg_server.go index 9a27d1d144..4863cd0d66 100644 --- a/x/ccv/provider/keeper/msg_server.go +++ b/x/ccv/provider/keeper/msg_server.go @@ -2,15 +2,12 @@ package keeper import ( "context" - "encoding/base64" - errorsmod "cosmossdk.io/errors" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" tmtypes "github.com/cometbft/cometbft/types" "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" @@ -45,47 +42,11 @@ func (k msgServer) AssignConsumerKey(goCtx context.Context, msg *types.MsgAssign return nil, stakingtypes.ErrNoValidatorFound } - // parse consumer key as long as it's in the right format - pkType, keyStr, err := types.ParseConsumerKeyFromJson(msg.ConsumerKey) - if err != nil { - return nil, err - } - - // Note: the correct way to decide if a key type is supported is to check the - // consensus params. However this functionality was disabled in https://github.com/cosmos/interchain-security/pull/916 - // as a quick way to get ed25519 working, avoiding amino/proto-any marshalling issues. - - // make sure the consumer key type is supported - // cp := ctx.ConsensusParams() - // if cp != nil && cp.Validator != nil { - // if !tmstrings.StringInSlice(pkType, cp.Validator.PubKeyTypes) { - // return nil, errorsmod.Wrapf( - // stakingtypes.ErrValidatorPubKeyTypeNotSupported, - // "got: %s, expected one of: %s", pkType, cp.Validator.PubKeyTypes, - // ) - // } - // } - - // For now, only accept ed25519. - // TODO: decide what types should be supported. - if pkType != "/cosmos.crypto.ed25519.PubKey" { - return nil, errorsmod.Wrapf( - stakingtypes.ErrValidatorPubKeyTypeNotSupported, - "got: %s, expected: %s", pkType, "/cosmos.crypto.ed25519.PubKey", - ) - } - - pubKeyBytes, err := base64.StdEncoding.DecodeString(keyStr) + consumerTMPublicKey, err := k.ParseConsumerKey(msg.ConsumerKey) if err != nil { return nil, err } - consumerTMPublicKey := tmprotocrypto.PublicKey{ - Sum: &tmprotocrypto.PublicKey_Ed25519{ - Ed25519: pubKeyBytes, - }, - } - if err := k.Keeper.AssignConsumerKey(ctx, msg.ChainId, validator, consumerTMPublicKey); err != nil { return nil, err } @@ -174,3 +135,63 @@ func (k msgServer) SubmitConsumerDoubleVoting(goCtx context.Context, msg *types. return &types.MsgSubmitConsumerDoubleVotingResponse{}, nil } + +func (k msgServer) OptIn(goCtx context.Context, msg *types.MsgOptIn) (*types.MsgOptInResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + valAddress, err := sdk.ConsAddressFromBech32(msg.ProviderAddr) + if err != nil { + return nil, err + } + providerAddr := types.NewProviderConsAddress(valAddress) + if err != nil { + return nil, err + } + + if msg.ConsumerKey != "" { + err = k.Keeper.HandleOptIn(ctx, msg.ChainId, providerAddr, &msg.ConsumerKey) + } else { + err = k.Keeper.HandleOptIn(ctx, msg.ChainId, providerAddr, nil) + } + + if err != nil { + return nil, err + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + ccvtypes.EventTypeOptIn, + sdk.NewAttribute(types.AttributeProviderValidatorAddress, msg.ProviderAddr), + sdk.NewAttribute(types.AttributeConsumerConsensusPubKey, msg.ConsumerKey), + ), + }) + + return &types.MsgOptInResponse{}, nil +} + +func (k msgServer) OptOut(goCtx context.Context, msg *types.MsgOptOut) (*types.MsgOptOutResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + valAddress, err := sdk.ConsAddressFromBech32(msg.ProviderAddr) + if err != nil { + return nil, err + } + providerAddr := types.NewProviderConsAddress(valAddress) + if err != nil { + return nil, err + } + + err = k.Keeper.HandleOptOut(ctx, msg.ChainId, providerAddr) + if err != nil { + return nil, err + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + ccvtypes.EventTypeOptOut, + sdk.NewAttribute(types.AttributeProviderValidatorAddress, msg.ProviderAddr), + ), + }) + + return &types.MsgOptOutResponse{}, nil +} diff --git a/x/ccv/provider/keeper/partial_set_security.go b/x/ccv/provider/keeper/partial_set_security.go new file mode 100644 index 0000000000..e1bf9cc14f --- /dev/null +++ b/x/ccv/provider/keeper/partial_set_security.go @@ -0,0 +1,69 @@ +package keeper + +import ( + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" +) + +type OptedInValidator struct { + ProviderAddr types.ProviderConsAddress + // block height the validator opted in at + BlockHeight uint64 +} + +func (k Keeper) HandleOptIn(ctx sdk.Context, chainID string, providerAddr types.ProviderConsAddress, consumerKey *string) error { + if !k.IsConsumerProposedOrRegistered(ctx, chainID) { + return errorsmod.Wrapf( + types.ErrUnknownConsumerChainId, + "opting in to an unknown consumer chain, with id: %s", chainID) + } + + if k.IsToBeOptedOut(ctx, chainID, providerAddr) { + // a validator to be opted in cancels out with a validator to be opted out + k.DeleteToBeOptedOut(ctx, chainID, providerAddr) + } else if !k.IsToBeOptedIn(ctx, chainID, providerAddr) && !k.IsOptedIn(ctx, chainID, providerAddr) { + // a validator can only be set for opt in if it is not opted in and not already set for opt in + k.SetToBeOptedIn(ctx, chainID, providerAddr) + } + + if consumerKey != nil { + consumerTMPublicKey, err := k.ParseConsumerKey(*consumerKey) + if err != nil { + return err + } + + validator, found := k.stakingKeeper.GetValidatorByConsAddr(ctx, providerAddr.Address) + if !found { + return stakingtypes.ErrNoValidatorFound + } + + err = k.AssignConsumerKey(ctx, chainID, validator, consumerTMPublicKey) + if err != nil { + return err + } + } + + return nil +} + +func (k Keeper) HandleOptOut(ctx sdk.Context, chainID string, providerAddr types.ProviderConsAddress) error { + if _, found := k.GetConsumerClientId(ctx, chainID); !found { + // A validator can only opt out from a running chain. We check this by checking the consumer client id, because + // `SetConsumerClientId` is set when the chain starts in `CreateConsumerClientInCachedCtx` of `BeginBlockInit`. + return errorsmod.Wrapf( + types.ErrUnknownConsumerChainId, + "opting out of an unknown or not running consumer chain, with id: %s", chainID) + } + + if k.IsToBeOptedIn(ctx, chainID, providerAddr) { + // a validator to be opted out cancels out a validator to be opted in + k.DeleteToBeOptedIn(ctx, chainID, providerAddr) + } else if !k.IsToBeOptedOut(ctx, chainID, providerAddr) && k.IsOptedIn(ctx, chainID, providerAddr) { + // a validator can only be set for opt out if it is opted in and not already set for opt out + k.SetToBeOptedOut(ctx, chainID, providerAddr) + } + + return nil +} diff --git a/x/ccv/provider/keeper/partial_set_security_test.go b/x/ccv/provider/keeper/partial_set_security_test.go new file mode 100644 index 0000000000..4831723bec --- /dev/null +++ b/x/ccv/provider/keeper/partial_set_security_test.go @@ -0,0 +1,111 @@ +package keeper_test + +import ( + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" + "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" + "testing" +) + +func TestHandleOptIn(t *testing.T) { + providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + providerAddr := types.NewProviderConsAddress([]byte("providerAddr")) + + // trying to opt in to a non-proposed and non-registered chain returns an error + require.Error(t, providerKeeper.HandleOptIn(ctx, "unknownChainID", providerAddr, nil)) + + // if validator (`providerAddr`) is to be opted out, then we cancel that the validator is about + // to be opted out and do not consider the validator to opt in + providerKeeper.SetToBeOptedOut(ctx, "chainID", providerAddr) + providerKeeper.SetProposedConsumerChain(ctx, "chainID", 1) + require.True(t, providerKeeper.IsToBeOptedOut(ctx, "chainID", providerAddr)) + providerKeeper.HandleOptIn(ctx, "chainID", providerAddr, nil) + require.False(t, providerKeeper.IsToBeOptedIn(ctx, "chainID", providerAddr)) + require.False(t, providerKeeper.IsToBeOptedOut(ctx, "chainID", providerAddr)) + + // if validator (`providerAddr`) is already opted in, then the validator cannot be opted in + providerKeeper.SetOptedIn(ctx, "chainID", providerAddr, 1) + providerKeeper.HandleOptIn(ctx, "chainID", providerAddr, nil) + require.False(t, providerKeeper.IsToBeOptedIn(ctx, "chainID", providerAddr)) +} + +func TestHandleOptInWithConsumerKey(t *testing.T) { + providerKeeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + // generate a consensus public key for the provider + providerConsPubKey := ed25519.GenPrivKeyFromSecret([]byte{1}).PubKey() + consAddr := sdk.ConsAddress(providerConsPubKey.Address()) + providerAddr := types.NewProviderConsAddress(consAddr) + + calls := []*gomock.Call{ + mocks.MockStakingKeeper.EXPECT(). + GetValidatorByConsAddr(gomock.Any(), gomock.Any()). + DoAndReturn(func(ctx sdk.Context, addr sdk.ConsAddress) (stakingtypes.Validator, bool) { + if addr.Equals(providerAddr.Address) { + // Given `providerAddr`, `GetValidatorByConsAddr` returns a validator with the + // exact same `ConsensusPubkey` + pkAny, _ := codectypes.NewAnyWithValue(providerConsPubKey) + return stakingtypes.Validator{ConsensusPubkey: pkAny}, true + } else { + // for any other consensus address, we cannot find a validator + return stakingtypes.Validator{}, false + } + }).Times(2), + } + + gomock.InOrder(calls...) + providerKeeper.SetProposedConsumerChain(ctx, "chainID", 1) + + // create a sample consumer key to assign to the `providerAddr` validator + // on the consumer chain with id `chainID` + consumerKey := "{\"@type\":\"/cosmos.crypto.ed25519.PubKey\",\"key\":\"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is=\"}" + expectedConsumerPubKey, _ := providerKeeper.ParseConsumerKey(consumerKey) + + err := providerKeeper.HandleOptIn(ctx, "chainID", providerAddr, &consumerKey) + require.NoError(t, err) + + // assert that the consumeKey was assigned to `providerAddr` validator on chain with id `chainID` + actualConsumerPubKey, found := providerKeeper.GetValidatorConsumerPubKey(ctx, "chainID", providerAddr) + require.True(t, found) + require.Equal(t, expectedConsumerPubKey, actualConsumerPubKey) + + // assert that the `consumerAddr` to `providerAddr` association was set as well + consumerAddr, _ := ccvtypes.TMCryptoPublicKeyToConsAddr(actualConsumerPubKey) + actualProviderConsAddr, found := providerKeeper.GetValidatorByConsumerAddr(ctx, "chainID", types.NewConsumerConsAddress(consumerAddr)) + require.Equal(t, providerAddr, actualProviderConsAddr) +} + +func TestHandleOptOut(t *testing.T) { + providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + providerAddr := types.NewProviderConsAddress([]byte("providerAddr")) + + // trying to opt out from a not running chain returns an error + require.Error(t, providerKeeper.HandleOptOut(ctx, "unknownChainID", providerAddr)) + + // if validator (`providerAddr`) is to be opted in, then we cancel that the validator is about + // to be opted out and do not consider the validator to opt out + providerKeeper.SetToBeOptedIn(ctx, "chainID", providerAddr) + providerKeeper.SetConsumerClientId(ctx, "chainID", "clientID") + require.True(t, providerKeeper.IsToBeOptedIn(ctx, "chainID", providerAddr)) + err := providerKeeper.HandleOptOut(ctx, "chainID", providerAddr) + require.NoError(t, err) + require.False(t, providerKeeper.IsToBeOptedOut(ctx, "chainID", providerAddr)) + require.False(t, providerKeeper.IsToBeOptedIn(ctx, "chainID", providerAddr)) + + // if validator (`providerAddr`) is not opted in, then the validator cannot be opted out + providerKeeper.DeleteOptedIn(ctx, "chainID", providerAddr) + err = providerKeeper.HandleOptOut(ctx, "chainID", providerAddr) + require.NoError(t, err) + require.False(t, providerKeeper.IsToBeOptedOut(ctx, "chainID", providerAddr)) +} diff --git a/x/ccv/provider/types/codec.go b/x/ccv/provider/types/codec.go index 6ab621f0e1..c0ab4f5aea 100644 --- a/x/ccv/provider/types/codec.go +++ b/x/ccv/provider/types/codec.go @@ -45,6 +45,14 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { (*sdk.Msg)(nil), &MsgSubmitConsumerDoubleVoting{}, ) + registry.RegisterImplementations( + (*sdk.Msg)(nil), + &MsgOptIn{}, + ) + registry.RegisterImplementations( + (*sdk.Msg)(nil), + &MsgOptOut{}, + ) registry.RegisterImplementations( (*exported.ClientMessage)(nil), &tendermint.Misbehaviour{}, diff --git a/x/ccv/provider/types/keys.go b/x/ccv/provider/types/keys.go index 125ad4a473..e2348821ee 100644 --- a/x/ccv/provider/types/keys.go +++ b/x/ccv/provider/types/keys.go @@ -153,6 +153,18 @@ const ( // TopNBytePrefix is the byte prefix storing the mapping from a consumer chain to the N value of this chain, // that corresponds to the N% of the top validators that have to validate this consumer chain TopNBytePrefix + + // OptedInBytePrefix is the byte prefix used when storing for each consumer chain all the opted in validators + OptedInBytePrefix + + // ToBeOptedInBytePrefix is the byte prefix used when storing for each consumer chain the validators that + // are about to be opted in + ToBeOptedInBytePrefix + + // ToBeOptedOutBytePrefix is the byte prefix used when storing for each consumer chain the validators that + // are about to be opted out + ToBeOptedOutBytePrefix + // NOTE: DO NOT ADD NEW BYTE PREFIXES HERE WITHOUT ADDING THEM TO getAllKeyPrefixes() IN keys_test.go ) @@ -530,6 +542,24 @@ func TopNKey(chainID string) []byte { return ChainIdWithLenKey(TopNBytePrefix, chainID) } +// OptedInKey returns the key of consumer chain `chainID` and validator with `providerAddr` +func OptedInKey(chainID string, providerAddr ProviderConsAddress) []byte { + prefix := ChainIdWithLenKey(OptedInBytePrefix, chainID) + return append(prefix, providerAddr.ToSdkConsAddr().Bytes()...) +} + +// ToBeOptedInKey returns the key of consumer chain `chainID` and validator with `providerAddr` +func ToBeOptedInKey(chainID string, providerAddr ProviderConsAddress) []byte { + prefix := ChainIdWithLenKey(ToBeOptedInBytePrefix, chainID) + return append(prefix, providerAddr.ToSdkConsAddr().Bytes()...) +} + +// ToBeOptedOutKey returns the key of consumer chain `chainID` and validator with `providerAddr` +func ToBeOptedOutKey(chainID string, providerAddr ProviderConsAddress) []byte { + prefix := ChainIdWithLenKey(ToBeOptedOutBytePrefix, chainID) + return append(prefix, providerAddr.ToSdkConsAddr().Bytes()...) +} + // // End of generic helpers section // diff --git a/x/ccv/provider/types/keys_test.go b/x/ccv/provider/types/keys_test.go index da2dbbea31..32dea17560 100644 --- a/x/ccv/provider/types/keys_test.go +++ b/x/ccv/provider/types/keys_test.go @@ -58,6 +58,9 @@ func getAllKeyPrefixes() []byte { providertypes.ProposedConsumerChainByteKey, providertypes.ConsumerValidatorBytePrefix, providertypes.TopNBytePrefix, + providertypes.OptedInBytePrefix, + providertypes.ToBeOptedInBytePrefix, + providertypes.ToBeOptedOutBytePrefix, } } diff --git a/x/ccv/provider/types/msg.go b/x/ccv/provider/types/msg.go index 55e6b2fae4..20aae43f6c 100644 --- a/x/ccv/provider/types/msg.go +++ b/x/ccv/provider/types/msg.go @@ -22,12 +22,16 @@ const ( TypeMsgAssignConsumerKey = "assign_consumer_key" TypeMsgSubmitConsumerMisbehaviour = "submit_consumer_misbehaviour" TypeMsgSubmitConsumerDoubleVoting = "submit_consumer_double_vote" + TypeMsgOptIn = "opt_in" + TypeMsgOptOut = "opt_out" ) var ( _ sdk.Msg = &MsgAssignConsumerKey{} _ sdk.Msg = &MsgSubmitConsumerMisbehaviour{} _ sdk.Msg = &MsgSubmitConsumerDoubleVoting{} + _ sdk.Msg = &MsgOptIn{} + _ sdk.Msg = &MsgOptOut{} ) // NewMsgAssignConsumerKey creates a new MsgAssignConsumerKey instance. @@ -203,3 +207,112 @@ func (msg MsgSubmitConsumerDoubleVoting) GetSigners() []sdk.AccAddress { } return []sdk.AccAddress{addr} } + +// NewMsgOptIn creates a new NewMsgOptIn instance. +func NewMsgOptIn(chainID string, providerValidatorAddress sdk.ValAddress, consumerConsensusPubKey string) (*MsgOptIn, error) { + return &MsgOptIn{ + ChainId: chainID, + ProviderAddr: providerValidatorAddress.String(), + ConsumerKey: consumerConsensusPubKey, + }, nil +} + +// Route implements the sdk.Msg interface. +func (msg MsgOptIn) Route() string { return RouterKey } + +// GetSigners implements the sdk.Msg interface. It returns the address(es) that +// must sign over msg.GetSignBytes(). +func (msg MsgOptIn) GetSigners() []sdk.AccAddress { + valAddr, err := sdk.ValAddressFromBech32(msg.ProviderAddr) + if err != nil { + // same behavior as in cosmos-sdk + panic(err) + } + return []sdk.AccAddress{valAddr.Bytes()} +} + +// GetSignBytes returns the message bytes to sign over. +func (msg MsgOptIn) GetSignBytes() []byte { + bz := ccvtypes.ModuleCdc.MustMarshalJSON(&msg) + return sdk.MustSortJSON(bz) +} + +// ValidateBasic implements the sdk.Msg interface. +func (msg MsgOptIn) ValidateBasic() error { + if strings.TrimSpace(msg.ChainId) == "" { + return errorsmod.Wrapf(ErrInvalidConsumerChainID, "chainId cannot be blank") + } + // It is possible to assign keys for consumer chains that are not yet approved. + // This can only be done by a signing validator, but it is still sensible + // to limit the chainID size to prevent abuse. + if 128 < len(msg.ChainId) { + return errorsmod.Wrapf(ErrInvalidConsumerChainID, "chainId cannot exceed 128 length") + } + _, err := sdk.ValAddressFromBech32(msg.ProviderAddr) + if err != nil { + return ErrInvalidProviderAddress + } + + if msg.ConsumerKey != "" { + if _, _, err := ParseConsumerKeyFromJson(msg.ConsumerKey); err != nil { + return ErrInvalidConsumerConsensusPubKey + } + } + return nil +} + +// NewMsgOptOut creates a new NewMsgOptIn instance. +func NewMsgOptOut(chainID string, providerValidatorAddress sdk.ValAddress) (*MsgOptOut, error) { + return &MsgOptOut{ + ChainId: chainID, + ProviderAddr: providerValidatorAddress.String(), + }, nil +} + +// Route implements the sdk.Msg interface. +func (msg MsgOptOut) Route() string { return RouterKey } + +// Type implements the sdk.Msg interface. +func (msg MsgOptIn) Type() string { + return TypeMsgOptIn +} + +// GetSigners implements the sdk.Msg interface. It returns the address(es) that +// must sign over msg.GetSignBytes(). +func (msg MsgOptOut) GetSigners() []sdk.AccAddress { + valAddr, err := sdk.ValAddressFromBech32(msg.ProviderAddr) + if err != nil { + // same behavior as in cosmos-sdk + panic(err) + } + return []sdk.AccAddress{valAddr.Bytes()} +} + +// GetSignBytes returns the message bytes to sign over. +func (msg MsgOptOut) GetSignBytes() []byte { + bz := ccvtypes.ModuleCdc.MustMarshalJSON(&msg) + return sdk.MustSortJSON(bz) +} + +// ValidateBasic implements the sdk.Msg interface. +func (msg MsgOptOut) ValidateBasic() error { + if strings.TrimSpace(msg.ChainId) == "" { + return errorsmod.Wrapf(ErrInvalidConsumerChainID, "chainId cannot be blank") + } + // It is possible to assign keys for consumer chains that are not yet approved. + // This can only be done by a signing validator, but it is still sensible + // to limit the chainID size to prevent abuse. + if 128 < len(msg.ChainId) { + return errorsmod.Wrapf(ErrInvalidConsumerChainID, "chainId cannot exceed 128 length") + } + _, err := sdk.ValAddressFromBech32(msg.ProviderAddr) + if err != nil { + return ErrInvalidProviderAddress + } + return nil +} + +// Type implements the sdk.Msg interface. +func (msg MsgOptOut) Type() string { + return TypeMsgOptOut +} diff --git a/x/ccv/provider/types/tx.pb.go b/x/ccv/provider/types/tx.pb.go index f72e95acb2..647f5f49dc 100644 --- a/x/ccv/provider/types/tx.pb.go +++ b/x/ccv/provider/types/tx.pb.go @@ -270,6 +270,162 @@ func (m *MsgSubmitConsumerDoubleVotingResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgSubmitConsumerDoubleVotingResponse proto.InternalMessageInfo +type MsgOptIn struct { + // the chain id of the consumer chain to opt in to + ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + // the validator address on the provider + ProviderAddr string `protobuf:"bytes,2,opt,name=provider_addr,json=providerAddr,proto3" json:"provider_addr,omitempty" yaml:"address"` + // (optional) the consensus public key to use on the consumer in json string format corresponding to proto-any, + // for example `{"@type":"/cosmos.crypto.ed25519.PubKey","key":"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is="}` + // we can set `consumer_key = ""` if we do not consider the `consumer_key` + ConsumerKey string `protobuf:"bytes,3,opt,name=consumer_key,json=consumerKey,proto3" json:"consumer_key,omitempty"` +} + +func (m *MsgOptIn) Reset() { *m = MsgOptIn{} } +func (m *MsgOptIn) String() string { return proto.CompactTextString(m) } +func (*MsgOptIn) ProtoMessage() {} +func (*MsgOptIn) Descriptor() ([]byte, []int) { + return fileDescriptor_43221a4391e9fbf4, []int{6} +} +func (m *MsgOptIn) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgOptIn) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgOptIn.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgOptIn) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgOptIn.Merge(m, src) +} +func (m *MsgOptIn) XXX_Size() int { + return m.Size() +} +func (m *MsgOptIn) XXX_DiscardUnknown() { + xxx_messageInfo_MsgOptIn.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgOptIn proto.InternalMessageInfo + +type MsgOptInResponse struct { +} + +func (m *MsgOptInResponse) Reset() { *m = MsgOptInResponse{} } +func (m *MsgOptInResponse) String() string { return proto.CompactTextString(m) } +func (*MsgOptInResponse) ProtoMessage() {} +func (*MsgOptInResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_43221a4391e9fbf4, []int{7} +} +func (m *MsgOptInResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgOptInResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgOptInResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgOptInResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgOptInResponse.Merge(m, src) +} +func (m *MsgOptInResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgOptInResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgOptInResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgOptInResponse proto.InternalMessageInfo + +type MsgOptOut struct { + // the chain id of the consumer chain to opt out from + ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + // the validator address on the provider + ProviderAddr string `protobuf:"bytes,2,opt,name=provider_addr,json=providerAddr,proto3" json:"provider_addr,omitempty" yaml:"address"` +} + +func (m *MsgOptOut) Reset() { *m = MsgOptOut{} } +func (m *MsgOptOut) String() string { return proto.CompactTextString(m) } +func (*MsgOptOut) ProtoMessage() {} +func (*MsgOptOut) Descriptor() ([]byte, []int) { + return fileDescriptor_43221a4391e9fbf4, []int{8} +} +func (m *MsgOptOut) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgOptOut) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgOptOut.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgOptOut) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgOptOut.Merge(m, src) +} +func (m *MsgOptOut) XXX_Size() int { + return m.Size() +} +func (m *MsgOptOut) XXX_DiscardUnknown() { + xxx_messageInfo_MsgOptOut.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgOptOut proto.InternalMessageInfo + +type MsgOptOutResponse struct { +} + +func (m *MsgOptOutResponse) Reset() { *m = MsgOptOutResponse{} } +func (m *MsgOptOutResponse) String() string { return proto.CompactTextString(m) } +func (*MsgOptOutResponse) ProtoMessage() {} +func (*MsgOptOutResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_43221a4391e9fbf4, []int{9} +} +func (m *MsgOptOutResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgOptOutResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgOptOutResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgOptOutResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgOptOutResponse.Merge(m, src) +} +func (m *MsgOptOutResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgOptOutResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgOptOutResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgOptOutResponse proto.InternalMessageInfo + func init() { proto.RegisterType((*MsgAssignConsumerKey)(nil), "interchain_security.ccv.provider.v1.MsgAssignConsumerKey") proto.RegisterType((*MsgAssignConsumerKeyResponse)(nil), "interchain_security.ccv.provider.v1.MsgAssignConsumerKeyResponse") @@ -277,6 +433,10 @@ func init() { proto.RegisterType((*MsgSubmitConsumerMisbehaviourResponse)(nil), "interchain_security.ccv.provider.v1.MsgSubmitConsumerMisbehaviourResponse") proto.RegisterType((*MsgSubmitConsumerDoubleVoting)(nil), "interchain_security.ccv.provider.v1.MsgSubmitConsumerDoubleVoting") proto.RegisterType((*MsgSubmitConsumerDoubleVotingResponse)(nil), "interchain_security.ccv.provider.v1.MsgSubmitConsumerDoubleVotingResponse") + proto.RegisterType((*MsgOptIn)(nil), "interchain_security.ccv.provider.v1.MsgOptIn") + proto.RegisterType((*MsgOptInResponse)(nil), "interchain_security.ccv.provider.v1.MsgOptInResponse") + proto.RegisterType((*MsgOptOut)(nil), "interchain_security.ccv.provider.v1.MsgOptOut") + proto.RegisterType((*MsgOptOutResponse)(nil), "interchain_security.ccv.provider.v1.MsgOptOutResponse") } func init() { @@ -284,46 +444,50 @@ func init() { } var fileDescriptor_43221a4391e9fbf4 = []byte{ - // 610 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x54, 0xcf, 0x4f, 0xd4, 0x4e, - 0x14, 0xdf, 0x42, 0xf2, 0xfd, 0xc2, 0x80, 0x26, 0x36, 0x10, 0x60, 0x83, 0x5d, 0x5d, 0xa3, 0x78, - 0xc0, 0x99, 0x80, 0x26, 0x46, 0x12, 0x0f, 0xac, 0x98, 0xf8, 0x23, 0x9b, 0x98, 0x9a, 0x60, 0xe2, - 0xc1, 0xa6, 0x9d, 0x3e, 0xba, 0x13, 0xda, 0x99, 0xcd, 0xcc, 0xb4, 0xa1, 0xff, 0x01, 0x47, 0x3d, - 0x19, 0x6f, 0xfc, 0x01, 0xfe, 0x21, 0x1e, 0x39, 0x7a, 0x32, 0x06, 0x2e, 0x9e, 0xbd, 0x78, 0x35, - 0x3b, 0x6d, 0xd9, 0x12, 0x2b, 0x10, 0xbc, 0xf5, 0xbd, 0xf7, 0x79, 0xef, 0x7d, 0x3e, 0x6f, 0x5e, - 0x1f, 0x5a, 0x65, 0x5c, 0x83, 0xa4, 0x03, 0x9f, 0x71, 0x4f, 0x01, 0x4d, 0x25, 0xd3, 0x39, 0xa1, - 0x34, 0x23, 0x43, 0x29, 0x32, 0x16, 0x82, 0x24, 0xd9, 0x1a, 0xd1, 0x7b, 0x78, 0x28, 0x85, 0x16, - 0xf6, 0xad, 0x06, 0x34, 0xa6, 0x34, 0xc3, 0x15, 0x1a, 0x67, 0x6b, 0xed, 0xb9, 0x48, 0x44, 0xc2, - 0xe0, 0xc9, 0xe8, 0xab, 0x48, 0x6d, 0x2f, 0x51, 0xa1, 0x12, 0xa1, 0xbc, 0x22, 0x50, 0x18, 0x55, - 0x28, 0x12, 0x22, 0x8a, 0x81, 0x18, 0x2b, 0x48, 0x77, 0x88, 0xcf, 0xf3, 0x32, 0x44, 0x58, 0x40, - 0x49, 0xcc, 0xa2, 0x81, 0xa6, 0x31, 0x03, 0xae, 0x15, 0xd1, 0xc0, 0x43, 0x90, 0x09, 0xe3, 0xda, - 0x30, 0x3b, 0xb1, 0xca, 0x84, 0x4e, 0x2d, 0xae, 0xf3, 0x21, 0x28, 0x02, 0x23, 0x62, 0x9c, 0x42, - 0x01, 0xe8, 0x7e, 0xb4, 0xd0, 0x5c, 0x5f, 0x45, 0x9b, 0x4a, 0xb1, 0x88, 0x3f, 0x11, 0x5c, 0xa5, - 0x09, 0xc8, 0x97, 0x90, 0xdb, 0x4b, 0x68, 0xaa, 0x10, 0xc6, 0xc2, 0x45, 0xeb, 0x86, 0x75, 0x77, - 0xda, 0xfd, 0xdf, 0xd8, 0xcf, 0x43, 0xfb, 0x21, 0xba, 0x52, 0x09, 0xf4, 0xfc, 0x30, 0x94, 0x8b, - 0x13, 0xa3, 0x78, 0xcf, 0xfe, 0xf9, 0xad, 0x73, 0x35, 0xf7, 0x93, 0x78, 0xa3, 0x3b, 0xf2, 0x82, - 0x52, 0x5d, 0x77, 0xb6, 0x02, 0x6e, 0x86, 0xa1, 0xb4, 0x6f, 0xa2, 0x59, 0x5a, 0xb6, 0xf0, 0x76, - 0x21, 0x5f, 0x9c, 0x34, 0x75, 0x67, 0xe8, 0xb8, 0xed, 0xc6, 0xd4, 0xfe, 0x41, 0xa7, 0xf5, 0xe3, - 0xa0, 0xd3, 0xea, 0x3a, 0x68, 0xb9, 0x89, 0x98, 0x0b, 0x6a, 0x28, 0xb8, 0x82, 0xee, 0x27, 0x0b, - 0x5d, 0xef, 0xab, 0xe8, 0x75, 0x1a, 0x24, 0x4c, 0x57, 0x80, 0x3e, 0x53, 0x01, 0x0c, 0xfc, 0x8c, - 0x89, 0x54, 0xda, 0xcb, 0x68, 0x5a, 0x99, 0xa8, 0x06, 0x59, 0x6a, 0x18, 0x3b, 0xec, 0x57, 0x68, - 0x36, 0xa9, 0xa1, 0x8d, 0x88, 0x99, 0xf5, 0x55, 0xcc, 0x02, 0x8a, 0xeb, 0x23, 0xc6, 0xb5, 0xa1, - 0x66, 0x6b, 0xb8, 0xde, 0xc1, 0x3d, 0x55, 0xa1, 0xc6, 0x7d, 0x05, 0xdd, 0x3e, 0x93, 0xda, 0x89, - 0x88, 0xfd, 0x89, 0x06, 0x11, 0x5b, 0x22, 0x0d, 0x62, 0xd8, 0x16, 0x9a, 0xf1, 0xe8, 0x1c, 0x11, - 0x1e, 0x5a, 0x08, 0xd3, 0x61, 0xcc, 0xa8, 0xaf, 0xc1, 0xcb, 0x84, 0x06, 0xaf, 0x7a, 0xdf, 0x52, - 0xcf, 0x4a, 0x9d, 0xbe, 0xd9, 0x00, 0xbc, 0x55, 0x25, 0x6c, 0x0b, 0x0d, 0x4f, 0x4b, 0xb8, 0x3b, - 0x1f, 0x36, 0xb9, 0xed, 0x77, 0x68, 0x81, 0xf1, 0x1d, 0xe9, 0x53, 0xcd, 0x04, 0xf7, 0x82, 0x58, - 0xd0, 0x5d, 0x6f, 0x00, 0x7e, 0x08, 0xd2, 0xbc, 0xde, 0xcc, 0xfa, 0x9d, 0xf3, 0x06, 0xf6, 0xcc, - 0xa0, 0xdd, 0xf9, 0x71, 0x99, 0xde, 0xa8, 0x4a, 0xe1, 0x3e, 0x67, 0x66, 0xf5, 0x49, 0x54, 0x33, - 0x5b, 0xff, 0x35, 0x89, 0x26, 0xfb, 0x2a, 0xb2, 0x3f, 0x58, 0xe8, 0xda, 0x9f, 0x7b, 0xfb, 0x08, - 0x5f, 0xe0, 0xa7, 0xc4, 0x4d, 0x9b, 0xd5, 0xde, 0xbc, 0x74, 0x6a, 0xc5, 0xcd, 0xfe, 0x6c, 0xa1, - 0xf6, 0x19, 0x1b, 0xd9, 0xbb, 0x68, 0x87, 0xbf, 0xd7, 0x68, 0xbf, 0xf8, 0xf7, 0x1a, 0x67, 0xd0, - 0x3d, 0xb5, 0x7b, 0x97, 0xa4, 0x5b, 0xaf, 0x71, 0x59, 0xba, 0x4d, 0x2f, 0xdf, 0x7b, 0xf3, 0xe5, - 0xc8, 0xb1, 0x0e, 0x8f, 0x1c, 0xeb, 0xfb, 0x91, 0x63, 0xbd, 0x3f, 0x76, 0x5a, 0x87, 0xc7, 0x4e, - 0xeb, 0xeb, 0xb1, 0xd3, 0x7a, 0xfb, 0x38, 0x62, 0x7a, 0x90, 0x06, 0x98, 0x8a, 0xa4, 0x3c, 0xa6, - 0x64, 0xdc, 0xf6, 0xde, 0xc9, 0x25, 0xcf, 0x1e, 0x90, 0xbd, 0xd3, 0xe7, 0xdc, 0xfc, 0x12, 0xc1, - 0x7f, 0xe6, 0x18, 0xde, 0xff, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x74, 0xf3, 0x13, 0x1f, 0xff, 0x05, - 0x00, 0x00, + // 683 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x55, 0x4d, 0x4f, 0xd4, 0x40, + 0x18, 0xde, 0x42, 0x40, 0x18, 0xd0, 0x48, 0x85, 0x00, 0x1b, 0xec, 0xea, 0x1a, 0xc5, 0x03, 0xcc, + 0x04, 0xfc, 0x8a, 0x24, 0x1e, 0x58, 0x31, 0x11, 0xcd, 0x06, 0xb3, 0x26, 0x98, 0x78, 0xb0, 0x69, + 0xa7, 0x43, 0x77, 0x42, 0x3b, 0xd3, 0xcc, 0x4c, 0x1b, 0xf6, 0x1f, 0x90, 0x78, 0xd1, 0x93, 0xf1, + 0xc6, 0x0f, 0xf0, 0x87, 0x78, 0xe4, 0xc8, 0xc9, 0x18, 0xb8, 0x78, 0xf6, 0x17, 0x98, 0x9d, 0x7e, + 0x6c, 0x89, 0x2b, 0x5f, 0xc6, 0x78, 0xeb, 0xbc, 0xef, 0x33, 0xcf, 0xf3, 0xbc, 0x6f, 0xe7, 0x9d, + 0x01, 0x0b, 0x94, 0x29, 0x22, 0x70, 0xdb, 0xa1, 0xcc, 0x96, 0x04, 0xc7, 0x82, 0xaa, 0x0e, 0xc2, + 0x38, 0x41, 0x91, 0xe0, 0x09, 0xf5, 0x88, 0x40, 0xc9, 0x12, 0x52, 0x3b, 0x30, 0x12, 0x5c, 0x71, + 0xf3, 0x56, 0x1f, 0x34, 0xc4, 0x38, 0x81, 0x39, 0x1a, 0x26, 0x4b, 0xd5, 0x49, 0x9f, 0xfb, 0x5c, + 0xe3, 0x51, 0xf7, 0x2b, 0xdd, 0x5a, 0x9d, 0xc5, 0x5c, 0x86, 0x5c, 0xda, 0x69, 0x22, 0x5d, 0xe4, + 0x29, 0x9f, 0x73, 0x3f, 0x20, 0x48, 0xaf, 0xdc, 0x78, 0x0b, 0x39, 0xac, 0x93, 0xa5, 0x10, 0x75, + 0x31, 0x0a, 0xa8, 0xdf, 0x56, 0x38, 0xa0, 0x84, 0x29, 0x89, 0x14, 0x61, 0x1e, 0x11, 0x21, 0x65, + 0x4a, 0x3b, 0x2b, 0x56, 0xd9, 0x86, 0x5a, 0x29, 0xaf, 0x3a, 0x11, 0x91, 0x88, 0x74, 0x8d, 0x31, + 0x4c, 0x52, 0x40, 0xfd, 0x93, 0x01, 0x26, 0x9b, 0xd2, 0x5f, 0x95, 0x92, 0xfa, 0xec, 0x29, 0x67, + 0x32, 0x0e, 0x89, 0x78, 0x49, 0x3a, 0xe6, 0x2c, 0x18, 0x49, 0x0b, 0xa3, 0xde, 0x8c, 0x71, 0xc3, + 0xb8, 0x3b, 0xda, 0xba, 0xa4, 0xd7, 0xeb, 0x9e, 0xf9, 0x08, 0x5c, 0xce, 0x0b, 0xb4, 0x1d, 0xcf, + 0x13, 0x33, 0x03, 0xdd, 0x7c, 0xc3, 0xfc, 0xf9, 0xad, 0x76, 0xa5, 0xe3, 0x84, 0xc1, 0x4a, 0xbd, + 0x1b, 0x25, 0x52, 0xd6, 0x5b, 0xe3, 0x39, 0x70, 0xd5, 0xf3, 0x84, 0x79, 0x13, 0x8c, 0xe3, 0x4c, + 0xc2, 0xde, 0x26, 0x9d, 0x99, 0x41, 0xcd, 0x3b, 0x86, 0x7b, 0xb2, 0x2b, 0x23, 0xbb, 0x7b, 0xb5, + 0xca, 0x8f, 0xbd, 0x5a, 0xa5, 0x6e, 0x81, 0xb9, 0x7e, 0xc6, 0x5a, 0x44, 0x46, 0x9c, 0x49, 0x52, + 0xff, 0x6c, 0x80, 0xeb, 0x4d, 0xe9, 0xbf, 0x8e, 0xdd, 0x90, 0xaa, 0x1c, 0xd0, 0xa4, 0xd2, 0x25, + 0x6d, 0x27, 0xa1, 0x3c, 0x16, 0xe6, 0x1c, 0x18, 0x95, 0x3a, 0xab, 0x88, 0xc8, 0x6a, 0xe8, 0x05, + 0xcc, 0x57, 0x60, 0x3c, 0x2c, 0xa1, 0x75, 0x11, 0x63, 0xcb, 0x0b, 0x90, 0xba, 0x18, 0x96, 0x5b, + 0x0c, 0x4b, 0x4d, 0x4d, 0x96, 0x60, 0x59, 0xa1, 0x75, 0x8c, 0xa1, 0xe4, 0x7d, 0x1e, 0xdc, 0x3e, + 0xd1, 0x5a, 0x51, 0xc4, 0xee, 0x40, 0x9f, 0x22, 0xd6, 0x78, 0xec, 0x06, 0x64, 0x93, 0x2b, 0xca, + 0xfc, 0x53, 0x8a, 0xb0, 0xc1, 0xb4, 0x17, 0x47, 0x01, 0xc5, 0x8e, 0x22, 0x76, 0xc2, 0x15, 0xb1, + 0xf3, 0xff, 0x9b, 0xd5, 0x33, 0x5f, 0xb6, 0xaf, 0x4f, 0x00, 0x5c, 0xcb, 0x37, 0x6c, 0x72, 0x45, + 0x9e, 0x65, 0xf0, 0xd6, 0x94, 0xd7, 0x2f, 0x6c, 0xbe, 0x03, 0xd3, 0x94, 0x6d, 0x09, 0x07, 0x2b, + 0xca, 0x99, 0xed, 0x06, 0x1c, 0x6f, 0xdb, 0x6d, 0xe2, 0x78, 0x44, 0xe8, 0xbf, 0x37, 0xb6, 0x7c, + 0xe7, 0xb4, 0x86, 0x3d, 0xd7, 0xe8, 0xd6, 0x54, 0x8f, 0xa6, 0xd1, 0x65, 0x49, 0xc3, 0xa7, 0xf4, + 0xac, 0xdc, 0x89, 0xa2, 0x67, 0xef, 0x0d, 0x30, 0xd2, 0x94, 0xfe, 0x46, 0xa4, 0xd6, 0xd9, 0xff, + 0x3f, 0xa6, 0x26, 0xb8, 0x9a, 0x9b, 0x29, 0x1c, 0x52, 0x30, 0x9a, 0xc6, 0x36, 0x62, 0xf5, 0x2f, + 0x1c, 0x96, 0xe4, 0xaf, 0x81, 0x89, 0x42, 0x2a, 0xd7, 0x5f, 0x3e, 0x18, 0x02, 0x83, 0x4d, 0xe9, + 0x9b, 0x1f, 0x0d, 0x30, 0xf1, 0xfb, 0x64, 0x3f, 0x86, 0x67, 0xb8, 0xb6, 0x60, 0xbf, 0xd9, 0xab, + 0xae, 0x5e, 0x78, 0x6b, 0xee, 0xcd, 0xfc, 0x62, 0x80, 0xea, 0x09, 0x33, 0xdb, 0x38, 0xab, 0xc2, + 0x9f, 0x39, 0xaa, 0x2f, 0xfe, 0x9e, 0xe3, 0x04, 0xbb, 0xc7, 0xa6, 0xf3, 0x82, 0x76, 0xcb, 0x1c, + 0x17, 0xb5, 0xdb, 0x6f, 0x36, 0xcc, 0x10, 0x0c, 0xa5, 0x73, 0xb1, 0x78, 0x56, 0x52, 0x0d, 0xaf, + 0x3e, 0x38, 0x17, 0xbc, 0x90, 0x8b, 0xc0, 0x70, 0x76, 0xca, 0xe1, 0x39, 0x08, 0x36, 0x62, 0x55, + 0x7d, 0x78, 0x3e, 0x7c, 0xae, 0xd8, 0x78, 0xf3, 0xf5, 0xd0, 0x32, 0xf6, 0x0f, 0x2d, 0xe3, 0xfb, + 0xa1, 0x65, 0x7c, 0x38, 0xb2, 0x2a, 0xfb, 0x47, 0x56, 0xe5, 0xe0, 0xc8, 0xaa, 0xbc, 0x7d, 0xe2, + 0x53, 0xd5, 0x8e, 0x5d, 0x88, 0x79, 0x98, 0xbd, 0xa7, 0xa8, 0x27, 0xb1, 0x58, 0x3c, 0xe6, 0xc9, + 0x7d, 0xb4, 0x73, 0xfc, 0x45, 0xd7, 0xb7, 0xa2, 0x3b, 0xac, 0xdf, 0xc3, 0x7b, 0xbf, 0x02, 0x00, + 0x00, 0xff, 0xff, 0x3b, 0x47, 0x43, 0x85, 0x02, 0x08, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -341,6 +505,8 @@ type MsgClient interface { AssignConsumerKey(ctx context.Context, in *MsgAssignConsumerKey, opts ...grpc.CallOption) (*MsgAssignConsumerKeyResponse, error) SubmitConsumerMisbehaviour(ctx context.Context, in *MsgSubmitConsumerMisbehaviour, opts ...grpc.CallOption) (*MsgSubmitConsumerMisbehaviourResponse, error) SubmitConsumerDoubleVoting(ctx context.Context, in *MsgSubmitConsumerDoubleVoting, opts ...grpc.CallOption) (*MsgSubmitConsumerDoubleVotingResponse, error) + OptIn(ctx context.Context, in *MsgOptIn, opts ...grpc.CallOption) (*MsgOptInResponse, error) + OptOut(ctx context.Context, in *MsgOptOut, opts ...grpc.CallOption) (*MsgOptOutResponse, error) } type msgClient struct { @@ -378,11 +544,31 @@ func (c *msgClient) SubmitConsumerDoubleVoting(ctx context.Context, in *MsgSubmi return out, nil } +func (c *msgClient) OptIn(ctx context.Context, in *MsgOptIn, opts ...grpc.CallOption) (*MsgOptInResponse, error) { + out := new(MsgOptInResponse) + err := c.cc.Invoke(ctx, "/interchain_security.ccv.provider.v1.Msg/OptIn", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) OptOut(ctx context.Context, in *MsgOptOut, opts ...grpc.CallOption) (*MsgOptOutResponse, error) { + out := new(MsgOptOutResponse) + err := c.cc.Invoke(ctx, "/interchain_security.ccv.provider.v1.Msg/OptOut", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // MsgServer is the server API for Msg service. type MsgServer interface { AssignConsumerKey(context.Context, *MsgAssignConsumerKey) (*MsgAssignConsumerKeyResponse, error) SubmitConsumerMisbehaviour(context.Context, *MsgSubmitConsumerMisbehaviour) (*MsgSubmitConsumerMisbehaviourResponse, error) SubmitConsumerDoubleVoting(context.Context, *MsgSubmitConsumerDoubleVoting) (*MsgSubmitConsumerDoubleVotingResponse, error) + OptIn(context.Context, *MsgOptIn) (*MsgOptInResponse, error) + OptOut(context.Context, *MsgOptOut) (*MsgOptOutResponse, error) } // UnimplementedMsgServer can be embedded to have forward compatible implementations. @@ -398,6 +584,12 @@ func (*UnimplementedMsgServer) SubmitConsumerMisbehaviour(ctx context.Context, r func (*UnimplementedMsgServer) SubmitConsumerDoubleVoting(ctx context.Context, req *MsgSubmitConsumerDoubleVoting) (*MsgSubmitConsumerDoubleVotingResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method SubmitConsumerDoubleVoting not implemented") } +func (*UnimplementedMsgServer) OptIn(ctx context.Context, req *MsgOptIn) (*MsgOptInResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method OptIn not implemented") +} +func (*UnimplementedMsgServer) OptOut(ctx context.Context, req *MsgOptOut) (*MsgOptOutResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method OptOut not implemented") +} func RegisterMsgServer(s grpc1.Server, srv MsgServer) { s.RegisterService(&_Msg_serviceDesc, srv) @@ -457,6 +649,42 @@ func _Msg_SubmitConsumerDoubleVoting_Handler(srv interface{}, ctx context.Contex return interceptor(ctx, in, info, handler) } +func _Msg_OptIn_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgOptIn) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).OptIn(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/interchain_security.ccv.provider.v1.Msg/OptIn", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).OptIn(ctx, req.(*MsgOptIn)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_OptOut_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgOptOut) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).OptOut(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/interchain_security.ccv.provider.v1.Msg/OptOut", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).OptOut(ctx, req.(*MsgOptOut)) + } + return interceptor(ctx, in, info, handler) +} + var _Msg_serviceDesc = grpc.ServiceDesc{ ServiceName: "interchain_security.ccv.provider.v1.Msg", HandlerType: (*MsgServer)(nil), @@ -473,6 +701,14 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ MethodName: "SubmitConsumerDoubleVoting", Handler: _Msg_SubmitConsumerDoubleVoting_Handler, }, + { + MethodName: "OptIn", + Handler: _Msg_OptIn_Handler, + }, + { + MethodName: "OptOut", + Handler: _Msg_OptOut_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "interchain_security/ccv/provider/v1/tx.proto", @@ -687,6 +923,133 @@ func (m *MsgSubmitConsumerDoubleVotingResponse) MarshalToSizedBuffer(dAtA []byte return len(dAtA) - i, nil } +func (m *MsgOptIn) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgOptIn) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgOptIn) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ConsumerKey) > 0 { + i -= len(m.ConsumerKey) + copy(dAtA[i:], m.ConsumerKey) + i = encodeVarintTx(dAtA, i, uint64(len(m.ConsumerKey))) + i-- + dAtA[i] = 0x1a + } + if len(m.ProviderAddr) > 0 { + i -= len(m.ProviderAddr) + copy(dAtA[i:], m.ProviderAddr) + i = encodeVarintTx(dAtA, i, uint64(len(m.ProviderAddr))) + i-- + dAtA[i] = 0x12 + } + if len(m.ChainId) > 0 { + i -= len(m.ChainId) + copy(dAtA[i:], m.ChainId) + i = encodeVarintTx(dAtA, i, uint64(len(m.ChainId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgOptInResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgOptInResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgOptInResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgOptOut) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgOptOut) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgOptOut) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ProviderAddr) > 0 { + i -= len(m.ProviderAddr) + copy(dAtA[i:], m.ProviderAddr) + i = encodeVarintTx(dAtA, i, uint64(len(m.ProviderAddr))) + i-- + dAtA[i] = 0x12 + } + if len(m.ChainId) > 0 { + i -= len(m.ChainId) + copy(dAtA[i:], m.ChainId) + i = encodeVarintTx(dAtA, i, uint64(len(m.ChainId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgOptOutResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgOptOutResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgOptOutResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + func encodeVarintTx(dAtA []byte, offset int, v uint64) int { offset -= sovTx(v) base := offset @@ -784,14 +1147,70 @@ func (m *MsgSubmitConsumerDoubleVotingResponse) Size() (n int) { return n } -func sovTx(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozTx(x uint64) (n int) { - return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *MsgAssignConsumerKey) Unmarshal(dAtA []byte) error { - l := len(dAtA) +func (m *MsgOptIn) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ChainId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ProviderAddr) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ConsumerKey) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgOptInResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgOptOut) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ChainId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ProviderAddr) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgOptOutResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovTx(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTx(x uint64) (n int) { + return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgAssignConsumerKey) Unmarshal(dAtA []byte) error { + l := len(dAtA) iNdEx := 0 for iNdEx < l { preIndex := iNdEx @@ -1358,6 +1777,366 @@ func (m *MsgSubmitConsumerDoubleVotingResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *MsgOptIn) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgOptIn: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgOptIn: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChainId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProviderAddr", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProviderAddr = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConsumerKey", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConsumerKey = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgOptInResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgOptInResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgOptInResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgOptOut) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgOptOut: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgOptOut: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChainId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProviderAddr", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProviderAddr = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgOptOutResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgOptOutResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgOptOutResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipTx(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/ccv/types/events.go b/x/ccv/types/events.go index 4c597ded56..2fa584dd40 100644 --- a/x/ccv/types/events.go +++ b/x/ccv/types/events.go @@ -12,6 +12,8 @@ const ( EventTypeRemoveConsumerRewardDenom = "remove_consumer_reward_denom" EventTypeSubmitConsumerMisbehaviour = "submit_consumer_misbehaviour" EventTypeSubmitConsumerDoubleVoting = "submit_consumer_double_voting" + EventTypeOptIn = "opt_in" + EventTypeOptOut = "opt_out" EventTypeExecuteConsumerChainSlash = "execute_consumer_chain_slash" EventTypeFeeDistribution = "fee_distribution" EventTypeConsumerSlashRequest = "consumer_slash_request" From 7ab3557bbce2d6c4c8d05c10c18c816a58c6cea9 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Date: Thu, 8 Feb 2024 10:39:49 +0100 Subject: [PATCH 008/110] test: MBT: Add partial set security to model (feature branch version) (#1627) * Port changes from branch to main * Add model analysis changes to Makefile --- Makefile | 7 +- tests/mbt/model/README.md | 17 ++- tests/mbt/model/ccv.qnt | 124 ++++++++++++----- tests/mbt/model/ccv_boundeddrift.qnt | 51 +++++-- tests/mbt/model/ccv_model.qnt | 44 +++--- tests/mbt/model/ccv_pss.qnt | 157 ++++++++++++++++++++++ tests/mbt/model/ccv_pss_model.qnt | 113 ++++++++++++++++ tests/mbt/model/ccv_pss_test.qnt | 34 +++++ tests/mbt/model/ccv_sync.qnt | 2 +- tests/mbt/model/ccv_test.qnt | 22 +-- tests/mbt/model/ccv_utils.qnt | 51 +++++-- tests/mbt/model/libraries/extraSpells.qnt | 121 +++++++++++++++++ tests/mbt/{ => model}/run_invariants.sh | 0 13 files changed, 644 insertions(+), 99 deletions(-) create mode 100644 tests/mbt/model/ccv_pss.qnt create mode 100644 tests/mbt/model/ccv_pss_model.qnt create mode 100644 tests/mbt/model/ccv_pss_test.qnt rename tests/mbt/{ => model}/run_invariants.sh (100%) diff --git a/Makefile b/Makefile index 1b3fa87e7f..af1d9da73a 100644 --- a/Makefile +++ b/Makefile @@ -140,8 +140,11 @@ test-trace: # Note: this is *not* using the Quint models to test the system, # this tests/verifies the Quint models *themselves*. verify-models: - cd tests/mbt/model;\ - ../run_invariants.sh + quint test tests/mbt/model/ccv_test.qnt;\ + quint test tests/mbt/model/ccv_model.qnt;\ + quint test tests/mbt/model/ccv_pss_test.qnt;\ + quint run --invariant "all{ValidatorUpdatesArePropagatedInv,ValidatorSetHasExistedInv,SameVscPacketsInv,MatureOnTimeInv,EventuallyMatureOnProviderInv}" tests/mbt/model/ccv_model.qnt --max-steps 200 --max-samples 200;\ + quint run --invariant "all{ValidatorUpdatesArePropagatedKeyAssignmentInv,ValidatorSetHasExistedKeyAssignmentInv,SameVscPacketsKeyAssignmentInv,MatureOnTimeInv,EventuallyMatureOnProviderInv,KeyAssignmentRulesInv}" tests/mbt/model/ccv_model.qnt --step stepKeyAssignment --max-steps 200 --max-samples 200 diff --git a/tests/mbt/model/README.md b/tests/mbt/model/README.md index 57f5b2eda9..df994b7f84 100644 --- a/tests/mbt/model/README.md +++ b/tests/mbt/model/README.md @@ -51,6 +51,12 @@ To run with key assignment, specify the step flag: `--step stepKeyAssignment`. KeyAssignment also needs some different invariants, see below. +#### Partial Set Security + +To run with Partial Set Security, specify the step flag `--step stepBoundedDriftKeyAndPSS`. +This runs both PSS and Key Assignment. +It also requires running with `ccv_boundeddrift.qnt`, see below. + #### ccv_boundeddrift.qnt This state machine layer is more restricted to generate more interesting traces: * It never allows consumer chains to drift more than `MaxDrift` time apart from each other. @@ -75,10 +81,7 @@ traces are not very useful for testing. To run unit tests, run ``` -quint test ccv_test.qnt -``` -and -``` +quint test ccv_test.qnt; quint test ccv_model.qnt ``` @@ -131,4 +134,8 @@ The available sanity checks are: - CanSendVscPackets - CanSendVscMaturedPackets - CanAssignConsumerKey (only with `--step stepKeyAssignment`) -- CanHaveConsumerAddresses (only with `--step stepKeyAssignment`) \ No newline at end of file +- CanHaveConsumerAddresses (only with `--step stepKeyAssignment`) +- CanOptIn (only with `--step stepBoundedDriftKeyAndPSS` on `ccv_boundeddrift.qnt`) +- CanOptOut (only with `--step stepBoundedDriftKeyAndPSS` on `ccv_boundeddrift.qnt`) +- CanFailOptOut (only with `--step stepBoundedDriftKeyAndPSS` on `ccv_boundeddrift.qnt`) +- CanHaveOptIn (only with `--step stepBoundedDriftKeyAndPSS` on `ccv_boundeddrift.qnt`) diff --git a/tests/mbt/model/ccv.qnt b/tests/mbt/model/ccv.qnt index 2a81fe3a2d..68d08e88a3 100644 --- a/tests/mbt/model/ccv.qnt +++ b/tests/mbt/model/ccv.qnt @@ -89,6 +89,12 @@ module ccv_types { // Stores VscPackets which have been sent but where the provider has *not received a response yet*. sentVscPacketsToConsumer: Chain -> List[VscPacket], + // stores whether, in this block, the validator set has changed. + // this is needed because the validator set might be considered to have changed, even though + // it is still technically identical at our level of abstraction, e.g. a validator power change on the provider + // might leave the validator set the same because a delegation and undelegation cancel each other out. + providerValidatorSetChangedInThisBlock: bool, + // stores for which consumer chains, in this epoch, the validator set is considered to have changed and we thus need to send a VscPacket to the consumer chains. consumersWithPowerChangesInThisEpoch: Set[Chain], @@ -120,7 +126,18 @@ module ccv_types { consumerAddrsToPrune: Chain -> VscId -> List[ConsumerAddr], // For every sent VSCPacket, stores the key assignments that were applied to send it. - keyAssignmentsForVSCPackets: VscId -> (Chain -> (Node -> ConsumerAddr)) + keyAssignmentsForVSCPackets: VscId -> (Chain -> (Node -> ConsumerAddr)), + + // For each consumer chain, + // stores the set of validators that are opted into running the chain. + optedInVals: Chain -> Set[Node], + + // for each consumer, stores the top N for that consumer. + // The top N% of the validator set by voting power + // is obliged to run a topN chain. + // If the chain is a pure opt-in chain (where noone is forced to run it), + // this is 0. + topNByConsumer: Chain -> int, } // utility function: returns a provider state that is initialized minimally. @@ -130,6 +147,7 @@ module ccv_types { outstandingPacketsToConsumer: Map(), receivedMaturations: Set(), sentVscPacketsToConsumer: Map(), + providerValidatorSetChangedInThisBlock: false, consumersWithPowerChangesInThisEpoch: Set(), consumerStatus: Map(), runningVscId: 0, @@ -138,7 +156,9 @@ module ccv_types { consumerAddrToValidator: Map(), consumerAddrsToPrune: Map(), keyAssignmentsForVSCPackets: Map(), - consumersWithAddrAssignmentChangesInThisEpoch: Set() + consumersWithAddrAssignmentChangesInThisEpoch: Set(), + optedInVals: Map(), + topNByConsumer: Map(), } @@ -226,6 +246,33 @@ module ccv_types { // given as a pure val so that we can switch cases based on // whether a chain is the provider or not pure val PROVIDER_CHAIN = "provider" + + // A record that keeps the information needed to add a new consumer. + // In particular, holds: + // the chain name/identifier, + // and the top N factor for the chain. + type ConsumerAdditionMsg = { + chain: Chain, + topN: int + } + + // Creates a new ConsumerAdditionMsg with a given top N. + pure def NewTopNConsumer(chain: Chain, topN: int): ConsumerAdditionMsg = { + { + chain: chain, + topN: topN + } + } + + // Creates a new ConsumerAdditionMsg with topN = 0. + pure def NewOptInConsumer(chain: Chain): ConsumerAdditionMsg = { + NewTopNConsumer(chain, 0) + } + + // Creates a new ConsumerAdditionMsg with top N = 100%. + pure def NewFullConsumer(chain: Chain): ConsumerAdditionMsg = { + NewTopNConsumer(chain, 100) + } } module ccv { @@ -246,6 +293,7 @@ module ccv { import Time.* from "./libraries/Time" import extraSpells.* from "./libraries/extraSpells" import ccv_types.* + import ccv_pss.* from "./ccv_pss" import ccv_utils.* from "./ccv_utils" @@ -417,13 +465,14 @@ module ccv { // i.e. the timestamp for the next block is oldTimestamp + timeAdvancement timeAdvancement: Time, // a set of consumers that were not consumers before, but should be set to running now. - consumersToStart: Set[Chain], + consumersToStart: Set[ConsumerAdditionMsg], // a set of consumers that were running before, but should be set to stopped now. // This argument only needs to contain "voluntary" stops - // forced stops, e.g. because a consumer timed out, // will be added automatically. consumersToStop: Set[Chain]): Result = { val currentProviderState = currentState.providerState + val curValSet = currentProviderState.chainState.currentValidatorSet // check for vsc timeouts val timedOutConsumers = getRunningConsumers(currentProviderState).filter( @@ -431,27 +480,11 @@ module ccv { val res = TimeoutDueToVscTimeout(currentState, consumer, VscTimeout) res._1 ) - - // for each consumer chain, apply the key assignment to the current validator set - val currentValSets = ConsumerChains.mapBy( - (consumer) => - currentProviderState.applyKeyAssignmentToValSet( - consumer, - currentProviderState.chainState.currentValidatorSet - ) - ) - // store the current validator set with the key assignments applied in the history - val newKeyAssignedValSetHistory = currentValSets.keys().mapBy( - (consumer) => - currentProviderState.keyAssignedValSetHistory - .getOrElse(consumer, List()) // get the existing history (empty list if no history yet) - .prepend(currentValSets.get(consumer)) // prepend the current validator set with key assignments applied - ) // run the shared core chainState logic val newChainState = currentProviderState.chainState.endAndBeginBlockShared(timeAdvancement) val providerStateAfterTimeAdvancement = - {...currentProviderState, chainState: newChainState, keyAssignedValSetHistory: newKeyAssignedValSetHistory} + {...currentProviderState, chainState: newChainState} val tmpState = currentState.with( "providerState", providerStateAfterTimeAdvancement ) @@ -472,41 +505,62 @@ module ccv { // start/stop chains - val res = providerStateAfterSending.consumerStatus.StartStopConsumers( + val res = providerStateAfterSending.StartStopConsumers( consumersToStart, consumersToStop, timedOutConsumers ) - val newConsumerStatus = res._1 + val providerStateAfterConsumerAdvancement = res._1.with("providerValidatorSetChangedInThisBlock", false) val err = res._2 - val providerStateAfterConsumerAdvancement = providerStateAfterSending.with( - "consumerStatus", newConsumerStatus - ) + + val consumerAdditions = consumersToStart.map(consumer => consumer.chain) + + // for each running consumer chain, opt in validators that are in the top N + val providerStateAfterPSS = providerStateAfterConsumerAdvancement.endBlockPSS() if (err != "") { Err(err) } else { - // for each consumer we just set to running, set its initial validator set to be the current one on the provider... - val valSet = providerStateAfterConsumerAdvancement.chainState.currentValidatorSet + // for each consumer chain, apply the key assignment to the current validator set + val currentValSets = getRunningConsumers(providerStateAfterPSS).mapBy( + (consumer) => + providerStateAfterPSS.applyKeyAssignmentToValSet( + consumer, + // get the validator set after partial set security has been applied + GetPSSValidatorSet(providerStateAfterPSS, curValSet, consumer) + ) + ) + + // store the current validator set with the key assignments applied in the history + val newKeyAssignedValSetHistory = currentValSets.keys().mapBy( + (consumer) => + providerStateAfterPSS.keyAssignedValSetHistory + .getOrElse(consumer, List()) // get the existing history (empty list if no history yet) + .prepend(currentValSets.get(consumer)) // prepend the current validator set with key assignments applied + ) + + val providerStateAfterStoringValSets = providerStateAfterPSS.with( + "keyAssignedValSetHistory", newKeyAssignedValSetHistory + ) + val newConsumerStateMap = tmpState.consumerStates.keys().mapBy( (consumer) => - if (consumersToStart.contains(consumer)) { - // ...modified by the key assignments for the consumer - val consValSet = applyKeyAssignmentToValSet(providerStateAfterConsumerAdvancement, consumer, valSet) + if (consumerAdditions.contains(consumer)) { val currentConsumerState: ConsumerState = tmpState.consumerStates.get(consumer) + // correctly set the state for the new consumer val newConsumerState: ConsumerState = currentConsumerState.with( "chainState", currentConsumerState.chainState.with( - "currentValidatorSet", consValSet + "currentValidatorSet", currentValSets.get(consumer) ).with( "votingPowerHistory", - List(consValSet) + List(currentValSets.get(consumer)) ).with( "lastTimestamp", - providerStateAfterConsumerAdvancement.chainState.lastTimestamp + providerStateAfterStoringValSets.chainState.lastTimestamp ).with( "runningTimestamp", - providerStateAfterConsumerAdvancement.chainState.runningTimestamp + providerStateAfterStoringValSets.chainState.runningTimestamp ) ) newConsumerState @@ -515,7 +569,7 @@ module ccv { } ) val newState = tmpState.with( - "providerState", providerStateAfterConsumerAdvancement + "providerState", providerStateAfterStoringValSets ).with( "consumerStates", newConsumerStateMap ) diff --git a/tests/mbt/model/ccv_boundeddrift.qnt b/tests/mbt/model/ccv_boundeddrift.qnt index 24db1d3eaf..b067ca79b2 100644 --- a/tests/mbt/model/ccv_boundeddrift.qnt +++ b/tests/mbt/model/ccv_boundeddrift.qnt @@ -5,6 +5,7 @@ module ccv_boundeddrift { import ccv from "ccv" import Time.* from "./libraries/Time" import extraSpells.* from "./libraries/extraSpells" + import ccv_pss_model.* from "ccv_pss_model" // The boundeddrift module has its own step function. @@ -60,19 +61,22 @@ module ccv_boundeddrift { stepCommon, // allow actions that do not influence time // advance a block for a consumer - all { - runningConsumers.size() > 0, // ensure there is a running consumer, otherwise this action does not make sense - nondet chain = runningConsumers.oneOf() - val maxAdv = findMaxTimeAdvancement(GetChainState(chain), GetOtherChainStates(chain), maxDrift) - val possibleAdvancements = timeAdvancements.filter(t => t <= maxAdv) - all { - possibleAdvancements.size() > 0, // ensure there is a possible advancement, otherwise this action does not make sense - nondet timeAdvancement = possibleAdvancements.oneOf() - EndAndBeginBlockForConsumer(chain, timeAdvancement), - } - }, + stepBoundedDriftConsumer, // advance a block for the provider + stepBoundedDriftProvider + } + + action stepBoundedDriftProvider: bool = { + stepBoundedDriftProvider_helper(allFullConsumers) + } + + action stepBoundedDriftProviderPSS: bool = { + stepBoundedDriftProvider_helper(variousPossibleTopN) + } + + // As an argument, takes a function that, when invoked, gives a top N value to use for a new consumer chain. + action stepBoundedDriftProvider_helper(topNOracle: Set[int]): bool = { val maxAdv = findMaxTimeAdvancement(GetChainState(Ccvt::PROVIDER_CHAIN), GetOtherChainStates(Ccvt::PROVIDER_CHAIN), maxDrift) val possibleAdvancements = timeAdvancements.filter(t => t <= maxAdv) all { @@ -80,14 +84,37 @@ module ccv_boundeddrift { // advance a block for the provider val consumerStatus = currentState.providerState.consumerStatus nondet consumersToStart = oneOf(nonConsumers.powerset()) + nondet topN = oneOf(topNOracle) + nondet consumerAdditions = consumersToStart.map(c => Ccvt::NewTopNConsumer(c, topN)) // make it so we stop consumers only with small likelihood: nondet stopConsumersRand = oneOf(1.to(100)) nondet consumersToStop = if (stopConsumersRand <= consumerStopChance) oneOf(runningConsumers.powerset()) else Set() nondet timeAdvancement = oneOf(possibleAdvancements) - EndAndBeginBlockForProvider(timeAdvancement, consumersToStart, consumersToStop), + EndAndBeginBlockForProvider(timeAdvancement, consumerAdditions, consumersToStop), } } + action stepBoundedDriftConsumer = all { + runningConsumers.size() > 0, // ensure there is a running consumer, otherwise this action does not make sense + nondet chain = runningConsumers.oneOf() + val maxAdv = findMaxTimeAdvancement(GetChainState(chain), GetOtherChainStates(chain), maxDrift) + val possibleAdvancements = timeAdvancements.filter(t => t <= maxAdv) + all { + possibleAdvancements.size() > 0, // ensure there is a possible advancement, otherwise this action does not make sense + nondet timeAdvancement = possibleAdvancements.oneOf() + EndAndBeginBlockForConsumer(chain, timeAdvancement), + } + } + + action stepBoundedDriftKeyAndPSS = any { + stepCommon, + stepBoundedDriftProviderPSS, + stepBoundedDriftConsumer, + nondetKeyAssignment, + StepOptIn, + StepOptOut, + } + action stepBoundedDriftKeyAssignment = any { stepBoundedDrift, nondetKeyAssignment, diff --git a/tests/mbt/model/ccv_model.qnt b/tests/mbt/model/ccv_model.qnt index 1509ad439f..b3b487d113 100644 --- a/tests/mbt/model/ccv_model.qnt +++ b/tests/mbt/model/ccv_model.qnt @@ -49,7 +49,13 @@ module ccv_model { var currentState: ProtocolState - // a type storing the parameters used in actions. + // a type storing the parameters used in actions, + // as well as return values that are not visible from the state, + // i.e. errors. + // Note that whether an error is returned, + // or whether the action is simply not possible when an error occurs, is + // a design choice that is different for each action, + // or can depend on the type of error. // this is used in the trace to store // the name of the last action, plus the parameters we passed to it. // Note: This type holds ALL parameters that are used in ANY action, @@ -59,11 +65,12 @@ module ccv_model { kind: str, consumerChain: Chain, timeAdvancement: Time, - consumersToStart: Set[Chain], + consumersToStart: Set[ConsumerAdditionMsg], consumersToStop: Set[Chain], validator: Node, changeAmount: int, consumerAddr: ConsumerAddr, + expectedError: str, // if the action returns an error, it goes here. } @@ -88,6 +95,7 @@ module ccv_model { validator: "", changeAmount: 0, consumerAddr: "", + expectedError: "", } @@ -101,7 +109,7 @@ module ccv_model { val consumerStates = ConsumerChains.mapBy(chain => GetEmptyConsumerState) val providerStateWithConsumers = providerState.with( "consumerStatus", - ConsumerChains.mapBy(chain => NOT_CONSUMER) + ConsumerChains.mapBy(chain => NOT_CONSUMER) ).with( "outstandingPacketsToConsumer", ConsumerChains.mapBy(chain => List()) @@ -171,7 +179,7 @@ module ccv_model { action EndAndBeginBlockForProvider( timeAdvancement: Time, - consumersToStart: Set[Chain], + consumersToStart: Set[ConsumerAdditionMsg], consumersToStop: Set[Chain]): bool = val result = endAndBeginBlockForProvider(currentState, timeAdvancement, consumersToStart, consumersToStop) all { @@ -232,9 +240,10 @@ module ccv_model { val consumerStatus = currentState.providerState.consumerStatus nondet consumersToStart = oneOf(nonConsumers.powerset()) + val consumerAdditions = consumersToStart.map(chain => NewFullConsumer(chain)) nondet consumersToStop = oneOf(runningConsumers.powerset()) nondet timeAdvancement = oneOf(timeAdvancements) - EndAndBeginBlockForProvider(timeAdvancement, consumersToStart, consumersToStop), + EndAndBeginBlockForProvider(timeAdvancement, consumerAdditions, consumersToStop), stepCommon } @@ -262,17 +271,6 @@ module ccv_model { // UTILITY FUNCTIONS // ================== - pure def removeZeroPowers(valSet: ValidatorSet): ValidatorSet = - valSet.keys().fold( - Map(), - (acc, node) => - if (valSet.get(node) == 0) { - acc - } else { - acc.put(node, valSet.get(node)) - } - ) - pure def oldest(packets: Set[VscPacket]): VscPacket = val newestPossiblePacket: VscPacket = { id: 0, @@ -531,7 +529,7 @@ module ccv_model { // the validator set has changed assert(currentState.providerState.chainState.currentValidatorSet == InitialValidatorSet.put("node1", 150)), // start consumer1 - EndAndBeginBlockForProvider(1 * Second, Set("consumer1"), Set()) + EndAndBeginBlockForProvider(1 * Second, Set(NewFullConsumer("consumer1")), Set()) }) .then( all { @@ -609,7 +607,7 @@ module ccv_model { run SameVscPacketsManualTest = init.then( // start all consumers except for consumer3 - EndAndBeginBlockForProvider(1 * Second, Set("consumer1", "consumer2"), Set()) + EndAndBeginBlockForProvider(1 * Second, Set(NewFullConsumer("consumer1"), NewFullConsumer("consumer2")), Set()) ).then( // change voting power VotingPowerChange("node1", 50) @@ -624,7 +622,7 @@ module ccv_model { DeliverVscPacket("consumer2") ).then( // start consumer3 - EndAndBeginBlockForProvider(1 * Second, Set("consumer3"), Set()) + EndAndBeginBlockForProvider(1 * Second, Set(NewFullConsumer("consumer3")), Set()) ).then( // do another voting power change VotingPowerChange("node2", 50) @@ -655,7 +653,7 @@ module ccv_model { init .then( // start all consumer chains - EndAndBeginBlockForProvider(1 * Second, ConsumerChains, Set()) + EndAndBeginBlockForProvider(1 * Second, ConsumerChains.map(c => NewFullConsumer(c)), Set()) ) .then( // change voting power @@ -868,7 +866,7 @@ module ccv_model { init .then( // start all consumer chains - EndAndBeginBlockForProvider(1 * Second, consumerChains, Set()) + EndAndBeginBlockForProvider(1 * Second, consumerChains.map(c => NewFullConsumer(c)), Set()) ) .then( // node 1 assigns a key on consumer1 @@ -891,7 +889,7 @@ module ccv_model { // the key should be present in the valset on the consumer, and the node itself should not assert(currentState.consumerStates.get("consumer1").chainState.currentValidatorSet.getOrElse("node1", 0) == 0), assert(currentState.consumerStates.get("consumer1").chainState.currentValidatorSet.get("consAddr1") == 100), - // try some key assignments that should fail/succeed without committing to state + // try some key assignments that should fail/succeed without comitting to state val res = assignConsumerKey(currentState, "consumer1", "node1", "consAddr1") // fail - key already assigned (even if it is the same node) assert(hasError(res)), @@ -940,7 +938,7 @@ module ccv_model { VotingPowerChange("node1", 50) ) .then( - EndAndBeginBlockForProvider(1 * Second, Set("consumer1", "consumer2"), Set()) + EndAndBeginBlockForProvider(1 * Second, Set(NewFullConsumer("consumer1"), NewFullConsumer("consumer2")), Set()) ).then( all { ValidatorSetHasExistedKeyAssignmentInv, diff --git a/tests/mbt/model/ccv_pss.qnt b/tests/mbt/model/ccv_pss.qnt new file mode 100644 index 0000000000..4759fe6b34 --- /dev/null +++ b/tests/mbt/model/ccv_pss.qnt @@ -0,0 +1,157 @@ +// This module contains logic for PSS (Partial Set Security). +// PSS is a variant/extension of CCV that +// allows for only a subset of the validator set +// to secure a consumer chain. +// Not all logic related to PSS is inside this module, as some logic is +// too tightly coupled with the core CCV logic, +// which is instead found in ccv.qnt +module ccv_pss { + import ccv_types.* from "./ccv" + import extraSpells.* from "./libraries/extraSpells" + import ccv_utils.* from "./ccv_utils" + + // Given a base validator set, an N for a top N chain, and a set of validators that have opted in to the chain, + // returns the validator set that should be sent to the chain. + // Assumes that the value for N is valid. + pure def GetPSSValidatorSet(providerState: ProviderState, origValSet: ValidatorSet, consumer: Chain): ValidatorSet = { + pure val optedInVals = providerState.optedInVals.getOrElse(consumer, Set()) + GetPSSValidatorSet_helper(origValSet, optedInVals) + } + + pure def GetPSSValidatorSet_helper(origValSet: ValidatorSet, optedInVals: Set[Node]): ValidatorSet = { + origValSet.mapFilter(v => optedInVals.contains(v)) + } + + // Given a validator set and N, returns the top N% of validators by power. + // Note that in the edge case of multiple validators having the same power, + // this will always include all validators with the same power as the lowest top N validator. + pure def GetTopNVals(origValSet: ValidatorSet, N: int): Set[Node] = { + // == sort validators by power == + // define a comparator that compares validators by power + pure def powerCompare(a: Node, b: Node): Ordering = { + pure val powA = origValSet.get(a) + pure val powB = origValSet.get(b) + intCompare(powB, powA) + } + // get a sorted list of validators by power + pure val sortedVals = origValSet.keys().toSortedList(powerCompare) + + // == compute the threshold of how much power the top N have == + pure val totalPower = origValSet.mapValuesSum() + pure val topNPower = totalPower * N / 100 + + // == construct the validator set by going through the sorted vals == + pure val res = sortedVals.foldl( + // accumulator carries 4 values: + // * set of vals in top N (starts with empty set) + // * total power added so far (starts with 0) + // * whether we should add the next validator if it has the same power as the previous one, + // regardless of total power (starts with false) + // * the power of the last validator added (starts with 0) + (Set(), 0, false, 0), + (acc, validator) => + pure val curValSet = acc._1 + pure val accPower = acc._2 + pure val shouldAddSamePow = acc._3 + pure val lastPow = acc._4 + + pure val validatorPower = origValSet.get(validator) + if (validatorPower == lastPow and shouldAddSamePow) { + // we should add the validator because it has the same power as the previous one, + // and we add regardless of total power because we need to include all + // vals with the same power if we include one of them + pure val newAccPower = accPower + validatorPower + (curValSet.union(Set(validator)), newAccPower, true, validatorPower) + } else if (validatorPower > 0 and accPower < topNPower) { + // if we don't have enough power yet, add the validator to the set + pure val newAccPower = accPower + validatorPower + (curValSet.union(Set(validator)), newAccPower, true, validatorPower) + } else { + // if we have enough power and we also are done adding + // all validators with the same power as the lowest top N validator, + // don't add them + (curValSet, accPower, false, 0) + } + ) + res._1 + } + + // Opts a validator in for a consumer chain the provider. + // Possible before the consumer chain starts running, + // and will then be applied when the consumer chain starts running. + pure def OptIn(currentState: ProtocolState, consumer: Chain, validator: Node): Result = { + pure val optedInVals = currentState.providerState.optedInVals.get(consumer) + pure val newOptedInVals = optedInVals.union(Set(validator)) + Ok({ + ...currentState, + providerState: { + ...currentState.providerState, + optedInVals: currentState.providerState.optedInVals.put(consumer, newOptedInVals) + } + }) + } + + // Returns true if the given validator is in the top N for the given consumer chain, + // and false otherwise. + pure def IsTopN(currentState: ProtocolState, validator: Node, consumer: Chain): bool = { + val proviValSet = currentState.providerState.chainState.currentValidatorSet + val N = currentState.providerState.topNByConsumer.get(consumer) + + val topNValSet = GetTopNVals(proviValSet, N) + + topNValSet.contains(validator) + } + + // Returns true if the given validator has opted in to the given consumer chain, + pure def IsOptedIn(currentState: ProtocolState, validator: Node, consumer: Chain): bool = { + currentState.providerState.optedInVals.getOrElse(consumer, Set()).contains(validator) + } + + // Opts a validator out. Safe to call before the consumer chain even runs. + // Will not stop the validator set from being forced to validate when in the top N. + // Validators that are in the top N will not be able to opt out, and + // an error will be returned. + // Similarly, if the validator is not opted in, an error will be returned. + pure def OptOut(currentState: ProtocolState, consumer: Chain, validator: Node): Result = { + if (currentState.IsTopN(validator, consumer)) { + Err("Cannot opt out a validator that is in the top N") + } else if (not(currentState.IsOptedIn(validator, consumer))) { + Err("Cannot opt out a validator that is not opted in") + } else { + pure val optedInVals = currentState.providerState.optedInVals.get(consumer) + pure val newOptedInVals = optedInVals.exclude(Set(validator)) + Ok({ + ...currentState, + providerState: { + ...currentState.providerState, + optedInVals: currentState.providerState.optedInVals.put(consumer, newOptedInVals) + } + }) + } + } + + // Runs the PSS logic that needs to run on endblock. + // Concretely, this will forcefully opt in all validators that are in the top N + // for each chain. + pure def endBlockPSS(providerState: ProviderState): ProviderState = { + val runningConsumers = providerState.getRunningConsumers() + runningConsumers.fold( + providerState, + (acc, consumer) => endBlockPSS_helper(acc, consumer) + ) + } + + // Runs the PSS logic for a single consumer. + // Should only be run for running chains. + pure def endBlockPSS_helper(providerState: ProviderState, consumer: Chain): ProviderState = { + val proviValSet = providerState.chainState.currentValidatorSet + val topNVals = GetTopNVals(proviValSet, providerState.topNByConsumer.get(consumer)) + val prevOptedInVals = providerState.optedInVals.getOrElse(consumer, Set()) + // opt in all the top N validators, i.e. union the top N vals with the previous opted in vals + val newOptedInVals = providerState.optedInVals.put(consumer, prevOptedInVals.union(topNVals)) + { + ...providerState, + optedInVals: newOptedInVals + } + } +} \ No newline at end of file diff --git a/tests/mbt/model/ccv_pss_model.qnt b/tests/mbt/model/ccv_pss_model.qnt new file mode 100644 index 0000000000..76c4873b43 --- /dev/null +++ b/tests/mbt/model/ccv_pss_model.qnt @@ -0,0 +1,113 @@ +module ccv_pss_model { + import ccv_types.* from "./ccv" + import ccv_model.* from "./ccv_model" + import ccv_pss.* from "./ccv_pss" + import extraSpells.* from "./libraries/extraSpells" + + action StepOptIn(): bool = { + all { + runningConsumers.size() > 0, + nondet consumer = oneOf(runningConsumers) + nondet validator = oneOf(nodes) + OptIn_Deterministic(consumer, validator) + } + } + + action OptIn_Deterministic(consumer: Chain, validator: Node): bool = { + val res = OptIn(currentState, consumer, validator) + all { + currentState' = res.newState, + trace' = trace.append( + { + ...emptyAction, + kind: "OptIn", + consumerChain: consumer, + validator: validator, + expectedError: res.error + } + ), + params' = params, + } + } + + action StepOptOut(): bool = { + all { + runningConsumers.size() > 0, + nondet consumer = oneOf(runningConsumers) + nondet validator = oneOf(nodes) + OptOut_Deterministic(consumer, validator) + } + } + + action OptOut_Deterministic(consumer: Chain, validator: Node): bool = { + val res = OptOut(currentState, consumer, validator) + all { + currentState' = res.newState, + trace' = trace.append( + { + ...emptyAction, + kind: "OptOut", + consumerChain: consumer, + validator: validator, + expectedError: res.error + } + ), + params' = params, + } + } + + // Different sets of possible values for the topN parameter. + val allFullConsumers: Set[int] = Set(100) + val allOptIn: Set[int] = Set(0) + // only choose a few values for top N here to not make the "edge cases" of 0 and 100 too unlikely + val variousPossibleTopN: Set[int] = Set(0, 50, 70, 80, 90, 100) + + // INVARIANTS + + // For a consumer chain with a given top N value, + // the total VP on the consumer is at least N% of the total VP of some historical val set on the provider. + val AtLeastTopNPower: bool = + runningConsumers.forall(consumer => { + val topN = currentState.providerState.topNByConsumer.get(consumer) + val totalPowerConsu = currentState.consumerStates.get(consumer).chainState.currentValidatorSet.mapValuesSum() + currentState.providerState.chainState.votingPowerHistory.toSet().exists( + valSet => { + val totalPowerProvi = valSet.mapValuesSum() + + totalPowerConsu >= totalPowerProvi * topN / 100 + } + ) + }) + + // SANITY CHECKS + + val CanOptIn = { + not( + trace[length(trace)-1].kind == "OptIn" + and + trace[length(trace)-1].expectedError == "" + ) + } + + val CanOptOut = { + not( + trace[length(trace)-1].kind == "OptOut" + and + trace[length(trace)-1].expectedError == "" + ) + } + + val CanFailOptOut = { + not( + trace[length(trace)-1].kind == "OptOut" + and + trace[length(trace)-1].expectedError != "" + ) + } + + val CanHaveOptIn = { + currentState.providerState.topNByConsumer.keys().exists(consumer => { + currentState.providerState.topNByConsumer.get(consumer) != 100 + }) + } +} \ No newline at end of file diff --git a/tests/mbt/model/ccv_pss_test.qnt b/tests/mbt/model/ccv_pss_test.qnt new file mode 100644 index 0000000000..2a84f6dbd4 --- /dev/null +++ b/tests/mbt/model/ccv_pss_test.qnt @@ -0,0 +1,34 @@ +// This module contains logic for PSS (Partial Set Security). +// PSS is a variant/extension of CCV that +// allows for only a subset of the validator set +// to secure a consumer chain. +// Not all logic related to PSS is inside this module, as some logic is +// too tightly coupled with the core CCV logic, +// which is instead found in ccv.qnt +module ccv_pss_test { + import ccv_types.* from "./ccv" + import extraSpells.* from "./libraries/extraSpells" + import ccv_utils.* from "./ccv_utils" + import ccv_pss.* from "./ccv_pss" + + run TopNTest = + val valSet = + Map("d" -> 25, "c1" -> 15, "c" -> 15, "b2" -> 10, "b1" -> 10, "b" -> 10, "a2" -> 5, "a1" -> 5, "a" -> 5) + // total power: 5*3 + 10*3 + 15*2 + 25 = 100 + all + { + assert(GetTopNVals(valSet, 0) == Set()), + assert(GetTopNVals(valSet, 1) == Set("d")), + assert(GetTopNVals(valSet, 10) == Set("d")), + assert(GetTopNVals(valSet, 25) == Set("d")), + // if one validator with a power is included, all validators with that power need to be included + assert(GetTopNVals(valSet, 26) == Set("d", "c1", "c")), + assert(GetTopNVals(valSet, 45) == Set("d", "c1", "c")), + assert(GetTopNVals(valSet, 55) == Set("d", "c1", "c")), + assert(GetTopNVals(valSet, 56) == Set("d", "c1", "c", "b2", "b1", "b")), + assert(GetTopNVals(valSet, 85) == Set("d", "c1", "c", "b2", "b1", "b")), + assert(GetTopNVals(valSet, 86) == valSet.keys()), + assert(GetTopNVals(valSet, 95) == valSet.keys()), + assert(GetTopNVals(valSet, 100) == valSet.keys()), + } +} \ No newline at end of file diff --git a/tests/mbt/model/ccv_sync.qnt b/tests/mbt/model/ccv_sync.qnt index d828b88a76..8af76693b8 100644 --- a/tests/mbt/model/ccv_sync.qnt +++ b/tests/mbt/model/ccv_sync.qnt @@ -25,7 +25,7 @@ module ccv_sync { action initSync = all { init.then( - EndAndBeginBlockForProvider(1 * Second, consumerChains, Set()) + EndAndBeginBlockForProvider(1 * Second, consumerChains.map(c => ccvt::NewFullConsumer(c)), Set()) ), QueuedChainsToEndBlock' = consumerChainList.foldl( List(), diff --git a/tests/mbt/model/ccv_test.qnt b/tests/mbt/model/ccv_test.qnt index ab47df50b7..af49ecfa14 100644 --- a/tests/mbt/model/ccv_test.qnt +++ b/tests/mbt/model/ccv_test.qnt @@ -247,15 +247,15 @@ module ccv_test { "chain3" -> STOPPED ) val res = StartStopConsumers( - currentConsumerStatusMap, - Set("chain1"), + GetEmptyProviderState.with("consumerStatus", currentConsumerStatusMap), + Set(NewOptInConsumer("chain1")), Set("chain2"), Set() ) res._2 == "" and - res._1.get("chain1") == RUNNING and - res._1.get("chain2") == STOPPED and - res._1.get("chain3") == STOPPED + res._1.consumerStatus.get("chain1") == RUNNING and + res._1.consumerStatus.get("chain2") == STOPPED and + res._1.consumerStatus.get("chain3") == STOPPED } run ConsumerStatusMapAlreadyRunningTest = @@ -266,8 +266,8 @@ module ccv_test { "chain3" -> STOPPED ) val res = StartStopConsumers( - currentConsumerStatusMap, - Set("chain2"), + GetEmptyProviderState.with("consumerStatus", currentConsumerStatusMap), + Set(NewOptInConsumer("chain2")), Set("chain3"), Set() ) @@ -282,8 +282,8 @@ module ccv_test { "chain3" -> STOPPED ) val res = StartStopConsumers( - currentConsumerStatusMap, - Set("chain1"), + GetEmptyProviderState.with("consumerStatus", currentConsumerStatusMap), + Set(NewOptInConsumer("chain1")), Set("chain3"), Set() ) @@ -298,8 +298,8 @@ module ccv_test { "chain3" -> STOPPED ) val res = StartStopConsumers( - currentConsumerStatusMap, - Set("chain1"), + GetEmptyProviderState.with("consumerStatus", currentConsumerStatusMap), + Set(NewOptInConsumer("chain1")), Set("chain1"), Set() ) diff --git a/tests/mbt/model/ccv_utils.qnt b/tests/mbt/model/ccv_utils.qnt index 476ef923dc..4e4582fd06 100644 --- a/tests/mbt/model/ccv_utils.qnt +++ b/tests/mbt/model/ccv_utils.qnt @@ -141,26 +141,33 @@ module ccv_utils { } pure def StartStopConsumers( - currentConsumerStatusMap: Chain -> str, - consumersToStart: Set[Chain], + currentProviderState: ProviderState, + consumersToStart: Set[ConsumerAdditionMsg], consumersToStop: Set[Chain], consumersToTimeout: Set[Chain] - ): (Chain -> str, str) = { + ): (ProviderState, str) = { + val consumerAdditions = consumersToStart.map( + msg => msg.chain + ) // check if any consumer is both started and stopped - if (consumersToStart.intersect(consumersToStop).size() > 0) { - (currentConsumerStatusMap, "Cannot start and stop a consumer at the same time") + if (consumerAdditions.intersect(consumersToStop).size() > 0) { + (currentProviderState, "Cannot start and stop a consumer at the same time") } else { - val res1 = currentConsumerStatusMap.startConsumers(consumersToStart) + val res1 = currentProviderState.consumerStatus.startConsumers(consumerAdditions) val newConsumerStatus = res1._1 val err1 = res1._2 val res2 = newConsumerStatus.stopConsumers(consumersToStop, consumersToTimeout) val err2 = res2._2 + // set the top N values in the provider correctly + if (err1 != "") { - (currentConsumerStatusMap, err1) + (currentProviderState, err1) } else if (err2 != "") { - (currentConsumerStatusMap, err2) + (currentProviderState, err2) } else { - (res2._1, "") + (currentProviderState + .with("consumerStatus", res2._1) + .SetTopNValues(consumersToStart), "") } } } @@ -170,7 +177,7 @@ module ccv_utils { pure def enterCurValSetIntoBlock(chainState: ChainState): ChainState = { chainState.with( "votingPowerHistory", chainState.votingPowerHistory.prepend( - chainState.currentValidatorSet + removeZeroPowers(chainState.currentValidatorSet) ) ) } @@ -460,4 +467,28 @@ module ccv_utils { (false, "") } } + + // Sets the top N values on the provider chain for the given consumer chains, + // taken as consumerAdditionMsgs = chains with the top N values. + // If a chain in the set is already present, the old value will be overwritten. + pure def SetTopNValues(providerState: ProviderState, consumers: Set[ConsumerAdditionMsg]): ProviderState = + providerState.with( + "topNByConsumer", + consumers.fold( + providerState.topNByConsumer, + (acc, consumer) => acc.put(consumer.chain, consumer.topN) + ) + ) + + // From a validator set, removes all validators with zero power. + pure def removeZeroPowers(valSet: ValidatorSet): ValidatorSet = + valSet.keys().fold( + Map(), + (acc, node) => + if (valSet.get(node) == 0) { + acc + } else { + acc.put(node, valSet.get(node)) + } + ) } \ No newline at end of file diff --git a/tests/mbt/model/libraries/extraSpells.qnt b/tests/mbt/model/libraries/extraSpells.qnt index 9167bb4bcb..6ab4063ad3 100644 --- a/tests/mbt/model/libraries/extraSpells.qnt +++ b/tests/mbt/model/libraries/extraSpells.qnt @@ -139,6 +139,72 @@ module extraSpells { __set.fold(List(), (__l, __e) => __l.append(__e)) } + /// The type of orderings between comparable things + // Follows https://hackage.haskell.org/package/base-4.19.0.0/docs/Data-Ord.html#t:Ordering + // and we think there are likely benefits to using 3 constant values rather than the more + // common integer range in Apalache. + type Ordering = + | EQ + | LT + | GT + + /// Comparison of integers + pure def intCompare(__a: int, __b:int): Ordering = { + if (__a < __b) + { LT } + else if (__a > __b) + { GT } + else + { EQ } + } + + /// Assuming `__l` is sorted according to `__cmp`, returns a list with the element `__x` + /// inserted in order. + /// + /// If `__l` is not sorted, `__x` will be inserted after the first element less than + /// or equal to it. + /// + /// - @param __l a sorted list + /// - @param __x an element to be inserted + /// - @param __cmp an operator defining an `Ordering` of the elemnts of type `a` + /// - @returns a sorted list that includes `__x` + pure def sortedListInsert(__l: List[a], __x: a, __cmp: (a, a) => Ordering): List[a] = { + // We need to track whether __x has been inserted, and the accumulator for the new list + val __init = { is_inserted: false, acc: List() } + + val __result = __l.foldl(__init, (__state, __y) => + if (__state.is_inserted) + { ...__state, acc: __state.acc.append(__y) } + else + match __cmp(__x, __y) { + | GT => { ...__state, acc: __state.acc.append(__y) } + | _ => { is_inserted: true, acc: __state.acc.append(__x).append(__y) } + }) + + if (not(__result.is_inserted)) + // If __x was not inserted, it was GT than every other element, so it goes at the end + __result.acc.append(__x) + else + __result.acc + } + + run sortedListInsertTest = all { + assert(List().sortedListInsert(3, intCompare) == List(3)), + assert(List(1,2,4).sortedListInsert(3, intCompare) == List(1,2,3,4)), + assert(List(4,1,2).sortedListInsert(3, intCompare) == List(3,4,1,2)), + assert(List(1,2,3).sortedListInsert(4, intCompare) == List(1,2,3,4)), + } + + //// Returns a list of all elements of a set. + //// The ordering will be arbitrary. + //// + //// - @param __set a set + //// - @param __cmp an operator defining an `Ordering` of the elemnts of type `a` + //// - @returns a sorted list of all elements of __set + pure def toSortedList(__set: Set[a], __cmp: (a, a) => Ordering): List[a] = { + __set.fold(List(), (__l, __e) => __l.sortedListInsert(__e, __cmp)) + } + //// Returns a set of the elements in the list. //// //// - @param __list a list @@ -207,4 +273,59 @@ module extraSpells { assert(not(listForAll(List(1, 2, 3), __x => __x > 1))), assert(listForAll(List(), __x => __x > 0)), } + + /// Compute the sum of the values over all entries in a map. + /// + /// - @param myMap a map from keys to integers + /// - @returns the sum; when the map is empty, the sum is 0. + pure def mapValuesSum(myMap: a -> int): int = { + myMap.keys().fold(0, ((sum, i) => sum + myMap.get(i))) + } + + run mapValuesSumTest = all { + assert(Map().mapValuesSum() == 0), + assert(2.to(5).mapBy(i => i * 2).mapValuesSum() == 28), + assert(Map(2 -> -4, 4 -> 2).mapValuesSum() == -2), + } + + /// Returns a map of a subset of keys and values from a map, + // where only those keys are included for which the given __f + // returns true. + pure def mapFilter(__map: a -> b, __f: a => bool): a -> b = { + __map.keys().filter(e => __f(e)).mapBy(__k => __map.get(__k)) + } + + /// Compute the maximum of two integers. + /// + /// - @param __i first integer + /// - @param __j second integer + /// - @returns the maximum of __i and __j + pure def max(__i: int, __j: int): int = { + if (__i > __j) __i else __j + } + + run maxTest = all { + assert(max(3, 4) == 4), + assert(max(6, 3) == 6), + assert(max(10, 10) == 10), + assert(max(-3, -5) == -3), + assert(max(-5, -3) == -3), + } + + /// Compute the minimum of two integers. + /// + /// - @param __i first integer + /// - @param __j second integer + /// - @returns the minimum of __i and __j + pure def min(__i: int, __j: int): int = { + if (__i < __j) __i else __j + } + + run minTest = all { + assert(min(3, 4) == 3), + assert(min(6, 3) == 3), + assert(min(10, 10) == 10), + assert(min(-3, -5) == -5), + assert(min(-5, -3) == -5), + } } \ No newline at end of file diff --git a/tests/mbt/run_invariants.sh b/tests/mbt/model/run_invariants.sh similarity index 100% rename from tests/mbt/run_invariants.sh rename to tests/mbt/model/run_invariants.sh From 4bf5917686101703032c4bea4206073bf44af645 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Date: Thu, 8 Feb 2024 14:31:44 +0100 Subject: [PATCH 009/110] test: Ports key assignment to the driver on the PSS feature branch (#1628) * Port key assignment to MBT driver * Add comment and make var names clearer --- tests/mbt/driver/core.go | 4 ++-- tests/mbt/driver/mbt_test.go | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/mbt/driver/core.go b/tests/mbt/driver/core.go index 803cd486f1..345122fa6e 100644 --- a/tests/mbt/driver/core.go +++ b/tests/mbt/driver/core.go @@ -379,12 +379,12 @@ func (s *Driver) setTime(chain ChainId, newTime time.Time) { testChain.App.BeginBlock(abcitypes.RequestBeginBlock{Header: testChain.CurrentHeader}) } -func (s *Driver) AssignKey(chain ChainId, valIndex int64, value crypto.PublicKey) error { +func (s *Driver) AssignKey(chain ChainId, valIndex int64, key crypto.PublicKey) error { stakingVal, found := s.stakingValidator(valIndex) if !found { return fmt.Errorf("validator with id %v not found on provider", valIndex) } - return s.providerKeeper().AssignConsumerKey(s.providerCtx(), string(chain), stakingVal, value) + return s.providerKeeper().AssignConsumerKey(s.providerCtx(), string(chain), stakingVal, key) } // DeliverPacketToConsumer delivers a packet from the provider to the given consumer recipient. diff --git a/tests/mbt/driver/mbt_test.go b/tests/mbt/driver/mbt_test.go index df748ea11f..692cf6ee14 100644 --- a/tests/mbt/driver/mbt_test.go +++ b/tests/mbt/driver/mbt_test.go @@ -127,6 +127,10 @@ func RunItfTrace(t *testing.T, path string) { _, _, consumerPrivVals, err := integration.CreateValidators(len(consumerAddressesExpr)) require.NoError(t, err, "Error creating consumer signers") + // consumerAddrNames are the human readable names of consumer addresses in the model + // "realAddrs" are the addresses of the consumer keys on chain + // these maps relate the consumerAddrNames to the priv validators (from which one can get the real address) + // and from the real ddresses to the consumerAddrNames to allow converting between the two easily consumerAddrNamesToPrivVals := make(map[string]cmttypes.PrivValidator, len(consumerAddressesExpr)) realAddrsToModelConsAddrs := make(map[string]string, len(consumerAddressesExpr)) i := 0 From 7b0afcd13542de755d748999dd6440c2cf3212d6 Mon Sep 17 00:00:00 2001 From: insumity Date: Thu, 8 Feb 2024 15:57:10 +0100 Subject: [PATCH 010/110] feat!: automatically opt in validators that vote Yes on consumer addition proposals (#1629) * init commit * changed providerKeeper.GetProposedConsumerChain to return a bool * add logging mesages * one more log message * fix comment * added one more test case of NO vote and made tabular test --- testutil/keeper/mocks.go | 53 ++++++++++++---- x/ccv/provider/keeper/hooks.go | 56 ++++++++++++++++- x/ccv/provider/keeper/hooks_test.go | 92 +++++++++++++++++++++++++++- x/ccv/provider/keeper/keeper.go | 5 +- x/ccv/provider/keeper/keeper_test.go | 6 +- x/ccv/types/expected_keepers.go | 2 + 6 files changed, 194 insertions(+), 20 deletions(-) diff --git a/testutil/keeper/mocks.go b/testutil/keeper/mocks.go index 5f9d9b2694..b183e8b377 100644 --- a/testutil/keeper/mocks.go +++ b/testutil/keeper/mocks.go @@ -473,18 +473,6 @@ func (mr *MockSlashingKeeperMockRecorder) GetValidatorSigningInfo(ctx, address i return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetValidatorSigningInfo", reflect.TypeOf((*MockSlashingKeeper)(nil).GetValidatorSigningInfo), ctx, address) } -// SetValidatorSigningInfo mocks base method. -func (m *MockSlashingKeeper) SetValidatorSigningInfo(ctx types0.Context, address types0.ConsAddress, info types3.ValidatorSigningInfo) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetValidatorSigningInfo", ctx, address, info) -} - -// SetValidatorSigningInfo indicates an expected call of SetValidatorSigningInfo. -func (mr *MockSlashingKeeperMockRecorder) SetValidatorSigningInfo(ctx, address interface{}, info interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetValidatorSigningInfo", reflect.TypeOf((*MockSlashingKeeper)(nil).SetValidatorSigningInfo), ctx, address, info) -} - // IsTombstoned mocks base method. func (m *MockSlashingKeeper) IsTombstoned(arg0 types0.Context, arg1 types0.ConsAddress) bool { m.ctrl.T.Helper() @@ -511,6 +499,18 @@ func (mr *MockSlashingKeeperMockRecorder) JailUntil(arg0, arg1, arg2 interface{} return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "JailUntil", reflect.TypeOf((*MockSlashingKeeper)(nil).JailUntil), arg0, arg1, arg2) } +// SetValidatorSigningInfo mocks base method. +func (m *MockSlashingKeeper) SetValidatorSigningInfo(ctx types0.Context, address types0.ConsAddress, info types3.ValidatorSigningInfo) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetValidatorSigningInfo", ctx, address, info) +} + +// SetValidatorSigningInfo indicates an expected call of SetValidatorSigningInfo. +func (mr *MockSlashingKeeperMockRecorder) SetValidatorSigningInfo(ctx, address, info interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetValidatorSigningInfo", reflect.TypeOf((*MockSlashingKeeper)(nil).SetValidatorSigningInfo), ctx, address, info) +} + // SlashFractionDoubleSign mocks base method. func (m *MockSlashingKeeper) SlashFractionDoubleSign(ctx types0.Context) types0.Dec { m.ctrl.T.Helper() @@ -1217,3 +1217,32 @@ func (mr *MockGovKeeperMockRecorder) GetProposal(ctx, proposalID interface{}) *g mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetProposal", reflect.TypeOf((*MockGovKeeper)(nil).GetProposal), ctx, proposalID) } + +// GetProposals mocks base method. +func (m *MockGovKeeper) GetProposals(ctx types0.Context) v1.Proposals { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetProposals", ctx) + ret0, _ := ret[0].(v1.Proposals) + return ret0 +} + +// GetProposals indicates an expected call of GetProposals. +func (mr *MockGovKeeperMockRecorder) GetProposals(ctx interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetProposals", reflect.TypeOf((*MockGovKeeper)(nil).GetProposals), ctx) +} + +// GetVote mocks base method. +func (m *MockGovKeeper) GetVote(ctx types0.Context, proposalID uint64, voterAddr types0.AccAddress) (v1.Vote, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetVote", ctx, proposalID, voterAddr) + ret0, _ := ret[0].(v1.Vote) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// GetVote indicates an expected call of GetVote. +func (mr *MockGovKeeperMockRecorder) GetVote(ctx, proposalID, voterAddr interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetVote", reflect.TypeOf((*MockGovKeeper)(nil).GetVote), ctx, proposalID, voterAddr) +} diff --git a/x/ccv/provider/keeper/hooks.go b/x/ccv/provider/keeper/hooks.go index 88590a9875..fcf8339187 100644 --- a/x/ccv/provider/keeper/hooks.go +++ b/x/ccv/provider/keeper/hooks.go @@ -1,8 +1,8 @@ package keeper import ( + "cosmossdk.io/math" "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" sdkgov "github.com/cosmos/cosmos-sdk/x/gov/types" v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" @@ -175,7 +175,61 @@ func (h Hooks) AfterProposalVotingPeriodEnded(ctx sdk.Context, proposalID uint64 func (h Hooks) AfterProposalDeposit(ctx sdk.Context, proposalID uint64, depositorAddr sdk.AccAddress) { } +// AfterProposalVote opts in validators that vote YES (with 100% weight) on a `ConsumerAdditionProposal`. If a +// validator votes multiple times, only the last vote would be considered on whether the validator is opted in or not. func (h Hooks) AfterProposalVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress) { + validator, found := h.k.stakingKeeper.GetValidator(ctx, voterAddr.Bytes()) + if !found { + return + } + + consAddr, err := validator.GetConsAddr() + if err != nil { + h.k.Logger(ctx).Error("could not extract validator's consensus address", + "error", err.Error(), + "validator acc addr", voterAddr, + ) + return + } + + chainID, found := h.k.GetProposedConsumerChain(ctx, proposalID) + if !found { + return + } + + vote, found := h.k.govKeeper.GetVote(ctx, proposalID, voterAddr) + if !found { + h.k.Logger(ctx).Error("could not find vote for validator", + "validator acc addr", voterAddr, + "proposalID", proposalID, + ) + return + } + + if len(vote.Options) == 1 && vote.Options[0].Option == v1.VoteOption_VOTE_OPTION_YES { + // only consider votes that vote YES with 100% weight + weight, err := sdk.NewDecFromStr(vote.Options[0].Weight) + if err != nil { + h.k.Logger(ctx).Error("could not extract decimal value from vote's weight", + "vote", vote, + "error", err.Error(), + ) + return + } + if !weight.Equal(math.LegacyNewDec(1)) { + h.k.Logger(ctx).Error("single vote does not have a weight of 1", + "vote", vote, + ) + return + } + + // in the validator is already to-be-opted in, the `SetToBeOptedIn` is a no-op + h.k.SetToBeOptedIn(ctx, chainID, providertypes.NewProviderConsAddress(consAddr)) + } else { + // if vote is not a YES vote with 100% weight, we delete the validator from to-be-opted in + // if the validator is not to-be-opted in, the `DeleteToBeOptedIn` is a no-op + h.k.DeleteToBeOptedIn(ctx, chainID, providertypes.NewProviderConsAddress(consAddr)) + } } func (h Hooks) AfterProposalFailedMinDeposit(ctx sdk.Context, proposalID uint64) { diff --git a/x/ccv/provider/keeper/hooks_test.go b/x/ccv/provider/keeper/hooks_test.go index f4aad8d441..140bb8a4ce 100644 --- a/x/ccv/provider/keeper/hooks_test.go +++ b/x/ccv/provider/keeper/hooks_test.go @@ -1,6 +1,10 @@ package keeper_test import ( + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" "testing" "time" @@ -123,11 +127,13 @@ func TestAfterPropSubmissionAndVotingPeriodEnded(t *testing.T) { k.Hooks().AfterProposalSubmission(ctx, prop.Id) // verify that the proposal ID is created - require.NotEmpty(t, k.GetProposedConsumerChain(ctx, prop.Id)) + _, found := k.GetProposedConsumerChain(ctx, prop.Id) + require.True(t, found) k.Hooks().AfterProposalVotingPeriodEnded(ctx, prop.Id) // verify that the proposal ID is deleted - require.Empty(t, k.GetProposedConsumerChain(ctx, prop.Id)) + _, found = k.GetProposedConsumerChain(ctx, prop.Id) + require.False(t, found) } func TestGetConsumerAdditionLegacyPropFromProp(t *testing.T) { @@ -223,3 +229,85 @@ func TestGetConsumerAdditionLegacyPropFromProp(t *testing.T) { }) } } + +func TestAfterProposalVoteWithYesVote(t *testing.T) { + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + providerConsPubKey := ed25519.GenPrivKeyFromSecret([]byte{1}).PubKey() + pkAny, _ := codectypes.NewAnyWithValue(providerConsPubKey) + providerAddr := types.NewProviderConsAddress(providerConsPubKey.Address().Bytes()) + + options := []*v1.WeightedVoteOption{{Option: v1.OptionYes, Weight: "1"}} + k.SetProposedConsumerChain(ctx, "chainID", 1) + + gomock.InOrder( + mocks.MockStakingKeeper.EXPECT().GetValidator(ctx, gomock.Any()).Return( + stakingtypes.Validator{ConsensusPubkey: pkAny}, true), + mocks.MockGovKeeper.EXPECT().GetVote(ctx, gomock.Any(), gomock.Any()).Return( + v1.Vote{ProposalId: 1, Voter: "voter", Options: options}, true, + ), + ) + + require.False(t, k.IsToBeOptedIn(ctx, "chainID", providerAddr)) + k.Hooks().AfterProposalVote(ctx, 1, sdk.AccAddress{}) + require.True(t, k.IsToBeOptedIn(ctx, "chainID", providerAddr)) +} + +func TestAfterProposalVoteWithNoVote(t *testing.T) { + testCases := []struct { + name string + options []*v1.WeightedVoteOption + setup func(sdk.Context, []*v1.WeightedVoteOption, testkeeper.MockedKeepers, *codectypes.Any) + }{ + { + "Weighted vote with 100% NO", + []*v1.WeightedVoteOption{{Option: v1.OptionNo, Weight: "1"}}, + func(ctx sdk.Context, options []*v1.WeightedVoteOption, + mocks testkeeper.MockedKeepers, pubKey *codectypes.Any) { + gomock.InOrder( + mocks.MockStakingKeeper.EXPECT().GetValidator(ctx, gomock.Any()).Return( + stakingtypes.Validator{ConsensusPubkey: pubKey}, true), + mocks.MockGovKeeper.EXPECT().GetVote(ctx, gomock.Any(), gomock.Any()).Return( + v1.Vote{ProposalId: 1, Voter: "voter", Options: options}, true, + ), + ) + }, + }, + { + "Weighted vote with 99.9% YES and 0.1% NO", + []*v1.WeightedVoteOption{{Option: v1.OptionYes, Weight: "0.999"}, {Option: v1.OptionNo, Weight: "0.001"}}, + func(ctx sdk.Context, options []*v1.WeightedVoteOption, + mocks testkeeper.MockedKeepers, pubKey *codectypes.Any) { + gomock.InOrder( + mocks.MockStakingKeeper.EXPECT().GetValidator(ctx, gomock.Any()).Return( + stakingtypes.Validator{ConsensusPubkey: pubKey}, true), + mocks.MockGovKeeper.EXPECT().GetVote(ctx, gomock.Any(), gomock.Any()).Return( + v1.Vote{ProposalId: 1, Voter: "voter", Options: options}, true, + ), + ) + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + providerConsPubKey := ed25519.GenPrivKeyFromSecret([]byte{1}).PubKey() + pkAny, _ := codectypes.NewAnyWithValue(providerConsPubKey) + providerAddr := types.NewProviderConsAddress(providerConsPubKey.Address().Bytes()) + + k.SetProposedConsumerChain(ctx, "chainID", 1) + + tc.setup(ctx, tc.options, mocks, pkAny) + + // set the validator to-be-opted in first to assert that a NO vote removes the validator from to-be-opted in + k.SetToBeOptedIn(ctx, "chainID", providerAddr) + require.True(t, k.IsToBeOptedIn(ctx, "chainID", providerAddr)) + k.Hooks().AfterProposalVote(ctx, 1, sdk.AccAddress{}) + require.False(t, k.IsToBeOptedIn(ctx, "chainID", providerAddr)) + }) + } +} diff --git a/x/ccv/provider/keeper/keeper.go b/x/ccv/provider/keeper/keeper.go index ea052ec5fd..42bcb12ace 100644 --- a/x/ccv/provider/keeper/keeper.go +++ b/x/ccv/provider/keeper/keeper.go @@ -186,9 +186,10 @@ func (k Keeper) SetProposedConsumerChain(ctx sdk.Context, chainID string, propos } // GetProposedConsumerChain returns the proposed chainID for the given consumerAddition proposal ID. -func (k Keeper) GetProposedConsumerChain(ctx sdk.Context, proposalID uint64) string { +func (k Keeper) GetProposedConsumerChain(ctx sdk.Context, proposalID uint64) (string, bool) { store := ctx.KVStore(k.storeKey) - return string(store.Get(types.ProposedConsumerChainKey(proposalID))) + consumerChain := store.Get(types.ProposedConsumerChainKey(proposalID)) + return string(consumerChain), consumerChain != nil } // DeleteProposedConsumerChainInStore deletes the consumer chainID from store diff --git a/x/ccv/provider/keeper/keeper_test.go b/x/ccv/provider/keeper/keeper_test.go index 6eb28675ba..35380a67aa 100644 --- a/x/ccv/provider/keeper/keeper_test.go +++ b/x/ccv/provider/keeper/keeper_test.go @@ -552,7 +552,7 @@ func TestSetProposedConsumerChains(t *testing.T) { for _, test := range tests { providerKeeper.SetProposedConsumerChain(ctx, test.chainID, test.proposalID) - cID := providerKeeper.GetProposedConsumerChain(ctx, test.proposalID) + cID, _ := providerKeeper.GetProposedConsumerChain(ctx, test.proposalID) require.Equal(t, cID, test.chainID) } } @@ -574,9 +574,9 @@ func TestDeleteProposedConsumerChainInStore(t *testing.T) { for _, test := range tests { providerKeeper.SetProposedConsumerChain(ctx, test.chainID, test.proposalID) providerKeeper.DeleteProposedConsumerChainInStore(ctx, test.deleteProposalID) - cID := providerKeeper.GetProposedConsumerChain(ctx, test.proposalID) + cID, found := providerKeeper.GetProposedConsumerChain(ctx, test.proposalID) if test.ok { - require.Equal(t, cID, "") + require.False(t, found) } else { require.Equal(t, cID, test.chainID) } diff --git a/x/ccv/types/expected_keepers.go b/x/ccv/types/expected_keepers.go index a2ef7ab465..df531e09ca 100644 --- a/x/ccv/types/expected_keepers.go +++ b/x/ccv/types/expected_keepers.go @@ -151,4 +151,6 @@ type ScopedKeeper interface { type GovKeeper interface { GetProposal(ctx sdk.Context, proposalID uint64) (v1.Proposal, bool) + GetProposals(ctx sdk.Context) (proposals v1.Proposals) + GetVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress) (vote v1.Vote, found bool) } From 64f5651e5a00b1d3f2c615eddd3ca816dc3d7d38 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Date: Wed, 14 Feb 2024 12:43:27 +0100 Subject: [PATCH 011/110] test: Add driver for PSS (#1636) * Port key assignment to MBT driver * Add PSS trace generation * Add PSS trace gen to longer trace gen * Start handling top N parameter for new consumers * Finish merge * Add handling for optin/optout steps * Remove expected error from OptIn, which should not error * set top N parameter during path setup * Add comment to setup.go --- tests/mbt/driver/core.go | 28 ++++++++++++++++++ tests/mbt/driver/generate_more_traces.sh | 3 +- tests/mbt/driver/generate_traces.sh | 3 +- tests/mbt/driver/mbt_test.go | 37 +++++++++++++++++++++--- tests/mbt/driver/setup.go | 12 ++++++-- tests/mbt/model/ccv_pss_model.qnt | 3 +- 6 files changed, 76 insertions(+), 10 deletions(-) diff --git a/tests/mbt/driver/core.go b/tests/mbt/driver/core.go index 345122fa6e..0e074c6580 100644 --- a/tests/mbt/driver/core.go +++ b/tests/mbt/driver/core.go @@ -387,6 +387,34 @@ func (s *Driver) AssignKey(chain ChainId, valIndex int64, key crypto.PublicKey) return s.providerKeeper().AssignConsumerKey(s.providerCtx(), string(chain), stakingVal, key) } +// Opts the given validator into the given consumer chain on the provider. +func (s *Driver) OptIn(chain ChainId, valIndex int64) error { + stakingVal, found := s.stakingValidator(valIndex) + if !found { + return fmt.Errorf("validator with id %v not found on provider", valIndex) + } + consPubKey, err := stakingVal.ConsPubKey() + if err != nil { + return err + } + consAddr := sdk.GetConsAddress(consPubKey) + return s.providerKeeper().HandleOptIn(s.providerCtx(), string(chain), providertypes.NewProviderConsAddress(consAddr), nil) +} + +// Opts the given validator out of the given consumer chain on the provider. +func (s *Driver) OptOut(chain ChainId, valIndex int64) error { + stakingVal, found := s.stakingValidator(valIndex) + if !found { + return fmt.Errorf("validator with id %v not found on provider", valIndex) + } + consPubKey, err := stakingVal.ConsPubKey() + if err != nil { + return err + } + consAddr := sdk.GetConsAddress(consPubKey) + return s.providerKeeper().HandleOptOut(s.providerCtx(), string(chain), providertypes.NewProviderConsAddress(consAddr)) +} + // DeliverPacketToConsumer delivers a packet from the provider to the given consumer recipient. // It updates the client before delivering the packet. // Since the channel is ordered, the packet that is delivered is the first packet in the outbox. diff --git a/tests/mbt/driver/generate_more_traces.sh b/tests/mbt/driver/generate_more_traces.sh index 40589bb83b..905507a108 100755 --- a/tests/mbt/driver/generate_more_traces.sh +++ b/tests/mbt/driver/generate_more_traces.sh @@ -10,4 +10,5 @@ echo "Generating synced traces with maturations" go run ./... -modelPath=../model/ccv_sync.qnt -init initSync -step stepSync -invariant CanReceiveMaturations -traceFolder traces/sync_mat -numTraces 20 -numSteps 300 -numSamples 20 echo "Generating long synced traces without invariants" go run ./... -modelPath=../model/ccv_sync.qnt -init initSync -step stepSync -traceFolder traces/sync_noinv -numTraces 20 -numSteps 500 -numSamples 1 -go run ./... -modelPath=../model/ccv_boundeddrift.qnt --step stepBoundedDriftKeyAssignment --traceFolder traces/bound_key -numTraces 20 -numSteps 100 -numSamples 20 \ No newline at end of file +go run ./... -modelPath=../model/ccv_boundeddrift.qnt --step stepBoundedDriftKeyAssignment --traceFolder traces/bound_key -numTraces 20 -numSteps 100 -numSamples 20 +go run ./... -modelPath=../model/ccv_boundeddrift.qnt --step stepBoundedDriftKeyAndPSS --traceFolder traces/bound_pss -numTraces 20 -numSteps 100 -numSamples 20 diff --git a/tests/mbt/driver/generate_traces.sh b/tests/mbt/driver/generate_traces.sh index 9f1134fb26..f898b27e2e 100755 --- a/tests/mbt/driver/generate_traces.sh +++ b/tests/mbt/driver/generate_traces.sh @@ -10,4 +10,5 @@ echo "Generating synced traces with maturations" go run ./... -modelPath=../model/ccv_sync.qnt -init initSync -step stepSync -invariant CanReceiveMaturations -traceFolder traces/sync_mat -numTraces 1 -numSteps 300 -numSamples 20 echo "Generating long synced traces without invariants" go run ./... -modelPath=../model/ccv_sync.qnt -init initSync -step stepSync -traceFolder traces/sync_noinv -numTraces 1 -numSteps 500 -numSamples 1 -go run ./... -modelPath=../model/ccv_boundeddrift.qnt --step stepBoundedDriftKeyAssignment --traceFolder traces/bound_key -numTraces 1 -numSteps 100 -numSamples 20 \ No newline at end of file +go run ./... -modelPath=../model/ccv_boundeddrift.qnt --step stepBoundedDriftKeyAssignment --traceFolder traces/bound_key -numTraces 1 -numSteps 100 -numSamples 20 +go run ./... -modelPath=../model/ccv_boundeddrift.qnt --step stepBoundedDriftKeyAndPSS --traceFolder traces/bound_pss -numTraces 1 -numSteps 100 -numSamples 20 diff --git a/tests/mbt/driver/mbt_test.go b/tests/mbt/driver/mbt_test.go index 692cf6ee14..c31ec28359 100644 --- a/tests/mbt/driver/mbt_test.go +++ b/tests/mbt/driver/mbt_test.go @@ -314,14 +314,17 @@ func RunItfTrace(t *testing.T, path string) { driver.coordinator.CurrentTime = driver.runningTime("provider") // start consumers for _, consumer := range consumersToStart { + chainId := consumer.Value.(itf.MapExprType)["chain"].Value.(string) + topN := consumer.Value.(itf.MapExprType)["topN"].Value.(int64) driver.setupConsumer( - consumer.Value.(string), + chainId, modelParams, driver.providerChain().Vals, consumerSigners, nodes, valNames, driver.providerChain(), + topN, ) } @@ -340,7 +343,8 @@ func RunItfTrace(t *testing.T, path string) { // unless it was the last consumer to be started, in which case it already has the header // as we called driver.setupConsumer for _, consumer := range driver.runningConsumers() { - if len(consumersToStart) > 0 && consumer.ChainId == consumersToStart[len(consumersToStart)-1].Value.(string) { + if len(consumersToStart) > 0 && + consumer.ChainId == consumersToStart[len(consumersToStart)-1].Value.(itf.MapExprType)["chain"].Value.(string) { continue } @@ -415,8 +419,33 @@ func RunItfTrace(t *testing.T, path string) { protoPubKey, err := tmencoding.PubKeyToProto(assignedKey) require.NoError(t, err, "Error converting pubkey to proto") - error := driver.AssignKey(ChainId(consumerChain), int64(valIndex), protoPubKey) - require.NoError(t, error, "Error assigning key") + err = driver.AssignKey(ChainId(consumerChain), int64(valIndex), protoPubKey) + require.NoError(t, err, "Error assigning key") + case "OptIn": + consumerChain := lastAction["consumerChain"].Value.(string) + validator := lastAction["validator"].Value.(string) + t.Log("OptIn", consumerChain, validator) + + valIndex := getIndexOfString(validator, valNames) + + err := driver.OptIn(ChainId(consumerChain), int64(valIndex)) + require.NoError(t, err, "Error opting in") + + case "OptOut": + consumerChain := lastAction["consumerChain"].Value.(string) + validator := lastAction["validator"].Value.(string) + expectedError := lastAction["expectedError"].Value.(string) + t.Log("OptOut", consumerChain, validator, expectedError) + + valIndex := getIndexOfString(validator, valNames) + + err := driver.OptOut(ChainId(consumerChain), int64(valIndex)) + + if expectedError != "" { + require.Error(t, err, "Expected an error: %v", expectedError) + } else { + require.NoError(t, err, "Error opting out, but expected no error") + } default: log.Fatalf("Error loading trace file %s, step %v: do not know action type %s", diff --git a/tests/mbt/driver/setup.go b/tests/mbt/driver/setup.go index c0020a4095..6408f0e873 100644 --- a/tests/mbt/driver/setup.go +++ b/tests/mbt/driver/setup.go @@ -310,7 +310,7 @@ func newChain( // Creates a path for cross-chain validation from the consumer to the provider and configures the channel config of the endpoints // as well as the clients. // this function stops when there is an initialized, ready-to-relay channel between the provider and consumer. -func (s *Driver) ConfigureNewPath(consumerChain, providerChain *ibctesting.TestChain, params ModelParams) *ibctesting.Path { +func (s *Driver) ConfigureNewPath(consumerChain, providerChain *ibctesting.TestChain, params ModelParams, topN uint32) *ibctesting.Path { consumerChainId := ChainId(consumerChain.ChainID) path := ibctesting.NewPath(consumerChain, providerChain) @@ -382,6 +382,11 @@ func (s *Driver) ConfigureNewPath(consumerChain, providerChain *ibctesting.TestC consumerGenesisForProvider) require.NoError(s.t, err, "Error setting consumer genesis on provider for chain %v", consumerChain.ChainID) + // set the top N percentage + // needs to be done before the provider queues the first vsc packet to the consumer + // TODO: might be able to move this into setupConsumer, need to test once more logic is here + s.providerKeeper().SetTopN(providerChain.GetContext(), consumerChain.ChainID, topN) + // Client ID is set in InitGenesis and we treat it as a black box. So // must query it to use it with the endpoint. clientID, _ := s.consumerKeeper(consumerChainId).GetProviderClientID(s.ctx(consumerChainId)) @@ -437,9 +442,12 @@ func (s *Driver) setupConsumer( nodes []*cmttypes.Validator, // the list of nodes, even ones that have no voting power initially valNames []string, providerChain *ibctesting.TestChain, + topN int64, ) { s.t.Logf("Starting consumer %v", chain) + // TODO: reuse the partial set computation logic to compute the initial validator set + // for top N chains initValUpdates := cmttypes.TM2PB.ValidatorUpdates(valSet) // start consumer chains @@ -447,7 +455,7 @@ func (s *Driver) setupConsumer( consumerChain := newChain(s.t, params, s.coordinator, icstestingutils.ConsumerAppIniter(initValUpdates), chain, valSet, signers, nodes, valNames) s.coordinator.Chains[chain] = consumerChain - path := s.ConfigureNewPath(consumerChain, providerChain, params) + path := s.ConfigureNewPath(consumerChain, providerChain, params, uint32(topN)) s.simibcs[ChainId(chain)] = simibc.MakeRelayedPath(s.t, path) } diff --git a/tests/mbt/model/ccv_pss_model.qnt b/tests/mbt/model/ccv_pss_model.qnt index 76c4873b43..d2911a0989 100644 --- a/tests/mbt/model/ccv_pss_model.qnt +++ b/tests/mbt/model/ccv_pss_model.qnt @@ -22,8 +22,7 @@ module ccv_pss_model { ...emptyAction, kind: "OptIn", consumerChain: consumer, - validator: validator, - expectedError: res.error + validator: validator } ), params' = params, From ab7236db1f999ca4a2e18bfab7de4c8f396aae36 Mon Sep 17 00:00:00 2001 From: Simon Noetzlin Date: Wed, 21 Feb 2024 17:16:15 +0100 Subject: [PATCH 012/110] feat!: add PSS reward distribution spike (#1632) * PSS reward distribution * "add optin mapping to test" * Update app/provider/app.go Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * docs * add TODO * fix Dos vector in IBCMiddlewarea * add reformat * fix DOS issue and make integration tests pass * doc * add integration test * doc * Compute total vp per consumer * add comments * remove opt-in comments and add TODOs * format * Update x/ccv/provider/keeper/distribution.go Co-authored-by: insumity * add UT + doc * Update tests/integration/distribution.go Co-authored-by: insumity * Update tests/integration/distribution.go Co-authored-by: insumity * nits * Update x/ccv/provider/ibc_middleware.go Co-authored-by: Marius Poke * add panics in IBC Middleware ICS4wrapper funcs * address comments --------- Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Co-authored-by: insumity Co-authored-by: Marius Poke --- app/provider/app.go | 14 +- .../ccv/provider/v1/provider.proto | 14 +- tests/integration/distribution.go | 506 +++++++++++++++++- testutil/integration/debug_test.go | 16 + testutil/keeper/mocks.go | 261 +++++++-- x/ccv/provider/ibc_middleware.go | 240 +++++++++ x/ccv/provider/ibc_middleware_test.go | 76 +++ x/ccv/provider/keeper/distribution.go | 239 ++++++++- x/ccv/provider/keeper/distribution_test.go | 238 ++++++++ x/ccv/provider/module.go | 4 +- x/ccv/provider/types/consumer.go | 8 + x/ccv/provider/types/keys.go | 9 + x/ccv/provider/types/keys_test.go | 1 + x/ccv/provider/types/provider.pb.go | 415 ++++++++++---- x/ccv/types/expected_keepers.go | 5 + 15 files changed, 1851 insertions(+), 195 deletions(-) create mode 100644 x/ccv/provider/ibc_middleware.go create mode 100644 x/ccv/provider/ibc_middleware_test.go create mode 100644 x/ccv/provider/keeper/distribution_test.go diff --git a/app/provider/app.go b/app/provider/app.go index 7527756d45..9cf45fe7e3 100644 --- a/app/provider/app.go +++ b/app/provider/app.go @@ -102,6 +102,7 @@ import ( appencoding "github.com/cosmos/interchain-security/v4/app/encoding" testutil "github.com/cosmos/interchain-security/v4/testutil/integration" + "github.com/cosmos/interchain-security/v4/x/ccv/provider" ibcprovider "github.com/cosmos/interchain-security/v4/x/ccv/provider" ibcproviderclient "github.com/cosmos/interchain-security/v4/x/ccv/provider/client" ibcproviderkeeper "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" @@ -470,12 +471,15 @@ func New( app.BankKeeper, scopedTransferKeeper, ) - transferModule := transfer.NewAppModule(app.TransferKeeper) - ibcmodule := transfer.NewIBCModule(app.TransferKeeper) + + // Add an IBC middleware callback to track the consumer rewards + var transferStack porttypes.IBCModule + transferStack = transfer.NewIBCModule(app.TransferKeeper) + transferStack = provider.NewIBCMiddleware(transferStack, app.ProviderKeeper) // create static IBC router, add transfer route, then set and seal it ibcRouter := porttypes.NewRouter() - ibcRouter.AddRoute(ibctransfertypes.ModuleName, ibcmodule) + ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) ibcRouter.AddRoute(providertypes.ModuleName, providerModule) app.IBCKeeper.SetRouter(ibcRouter) @@ -514,7 +518,7 @@ func New( evidence.NewAppModule(app.EvidenceKeeper), ibc.NewAppModule(app.IBCKeeper), params.NewAppModule(app.ParamsKeeper), - transferModule, + transfer.NewAppModule(app.TransferKeeper), providerModule, ) @@ -610,7 +614,7 @@ func New( params.NewAppModule(app.ParamsKeeper), evidence.NewAppModule(app.EvidenceKeeper), ibc.NewAppModule(app.IBCKeeper), - transferModule, + transfer.NewAppModule(app.TransferKeeper), ) app.sm.RegisterStoreDecoders() diff --git a/proto/interchain_security/ccv/provider/v1/provider.proto b/proto/interchain_security/ccv/provider/v1/provider.proto index 9d815a1768..1b5f7a515f 100644 --- a/proto/interchain_security/ccv/provider/v1/provider.proto +++ b/proto/interchain_security/ccv/provider/v1/provider.proto @@ -13,6 +13,8 @@ import "ibc/lightclients/tendermint/v1/tendermint.proto"; import "tendermint/crypto/keys.proto"; import "cosmos/evidence/v1beta1/evidence.proto"; import "cosmos/base/v1beta1/coin.proto"; +import "amino/amino.proto"; + // // Note any type defined in this file is ONLY used internally to the provider CCV module. @@ -313,4 +315,14 @@ message ConsumerValidator { int64 power = 2; // public key the validator uses on the consumer chain during this epoch tendermint.crypto.PublicKey consumer_public_key = 3; -} \ No newline at end of file +} +// ConsumerRewardsAllocation stores the rewards allocated by a consumer chain +// 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.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins" + ]; +} diff --git a/tests/integration/distribution.go b/tests/integration/distribution.go index 1ea5bfcd00..d6dd6196ec 100644 --- a/tests/integration/distribution.go +++ b/tests/integration/distribution.go @@ -3,14 +3,22 @@ package integration import ( "strings" + "cosmossdk.io/math" + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/libs/bytes" + "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" icstestingutils "github.com/cosmos/interchain-security/v4/testutil/integration" consumerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/consumer/keeper" consumertypes "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" + providerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" ) @@ -93,25 +101,41 @@ func (s *CCVTestSuite) TestRewardsDistribution() { s.Require().Greater(ibcCoinIndex, -1) // Check that the coins got into the ConsumerRewardsPool - s.Require().True(rewardCoins[ibcCoinIndex].Amount.Equal(providerExpectedRewards[0].Amount)) + s.Require().Equal(rewardCoins[ibcCoinIndex].Amount, (providerExpectedRewards[0].Amount)) // Advance a block and check that the coins are still in the ConsumerRewardsPool s.providerChain.NextBlock() rewardCoins = providerBankKeeper.GetAllBalances(s.providerCtx(), rewardPool) - s.Require().True(rewardCoins[ibcCoinIndex].Amount.Equal(providerExpectedRewards[0].Amount)) + s.Require().Equal(rewardCoins[ibcCoinIndex].Amount, (providerExpectedRewards[0].Amount)) // Set the consumer reward denom. This would be done by a governance proposal in prod s.providerApp.GetProviderKeeper().SetConsumerRewardDenom(s.providerCtx(), rewardCoins[ibcCoinIndex].Denom) - s.providerChain.NextBlock() + // Refill the consumer fee pool + err = consumerBankKeeper.SendCoinsFromAccountToModule(s.consumerCtx(), s.consumerChain.SenderAccount.GetAddress(), authtypes.FeeCollectorName, fees) + s.Require().NoError(err) + + // pass two blocks + s.consumerChain.NextBlock() + s.consumerChain.NextBlock() + + // transfer rewards from consumer to provider + relayAllCommittedPackets(s, s.consumerChain, s.transferPath, transfertypes.PortID, s.transferPath.EndpointA.ChannelID, 1) + + // check that the consumer rewards allocation are empty since relayAllCommittedPackets call BeginBlock + rewardsAlloc := s.providerApp.GetProviderKeeper().GetConsumerRewardsAllocation(s.providerCtx(), s.consumerChain.ChainID) + s.Require().Empty(rewardsAlloc.Rewards) - // Check that the reward pool has no more coins because they were transferred to the fee pool + // Check that the reward pool still has the first coins transferred that were never allocated rewardCoins = providerBankKeeper.GetAllBalances(s.providerCtx(), rewardPool) - s.Require().Equal(0, len(rewardCoins)) + s.Require().Equal(rewardCoins[ibcCoinIndex].Amount, (providerExpectedRewards[0].Amount)) // check that the fee pool has the expected amount of coins + // Note that all rewards are allocated to the community pool since + // BeginBlock is called without the validators' votes in ibctesting. + // See NextBlock() in https://github.com/cosmos/ibc-go/blob/release/v7.3.x/testing/chain.go#L281 communityCoins := s.providerApp.GetTestDistributionKeeper().GetFeePoolCommunityCoins(s.providerCtx()) - s.Require().True(communityCoins[ibcCoinIndex].Amount.Equal(sdk.NewDecCoinFromCoin(providerExpectedRewards[0]).Amount)) + s.Require().Equal(communityCoins[ibcCoinIndex].Amount, (sdk.NewDecCoinFromCoin(providerExpectedRewards[0]).Amount)) } // TestSendRewardsRetries tests that failed reward transmissions are retried every BlocksPerDistributionTransmission blocks @@ -454,6 +478,397 @@ func (s *CCVTestSuite) TestSendRewardsToProvider() { } } +// TestIBCTransferMiddleware tests the logic of the IBC transfer OnRecvPacket callback +func (s *CCVTestSuite) TestIBCTransferMiddleware() { + + var ( + data ibctransfertypes.FungibleTokenPacketData + packet channeltypes.Packet + getIBCDenom func(string, string) string + ) + + testCases := []struct { + name string + setup func(sdk.Context, *providerkeeper.Keeper, icstestingutils.TestBankKeeper) + rewardsAllocated bool + expErr bool + }{ + { + "invalid IBC packet", + func(sdk.Context, *providerkeeper.Keeper, icstestingutils.TestBankKeeper) { + packet = channeltypes.Packet{} + }, + false, + true, + }, + { + "IBC packet sender isn't a consumer chain", + func(ctx sdk.Context, keeper *providerkeeper.Keeper, bankKeeper icstestingutils.TestBankKeeper) { + // make the sender consumer chain impossible to identify + packet.DestinationChannel = "CorruptedChannelId" + }, + false, + false, + }, + { + "IBC Transfer recipient is not the consumer rewards pool address", + func(ctx sdk.Context, keeper *providerkeeper.Keeper, bankKeeper icstestingutils.TestBankKeeper) { + data.Receiver = "cosmos149lw9fktlqfed3zt8ah48r5czmsug5s7kw77u9" // random acct address + packet.Data = data.GetBytes() + }, + false, + false, + }, + { + "IBC Transfer coin denom isn't registered", + func(ctx sdk.Context, keeper *providerkeeper.Keeper, bankKeeper icstestingutils.TestBankKeeper) {}, + false, + false, + }, + { + "successful token transfer to empty pool", + func(ctx sdk.Context, keeper *providerkeeper.Keeper, bankKeeper icstestingutils.TestBankKeeper) { + keeper.SetConsumerRewardDenom( + s.providerCtx(), + getIBCDenom(packet.DestinationPort, packet.DestinationChannel), + ) + }, + true, + false, + }, + { + "successful token transfer to filled pool", + func(ctx sdk.Context, keeper *providerkeeper.Keeper, bankKeeper icstestingutils.TestBankKeeper) { + keeper.SetConsumerRewardDenom( + ctx, + getIBCDenom(packet.DestinationPort, packet.DestinationChannel), + ) + + // fill consumer reward pool + bankKeeper.SendCoinsFromAccountToModule( + ctx, + s.providerChain.SenderAccount.GetAddress(), + providertypes.ConsumerRewardsPool, + sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(100_000))), + ) + // update consumer allocation + keeper.SetConsumerRewardsAllocation( + ctx, + s.consumerChain.ChainID, + providertypes.ConsumerRewardsAllocation{ + Rewards: sdk.NewDecCoins(sdk.NewDecCoin(sdk.DefaultBondDenom, math.NewInt(100_000))), + }, + ) + }, + true, + false, + }, + } + + for _, tc := range testCases { + s.Run(tc.name, func() { + s.SetupTest() + s.SetupCCVChannel(s.path) + s.SetupTransferChannel() + + providerKeeper := s.providerApp.GetProviderKeeper() + bankKeeper := s.providerApp.GetTestBankKeeper() + amount := sdk.NewInt(100) + + data = types.NewFungibleTokenPacketData( // can be explicitly changed in setup + sdk.DefaultBondDenom, + amount.String(), + authtypes.NewModuleAddress(consumertypes.ConsumerToSendToProviderName).String(), + providerKeeper.GetConsumerRewardsPoolAddressStr(s.providerCtx()), + "", + ) + + packet = channeltypes.NewPacket( // can be explicitly changed in setup + data.GetBytes(), + uint64(1), + s.transferPath.EndpointA.ChannelConfig.PortID, + s.transferPath.EndpointA.ChannelID, + s.transferPath.EndpointB.ChannelConfig.PortID, + s.transferPath.EndpointB.ChannelID, + clienttypes.NewHeight(1, 100), + 0, + ) + + providerKeeper.SetConsumerRewardDenom(s.providerCtx(), + transfertypes.GetPrefixedDenom( + packet.DestinationPort, + packet.DestinationChannel, + sdk.DefaultBondDenom, + ), + ) + + getIBCDenom = func(dstPort, dstChannel string) string { + return transfertypes.ParseDenomTrace( + transfertypes.GetPrefixedDenom( + packet.DestinationPort, + packet.DestinationChannel, + sdk.DefaultBondDenom, + ), + ).IBCDenom() + } + + tc.setup(s.providerCtx(), &providerKeeper, bankKeeper) + + cbs, ok := s.providerChain.App.GetIBCKeeper().Router.GetRoute(ibctransfertypes.ModuleName) + s.Require().True(ok) + + // save the IBC transfer rewards transferred + rewardsPoolBalance := bankKeeper.GetAllBalances(s.providerCtx(), sdk.MustAccAddressFromBech32(data.Receiver)) + + // save the consumer's rewards allocated + consumerRewardsAllocations := providerKeeper.GetConsumerRewardsAllocation(s.providerCtx(), s.consumerChain.ChainID) + + // execute middleware OnRecvPacket logic + ack := cbs.OnRecvPacket(s.providerCtx(), packet, sdk.AccAddress{}) + + // compute expected rewards with provider denom + expRewards := sdk.Coin{ + Amount: amount, + Denom: getIBCDenom(packet.DestinationPort, packet.DestinationChannel), + } + + // compute the balance and allocation difference + rewardsTransferred := bankKeeper.GetAllBalances(s.providerCtx(), sdk.MustAccAddressFromBech32(data.Receiver)). + Sub(rewardsPoolBalance...) + rewardsAllocated := providerKeeper.GetConsumerRewardsAllocation(s.providerCtx(), s.consumerChain.ChainID). + Rewards.Sub(consumerRewardsAllocations.Rewards) + + if !tc.expErr { + s.Require().True(ack.Success()) + // verify that the consumer rewards pool received the IBC coins + s.Require().Equal(rewardsTransferred, sdk.Coins{expRewards}) + + if tc.rewardsAllocated { + // check the data receiver address is set to the consumer rewards pool address + s.Require().Equal(data.GetReceiver(), providerKeeper.GetConsumerRewardsPoolAddressStr(s.providerCtx())) + + // verify that consumer rewards allocation is updated + s.Require().Equal(rewardsAllocated, sdk.NewDecCoinsFromCoins(expRewards)) + } else { + // verify that consumer rewards aren't allocated + s.Require().Empty(rewardsAllocated) + } + } else { + s.Require().False(ack.Success()) + } + }) + } +} + +// TestAllocateTokens is a happy-path test of the consumer rewards pool allocation +// to opted-in validators and the community pool +func (s *CCVTestSuite) TestAllocateTokens() { + // set up channel and delegate some tokens in order for validator set update to be sent to the consumer chain + s.SetupAllCCVChannels() + providerKeeper := s.providerApp.GetProviderKeeper() + bankKeeper := s.providerApp.GetTestBankKeeper() + distributionKeeper := s.providerApp.GetTestDistributionKeeper() + + totalRewards := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))} + + // fund consumer rewards pool + bankKeeper.SendCoinsFromAccountToModule( + s.providerCtx(), + s.providerChain.SenderAccount.GetAddress(), + providertypes.ConsumerRewardsPool, + totalRewards, + ) + + // Allocate rewards evenly between consumers + rewardsPerConsumer := totalRewards.QuoInt(math.NewInt(int64(len(s.consumerBundles)))) + for chainID := range s.consumerBundles { + // update consumer allocation + providerKeeper.SetConsumerRewardsAllocation( + s.providerCtx(), + chainID, + providertypes.ConsumerRewardsAllocation{ + Rewards: sdk.NewDecCoinsFromCoins(rewardsPerConsumer...), + }, + ) + } + + // Iterate over the validators and + // store their current voting power and outstanding rewards + lastValOutRewards := map[string]sdk.DecCoins{} + votes := []abci.VoteInfo{} + for _, val := range s.providerChain.Vals.Validators { + votes = append(votes, + abci.VoteInfo{ + Validator: abci.Validator{Address: val.Address, Power: val.VotingPower}, + SignedLastBlock: true, + }, + ) + + valRewards := distributionKeeper.GetValidatorOutstandingRewards(s.providerCtx(), sdk.ValAddress(val.Address)) + lastValOutRewards[sdk.ValAddress(val.Address).String()] = valRewards.Rewards + } + + // store community pool balance + lastCommPool := distributionKeeper.GetFeePoolCommunityCoins(s.providerCtx()) + + // execute BeginBlock to trigger the token allocation + providerKeeper.BeginBlockRD( + s.providerCtx(), + abci.RequestBeginBlock{ + LastCommitInfo: abci.CommitInfo{ + Votes: votes, + }, + }, + ) + + valNum := len(s.providerChain.Vals.Validators) + consuNum := len(s.consumerBundles) + + // compute the expected validators token allocation by subtracting the community tax + rewardsPerConsumerDec := sdk.NewDecCoinsFromCoins(rewardsPerConsumer...) + communityTax := distributionKeeper.GetCommunityTax(s.providerCtx()) + validatorsExpRewards := rewardsPerConsumerDec. + MulDecTruncate(math.LegacyOneDec().Sub(communityTax)). + // multiply by the number of consumers since all the validators opted in + MulDec(sdk.NewDec(int64(consuNum))) + perValExpReward := validatorsExpRewards.QuoDec(sdk.NewDec(int64(valNum))) + + // verify the validator tokens allocation + // note all validators have the same voting power to keep things simple + for _, val := range s.providerChain.Vals.Validators { + valReward := distributionKeeper.GetValidatorOutstandingRewards(s.providerCtx(), sdk.ValAddress(val.Address)) + s.Require().Equal( + valReward.Rewards, + lastValOutRewards[sdk.ValAddress(val.Address).String()].Add(perValExpReward...), + ) + } + + commPoolExpRewards := sdk.NewDecCoinsFromCoins(totalRewards...).Sub(validatorsExpRewards) + currCommPool := distributionKeeper.GetFeePoolCommunityCoins(s.providerCtx()) + + s.Require().Equal(currCommPool, (lastCommPool.Add(commPoolExpRewards...))) +} + +// TestAllocateTokens is a unit-test for TransferConsumerRewardsToDistributionModule() +// but is written as an integration test to avoid excessive mocking. +func (s *CCVTestSuite) TransferConsumerRewardsToDistributionModule() { + testCases := []struct { + name string + rewardsPool sdk.Coins + rewardsAlloc sdk.DecCoins + expErr bool + }{ + { + "empty consumer rewards pool", + sdk.Coins{}, + sdk.DecCoins{}, + false, + }, + { + "empty consumer allocation", + sdk.Coins{ + sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), + }, + sdk.DecCoins{}, + false, + }, + { + "equal consumer rewards pool and allocation", + sdk.Coins{ + sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), + }, + sdk.DecCoins{ + sdk.NewDecCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), + }, + false, + }, + { + "less consumer rewards than allocation", + sdk.Coins{ + sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(90)), + }, + sdk.DecCoins{ + sdk.NewDecCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), + }, + true, + }, + { + "remaining consumer rewards allocation", + sdk.Coins{ + sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), + }, + sdk.DecCoins{ + sdk.DecCoin{ + Denom: sdk.DefaultBondDenom, + Amount: sdk.NewDecWithPrec(995, 1), + }, + }, + false, + }, + } + + providerKeeper := s.providerApp.GetProviderKeeper() + bankKeeper := s.providerApp.GetTestBankKeeper() + distributionKeeper := s.providerApp.GetTestDistributionKeeper() + + chainID := s.consumerChain.ChainID + + for _, tc := range testCases { + s.Run(tc.name, func() { + ctx, _ := s.providerCtx().CacheContext() + // fund consumer rewards pool + bankKeeper.SendCoinsFromAccountToModule( + ctx, + s.providerChain.SenderAccount.GetAddress(), + providertypes.ConsumerRewardsPool, + tc.rewardsPool, + ) + + // update consumer rewars allocation + providerKeeper.SetConsumerRewardsAllocation( + ctx, + chainID, + providertypes.ConsumerRewardsAllocation{ + Rewards: tc.rewardsAlloc, + }, + ) + + // store pool balance + oldPool := bankKeeper.GetAllBalances( + ctx, + distributionKeeper.GetDistributionAccount(ctx).GetAddress(), + ) + + // transfer consumer rewars to distribution module + coinsTransferred, err := providerKeeper.TransferConsumerRewardsToDistributionModule( + ctx, + chainID, + ) + if tc.expErr { + s.Require().Error(err) + return + } + + // check remaining consumer rewards allocation + expCoinTransferred, expRemaining := tc.rewardsAlloc.TruncateDecimal() + s.Require().Equal(expCoinTransferred, coinsTransferred) + + s.Require().Equal( + expRemaining, + providerKeeper.GetConsumerRewardsAllocation(ctx, chainID).Rewards, + ) + + // check updated consuemer rewards pool balance + newPool := bankKeeper.GetAllBalances( + ctx, + distributionKeeper.GetDistributionAccount(ctx).GetAddress(), + ) + + s.Require().Equal(newPool.Sub(oldPool...), coinsTransferred) + }) + } +} + // getEscrowBalance gets the current balances in the escrow account holding the transferred tokens to the provider func (s *CCVTestSuite) getEscrowBalance() sdk.Coins { consumerBankKeeper := s.consumerApp.GetTestBankKeeper() @@ -485,3 +900,82 @@ func (s *CCVTestSuite) prepareRewardDist() { blocksToGo := bpdt - blocksSinceLastTrans s.coordinator.CommitNBlocks(s.consumerChain, uint64(blocksToGo)) } + +func (s *CCVTestSuite) TestAllocateTokensToValidator() { + + providerkeepr := s.providerApp.GetProviderKeeper() + + chainID := "consumer" + + validators := []bytes.HexBytes{ + s.providerChain.Vals.Validators[0].Address, + s.providerChain.Vals.Validators[1].Address, + } + + votes := []abci.VoteInfo{ + {Validator: abci.Validator{Address: validators[0], Power: 1}}, + {Validator: abci.Validator{Address: validators[1], Power: 1}}, + } + + testCases := []struct { + name string + votes []abci.VoteInfo + tokens sdk.DecCoins + expCoinTransferred sdk.DecCoins + }{ + { + name: "reward tokens are empty", + }, + { + name: "total voting power is zero", + tokens: sdk.DecCoins{sdk.NewDecCoin("uatom", math.NewInt(100_000))}, + }, + { + name: "expect all tokens to be allocated to a single validator", + votes: []abci.VoteInfo{votes[0]}, + tokens: sdk.DecCoins{sdk.NewDecCoin("uatom", math.NewInt(100_000))}, + expCoinTransferred: sdk.DecCoins{sdk.NewDecCoin("uatom", math.NewInt(100_000))}, + }, + { + name: "expect tokens to be allocated evenly between validators", + votes: []abci.VoteInfo{votes[0], votes[1]}, + tokens: sdk.DecCoins{sdk.NewDecCoin("uatom", math.NewInt(555_555))}, + expCoinTransferred: sdk.DecCoins{sdk.NewDecCoin("uatom", math.NewInt(555_555))}, + }, + } + + for _, tc := range testCases { + s.Run(tc.name, func() { + // TODO: opt validators in and verify + // that rewards are solely allocated to them + + ctx, _ := s.providerCtx().CacheContext() + + // allocate tokens + res := providerkeepr.AllocateTokensToConsumerValidators( + ctx, + chainID, + tc.votes, + tc.tokens, + ) + + // check that the expect result is returned + s.Require().Equal(tc.expCoinTransferred, res) + + if !tc.expCoinTransferred.Empty() { + // rewards are expected to be allocated evenly between validators + rewardsPerVal := tc.expCoinTransferred.QuoDec(sdk.NewDec(int64(len(tc.votes)))) + + // check that the rewards are allocated to validators as expected + for _, v := range tc.votes { + rewards := s.providerApp.GetTestDistributionKeeper().GetValidatorOutstandingRewards( + ctx, + sdk.ValAddress(v.Validator.Address), + ) + s.Require().Equal(rewardsPerVal, rewards.Rewards) + } + } + + }) + } +} diff --git a/testutil/integration/debug_test.go b/testutil/integration/debug_test.go index 77d460f05f..c370e8e701 100644 --- a/testutil/integration/debug_test.go +++ b/testutil/integration/debug_test.go @@ -283,3 +283,19 @@ func TestHandleConsumerDoubleVotingSlashesUndelegationsAndRelegations(t *testing func TestSlashRetries(t *testing.T) { runCCVTestByName(t, "TestSlashRetries") } + +func TestIBCTransferMiddleware(t *testing.T) { + runCCVTestByName(t, "TestIBCTransferMiddleware") +} + +func TestAllocateTokens(t *testing.T) { + runCCVTestByName(t, "TestAllocateTokens") +} + +func TestTransferConsumerRewardsToDistributionModule(t *testing.T) { + runCCVTestByName(t, "TransferConsumerRewardsToDistributionModule") +} + +func TestAllocateTokensToValidator(t *testing.T) { + runCCVTestByName(t, "TestAllocateTokensToValidator") +} diff --git a/testutil/keeper/mocks.go b/testutil/keeper/mocks.go index b183e8b377..a192765ec9 100644 --- a/testutil/keeper/mocks.go +++ b/testutil/keeper/mocks.go @@ -14,13 +14,14 @@ import ( types0 "github.com/cosmos/cosmos-sdk/types" types1 "github.com/cosmos/cosmos-sdk/x/auth/types" types2 "github.com/cosmos/cosmos-sdk/x/capability/types" + types3 "github.com/cosmos/cosmos-sdk/x/distribution/types" v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" - types3 "github.com/cosmos/cosmos-sdk/x/slashing/types" - types4 "github.com/cosmos/cosmos-sdk/x/staking/types" - types5 "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" - types6 "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" - types7 "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" - types8 "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + types4 "github.com/cosmos/cosmos-sdk/x/slashing/types" + types5 "github.com/cosmos/cosmos-sdk/x/staking/types" + types6 "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + types7 "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + types8 "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" + types9 "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" exported "github.com/cosmos/ibc-go/v7/modules/core/exported" gomock "github.com/golang/mock/gomock" ) @@ -63,10 +64,10 @@ func (mr *MockStakingKeeperMockRecorder) BondDenom(ctx interface{}) *gomock.Call } // Delegation mocks base method. -func (m *MockStakingKeeper) Delegation(ctx types0.Context, addr types0.AccAddress, valAddr types0.ValAddress) types4.DelegationI { +func (m *MockStakingKeeper) Delegation(ctx types0.Context, addr types0.AccAddress, valAddr types0.ValAddress) types5.DelegationI { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Delegation", ctx, addr, valAddr) - ret0, _ := ret[0].(types4.DelegationI) + ret0, _ := ret[0].(types5.DelegationI) return ret0 } @@ -105,10 +106,10 @@ func (mr *MockStakingKeeperMockRecorder) GetLastValidatorPower(ctx, operator int } // GetLastValidators mocks base method. -func (m *MockStakingKeeper) GetLastValidators(ctx types0.Context) []types4.Validator { +func (m *MockStakingKeeper) GetLastValidators(ctx types0.Context) []types5.Validator { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetLastValidators", ctx) - ret0, _ := ret[0].([]types4.Validator) + ret0, _ := ret[0].([]types5.Validator) return ret0 } @@ -119,10 +120,10 @@ func (mr *MockStakingKeeperMockRecorder) GetLastValidators(ctx interface{}) *gom } // GetRedelegationsFromSrcValidator mocks base method. -func (m *MockStakingKeeper) GetRedelegationsFromSrcValidator(ctx types0.Context, valAddr types0.ValAddress) []types4.Redelegation { +func (m *MockStakingKeeper) GetRedelegationsFromSrcValidator(ctx types0.Context, valAddr types0.ValAddress) []types5.Redelegation { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetRedelegationsFromSrcValidator", ctx, valAddr) - ret0, _ := ret[0].([]types4.Redelegation) + ret0, _ := ret[0].([]types5.Redelegation) return ret0 } @@ -133,10 +134,10 @@ func (mr *MockStakingKeeperMockRecorder) GetRedelegationsFromSrcValidator(ctx, v } // GetUnbondingDelegationsFromValidator mocks base method. -func (m *MockStakingKeeper) GetUnbondingDelegationsFromValidator(ctx types0.Context, valAddr types0.ValAddress) []types4.UnbondingDelegation { +func (m *MockStakingKeeper) GetUnbondingDelegationsFromValidator(ctx types0.Context, valAddr types0.ValAddress) []types5.UnbondingDelegation { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetUnbondingDelegationsFromValidator", ctx, valAddr) - ret0, _ := ret[0].([]types4.UnbondingDelegation) + ret0, _ := ret[0].([]types5.UnbondingDelegation) return ret0 } @@ -147,10 +148,10 @@ func (mr *MockStakingKeeperMockRecorder) GetUnbondingDelegationsFromValidator(ct } // GetUnbondingType mocks base method. -func (m *MockStakingKeeper) GetUnbondingType(ctx types0.Context, id uint64) (types4.UnbondingType, bool) { +func (m *MockStakingKeeper) GetUnbondingType(ctx types0.Context, id uint64) (types5.UnbondingType, bool) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetUnbondingType", ctx, id) - ret0, _ := ret[0].(types4.UnbondingType) + ret0, _ := ret[0].(types5.UnbondingType) ret1, _ := ret[1].(bool) return ret0, ret1 } @@ -162,10 +163,10 @@ func (mr *MockStakingKeeperMockRecorder) GetUnbondingType(ctx, id interface{}) * } // GetValidator mocks base method. -func (m *MockStakingKeeper) GetValidator(ctx types0.Context, addr types0.ValAddress) (types4.Validator, bool) { +func (m *MockStakingKeeper) GetValidator(ctx types0.Context, addr types0.ValAddress) (types5.Validator, bool) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetValidator", ctx, addr) - ret0, _ := ret[0].(types4.Validator) + ret0, _ := ret[0].(types5.Validator) ret1, _ := ret[1].(bool) return ret0, ret1 } @@ -177,10 +178,10 @@ func (mr *MockStakingKeeperMockRecorder) GetValidator(ctx, addr interface{}) *go } // GetValidatorByConsAddr mocks base method. -func (m *MockStakingKeeper) GetValidatorByConsAddr(ctx types0.Context, consAddr types0.ConsAddress) (types4.Validator, bool) { +func (m *MockStakingKeeper) GetValidatorByConsAddr(ctx types0.Context, consAddr types0.ConsAddress) (types5.Validator, bool) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetValidatorByConsAddr", ctx, consAddr) - ret0, _ := ret[0].(types4.Validator) + ret0, _ := ret[0].(types5.Validator) ret1, _ := ret[1].(bool) return ret0, ret1 } @@ -232,7 +233,7 @@ func (mr *MockStakingKeeperMockRecorder) IterateLastValidatorPowers(ctx, cb inte } // IterateValidators mocks base method. -func (m *MockStakingKeeper) IterateValidators(ctx types0.Context, f func(int64, types4.ValidatorI) bool) { +func (m *MockStakingKeeper) IterateValidators(ctx types0.Context, f func(int64, types5.ValidatorI) bool) { m.ctrl.T.Helper() m.ctrl.Call(m, "IterateValidators", ctx, f) } @@ -312,7 +313,7 @@ func (mr *MockStakingKeeperMockRecorder) Slash(arg0, arg1, arg2, arg3, arg4 inte } // SlashRedelegation mocks base method. -func (m *MockStakingKeeper) SlashRedelegation(arg0 types0.Context, arg1 types4.Validator, arg2 types4.Redelegation, arg3 int64, arg4 types0.Dec) math.Int { +func (m *MockStakingKeeper) SlashRedelegation(arg0 types0.Context, arg1 types5.Validator, arg2 types5.Redelegation, arg3 int64, arg4 types0.Dec) math.Int { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SlashRedelegation", arg0, arg1, arg2, arg3, arg4) ret0, _ := ret[0].(math.Int) @@ -326,7 +327,7 @@ func (mr *MockStakingKeeperMockRecorder) SlashRedelegation(arg0, arg1, arg2, arg } // SlashUnbondingDelegation mocks base method. -func (m *MockStakingKeeper) SlashUnbondingDelegation(arg0 types0.Context, arg1 types4.UnbondingDelegation, arg2 int64, arg3 types0.Dec) math.Int { +func (m *MockStakingKeeper) SlashUnbondingDelegation(arg0 types0.Context, arg1 types5.UnbondingDelegation, arg2 int64, arg3 types0.Dec) math.Int { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SlashUnbondingDelegation", arg0, arg1, arg2, arg3) ret0, _ := ret[0].(math.Int) @@ -340,7 +341,7 @@ func (mr *MockStakingKeeperMockRecorder) SlashUnbondingDelegation(arg0, arg1, ar } // SlashWithInfractionReason mocks base method. -func (m *MockStakingKeeper) SlashWithInfractionReason(arg0 types0.Context, arg1 types0.ConsAddress, arg2, arg3 int64, arg4 types0.Dec, arg5 types4.Infraction) math.Int { +func (m *MockStakingKeeper) SlashWithInfractionReason(arg0 types0.Context, arg1 types0.ConsAddress, arg2, arg3 int64, arg4 types0.Dec, arg5 types5.Infraction) math.Int { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SlashWithInfractionReason", arg0, arg1, arg2, arg3, arg4, arg5) ret0, _ := ret[0].(math.Int) @@ -394,10 +395,10 @@ func (mr *MockStakingKeeperMockRecorder) Unjail(ctx, addr interface{}) *gomock.C } // Validator mocks base method. -func (m *MockStakingKeeper) Validator(ctx types0.Context, addr types0.ValAddress) types4.ValidatorI { +func (m *MockStakingKeeper) Validator(ctx types0.Context, addr types0.ValAddress) types5.ValidatorI { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Validator", ctx, addr) - ret0, _ := ret[0].(types4.ValidatorI) + ret0, _ := ret[0].(types5.ValidatorI) return ret0 } @@ -408,10 +409,10 @@ func (mr *MockStakingKeeperMockRecorder) Validator(ctx, addr interface{}) *gomoc } // ValidatorByConsAddr mocks base method. -func (m *MockStakingKeeper) ValidatorByConsAddr(ctx types0.Context, consAddr types0.ConsAddress) types4.ValidatorI { +func (m *MockStakingKeeper) ValidatorByConsAddr(ctx types0.Context, consAddr types0.ConsAddress) types5.ValidatorI { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ValidatorByConsAddr", ctx, consAddr) - ret0, _ := ret[0].(types4.ValidatorI) + ret0, _ := ret[0].(types5.ValidatorI) return ret0 } @@ -459,10 +460,10 @@ func (mr *MockSlashingKeeperMockRecorder) DowntimeJailDuration(arg0 interface{}) } // GetValidatorSigningInfo mocks base method. -func (m *MockSlashingKeeper) GetValidatorSigningInfo(ctx types0.Context, address types0.ConsAddress) (types3.ValidatorSigningInfo, bool) { +func (m *MockSlashingKeeper) GetValidatorSigningInfo(ctx types0.Context, address types0.ConsAddress) (types4.ValidatorSigningInfo, bool) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetValidatorSigningInfo", ctx, address) - ret0, _ := ret[0].(types3.ValidatorSigningInfo) + ret0, _ := ret[0].(types4.ValidatorSigningInfo) ret1, _ := ret[1].(bool) return ret0, ret1 } @@ -500,7 +501,7 @@ func (mr *MockSlashingKeeperMockRecorder) JailUntil(arg0, arg1, arg2 interface{} } // SetValidatorSigningInfo mocks base method. -func (m *MockSlashingKeeper) SetValidatorSigningInfo(ctx types0.Context, address types0.ConsAddress, info types3.ValidatorSigningInfo) { +func (m *MockSlashingKeeper) SetValidatorSigningInfo(ctx types0.Context, address types0.ConsAddress, info types4.ValidatorSigningInfo) { m.ctrl.T.Helper() m.ctrl.Call(m, "SetValidatorSigningInfo", ctx, address, info) } @@ -589,10 +590,10 @@ func (mr *MockChannelKeeperMockRecorder) ChanCloseInit(ctx, portID, channelID, c } // GetChannel mocks base method. -func (m *MockChannelKeeper) GetChannel(ctx types0.Context, srcPort, srcChan string) (types8.Channel, bool) { +func (m *MockChannelKeeper) GetChannel(ctx types0.Context, srcPort, srcChan string) (types9.Channel, bool) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetChannel", ctx, srcPort, srcChan) - ret0, _ := ret[0].(types8.Channel) + ret0, _ := ret[0].(types9.Channel) ret1, _ := ret[1].(bool) return ret0, ret1 } @@ -635,7 +636,7 @@ func (mr *MockChannelKeeperMockRecorder) GetNextSequenceSend(ctx, portID, channe } // SendPacket mocks base method. -func (m *MockChannelKeeper) SendPacket(ctx types0.Context, chanCap *types2.Capability, sourcePort, sourceChannel string, timeoutHeight types6.Height, timeoutTimestamp uint64, data []byte) (uint64, error) { +func (m *MockChannelKeeper) SendPacket(ctx types0.Context, chanCap *types2.Capability, sourcePort, sourceChannel string, timeoutHeight types7.Height, timeoutTimestamp uint64, data []byte) (uint64, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SendPacket", ctx, chanCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data) ret0, _ := ret[0].(uint64) @@ -724,10 +725,10 @@ func (m *MockConnectionKeeper) EXPECT() *MockConnectionKeeperMockRecorder { } // GetConnection mocks base method. -func (m *MockConnectionKeeper) GetConnection(ctx types0.Context, connectionID string) (types7.ConnectionEnd, bool) { +func (m *MockConnectionKeeper) GetConnection(ctx types0.Context, connectionID string) (types8.ConnectionEnd, bool) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetConnection", ctx, connectionID) - ret0, _ := ret[0].(types7.ConnectionEnd) + ret0, _ := ret[0].(types8.ConnectionEnd) ret1, _ := ret[1].(bool) return ret0, ret1 } @@ -885,6 +886,18 @@ func (m *MockDistributionKeeper) EXPECT() *MockDistributionKeeperMockRecorder { return m.recorder } +// AllocateTokensToValidator mocks base method. +func (m *MockDistributionKeeper) AllocateTokensToValidator(ctx types0.Context, validator types5.ValidatorI, reward types0.DecCoins) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "AllocateTokensToValidator", ctx, validator, reward) +} + +// AllocateTokensToValidator indicates an expected call of AllocateTokensToValidator. +func (mr *MockDistributionKeeperMockRecorder) AllocateTokensToValidator(ctx, validator, reward interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AllocateTokensToValidator", reflect.TypeOf((*MockDistributionKeeper)(nil).AllocateTokensToValidator), ctx, validator, reward) +} + // FundCommunityPool mocks base method. func (m *MockDistributionKeeper) FundCommunityPool(ctx types0.Context, amount types0.Coins, sender types0.AccAddress) error { m.ctrl.T.Helper() @@ -899,6 +912,46 @@ func (mr *MockDistributionKeeperMockRecorder) FundCommunityPool(ctx, amount, sen return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FundCommunityPool", reflect.TypeOf((*MockDistributionKeeper)(nil).FundCommunityPool), ctx, amount, sender) } +// GetCommunityTax mocks base method. +func (m *MockDistributionKeeper) GetCommunityTax(ctx types0.Context) math.LegacyDec { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetCommunityTax", ctx) + ret0, _ := ret[0].(math.LegacyDec) + return ret0 +} + +// GetCommunityTax indicates an expected call of GetCommunityTax. +func (mr *MockDistributionKeeperMockRecorder) GetCommunityTax(ctx interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCommunityTax", reflect.TypeOf((*MockDistributionKeeper)(nil).GetCommunityTax), ctx) +} + +// GetFeePool mocks base method. +func (m *MockDistributionKeeper) GetFeePool(ctx types0.Context) types3.FeePool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetFeePool", ctx) + ret0, _ := ret[0].(types3.FeePool) + return ret0 +} + +// GetFeePool indicates an expected call of GetFeePool. +func (mr *MockDistributionKeeperMockRecorder) GetFeePool(ctx interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFeePool", reflect.TypeOf((*MockDistributionKeeper)(nil).GetFeePool), ctx) +} + +// SetFeePool mocks base method. +func (m *MockDistributionKeeper) SetFeePool(ctx types0.Context, feePool types3.FeePool) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetFeePool", ctx, feePool) +} + +// SetFeePool indicates an expected call of SetFeePool. +func (mr *MockDistributionKeeperMockRecorder) SetFeePool(ctx, feePool interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFeePool", reflect.TypeOf((*MockDistributionKeeper)(nil).SetFeePool), ctx, feePool) +} + // MockConsumerHooks is a mock of ConsumerHooks interface. type MockConsumerHooks struct { ctrl *gomock.Controller @@ -1061,11 +1114,139 @@ func (m *MockIBCTransferKeeper) EXPECT() *MockIBCTransferKeeperMockRecorder { return m.recorder } +// OnAcknowledgementPacket mocks base method. +func (m *MockIBCTransferKeeper) OnAcknowledgementPacket(ctx types0.Context, packet types9.Packet, acknowledgement []byte, relayer types0.AccAddress) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnAcknowledgementPacket", ctx, packet, acknowledgement, relayer) + ret0, _ := ret[0].(error) + return ret0 +} + +// OnAcknowledgementPacket indicates an expected call of OnAcknowledgementPacket. +func (mr *MockIBCTransferKeeperMockRecorder) OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnAcknowledgementPacket", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnAcknowledgementPacket), ctx, packet, acknowledgement, relayer) +} + +// OnChanCloseConfirm mocks base method. +func (m *MockIBCTransferKeeper) OnChanCloseConfirm(ctx types0.Context, portID, channelID string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnChanCloseConfirm", ctx, portID, channelID) + ret0, _ := ret[0].(error) + return ret0 +} + +// OnChanCloseConfirm indicates an expected call of OnChanCloseConfirm. +func (mr *MockIBCTransferKeeperMockRecorder) OnChanCloseConfirm(ctx, portID, channelID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnChanCloseConfirm", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnChanCloseConfirm), ctx, portID, channelID) +} + +// OnChanCloseInit mocks base method. +func (m *MockIBCTransferKeeper) OnChanCloseInit(ctx types0.Context, portID, channelID string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnChanCloseInit", ctx, portID, channelID) + ret0, _ := ret[0].(error) + return ret0 +} + +// OnChanCloseInit indicates an expected call of OnChanCloseInit. +func (mr *MockIBCTransferKeeperMockRecorder) OnChanCloseInit(ctx, portID, channelID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnChanCloseInit", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnChanCloseInit), ctx, portID, channelID) +} + +// OnChanOpenAck mocks base method. +func (m *MockIBCTransferKeeper) OnChanOpenAck(ctx types0.Context, portID, channelID, counterpartyChannelID, counterpartyVersion string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnChanOpenAck", ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) + ret0, _ := ret[0].(error) + return ret0 +} + +// OnChanOpenAck indicates an expected call of OnChanOpenAck. +func (mr *MockIBCTransferKeeperMockRecorder) OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnChanOpenAck", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnChanOpenAck), ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) +} + +// OnChanOpenConfirm mocks base method. +func (m *MockIBCTransferKeeper) OnChanOpenConfirm(ctx types0.Context, portID, channelID string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnChanOpenConfirm", ctx, portID, channelID) + ret0, _ := ret[0].(error) + return ret0 +} + +// OnChanOpenConfirm indicates an expected call of OnChanOpenConfirm. +func (mr *MockIBCTransferKeeperMockRecorder) OnChanOpenConfirm(ctx, portID, channelID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnChanOpenConfirm", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnChanOpenConfirm), ctx, portID, channelID) +} + +// OnChanOpenInit mocks base method. +func (m *MockIBCTransferKeeper) OnChanOpenInit(ctx types0.Context, order types9.Order, connectionHops []string, portID, channelID string, channelCap *types2.Capability, counterparty types9.Counterparty, version string) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnChanOpenInit", ctx, order, connectionHops, portID, channelID, channelCap, counterparty, version) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// OnChanOpenInit indicates an expected call of OnChanOpenInit. +func (mr *MockIBCTransferKeeperMockRecorder) OnChanOpenInit(ctx, order, connectionHops, portID, channelID, channelCap, counterparty, version interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnChanOpenInit", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnChanOpenInit), ctx, order, connectionHops, portID, channelID, channelCap, counterparty, version) +} + +// OnChanOpenTry mocks base method. +func (m *MockIBCTransferKeeper) OnChanOpenTry(ctx types0.Context, order types9.Order, connectionHops []string, portID, channelID string, channelCap *types2.Capability, counterparty types9.Counterparty, counterpartyVersion string) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnChanOpenTry", ctx, order, connectionHops, portID, channelID, channelCap, counterparty, counterpartyVersion) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// OnChanOpenTry indicates an expected call of OnChanOpenTry. +func (mr *MockIBCTransferKeeperMockRecorder) OnChanOpenTry(ctx, order, connectionHops, portID, channelID, channelCap, counterparty, counterpartyVersion interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnChanOpenTry", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnChanOpenTry), ctx, order, connectionHops, portID, channelID, channelCap, counterparty, counterpartyVersion) +} + +// OnRecvPacket mocks base method. +func (m *MockIBCTransferKeeper) OnRecvPacket(ctx types0.Context, packet types9.Packet, relayer types0.AccAddress) exported.Acknowledgement { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnRecvPacket", ctx, packet, relayer) + ret0, _ := ret[0].(exported.Acknowledgement) + return ret0 +} + +// OnRecvPacket indicates an expected call of OnRecvPacket. +func (mr *MockIBCTransferKeeperMockRecorder) OnRecvPacket(ctx, packet, relayer interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnRecvPacket", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnRecvPacket), ctx, packet, relayer) +} + +// OnTimeoutPacket mocks base method. +func (m *MockIBCTransferKeeper) OnTimeoutPacket(ctx types0.Context, packet types9.Packet, relayer types0.AccAddress) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnTimeoutPacket", ctx, packet, relayer) + ret0, _ := ret[0].(error) + return ret0 +} + +// OnTimeoutPacket indicates an expected call of OnTimeoutPacket. +func (mr *MockIBCTransferKeeperMockRecorder) OnTimeoutPacket(ctx, packet, relayer interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnTimeoutPacket", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnTimeoutPacket), ctx, packet, relayer) +} + // Transfer mocks base method. -func (m *MockIBCTransferKeeper) Transfer(arg0 context.Context, arg1 *types5.MsgTransfer) (*types5.MsgTransferResponse, error) { +func (m *MockIBCTransferKeeper) Transfer(arg0 context.Context, arg1 *types6.MsgTransfer) (*types6.MsgTransferResponse, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Transfer", arg0, arg1) - ret0, _ := ret[0].(*types5.MsgTransferResponse) + ret0, _ := ret[0].(*types6.MsgTransferResponse) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -1100,10 +1281,10 @@ func (m *MockIBCCoreKeeper) EXPECT() *MockIBCCoreKeeperMockRecorder { } // ChannelOpenInit mocks base method. -func (m *MockIBCCoreKeeper) ChannelOpenInit(goCtx context.Context, msg *types8.MsgChannelOpenInit) (*types8.MsgChannelOpenInitResponse, error) { +func (m *MockIBCCoreKeeper) ChannelOpenInit(goCtx context.Context, msg *types9.MsgChannelOpenInit) (*types9.MsgChannelOpenInitResponse, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ChannelOpenInit", goCtx, msg) - ret0, _ := ret[0].(*types8.MsgChannelOpenInitResponse) + ret0, _ := ret[0].(*types9.MsgChannelOpenInitResponse) ret1, _ := ret[1].(error) return ret0, ret1 } diff --git a/x/ccv/provider/ibc_middleware.go b/x/ccv/provider/ibc_middleware.go new file mode 100644 index 0000000000..1c1b1ce824 --- /dev/null +++ b/x/ccv/provider/ibc_middleware.go @@ -0,0 +1,240 @@ +package provider + +import ( + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" + "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + + ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" + "github.com/cosmos/ibc-go/v7/modules/core/exported" +) + +var _ porttypes.Middleware = &IBCMiddleware{} + +// IBCMiddleware implements the callbacks for the IBC transfer middleware given the +// provider keeper and the underlying application. +type IBCMiddleware struct { + app porttypes.IBCModule + keeper keeper.Keeper +} + +// NewIBCMiddleware creates a new IBCMiddlware given the keeper and underlying application +func NewIBCMiddleware(app porttypes.IBCModule, k keeper.Keeper) IBCMiddleware { + return IBCMiddleware{ + app: app, + keeper: k, + } +} + +// OnChanOpenInit implements the IBCMiddleware interface +func (im IBCMiddleware) OnChanOpenInit( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID string, + channelID string, + chanCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + version string, +) (string, error) { + // call underlying app's OnChanOpenInit callback with the appVersion + return im.app.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version) +} + +// OnChanOpenTry implements the IBCMiddleware interface +func (im IBCMiddleware) OnChanOpenTry( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID, + channelID string, + chanCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + counterpartyVersion string, +) (string, error) { + // call underlying app's OnChanOpenTry callback with the appVersion + return im.app.OnChanOpenTry(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, counterpartyVersion) +} + +// OnChanOpenAck implements the IBCMiddleware interface +func (im IBCMiddleware) OnChanOpenAck( + ctx sdk.Context, + portID, + channelID string, + counterpartyChannelID string, + counterpartyVersion string, +) error { + // call underlying app's OnChanOpenAck callback with the counterparty app version. + return im.app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) +} + +// OnChanOpenConfirm implements the IBCMiddleware interface +func (im IBCMiddleware) OnChanOpenConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + // call underlying app's OnChanOpenConfirm callback. + return im.app.OnChanOpenConfirm(ctx, portID, channelID) +} + +// OnChanCloseInit implements the IBCMiddleware interface +func (im IBCMiddleware) OnChanCloseInit( + ctx sdk.Context, + portID, + channelID string, +) error { + // call underlying app's OnChanCloseInit callback. + return im.app.OnChanCloseInit(ctx, portID, channelID) +} + +// OnChanCloseConfirm implements the IBCMiddleware interface +func (im IBCMiddleware) OnChanCloseConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + return im.app.OnChanCloseConfirm(ctx, portID, channelID) +} + +// OnRecvPacket executes the IBC transfer. In case of success, +// it verifies if the packet sender is a consumer chain +// and if the received IBC coin is whitelisted. In such instances, +// it appends the coin to the consumer's chain allocation record +func (im IBCMiddleware) OnRecvPacket( + ctx sdk.Context, + packet channeltypes.Packet, + relayer sdk.AccAddress, +) exported.Acknowledgement { + // executes the IBC transfer OnRecv logic + ack := im.app.OnRecvPacket(ctx, packet, relayer) + + // execute the middleware logic only if the sender is a consumer chain + consumerID, err := im.keeper.IdentifyConsumerChainIDFromIBCPacket(ctx, packet) + if err != nil { + return ack + } + + // Note that inside the below if condition statement, + // we know that the IBC transfer succeeded. That entails + // that the packet data is valid and can be safely + // deserialized without checking errors. + if ack.Success() { + // extract the coin info received from the packet data + var data ibctransfertypes.FungibleTokenPacketData + _ = types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data) + + // check if the recipient is the consumer reward's pool address + receiver, _ := sdk.AccAddressFromBech32(data.Receiver) + if receiver.String() != im.keeper.GetConsumerRewardsPoolAddressStr(ctx) { + return ack + } + + coinAmt, _ := math.NewIntFromString(data.Amount) + coinDenom := GetProviderDenom(data.Denom, packet) + + // verify that the coin's denom is a whitelisted consumer denom, + // and if so, adds it to the consumer chain rewards allocation, + // otherwise the prohibited coin just stays in the pool forever. + if im.keeper.ConsumerRewardDenomExists(ctx, coinDenom) { + alloc := im.keeper.GetConsumerRewardsAllocation(ctx, consumerID) + alloc.Rewards = alloc.Rewards.Add( + sdk.NewDecCoinsFromCoins(sdk.Coin{ + Denom: coinDenom, + Amount: coinAmt, + })...) + im.keeper.SetConsumerRewardsAllocation(ctx, consumerID, alloc) + } + } + + return ack +} + +// OnAcknowledgementPacket implements the IBCMiddleware interface +// If fees are not enabled, this callback will default to the ibc-core packet callback +func (im IBCMiddleware) OnAcknowledgementPacket( + ctx sdk.Context, + packet channeltypes.Packet, + acknowledgement []byte, + relayer sdk.AccAddress, +) error { + // call underlying app's OnAcknowledgementPacket callback. + return im.app.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer) +} + +// OnTimeoutPacket implements the IBCMiddleware interface +// If fees are not enabled, this callback will default to the ibc-core packet callback +func (im IBCMiddleware) OnTimeoutPacket( + ctx sdk.Context, + packet channeltypes.Packet, + relayer sdk.AccAddress, +) error { + // call underlying app's OnTimeoutPacket callback. + return im.app.OnTimeoutPacket(ctx, packet, relayer) +} + +// SendPacket implements the ICS4 Wrapper interface +func (im IBCMiddleware) SendPacket( + sdk.Context, + *capabilitytypes.Capability, + string, + string, + clienttypes.Height, + uint64, + []byte, +) (uint64, error) { + panic("should never be called since the IBC middleware doesn't have an ICS4wrapper") +} + +// WriteAcknowledgement implements the ICS4 Wrapper interface +func (im IBCMiddleware) WriteAcknowledgement( + ctx sdk.Context, + chanCap *capabilitytypes.Capability, + packet exported.PacketI, + ack exported.Acknowledgement, +) error { + panic("should never be called since the IBC middleware doesn't have an ICS4wrapper") +} + +// GetAppVersion returns the application version of the underlying application +func (im IBCMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { + panic("should never be called since the IBC middleware doesn't have an ICS4wrapper") +} + +// GetProviderDenom returns the updated given denom according to the given IBC packet +// It follows the same logic than the OnRecvPacket method of the IBC transfer module +// see https://github.com/cosmos/ibc-go/blob/v7.3.2/modules/apps/transfer/keeper/relay.go#L162 +func GetProviderDenom(denom string, packet channeltypes.Packet) (providerDenom string) { + // If the the prefix denom corresponds to the packet's source port and channel, + // returns the base denom + if ibctransfertypes.ReceiverChainIsSource(packet.GetSourcePort(), packet.GetSourceChannel(), denom) { + voucherPrefix := ibctransfertypes.GetDenomPrefix(packet.GetSourcePort(), packet.GetSourceChannel()) + unprefixedDenom := denom[len(voucherPrefix):] + + // coin denomination used in sending from the escrow address + providerDenom = unprefixedDenom + + // The denomination used to send the coins is either the native denom or the hash of the path + // if the denomination is not native. + denomTrace := ibctransfertypes.ParseDenomTrace(unprefixedDenom) + if denomTrace.Path != "" { + providerDenom = denomTrace.IBCDenom() + } + // update the prefix denom according to the packet info + } else { + prefixedDenom := ibctransfertypes.GetPrefixedDenom( + packet.GetDestPort(), + packet.GetDestChannel(), + denom, + ) + + providerDenom = ibctransfertypes.ParseDenomTrace(prefixedDenom).IBCDenom() + } + + return providerDenom +} diff --git a/x/ccv/provider/ibc_middleware_test.go b/x/ccv/provider/ibc_middleware_test.go new file mode 100644 index 0000000000..3701a65402 --- /dev/null +++ b/x/ccv/provider/ibc_middleware_test.go @@ -0,0 +1,76 @@ +package provider_test + +import ( + "testing" + + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + "github.com/cosmos/interchain-security/v4/x/ccv/provider" + "github.com/stretchr/testify/require" +) + +func TestGetProviderDenom(t *testing.T) { + testCases := []struct { + name string + denom string + packet channeltypes.Packet + expProviderDenom string + }{ + { + name: "returns base denom with destination port and channel as prefix", + denom: "stake", + packet: channeltypes.NewPacket( + []byte{}, + 0, + "srcPort", + "srcChannel", + "dstPort", + "dstChannel", + clienttypes.NewHeight(1, 1), + 0, + ), + expProviderDenom: "dstPort/dstChannel/stake", + }, + { + name: "returns base denom if the prefix denom corresponds to the packet's port and channel source", + denom: "srcPort/srcChannel/stake", + packet: channeltypes.NewPacket( + []byte{}, + 0, + "srcPort", + "srcChannel", + "dstPort", + "dstChannel", + clienttypes.NewHeight(1, 1), + 0, + ), + expProviderDenom: "stake", + }, + { + name: "returns prefixed denom updated with packet's port and channel destination as prefix", + denom: "dstPort/dstChannel/stake", + packet: channeltypes.NewPacket( + []byte{}, + 0, + "srcPort", + "srcChannel", + "dstPort", + "dstChannel", + clienttypes.NewHeight(1, 1), + 0, + ), + expProviderDenom: "dstPort/dstChannel/dstPort/dstChannel/stake", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + res := provider.GetProviderDenom( + tc.denom, + tc.packet, + ) + + require.Equal(t, tc.expProviderDenom, res) + }) + } +} diff --git a/x/ccv/provider/keeper/distribution.go b/x/ccv/provider/keeper/distribution.go index 5b2e6025ef..45af3eb262 100644 --- a/x/ccv/provider/keeper/distribution.go +++ b/x/ccv/provider/keeper/distribution.go @@ -1,17 +1,30 @@ package keeper import ( + errorsmod "cosmossdk.io/errors" + "cosmossdk.io/math" + abci "github.com/cometbft/cometbft/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" ) -// EndBlockRD executes EndBlock logic for the Reward Distribution sub-protocol. -// Reward Distribution follows a simple model: send tokens to the ConsumerRewardsPool, -// from where they sent to the fee collector address -func (k Keeper) EndBlockRD(ctx sdk.Context) { - // transfers all whitelisted consumer rewards to the fee collector address - k.TransferRewardsToFeeCollector(ctx) +// BeginBlockRD executes BeginBlock logic for the Reward Distribution sub-protocol. +func (k Keeper) BeginBlockRD(ctx sdk.Context, req abci.RequestBeginBlock) { + + // determine the total power signing the block + var previousTotalPower int64 + for _, voteInfo := range req.LastCommitInfo.GetVotes() { + previousTotalPower += voteInfo.Validator.Power + } + + // TODO this is Tendermint-dependent + // ref https://github.com/cosmos/cosmos-sdk/issues/3095 + if ctx.BlockHeight() > 1 { + k.AllocateTokens(ctx, previousTotalPower, req.LastCommitInfo.GetVotes()) + } } func (k Keeper) GetConsumerRewardsPoolAddressStr(ctx sdk.Context) string { @@ -57,32 +70,200 @@ func (k Keeper) GetAllConsumerRewardDenoms(ctx sdk.Context) (consumerRewardDenom return consumerRewardDenoms } -// TransferRewardsToFeeCollector transfers all consumer rewards to the fee collector address -func (k Keeper) TransferRewardsToFeeCollector(ctx sdk.Context) { - // 1. Get the denom whitelist from the store - denoms := k.GetAllConsumerRewardDenoms(ctx) +// 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, totalPreviousPower int64, bondedVotes []abci.VoteInfo) { + // return if there is no coins in the consumer rewards pool + if k.GetConsumerRewardsPool(ctx).IsZero() { + return + } + + // Iterate over all registered consumer chains + for _, consumer := range k.GetAllConsumerChains(ctx) { + // transfer the consumer rewards to the distribution module account + // note that the rewards transferred are only consumer whitelisted denoms + rewardsCollected, err := k.TransferConsumerRewardsToDistributionModule(ctx, consumer.ChainId) + if err != nil { + k.Logger(ctx).Error( + "fail to transfer rewards to distribution module for chain %s: %s", + consumer.ChainId, + err, + ) + continue + } + + if rewardsCollected.IsZero() { + continue + } + + rewardsCollectedDec := sdk.NewDecCoinsFromCoins(rewardsCollected...) + + // temporary workaround to keep CanWithdrawInvariant happy + // general discussions here: https://github.com/cosmos/cosmos-sdk/issues/2906#issuecomment-441867634 + feePool := k.distributionKeeper.GetFeePool(ctx) + if k.ComputeConsumerTotalVotingPower(ctx, consumer.ChainId, bondedVotes) == 0 { + feePool.CommunityPool = feePool.CommunityPool.Add(rewardsCollectedDec...) + k.distributionKeeper.SetFeePool(ctx, feePool) + return + } + + // Calculate the reward allocations + remaining := rewardsCollectedDec + communityTax := k.distributionKeeper.GetCommunityTax(ctx) + voteMultiplier := math.LegacyOneDec().Sub(communityTax) + feeMultiplier := rewardsCollectedDec.MulDecTruncate(voteMultiplier) - // 2. Iterate over the whitelist - for _, denom := range denoms { - // 3. For each denom, retrieve the balance from the consumer rewards pool - balance := k.bankKeeper.GetBalance( + // allocate tokens to consumer validators + feeAllocated := k.AllocateTokensToConsumerValidators( ctx, - k.accountKeeper.GetModuleAccount(ctx, types.ConsumerRewardsPool).GetAddress(), - denom, + consumer.ChainId, + bondedVotes, + feeMultiplier, ) + remaining = remaining.Sub(feeAllocated) - // if the balance is not zero, - if !balance.IsZero() { - // 4. Transfer the balance to the fee collector address - err := k.bankKeeper.SendCoinsFromModuleToModule( - ctx, - types.ConsumerRewardsPool, - k.feeCollectorName, - sdk.NewCoins(balance), - ) - if err != nil { - k.Logger(ctx).Error("cannot sent consumer rewards to fee collector:", "reward", balance.String()) - } - } + // allocate community funding + feePool.CommunityPool = feePool.CommunityPool.Add(remaining...) + k.distributionKeeper.SetFeePool(ctx, feePool) } } + +// TODO: allocate tokens to validators that opted-in and for long enough e.g. 1000 blocks +// once the opt-in logic is integrated QueueVSCPackets() +// +// AllocateTokensToConsumerValidators allocates the given tokens from the +// from consumer rewards pool to validator according to their voting power +func (k Keeper) AllocateTokensToConsumerValidators( + ctx sdk.Context, + chainID string, + bondedVotes []abci.VoteInfo, + tokens sdk.DecCoins, +) (totalReward sdk.DecCoins) { + // return early if the tokens are empty + if tokens.Empty() { + return totalReward + } + + // get the consumer total voting power from the votes + totalPower := k.ComputeConsumerTotalVotingPower(ctx, chainID, bondedVotes) + if totalPower == 0 { + return totalReward + } + + for _, vote := range bondedVotes { + // TODO: should check if validator IsOptIn or continue here + consAddr := sdk.ConsAddress(vote.Validator.Address) + + powerFraction := math.LegacyNewDec(vote.Validator.Power).QuoTruncate(math.LegacyNewDec(totalPower)) + tokensFraction := tokens.MulDecTruncate(powerFraction) + + k.distributionKeeper.AllocateTokensToValidator( + ctx, + k.stakingKeeper.ValidatorByConsAddr(ctx, consAddr), + tokensFraction, + ) + totalReward = totalReward.Add(tokensFraction...) + } + + return totalReward +} + +// TransferConsumerRewardsToDistributionModule transfers the collected rewards of the given consumer chain +// from the consumer rewards pool module account to a the distribution module +func (k Keeper) TransferConsumerRewardsToDistributionModule( + ctx sdk.Context, + chainID string, +) (sdk.Coins, error) { + // Get coins of the consumer rewards allocation + allocation := k.GetConsumerRewardsAllocation(ctx, chainID) + + if allocation.Rewards.IsZero() { + return sdk.Coins{}, nil + } + + // Truncate coin rewards + rewardsToSend, _ := allocation.Rewards.TruncateDecimal() + + // NOTE the consumer rewards allocation isn't a module account, however its coins + // are held in the consumer reward pool module account. Thus the consumer + // rewards allocation must be reduced separately from the SendCoinsFromModuleToAccount call. + + // Update consumer rewards allocation with the remaining decimal coins + allocation.Rewards = allocation.Rewards.Sub(sdk.NewDecCoinsFromCoins(rewardsToSend...)) + + // Send coins to distribution module account + err := k.bankKeeper.SendCoinsFromModuleToModule(ctx, types.ConsumerRewardsPool, distrtypes.ModuleName, rewardsToSend) + if err != nil { + return sdk.Coins{}, err + } + + k.SetConsumerRewardsAllocation(ctx, chainID, allocation) + return rewardsToSend, nil +} + +// consumer reward pools getter and setter + +// GetConsumerRewardsAllocation returns the consumer rewards allocation for the given chain ID +func (k Keeper) GetConsumerRewardsAllocation(ctx sdk.Context, chainID string) (pool types.ConsumerRewardsAllocation) { + store := ctx.KVStore(k.storeKey) + b := store.Get(types.ConsumerRewardsAllocationKey(chainID)) + k.cdc.MustUnmarshal(b, &pool) + return +} + +// SetConsumerRewardsAllocation sets the consumer rewards allocation for the given chain ID +func (k Keeper) SetConsumerRewardsAllocation(ctx sdk.Context, chainID string, pool types.ConsumerRewardsAllocation) { + store := ctx.KVStore(k.storeKey) + b := k.cdc.MustMarshal(&pool) + store.Set(types.ConsumerRewardsAllocationKey(chainID), b) +} + +// GetConsumerRewardsPool returns the balance +// of the consumer rewards pool module account +func (k Keeper) GetConsumerRewardsPool(ctx sdk.Context) sdk.Coins { + return k.bankKeeper.GetAllBalances( + ctx, + k.accountKeeper.GetModuleAccount(ctx, types.ConsumerRewardsPool).GetAddress(), + ) +} + +// ComputeConsumerTotalVotingPower returns the total voting power for a given consumer chain +// by summing its opted-in validators votes +func (k Keeper) ComputeConsumerTotalVotingPower(ctx sdk.Context, chainID string, votes []abci.VoteInfo) int64 { + // TODO: create a optedIn set from the OptedIn validators + // and sum their validator power + var totalPower int64 + + // sum the opted-in validators set voting powers + for _, vote := range votes { + // TODO: check that val is in the optedIn set + + totalPower += vote.Validator.Power + } + + return totalPower +} + +// IdentifyConsumerChainIDFromIBCPacket checks if the packet destination matches a registered consumer chain. +// If so, it returns the consumer chain ID, otherwise an error. +func (k Keeper) IdentifyConsumerChainIDFromIBCPacket(ctx sdk.Context, packet channeltypes.Packet) (string, error) { + channel, ok := k.channelKeeper.GetChannel(ctx, packet.DestinationPort, packet.DestinationChannel) + if !ok { + return "", errorsmod.Wrapf(channeltypes.ErrChannelNotFound, "channel not found for channel ID: %s", packet.DestinationChannel) + } + if len(channel.ConnectionHops) != 1 { + return "", errorsmod.Wrap(channeltypes.ErrTooManyConnectionHops, "must have direct connection to consumer chain") + } + connectionID := channel.ConnectionHops[0] + _, tmClient, err := k.getUnderlyingClient(ctx, connectionID) + if err != nil { + return "", err + } + + chainID := tmClient.ChainId + if _, ok := k.GetChainToChannel(ctx, chainID); !ok { + return "", errorsmod.Wrapf(types.ErrUnknownConsumerChannelId, "no CCV channel found for chain with ID: %s", chainID) + } + + return chainID, nil +} diff --git a/x/ccv/provider/keeper/distribution_test.go b/x/ccv/provider/keeper/distribution_test.go new file mode 100644 index 0000000000..b8883177b1 --- /dev/null +++ b/x/ccv/provider/keeper/distribution_test.go @@ -0,0 +1,238 @@ +package keeper_test + +import ( + "testing" + + abci "github.com/cometbft/cometbft/abci/types" + tmtypes "github.com/cometbft/cometbft/types" + sdk "github.com/cosmos/cosmos-sdk/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + conntypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" + "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" +) + +func TestComputeConsumerTotalVotingPower(t *testing.T) { + keeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + createVal := func(power int64) tmtypes.Validator { + signer := tmtypes.NewMockPV() + val := tmtypes.NewValidator(signer.PrivKey.PubKey(), power) + return *val + } + + chainID := "consumer" + validatorsVotes := make([]abci.VoteInfo, 5) + + expTotalPower := int64(0) + + // create validators, opt them in and use them + // to create block votes + for i := 0; i < 5; i++ { + val := createVal(int64(i)) + keeper.SetOptedIn( + ctx, + chainID, + types.NewProviderConsAddress(sdk.ConsAddress(val.Address)), + 0, + ) + + validatorsVotes = append( + validatorsVotes, + abci.VoteInfo{ + Validator: abci.Validator{ + Address: val.Address, + Power: val.VotingPower, + }, + }, + ) + + expTotalPower += val.VotingPower + } + + res := keeper.ComputeConsumerTotalVotingPower( + ctx, + chainID, + validatorsVotes, + ) + + require.Equal(t, expTotalPower, res) +} + +func TestIdentifyConsumerChainIDFromIBCPacket(t *testing.T) { + + var ( + chainID = "consumer" + ccvChannel = "channel-0" + ) + + testCases := []struct { + name string + packet channeltypes.Packet + expectedCalls func(sdk.Context, testkeeper.MockedKeepers, channeltypes.Packet) []*gomock.Call + expCCVChannel bool + expErr bool + }{ + { + "channel not found", + channeltypes.NewPacket( + []byte{}, + 0, + "srcPort", + "srcChannel", + "dstPort", + "dstChannel", + clienttypes.NewHeight(1, 1), + 0, + ), + func(ctx sdk.Context, mocks testkeeper.MockedKeepers, packet channeltypes.Packet) []*gomock.Call { + return []*gomock.Call{ + mocks.MockChannelKeeper.EXPECT().GetChannel( + ctx, + packet.DestinationPort, + packet.DestinationChannel, + ).Return(channeltypes.Channel{}, false).Times(1), + } + }, + false, + true, + }, + { + "connection hops can't be greater than 1", + channeltypes.NewPacket( + []byte{}, + 0, + "srcPort", + "srcChannel", + "dstPort", + "dstChannel", + clienttypes.NewHeight(1, 1), + 0, + ), + func(ctx sdk.Context, mocks testkeeper.MockedKeepers, packet channeltypes.Packet) []*gomock.Call { + return []*gomock.Call{ + mocks.MockChannelKeeper.EXPECT().GetChannel( + ctx, + packet.DestinationPort, + packet.DestinationChannel, + ).Return(channeltypes.Channel{ConnectionHops: []string{"conn1", "conn2"}}, true).Times(1), + } + }, + false, + true, + }, + { + "underlying client isn't found", + channeltypes.NewPacket( + []byte{}, + 0, + "srcPort", + "srcChannel", + "dstPort", + "dstChannel", + clienttypes.NewHeight(1, 1), + 0, + ), + func(ctx sdk.Context, mocks testkeeper.MockedKeepers, packet channeltypes.Packet) []*gomock.Call { + return []*gomock.Call{ + mocks.MockChannelKeeper.EXPECT().GetChannel( + ctx, + packet.DestinationPort, + packet.DestinationChannel, + ).Return(channeltypes.Channel{ConnectionHops: []string{"connectionID"}}, true).Times(1), + mocks.MockConnectionKeeper.EXPECT().GetConnection(ctx, "connectionID").Return( + conntypes.ConnectionEnd{ClientId: "clientID"}, true, + ).Times(1), + mocks.MockClientKeeper.EXPECT().GetClientState(ctx, "clientID").Return( + &ibctmtypes.ClientState{ChainId: ""}, false, + ).Times(1), + } + }, + false, + true, + }, + { + "no CCV channel registered", + channeltypes.NewPacket( + []byte{}, + 0, + "srcPort", + "srcChannel", + "dstPort", + "dstChannel", + clienttypes.NewHeight(1, 1), + 0, + ), + func(ctx sdk.Context, mocks testkeeper.MockedKeepers, packet channeltypes.Packet) []*gomock.Call { + return []*gomock.Call{ + mocks.MockChannelKeeper.EXPECT().GetChannel( + ctx, + packet.DestinationPort, + packet.DestinationChannel, + ).Return(channeltypes.Channel{ConnectionHops: []string{"connectionID"}}, true).Times(1), + mocks.MockConnectionKeeper.EXPECT().GetConnection(ctx, "connectionID").Return( + conntypes.ConnectionEnd{ClientId: "clientID"}, true, + ).Times(1), + mocks.MockClientKeeper.EXPECT().GetClientState(ctx, "clientID").Return( + &ibctmtypes.ClientState{ChainId: chainID}, true, + ).Times(1), + } + }, + false, + true, + }, + { + "consumer chain identified", + channeltypes.NewPacket( + []byte{}, + 0, + "srcPort", + "srcChannel", + "dstPort", + "dstChannel", + clienttypes.NewHeight(1, 1), + 0, + ), + func(ctx sdk.Context, mocks testkeeper.MockedKeepers, packet channeltypes.Packet) []*gomock.Call { + return []*gomock.Call{ + mocks.MockChannelKeeper.EXPECT().GetChannel( + ctx, + packet.DestinationPort, + packet.DestinationChannel, + ), + } + }, + false, + true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + + keeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + tc.expectedCalls(ctx, mocks, tc.packet) + _, err := keeper.IdentifyConsumerChainIDFromIBCPacket( + ctx, + tc.packet, + ) + + if tc.expCCVChannel { + keeper.SetChainToChannel(ctx, chainID, ccvChannel) + } + + if !tc.expErr { + require.NoError(t, err) + } else { + require.Error(t, err) + } + }) + } +} diff --git a/x/ccv/provider/module.go b/x/ccv/provider/module.go index f34b92bb07..1fe4ae08bb 100644 --- a/x/ccv/provider/module.go +++ b/x/ccv/provider/module.go @@ -144,6 +144,8 @@ func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) { am.keeper.BeginBlockCCR(ctx) // Check for replenishing slash meter before any slash packets are processed for this block am.keeper.BeginBlockCIS(ctx) + // BeginBlock logic need for the Reward Distribution sub-protocol + am.keeper.BeginBlockRD(ctx, req) } // EndBlock implements the AppModule interface @@ -155,8 +157,6 @@ func (am AppModule) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.V am.keeper.EndBlockCCR(ctx) // EndBlock logic needed for the Validator Set Update sub-protocol am.keeper.EndBlockVSU(ctx) - // EndBlock logic need for the Reward Distribution sub-protocol - am.keeper.EndBlockRD(ctx) return []abci.ValidatorUpdate{} } diff --git a/x/ccv/provider/types/consumer.go b/x/ccv/provider/types/consumer.go index 4c43bd58e7..2a89859a36 100644 --- a/x/ccv/provider/types/consumer.go +++ b/x/ccv/provider/types/consumer.go @@ -1,6 +1,7 @@ package types import ( + sdk "github.com/cosmos/cosmos-sdk/types" ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" ) @@ -25,3 +26,10 @@ func NewConsumerStates( SlashDowntimeAck: slashDowntimeAck, } } + +// zero consumer rewards allocation +func InitialConsumerRewardsAllocation() ConsumerRewardsAllocation { + return ConsumerRewardsAllocation{ + Rewards: sdk.DecCoins{}, + } +} diff --git a/x/ccv/provider/types/keys.go b/x/ccv/provider/types/keys.go index e2348821ee..b82346b674 100644 --- a/x/ccv/provider/types/keys.go +++ b/x/ccv/provider/types/keys.go @@ -165,6 +165,10 @@ const ( // are about to be opted out ToBeOptedOutBytePrefix + // ConsumerRewardsAllocationBytePrefix is the byte prefix used when storing for each consumer the rewards + // it allocated to the consumer rewards pool + ConsumerRewardsAllocationBytePrefix + // NOTE: DO NOT ADD NEW BYTE PREFIXES HERE WITHOUT ADDING THEM TO getAllKeyPrefixes() IN keys_test.go ) @@ -560,6 +564,11 @@ func ToBeOptedOutKey(chainID string, providerAddr ProviderConsAddress) []byte { return append(prefix, providerAddr.ToSdkConsAddr().Bytes()...) } +// ConsumerModuleAccount returns the module account byte prefix for a consumer chain +func ConsumerRewardsAllocationKey(chainID string) []byte { + return append([]byte{ConsumerRewardsAllocationBytePrefix}, []byte(chainID)...) +} + // // End of generic helpers section // diff --git a/x/ccv/provider/types/keys_test.go b/x/ccv/provider/types/keys_test.go index 32dea17560..87864d67be 100644 --- a/x/ccv/provider/types/keys_test.go +++ b/x/ccv/provider/types/keys_test.go @@ -61,6 +61,7 @@ func getAllKeyPrefixes() []byte { providertypes.OptedInBytePrefix, providertypes.ToBeOptedInBytePrefix, providertypes.ToBeOptedOutBytePrefix, + providertypes.ConsumerRewardsAllocationBytePrefix, } } diff --git a/x/ccv/provider/types/provider.pb.go b/x/ccv/provider/types/provider.pb.go index 2ef5f607d0..dee8a9520a 100644 --- a/x/ccv/provider/types/provider.pb.go +++ b/x/ccv/provider/types/provider.pb.go @@ -6,7 +6,9 @@ package types import ( fmt "fmt" crypto "github.com/cometbft/cometbft/proto/tendermint/crypto" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" types2 "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/cosmos-sdk/types/tx/amino" types1 "github.com/cosmos/cosmos-sdk/x/evidence/types" _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/cosmos/gogoproto/proto" @@ -1464,6 +1466,53 @@ func (m *ConsumerValidator) GetConsumerPublicKey() *crypto.PublicKey { return nil } +// ConsumerRewardsAllocation stores the rewards allocated by a consumer chain +// to the consumer rewards pool. It is used to allocate the tokens to the consumer +// opted-in validators and the community pool during BeginBlock. +type ConsumerRewardsAllocation struct { + Rewards github_com_cosmos_cosmos_sdk_types.DecCoins `protobuf:"bytes,1,rep,name=rewards,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.DecCoins" json:"rewards"` +} + +func (m *ConsumerRewardsAllocation) Reset() { *m = ConsumerRewardsAllocation{} } +func (m *ConsumerRewardsAllocation) String() string { return proto.CompactTextString(m) } +func (*ConsumerRewardsAllocation) ProtoMessage() {} +func (*ConsumerRewardsAllocation) Descriptor() ([]byte, []int) { + return fileDescriptor_f22ec409a72b7b72, []int{23} +} +func (m *ConsumerRewardsAllocation) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ConsumerRewardsAllocation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ConsumerRewardsAllocation.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ConsumerRewardsAllocation) XXX_Merge(src proto.Message) { + xxx_messageInfo_ConsumerRewardsAllocation.Merge(m, src) +} +func (m *ConsumerRewardsAllocation) XXX_Size() int { + return m.Size() +} +func (m *ConsumerRewardsAllocation) XXX_DiscardUnknown() { + xxx_messageInfo_ConsumerRewardsAllocation.DiscardUnknown(m) +} + +var xxx_messageInfo_ConsumerRewardsAllocation proto.InternalMessageInfo + +func (m *ConsumerRewardsAllocation) GetRewards() github_com_cosmos_cosmos_sdk_types.DecCoins { + if m != nil { + return m.Rewards + } + return nil +} + func init() { proto.RegisterType((*ConsumerAdditionProposal)(nil), "interchain_security.ccv.provider.v1.ConsumerAdditionProposal") proto.RegisterType((*ConsumerRemovalProposal)(nil), "interchain_security.ccv.provider.v1.ConsumerRemovalProposal") @@ -1488,6 +1537,7 @@ func init() { proto.RegisterType((*ValidatorByConsumerAddr)(nil), "interchain_security.ccv.provider.v1.ValidatorByConsumerAddr") proto.RegisterType((*ConsumerAddrsToPrune)(nil), "interchain_security.ccv.provider.v1.ConsumerAddrsToPrune") proto.RegisterType((*ConsumerValidator)(nil), "interchain_security.ccv.provider.v1.ConsumerValidator") + proto.RegisterType((*ConsumerRewardsAllocation)(nil), "interchain_security.ccv.provider.v1.ConsumerRewardsAllocation") } func init() { @@ -1495,118 +1545,123 @@ func init() { } var fileDescriptor_f22ec409a72b7b72 = []byte{ - // 1776 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0x4f, 0x6f, 0x1b, 0xc7, - 0x15, 0xd7, 0x8a, 0x94, 0x2c, 0x3e, 0x4a, 0x94, 0xb4, 0x52, 0xe2, 0x95, 0xab, 0x52, 0xf4, 0xa6, - 0x49, 0x55, 0xa4, 0x59, 0x56, 0x4a, 0x0b, 0x04, 0x46, 0x83, 0x40, 0xa2, 0x9c, 0x58, 0x56, 0x62, - 0x2b, 0x2b, 0x55, 0x46, 0xdb, 0xc3, 0x62, 0x38, 0x3b, 0x26, 0x07, 0x5a, 0xee, 0xac, 0x67, 0x66, - 0xd7, 0xe1, 0xa5, 0xe7, 0x1e, 0xd3, 0x5b, 0xd0, 0x4b, 0xd3, 0x02, 0x3d, 0xf7, 0x6b, 0xe4, 0x98, - 0x63, 0x4f, 0x69, 0x61, 0x1f, 0x7b, 0xed, 0x07, 0x28, 0x66, 0xf6, 0x2f, 0x29, 0xc9, 0xa5, 0x91, - 0xf6, 0xb6, 0x7c, 0xf3, 0xde, 0xef, 0xbd, 0x79, 0x7f, 0x7e, 0x6f, 0x24, 0xd8, 0xa7, 0xa1, 0x24, - 0x1c, 0x0f, 0x11, 0x0d, 0x3d, 0x41, 0x70, 0xcc, 0xa9, 0x1c, 0x77, 0x31, 0x4e, 0xba, 0x11, 0x67, - 0x09, 0xf5, 0x09, 0xef, 0x26, 0x7b, 0xc5, 0xb7, 0x13, 0x71, 0x26, 0x99, 0xf9, 0xd6, 0x35, 0x36, - 0x0e, 0xc6, 0x89, 0x53, 0xe8, 0x25, 0x7b, 0x77, 0xde, 0xbe, 0x09, 0x38, 0xd9, 0xeb, 0x3e, 0xa7, - 0x9c, 0xa4, 0x58, 0x77, 0x36, 0x07, 0x6c, 0xc0, 0xf4, 0x67, 0x57, 0x7d, 0x65, 0xd2, 0x9d, 0x01, - 0x63, 0x83, 0x80, 0x74, 0xf5, 0xaf, 0x7e, 0xfc, 0xb4, 0x2b, 0xe9, 0x88, 0x08, 0x89, 0x46, 0x51, - 0xa6, 0xd0, 0x9e, 0x56, 0xf0, 0x63, 0x8e, 0x24, 0x65, 0x61, 0x0e, 0x40, 0xfb, 0xb8, 0x8b, 0x19, - 0x27, 0x5d, 0x1c, 0x50, 0x12, 0x4a, 0xe5, 0x35, 0xfd, 0xca, 0x14, 0xba, 0x4a, 0x21, 0xa0, 0x83, - 0xa1, 0x4c, 0xc5, 0xa2, 0x2b, 0x49, 0xe8, 0x13, 0x3e, 0xa2, 0xa9, 0x72, 0xf9, 0x2b, 0x33, 0xd8, - 0xae, 0x9c, 0x63, 0x3e, 0x8e, 0x24, 0xeb, 0x5e, 0x92, 0xb1, 0xc8, 0x4e, 0xdf, 0xc1, 0x4c, 0x8c, - 0x98, 0xe8, 0x12, 0x75, 0xff, 0x10, 0x93, 0x6e, 0xb2, 0xd7, 0x27, 0x12, 0xed, 0x15, 0x82, 0x3c, - 0xee, 0x4c, 0xaf, 0x8f, 0x44, 0xa9, 0x83, 0x19, 0xcd, 0xe2, 0xb6, 0xff, 0xbd, 0x08, 0x56, 0x8f, - 0x85, 0x22, 0x1e, 0x11, 0x7e, 0xe0, 0xfb, 0x54, 0x5d, 0xe9, 0x94, 0xb3, 0x88, 0x09, 0x14, 0x98, - 0x9b, 0xb0, 0x20, 0xa9, 0x0c, 0x88, 0x65, 0x74, 0x8c, 0xdd, 0x86, 0x9b, 0xfe, 0x30, 0x3b, 0xd0, - 0xf4, 0x89, 0xc0, 0x9c, 0x46, 0x4a, 0xd9, 0x9a, 0xd7, 0x67, 0x55, 0x91, 0xb9, 0x05, 0x4b, 0x69, - 0x1d, 0xa8, 0x6f, 0xd5, 0xf4, 0xf1, 0x2d, 0xfd, 0xfb, 0xd8, 0x37, 0x3f, 0x81, 0x16, 0x0d, 0xa9, - 0xa4, 0x28, 0xf0, 0x86, 0x44, 0x65, 0xc3, 0xaa, 0x77, 0x8c, 0xdd, 0xe6, 0xfe, 0x1d, 0x87, 0xf6, - 0xb1, 0xa3, 0x12, 0xe8, 0x64, 0x69, 0x4b, 0xf6, 0x9c, 0x07, 0x5a, 0xe3, 0xb0, 0xfe, 0xcd, 0x77, - 0x3b, 0x73, 0xee, 0x4a, 0x66, 0x97, 0x0a, 0xcd, 0xbb, 0xb0, 0x3c, 0x20, 0x21, 0x11, 0x54, 0x78, - 0x43, 0x24, 0x86, 0xd6, 0x42, 0xc7, 0xd8, 0x5d, 0x76, 0x9b, 0x99, 0xec, 0x01, 0x12, 0x43, 0x73, - 0x07, 0x9a, 0x7d, 0x1a, 0x22, 0x3e, 0x4e, 0x35, 0x16, 0xb5, 0x06, 0xa4, 0x22, 0xad, 0xd0, 0x03, - 0x10, 0x11, 0x7a, 0x1e, 0x7a, 0xaa, 0xda, 0xd6, 0xad, 0x2c, 0x90, 0xb4, 0xd2, 0x4e, 0x5e, 0x69, - 0xe7, 0x3c, 0x6f, 0x85, 0xc3, 0x25, 0x15, 0xc8, 0x97, 0xff, 0xd8, 0x31, 0xdc, 0x86, 0xb6, 0x53, - 0x27, 0xe6, 0x23, 0x58, 0x8b, 0xc3, 0x3e, 0x0b, 0x7d, 0x1a, 0x0e, 0xbc, 0x88, 0x70, 0xca, 0x7c, - 0x6b, 0x49, 0x43, 0x6d, 0x5d, 0x81, 0x3a, 0xca, 0x9a, 0x26, 0x45, 0xfa, 0x4a, 0x21, 0xad, 0x16, - 0xc6, 0xa7, 0xda, 0xd6, 0xfc, 0x1c, 0x4c, 0x8c, 0x13, 0x1d, 0x12, 0x8b, 0x65, 0x8e, 0xd8, 0x98, - 0x1d, 0x71, 0x0d, 0xe3, 0xe4, 0x3c, 0xb5, 0xce, 0x20, 0x7f, 0x0b, 0xb7, 0x25, 0x47, 0xa1, 0x78, - 0x4a, 0xf8, 0x34, 0x2e, 0xcc, 0x8e, 0xfb, 0x46, 0x8e, 0x31, 0x09, 0xfe, 0x00, 0x3a, 0x38, 0x6b, - 0x20, 0x8f, 0x13, 0x9f, 0x0a, 0xc9, 0x69, 0x3f, 0x56, 0xb6, 0xde, 0x53, 0x8e, 0xb0, 0xee, 0x91, - 0xa6, 0x6e, 0x82, 0x76, 0xae, 0xe7, 0x4e, 0xa8, 0x7d, 0x9c, 0x69, 0x99, 0x8f, 0xe1, 0x47, 0xfd, - 0x80, 0xe1, 0x4b, 0xa1, 0x82, 0xf3, 0x26, 0x90, 0xb4, 0xeb, 0x11, 0x15, 0x42, 0xa1, 0x2d, 0x77, - 0x8c, 0xdd, 0x9a, 0x7b, 0x37, 0xd5, 0x3d, 0x25, 0xfc, 0xa8, 0xa2, 0x79, 0x5e, 0x51, 0x34, 0xdf, - 0x03, 0x73, 0x48, 0x85, 0x64, 0x9c, 0x62, 0x14, 0x78, 0x24, 0x94, 0x9c, 0x12, 0x61, 0xad, 0x68, - 0xf3, 0xf5, 0xf2, 0xe4, 0x7e, 0x7a, 0x60, 0x3e, 0x84, 0xbb, 0x37, 0x3a, 0xf5, 0xf0, 0x10, 0x85, - 0x21, 0x09, 0xac, 0x96, 0xbe, 0xca, 0x8e, 0x7f, 0x83, 0xcf, 0x5e, 0xaa, 0x66, 0x6e, 0xc0, 0x82, - 0x64, 0x91, 0xf7, 0xc8, 0x5a, 0xed, 0x18, 0xbb, 0x2b, 0x6e, 0x5d, 0xb2, 0xe8, 0xd1, 0xbd, 0xa5, - 0xdf, 0x7f, 0xbd, 0x33, 0xf7, 0xd5, 0xd7, 0x3b, 0x73, 0xf6, 0xdf, 0x0c, 0xb8, 0xdd, 0x2b, 0xb2, - 0x31, 0x62, 0x09, 0x0a, 0xfe, 0x9f, 0x53, 0x77, 0x00, 0x0d, 0xa1, 0xc2, 0xd1, 0x7d, 0x5e, 0x7f, - 0x8d, 0x3e, 0x5f, 0x52, 0x66, 0xea, 0xc0, 0xfe, 0x93, 0x01, 0x9b, 0xf7, 0x9f, 0xc5, 0x34, 0x61, - 0x18, 0xfd, 0x4f, 0x48, 0xe2, 0x04, 0x56, 0x48, 0x05, 0x4f, 0x58, 0xb5, 0x4e, 0x6d, 0xb7, 0xb9, - 0xff, 0xb6, 0x93, 0x32, 0x96, 0x53, 0x10, 0x59, 0xc6, 0x5a, 0x4e, 0xd5, 0xbb, 0x3b, 0x69, 0x7b, - 0x6f, 0xde, 0x32, 0xec, 0xbf, 0x18, 0x70, 0x47, 0xa5, 0x7f, 0x40, 0x5c, 0xf2, 0x1c, 0x71, 0xff, - 0x88, 0x84, 0x6c, 0x24, 0xbe, 0x77, 0x9c, 0x36, 0xac, 0xf8, 0x1a, 0xc9, 0x93, 0xcc, 0x43, 0xbe, - 0xaf, 0xe3, 0xd4, 0x3a, 0x4a, 0x78, 0xce, 0x0e, 0x7c, 0xdf, 0xdc, 0x85, 0xb5, 0x52, 0x87, 0xab, - 0x7a, 0xaa, 0x34, 0x2b, 0xb5, 0x56, 0xae, 0xa6, 0xab, 0x4c, 0xec, 0x7f, 0x19, 0xb0, 0xf6, 0x49, - 0xc0, 0xfa, 0x28, 0x38, 0x0b, 0x90, 0x18, 0xaa, 0xd6, 0x1b, 0xab, 0xf2, 0x70, 0x92, 0xcd, 0xbc, - 0x0e, 0x6f, 0xe6, 0xf2, 0x28, 0x33, 0xcd, 0x42, 0x1f, 0xc1, 0x7a, 0x31, 0x85, 0x45, 0x17, 0xe8, - 0xdb, 0x1c, 0x6e, 0xbc, 0xf8, 0x6e, 0x67, 0x35, 0x6f, 0xb6, 0x9e, 0xee, 0x88, 0x23, 0x77, 0x15, - 0x4f, 0x08, 0x7c, 0xb3, 0x0d, 0x4d, 0xda, 0xc7, 0x9e, 0x20, 0xcf, 0xbc, 0x30, 0x1e, 0xe9, 0x06, - 0xaa, 0xbb, 0x0d, 0xda, 0xc7, 0x67, 0xe4, 0xd9, 0xa3, 0x78, 0x64, 0xbe, 0x0f, 0x6f, 0xe6, 0xdb, - 0xd6, 0x4b, 0x50, 0xe0, 0x29, 0x7b, 0x95, 0x0e, 0xae, 0xfb, 0x69, 0xd9, 0xdd, 0xc8, 0x4f, 0x2f, - 0x50, 0xa0, 0x9c, 0x1d, 0xf8, 0x3e, 0xb7, 0x5f, 0x2e, 0xc0, 0xe2, 0x29, 0xe2, 0x68, 0x24, 0xcc, - 0x73, 0x58, 0x95, 0x64, 0x14, 0x05, 0x48, 0x12, 0x2f, 0x65, 0xf8, 0xec, 0xa6, 0xef, 0x6a, 0xe6, - 0xaf, 0x6e, 0x46, 0xa7, 0xb2, 0x0b, 0x93, 0x3d, 0xa7, 0xa7, 0xa5, 0x67, 0x12, 0x49, 0xe2, 0xb6, - 0x72, 0x8c, 0x54, 0x68, 0x7e, 0x00, 0x96, 0xe4, 0xb1, 0x90, 0x25, 0xf7, 0x96, 0xa4, 0x93, 0xd6, - 0xf2, 0xcd, 0xfc, 0x3c, 0xa5, 0xab, 0x82, 0x6c, 0xae, 0xa7, 0xd9, 0xda, 0xf7, 0xa1, 0xd9, 0x33, - 0xd8, 0x50, 0x3b, 0x6a, 0x1a, 0xb3, 0x3e, 0x3b, 0xe6, 0xba, 0xb2, 0x9f, 0x04, 0xfd, 0x1c, 0xcc, - 0x44, 0xe0, 0x69, 0xcc, 0x85, 0xd7, 0x88, 0x33, 0x11, 0x78, 0x12, 0xd2, 0x87, 0x6d, 0xa1, 0x9a, - 0xcf, 0x1b, 0x11, 0xa9, 0x49, 0x3b, 0x0a, 0x48, 0x48, 0xc5, 0x30, 0x07, 0x5f, 0x9c, 0x1d, 0x7c, - 0x4b, 0x03, 0x7d, 0xa6, 0x70, 0xdc, 0x1c, 0x26, 0xf3, 0xd2, 0x83, 0xf6, 0xf5, 0x5e, 0x8a, 0x02, - 0xdd, 0xd2, 0x05, 0xfa, 0xc1, 0x35, 0x10, 0x45, 0x95, 0x04, 0xbc, 0x53, 0x59, 0x2e, 0x6a, 0xaa, - 0x3d, 0x3d, 0x50, 0x1e, 0x27, 0x03, 0xc5, 0xc0, 0x28, 0xdd, 0x33, 0x84, 0x14, 0x0b, 0x32, 0x63, - 0x0f, 0xf5, 0xde, 0x29, 0x98, 0xa3, 0xc7, 0x68, 0x98, 0xbd, 0x22, 0xec, 0x72, 0x07, 0x15, 0x1c, - 0xe1, 0x56, 0xb0, 0x3e, 0x26, 0x44, 0x4d, 0x73, 0x65, 0x0f, 0x91, 0x88, 0xe1, 0xa1, 0xde, 0x93, - 0x35, 0xb7, 0x55, 0xec, 0x9c, 0xfb, 0x4a, 0xfa, 0xb0, 0xbe, 0xb4, 0xb4, 0xd6, 0xb0, 0x7f, 0x02, - 0x0d, 0x3d, 0xcc, 0x07, 0xf8, 0x52, 0x98, 0xdb, 0xd0, 0x50, 0x53, 0x41, 0x84, 0x20, 0xc2, 0x32, - 0x34, 0x07, 0x94, 0x02, 0x5b, 0xc2, 0xd6, 0x4d, 0xaf, 0x2d, 0x61, 0x3e, 0x81, 0x5b, 0x11, 0xd1, - 0x4f, 0x01, 0x6d, 0xd8, 0xdc, 0xff, 0xd0, 0x99, 0xe1, 0xe1, 0xeb, 0xdc, 0x04, 0xe8, 0xe6, 0x68, - 0x36, 0x2f, 0xdf, 0x78, 0x53, 0xcb, 0x46, 0x98, 0x17, 0xd3, 0x4e, 0x7f, 0xf9, 0x5a, 0x4e, 0xa7, - 0xf0, 0x4a, 0x9f, 0xef, 0x42, 0xf3, 0x20, 0xbd, 0xf6, 0xa7, 0x54, 0xc8, 0xab, 0x69, 0x59, 0xae, - 0xa6, 0xe5, 0x21, 0xb4, 0xb2, 0xc5, 0x79, 0xce, 0x34, 0x21, 0x99, 0x3f, 0x04, 0xc8, 0x36, 0xae, - 0x22, 0xb2, 0x94, 0xb2, 0x1b, 0x99, 0xe4, 0xd8, 0x9f, 0xd8, 0x75, 0xf3, 0x13, 0xbb, 0xce, 0x76, - 0x61, 0xf5, 0x42, 0xe0, 0x5f, 0xe5, 0xaf, 0xaa, 0xc7, 0x91, 0x30, 0xdf, 0x80, 0x45, 0x35, 0x43, - 0x19, 0x50, 0xdd, 0x5d, 0x48, 0x04, 0x3e, 0xd6, 0xac, 0x5d, 0xbe, 0xdc, 0x58, 0xe4, 0x51, 0x5f, - 0x58, 0xf3, 0x9d, 0xda, 0x6e, 0xdd, 0x6d, 0xc5, 0xa5, 0xf9, 0xb1, 0x2f, 0xec, 0x5f, 0x43, 0xb3, - 0x02, 0x68, 0xb6, 0x60, 0xbe, 0xc0, 0x9a, 0xa7, 0xbe, 0x79, 0x0f, 0xb6, 0x4a, 0xa0, 0x49, 0x1a, - 0x4e, 0x11, 0x1b, 0xee, 0xed, 0x42, 0x61, 0x82, 0x89, 0x85, 0xfd, 0x18, 0x36, 0x8f, 0xcb, 0xa1, - 0x2f, 0x48, 0x7e, 0xe2, 0x86, 0xc6, 0xe4, 0x36, 0xdf, 0x86, 0x46, 0xf1, 0xe7, 0x89, 0xbe, 0x7d, - 0xdd, 0x2d, 0x05, 0xf6, 0x08, 0xd6, 0x2e, 0x04, 0x3e, 0x23, 0xa1, 0x5f, 0x82, 0xdd, 0x90, 0x80, - 0xc3, 0x69, 0xa0, 0x99, 0x9f, 0xbf, 0xa5, 0x3b, 0x06, 0x5b, 0x17, 0x28, 0xa0, 0x3e, 0x92, 0x8c, - 0x9f, 0x11, 0x99, 0x2e, 0xe0, 0x53, 0x84, 0x2f, 0x89, 0x14, 0xa6, 0x0b, 0xf5, 0x80, 0x0a, 0x99, - 0x75, 0xd6, 0x07, 0x37, 0x76, 0x56, 0xb2, 0xe7, 0xdc, 0x04, 0x72, 0x84, 0x24, 0xca, 0x66, 0x57, - 0x63, 0xd9, 0x3f, 0x86, 0x8d, 0xcf, 0x90, 0x8c, 0x39, 0xf1, 0x27, 0x6a, 0xbc, 0x06, 0x35, 0x55, - 0x3f, 0x43, 0xd7, 0x4f, 0x7d, 0xaa, 0xf7, 0x80, 0x75, 0xff, 0x8b, 0x88, 0x71, 0x49, 0xfc, 0x2b, - 0x19, 0x79, 0x45, 0x7a, 0x2f, 0x61, 0x43, 0x25, 0x4b, 0x90, 0xd0, 0xf7, 0x8a, 0x7b, 0xa6, 0x75, - 0x6c, 0xee, 0xff, 0x62, 0xa6, 0xe9, 0x98, 0x76, 0x97, 0x5d, 0x60, 0x3d, 0x99, 0x92, 0x0b, 0xfb, - 0x0f, 0x06, 0x58, 0x27, 0x64, 0x7c, 0x20, 0x04, 0x1d, 0x84, 0x23, 0x12, 0x4a, 0xc5, 0x81, 0x08, - 0x13, 0xf5, 0x69, 0xbe, 0x05, 0x2b, 0xc5, 0xce, 0xd5, 0xab, 0xd6, 0xd0, 0xab, 0x76, 0x39, 0x17, - 0xaa, 0x01, 0x33, 0xef, 0x01, 0x44, 0x9c, 0x24, 0x1e, 0xf6, 0x2e, 0xc9, 0x38, 0xab, 0xe2, 0x76, - 0x75, 0x85, 0xa6, 0x7f, 0x3c, 0x3a, 0xa7, 0x71, 0x3f, 0xa0, 0xf8, 0x84, 0x8c, 0xdd, 0x25, 0xa5, - 0xdf, 0x3b, 0x21, 0x63, 0xf5, 0x26, 0x8a, 0xd8, 0x73, 0xc2, 0xf5, 0xde, 0xab, 0xb9, 0xe9, 0x0f, - 0xfb, 0x8f, 0x06, 0xdc, 0x2e, 0xca, 0x91, 0xb7, 0xeb, 0x69, 0xdc, 0x57, 0x16, 0xaf, 0xc8, 0xdb, - 0x95, 0x68, 0xe7, 0xaf, 0x89, 0xf6, 0x23, 0x58, 0x2e, 0x06, 0x44, 0xc5, 0x5b, 0x9b, 0x21, 0xde, - 0x66, 0x6e, 0x71, 0x42, 0xc6, 0xf6, 0xef, 0x2a, 0xb1, 0x1d, 0x8e, 0x2b, 0xdc, 0xc7, 0xff, 0x4b, - 0x6c, 0x85, 0xdb, 0x6a, 0x6c, 0xb8, 0x6a, 0x7f, 0xe5, 0x02, 0xb5, 0xab, 0x17, 0xb0, 0xff, 0x6c, - 0xc0, 0x66, 0xd5, 0xab, 0x38, 0x67, 0xa7, 0x3c, 0x0e, 0xc9, 0xab, 0xbc, 0x97, 0xe3, 0x37, 0x5f, - 0x1d, 0xbf, 0x27, 0xd0, 0x9a, 0x08, 0x4a, 0x64, 0xd9, 0xf8, 0xd9, 0x4c, 0x3d, 0x56, 0x61, 0x57, - 0x77, 0xa5, 0x7a, 0x0f, 0x61, 0xff, 0xd5, 0x80, 0xf5, 0x3c, 0xc6, 0x22, 0x59, 0xe6, 0x4f, 0xc1, - 0x2c, 0xae, 0x57, 0xbe, 0xde, 0xd2, 0x96, 0x5a, 0xcb, 0x4f, 0xf2, 0xa7, 0x5b, 0xd9, 0x1a, 0xf3, - 0x95, 0xd6, 0x30, 0x3f, 0x85, 0x8d, 0x22, 0xe4, 0x48, 0x17, 0x68, 0xe6, 0x2a, 0x16, 0xef, 0xd3, - 0x42, 0x74, 0xf8, 0xe4, 0x9b, 0x17, 0x6d, 0xe3, 0xdb, 0x17, 0x6d, 0xe3, 0x9f, 0x2f, 0xda, 0xc6, - 0x97, 0x2f, 0xdb, 0x73, 0xdf, 0xbe, 0x6c, 0xcf, 0xfd, 0xfd, 0x65, 0x7b, 0xee, 0x37, 0x1f, 0x0e, - 0xa8, 0x1c, 0xc6, 0x7d, 0x07, 0xb3, 0x51, 0x37, 0xfb, 0x0f, 0x46, 0x99, 0x93, 0xf7, 0x8a, 0x7f, - 0xef, 0x24, 0x3f, 0xef, 0x7e, 0x31, 0xf9, 0xcf, 0x23, 0x39, 0x8e, 0x88, 0xe8, 0x2f, 0x6a, 0xf6, - 0x7a, 0xff, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xc4, 0xae, 0x39, 0x65, 0x6d, 0x12, 0x00, 0x00, + // 1852 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0x4d, 0x6f, 0x1c, 0xc7, + 0xd1, 0xe6, 0x70, 0x97, 0x1f, 0x5b, 0xcb, 0xcf, 0x21, 0x6d, 0x0d, 0xf5, 0xf2, 0x5d, 0x52, 0xe3, + 0xd8, 0x61, 0xa2, 0x68, 0x26, 0xa4, 0x13, 0x40, 0x10, 0x62, 0x18, 0xe4, 0x52, 0xb6, 0x28, 0xda, + 0x12, 0x3d, 0x64, 0x28, 0x24, 0x39, 0x0c, 0x7a, 0x7b, 0x5a, 0xbb, 0x0d, 0xce, 0x4e, 0x8f, 0xba, + 0x7b, 0x47, 0xde, 0x4b, 0xce, 0xb9, 0x04, 0x70, 0x6e, 0x46, 0x2e, 0x71, 0x02, 0x04, 0x08, 0x72, + 0x49, 0x7e, 0x86, 0x8f, 0x3e, 0xe6, 0x64, 0x07, 0xd2, 0x21, 0x87, 0x5c, 0xf3, 0x03, 0x82, 0xee, + 0xf9, 0xdc, 0x25, 0xa9, 0xac, 0xe0, 0xe4, 0x42, 0xce, 0x54, 0x57, 0x3d, 0x55, 0xdd, 0x55, 0xf5, + 0x54, 0xef, 0xc0, 0x1e, 0x8d, 0x24, 0xe1, 0xb8, 0x87, 0x68, 0xe4, 0x0b, 0x82, 0x07, 0x9c, 0xca, + 0xa1, 0x8b, 0x71, 0xe2, 0xc6, 0x9c, 0x25, 0x34, 0x20, 0xdc, 0x4d, 0x76, 0x8b, 0x67, 0x27, 0xe6, + 0x4c, 0x32, 0xf3, 0xad, 0x2b, 0x6c, 0x1c, 0x8c, 0x13, 0xa7, 0xd0, 0x4b, 0x76, 0x6f, 0xbe, 0x7d, + 0x1d, 0x70, 0xb2, 0xeb, 0x3e, 0xa7, 0x9c, 0xa4, 0x58, 0x37, 0xd7, 0xbb, 0xac, 0xcb, 0xf4, 0xa3, + 0xab, 0x9e, 0x32, 0xe9, 0x56, 0x97, 0xb1, 0x6e, 0x48, 0x5c, 0xfd, 0xd6, 0x19, 0x3c, 0x75, 0x25, + 0xed, 0x13, 0x21, 0x51, 0x3f, 0xce, 0x14, 0x5a, 0xe3, 0x0a, 0xc1, 0x80, 0x23, 0x49, 0x59, 0x94, + 0x03, 0xd0, 0x0e, 0x76, 0x31, 0xe3, 0xc4, 0xc5, 0x21, 0x25, 0x91, 0x54, 0x5e, 0xd3, 0xa7, 0x4c, + 0xc1, 0x55, 0x0a, 0x21, 0xed, 0xf6, 0x64, 0x2a, 0x16, 0xae, 0x24, 0x51, 0x40, 0x78, 0x9f, 0xa6, + 0xca, 0xe5, 0x5b, 0x66, 0xb0, 0x59, 0x59, 0xc7, 0x7c, 0x18, 0x4b, 0xe6, 0x5e, 0x90, 0xa1, 0xc8, + 0x56, 0xdf, 0xc1, 0x4c, 0xf4, 0x99, 0x70, 0x89, 0xda, 0x7f, 0x84, 0x89, 0x9b, 0xec, 0x76, 0x88, + 0x44, 0xbb, 0x85, 0x20, 0x8f, 0x3b, 0xd3, 0xeb, 0x20, 0x51, 0xea, 0x60, 0x46, 0xf3, 0xb8, 0x57, + 0x51, 0x9f, 0x46, 0xcc, 0xd5, 0x7f, 0x53, 0x91, 0xfd, 0xaf, 0x59, 0xb0, 0xda, 0x2c, 0x12, 0x83, + 0x3e, 0xe1, 0xfb, 0x41, 0x40, 0xd5, 0x2e, 0x4f, 0x38, 0x8b, 0x99, 0x40, 0xa1, 0xb9, 0x0e, 0x33, + 0x92, 0xca, 0x90, 0x58, 0xc6, 0xb6, 0xb1, 0xd3, 0xf0, 0xd2, 0x17, 0x73, 0x1b, 0x9a, 0x01, 0x11, + 0x98, 0xd3, 0x58, 0x29, 0x5b, 0xd3, 0x7a, 0xad, 0x2a, 0x32, 0x37, 0x60, 0x3e, 0x4d, 0x0d, 0x0d, + 0xac, 0x9a, 0x5e, 0x9e, 0xd3, 0xef, 0x47, 0x81, 0xf9, 0x21, 0x2c, 0xd1, 0x88, 0x4a, 0x8a, 0x42, + 0xbf, 0x47, 0xd4, 0x01, 0x59, 0xf5, 0x6d, 0x63, 0xa7, 0xb9, 0x77, 0xd3, 0xa1, 0x1d, 0xec, 0xa8, + 0x33, 0x75, 0xb2, 0x93, 0x4c, 0x76, 0x9d, 0x07, 0x5a, 0xe3, 0xa0, 0xfe, 0xe5, 0xd7, 0x5b, 0x53, + 0xde, 0x62, 0x66, 0x97, 0x0a, 0xcd, 0x5b, 0xb0, 0xd0, 0x25, 0x11, 0x11, 0x54, 0xf8, 0x3d, 0x24, + 0x7a, 0xd6, 0xcc, 0xb6, 0xb1, 0xb3, 0xe0, 0x35, 0x33, 0xd9, 0x03, 0x24, 0x7a, 0xe6, 0x16, 0x34, + 0x3b, 0x34, 0x42, 0x7c, 0x98, 0x6a, 0xcc, 0x6a, 0x0d, 0x48, 0x45, 0x5a, 0xa1, 0x0d, 0x20, 0x62, + 0xf4, 0x3c, 0xf2, 0x55, 0x01, 0x58, 0x73, 0x59, 0x20, 0x69, 0xf2, 0x9d, 0x3c, 0xf9, 0xce, 0x59, + 0x5e, 0x1d, 0x07, 0xf3, 0x2a, 0x90, 0xcf, 0xbe, 0xd9, 0x32, 0xbc, 0x86, 0xb6, 0x53, 0x2b, 0xe6, + 0x23, 0x58, 0x19, 0x44, 0x1d, 0x16, 0x05, 0x34, 0xea, 0xfa, 0x31, 0xe1, 0x94, 0x05, 0xd6, 0xbc, + 0x86, 0xda, 0xb8, 0x04, 0x75, 0x98, 0xd5, 0x51, 0x8a, 0xf4, 0xb9, 0x42, 0x5a, 0x2e, 0x8c, 0x4f, + 0xb4, 0xad, 0xf9, 0x09, 0x98, 0x18, 0x27, 0x3a, 0x24, 0x36, 0x90, 0x39, 0x62, 0x63, 0x72, 0xc4, + 0x15, 0x8c, 0x93, 0xb3, 0xd4, 0x3a, 0x83, 0xfc, 0x05, 0xdc, 0x90, 0x1c, 0x45, 0xe2, 0x29, 0xe1, + 0xe3, 0xb8, 0x30, 0x39, 0xee, 0x1b, 0x39, 0xc6, 0x28, 0xf8, 0x03, 0xd8, 0xc6, 0x59, 0x01, 0xf9, + 0x9c, 0x04, 0x54, 0x48, 0x4e, 0x3b, 0x03, 0x65, 0xeb, 0x3f, 0xe5, 0x08, 0xeb, 0x1a, 0x69, 0xea, + 0x22, 0x68, 0xe5, 0x7a, 0xde, 0x88, 0xda, 0x07, 0x99, 0x96, 0xf9, 0x18, 0xbe, 0xd3, 0x09, 0x19, + 0xbe, 0x10, 0x2a, 0x38, 0x7f, 0x04, 0x49, 0xbb, 0xee, 0x53, 0x21, 0x14, 0xda, 0xc2, 0xb6, 0xb1, + 0x53, 0xf3, 0x6e, 0xa5, 0xba, 0x27, 0x84, 0x1f, 0x56, 0x34, 0xcf, 0x2a, 0x8a, 0xe6, 0x1d, 0x30, + 0x7b, 0x54, 0x48, 0xc6, 0x29, 0x46, 0xa1, 0x4f, 0x22, 0xc9, 0x29, 0x11, 0xd6, 0xa2, 0x36, 0x5f, + 0x2d, 0x57, 0xee, 0xa7, 0x0b, 0xe6, 0x43, 0xb8, 0x75, 0xad, 0x53, 0x1f, 0xf7, 0x50, 0x14, 0x91, + 0xd0, 0x5a, 0xd2, 0x5b, 0xd9, 0x0a, 0xae, 0xf1, 0xd9, 0x4e, 0xd5, 0xcc, 0x35, 0x98, 0x91, 0x2c, + 0xf6, 0x1f, 0x59, 0xcb, 0xdb, 0xc6, 0xce, 0xa2, 0x57, 0x97, 0x2c, 0x7e, 0x74, 0x6f, 0xfe, 0x57, + 0x5f, 0x6c, 0x4d, 0x7d, 0xfe, 0xc5, 0xd6, 0x94, 0xfd, 0x17, 0x03, 0x6e, 0xb4, 0x8b, 0xd3, 0xe8, + 0xb3, 0x04, 0x85, 0xff, 0xcb, 0xae, 0xdb, 0x87, 0x86, 0x50, 0xe1, 0xe8, 0x3a, 0xaf, 0xbf, 0x46, + 0x9d, 0xcf, 0x2b, 0x33, 0xb5, 0x60, 0xff, 0xce, 0x80, 0xf5, 0xfb, 0xcf, 0x06, 0x34, 0x61, 0x18, + 0xfd, 0x57, 0x48, 0xe2, 0x18, 0x16, 0x49, 0x05, 0x4f, 0x58, 0xb5, 0xed, 0xda, 0x4e, 0x73, 0xef, + 0x6d, 0x27, 0x25, 0x31, 0xa7, 0xe0, 0xb6, 0x8c, 0xc8, 0x9c, 0xaa, 0x77, 0x6f, 0xd4, 0xf6, 0xde, + 0xb4, 0x65, 0xd8, 0x7f, 0x30, 0xe0, 0xa6, 0x3a, 0xfe, 0x2e, 0xf1, 0xc8, 0x73, 0xc4, 0x83, 0x43, + 0x12, 0xb1, 0xbe, 0xf8, 0xd6, 0x71, 0xda, 0xb0, 0x18, 0x68, 0x24, 0x5f, 0x32, 0x1f, 0x05, 0x81, + 0x8e, 0x53, 0xeb, 0x28, 0xe1, 0x19, 0xdb, 0x0f, 0x02, 0x73, 0x07, 0x56, 0x4a, 0x1d, 0xae, 0xf2, + 0xa9, 0x8e, 0x59, 0xa9, 0x2d, 0xe5, 0x6a, 0x3a, 0xcb, 0xc4, 0xfe, 0xa7, 0x01, 0x2b, 0x1f, 0x86, + 0xac, 0x83, 0xc2, 0xd3, 0x10, 0x89, 0x9e, 0x2a, 0xbd, 0xa1, 0x4a, 0x0f, 0x27, 0x59, 0xcf, 0xeb, + 0xf0, 0x26, 0x4e, 0x8f, 0x32, 0xd3, 0x2c, 0xf4, 0x3e, 0xac, 0x16, 0x5d, 0x58, 0x54, 0x81, 0xde, + 0xcd, 0xc1, 0xda, 0x8b, 0xaf, 0xb7, 0x96, 0xf3, 0x62, 0x6b, 0xeb, 0x8a, 0x38, 0xf4, 0x96, 0xf1, + 0x88, 0x20, 0x30, 0x5b, 0xd0, 0xa4, 0x1d, 0xec, 0x0b, 0xf2, 0xcc, 0x8f, 0x06, 0x7d, 0x5d, 0x40, + 0x75, 0xaf, 0x41, 0x3b, 0xf8, 0x94, 0x3c, 0x7b, 0x34, 0xe8, 0x9b, 0xef, 0xc2, 0x9b, 0xf9, 0x00, + 0xf6, 0x13, 0x14, 0xfa, 0xca, 0x5e, 0x1d, 0x07, 0xd7, 0xf5, 0xb4, 0xe0, 0xad, 0xe5, 0xab, 0xe7, + 0x28, 0x54, 0xce, 0xf6, 0x83, 0x80, 0xdb, 0x2f, 0x67, 0x60, 0xf6, 0x04, 0x71, 0xd4, 0x17, 0xe6, + 0x19, 0x2c, 0x4b, 0xd2, 0x8f, 0x43, 0x24, 0x89, 0x9f, 0x32, 0x7c, 0xb6, 0xd3, 0xdb, 0x9a, 0xf9, + 0xab, 0xc3, 0xd2, 0xa9, 0x8c, 0xc7, 0x64, 0xd7, 0x69, 0x6b, 0xe9, 0xa9, 0x44, 0x92, 0x78, 0x4b, + 0x39, 0x46, 0x2a, 0x34, 0xef, 0x82, 0x25, 0xf9, 0x40, 0xc8, 0x92, 0x7b, 0x4b, 0xd2, 0x49, 0x73, + 0xf9, 0x66, 0xbe, 0x9e, 0xd2, 0x55, 0x41, 0x36, 0x57, 0xd3, 0x6c, 0xed, 0xdb, 0xd0, 0xec, 0x29, + 0xac, 0xa9, 0x19, 0x35, 0x8e, 0x59, 0x9f, 0x1c, 0x73, 0x55, 0xd9, 0x8f, 0x82, 0x7e, 0x02, 0x66, + 0x22, 0xf0, 0x38, 0xe6, 0xcc, 0x6b, 0xc4, 0x99, 0x08, 0x3c, 0x0a, 0x19, 0xc0, 0xa6, 0x50, 0xc5, + 0xe7, 0xf7, 0x89, 0xd4, 0xa4, 0x1d, 0x87, 0x24, 0xa2, 0xa2, 0x97, 0x83, 0xcf, 0x4e, 0x0e, 0xbe, + 0xa1, 0x81, 0x3e, 0x56, 0x38, 0x5e, 0x0e, 0x93, 0x79, 0x69, 0x43, 0xeb, 0x6a, 0x2f, 0x45, 0x82, + 0xe6, 0x74, 0x82, 0xfe, 0xef, 0x0a, 0x88, 0x22, 0x4b, 0x02, 0xde, 0xa9, 0x0c, 0x17, 0xd5, 0xd5, + 0xbe, 0x6e, 0x28, 0x9f, 0x93, 0xae, 0x62, 0x60, 0x94, 0xce, 0x19, 0x42, 0x8a, 0x01, 0x99, 0xb1, + 0x87, 0xba, 0x02, 0x15, 0xcc, 0xd1, 0x66, 0x34, 0xca, 0x6e, 0x11, 0x76, 0x39, 0x83, 0x0a, 0x8e, + 0xf0, 0x2a, 0x58, 0x1f, 0x10, 0xa2, 0xba, 0xb9, 0x32, 0x87, 0x48, 0xcc, 0x70, 0x4f, 0xcf, 0xc9, + 0x9a, 0xb7, 0x54, 0xcc, 0x9c, 0xfb, 0x4a, 0xfa, 0xb0, 0x3e, 0x3f, 0xbf, 0xd2, 0xb0, 0xbf, 0x07, + 0x0d, 0xdd, 0xcc, 0xfb, 0xf8, 0x42, 0x98, 0x9b, 0xd0, 0x50, 0x5d, 0x41, 0x84, 0x20, 0xc2, 0x32, + 0x34, 0x07, 0x94, 0x02, 0x5b, 0xc2, 0xc6, 0x75, 0xb7, 0x2d, 0x61, 0x3e, 0x81, 0xb9, 0x98, 0xe8, + 0xab, 0x80, 0x36, 0x6c, 0xee, 0xbd, 0xe7, 0x4c, 0x70, 0x17, 0x76, 0xae, 0x03, 0xf4, 0x72, 0x34, + 0x9b, 0x97, 0x77, 0xbc, 0xb1, 0x61, 0x23, 0xcc, 0xf3, 0x71, 0xa7, 0x3f, 0x79, 0x2d, 0xa7, 0x63, + 0x78, 0xa5, 0xcf, 0xdb, 0xd0, 0xdc, 0x4f, 0xb7, 0xfd, 0x11, 0x15, 0xf2, 0xf2, 0xb1, 0x2c, 0x54, + 0x8f, 0xe5, 0x21, 0x2c, 0x65, 0x83, 0xf3, 0x8c, 0x69, 0x42, 0x32, 0xff, 0x1f, 0x20, 0x9b, 0xb8, + 0x8a, 0xc8, 0x52, 0xca, 0x6e, 0x64, 0x92, 0xa3, 0x60, 0x64, 0xd6, 0x4d, 0x8f, 0xcc, 0x3a, 0xdb, + 0x83, 0xe5, 0x73, 0x81, 0x7f, 0x9a, 0xdf, 0xaa, 0x1e, 0xc7, 0xc2, 0x7c, 0x03, 0x66, 0x55, 0x0f, + 0x65, 0x40, 0x75, 0x6f, 0x26, 0x11, 0xf8, 0x48, 0xb3, 0x76, 0x79, 0x73, 0x63, 0xb1, 0x4f, 0x03, + 0x61, 0x4d, 0x6f, 0xd7, 0x76, 0xea, 0xde, 0xd2, 0xa0, 0x34, 0x3f, 0x0a, 0x84, 0xfd, 0x33, 0x68, + 0x56, 0x00, 0xcd, 0x25, 0x98, 0x2e, 0xb0, 0xa6, 0x69, 0x60, 0xde, 0x83, 0x8d, 0x12, 0x68, 0x94, + 0x86, 0x53, 0xc4, 0x86, 0x77, 0xa3, 0x50, 0x18, 0x61, 0x62, 0x61, 0x3f, 0x86, 0xf5, 0xa3, 0xb2, + 0xe9, 0x0b, 0x92, 0x1f, 0xd9, 0xa1, 0x31, 0x3a, 0xcd, 0x37, 0xa1, 0x51, 0xfc, 0x62, 0xd1, 0xbb, + 0xaf, 0x7b, 0xa5, 0xc0, 0xee, 0xc3, 0xca, 0xb9, 0xc0, 0xa7, 0x24, 0x0a, 0x4a, 0xb0, 0x6b, 0x0e, + 0xe0, 0x60, 0x1c, 0x68, 0xe2, 0xeb, 0x6f, 0xe9, 0x8e, 0xc1, 0xc6, 0x39, 0x0a, 0x69, 0x80, 0x24, + 0xe3, 0xa7, 0x44, 0xa6, 0x03, 0xf8, 0x04, 0xe1, 0x0b, 0x22, 0x85, 0xe9, 0x41, 0x3d, 0xa4, 0x42, + 0x66, 0x95, 0x75, 0xf7, 0xda, 0xca, 0x4a, 0x76, 0x9d, 0xeb, 0x40, 0x0e, 0x91, 0x44, 0x59, 0xef, + 0x6a, 0x2c, 0xfb, 0xbb, 0xb0, 0xf6, 0x31, 0x92, 0x03, 0x4e, 0x82, 0x91, 0x1c, 0xaf, 0x40, 0x4d, + 0xe5, 0xcf, 0xd0, 0xf9, 0x53, 0x8f, 0xea, 0x3e, 0x60, 0xdd, 0xff, 0x34, 0x66, 0x5c, 0x92, 0xe0, + 0xd2, 0x89, 0xbc, 0xe2, 0x78, 0x2f, 0x60, 0x4d, 0x1d, 0x96, 0x20, 0x51, 0xe0, 0x17, 0xfb, 0x4c, + 0xf3, 0xd8, 0xdc, 0xfb, 0xf1, 0x44, 0xdd, 0x31, 0xee, 0x2e, 0xdb, 0xc0, 0x6a, 0x32, 0x26, 0x17, + 0xf6, 0x6f, 0x0c, 0xb0, 0x8e, 0xc9, 0x70, 0x5f, 0x08, 0xda, 0x8d, 0xfa, 0x24, 0x92, 0x8a, 0x03, + 0x11, 0x26, 0xea, 0xd1, 0x7c, 0x0b, 0x16, 0x8b, 0x99, 0xab, 0x47, 0xad, 0xa1, 0x47, 0xed, 0x42, + 0x2e, 0x54, 0x0d, 0x66, 0xde, 0x03, 0x88, 0x39, 0x49, 0x7c, 0xec, 0x5f, 0x90, 0x61, 0x96, 0xc5, + 0xcd, 0xea, 0x08, 0x4d, 0x7f, 0x4f, 0x3a, 0x27, 0x83, 0x4e, 0x48, 0xf1, 0x31, 0x19, 0x7a, 0xf3, + 0x4a, 0xbf, 0x7d, 0x4c, 0x86, 0xea, 0x4e, 0x14, 0xb3, 0xe7, 0x84, 0xeb, 0xb9, 0x57, 0xf3, 0xd2, + 0x17, 0xfb, 0xb7, 0x06, 0xdc, 0x28, 0xd2, 0x91, 0x97, 0xeb, 0xc9, 0xa0, 0xa3, 0x2c, 0x5e, 0x71, + 0x6e, 0x97, 0xa2, 0x9d, 0xbe, 0x22, 0xda, 0xf7, 0x61, 0xa1, 0x68, 0x10, 0x15, 0x6f, 0x6d, 0x82, + 0x78, 0x9b, 0xb9, 0xc5, 0x31, 0x19, 0xda, 0xbf, 0xac, 0xc4, 0x76, 0x30, 0xac, 0x70, 0x1f, 0xff, + 0x0f, 0xb1, 0x15, 0x6e, 0xab, 0xb1, 0xe1, 0xaa, 0xfd, 0xa5, 0x0d, 0xd4, 0x2e, 0x6f, 0xc0, 0xfe, + 0xbd, 0x01, 0xeb, 0x55, 0xaf, 0xe2, 0x8c, 0x9d, 0xf0, 0x41, 0x44, 0x5e, 0xe5, 0xbd, 0x6c, 0xbf, + 0xe9, 0x6a, 0xfb, 0x3d, 0x81, 0xa5, 0x91, 0xa0, 0x44, 0x76, 0x1a, 0x3f, 0x9c, 0xa8, 0xc6, 0x2a, + 0xec, 0xea, 0x2d, 0x56, 0xf7, 0x21, 0xec, 0x3f, 0x1a, 0xb0, 0x9a, 0xc7, 0x58, 0x1c, 0x96, 0xf9, + 0x03, 0x30, 0x8b, 0xed, 0x95, 0xb7, 0xb7, 0xb4, 0xa4, 0x56, 0xf2, 0x95, 0xfc, 0xea, 0x56, 0x96, + 0xc6, 0x74, 0xa5, 0x34, 0xcc, 0x8f, 0x60, 0xad, 0x08, 0x39, 0xd6, 0x09, 0x9a, 0x38, 0x8b, 0xc5, + 0xfd, 0xb4, 0x10, 0xd9, 0xbf, 0x36, 0xca, 0x71, 0x98, 0xce, 0x63, 0xb1, 0x1f, 0x86, 0xd9, 0xa5, + 0xde, 0x8c, 0x61, 0x2e, 0x1d, 0xf9, 0x22, 0xe3, 0x8f, 0xcd, 0x2b, 0x87, 0xfb, 0x21, 0xc1, 0x7a, + 0xbe, 0xdf, 0x55, 0x2d, 0xf6, 0xe7, 0x6f, 0xb6, 0x6e, 0x77, 0xa9, 0xec, 0x0d, 0x3a, 0x0e, 0x66, + 0x7d, 0x37, 0xfb, 0x1e, 0x92, 0xfe, 0xbb, 0x23, 0x82, 0x0b, 0x57, 0x0e, 0x63, 0x22, 0x72, 0x1b, + 0xf1, 0xa7, 0x7f, 0xfc, 0xf5, 0xfb, 0x86, 0x97, 0xbb, 0x39, 0x78, 0xf2, 0xe5, 0x8b, 0x96, 0xf1, + 0xd5, 0x8b, 0x96, 0xf1, 0xf7, 0x17, 0x2d, 0xe3, 0xb3, 0x97, 0xad, 0xa9, 0xaf, 0x5e, 0xb6, 0xa6, + 0xfe, 0xf6, 0xb2, 0x35, 0xf5, 0xf3, 0xf7, 0x2e, 0x83, 0x96, 0x39, 0xba, 0x53, 0x7c, 0x81, 0x4a, + 0x7e, 0xe4, 0x7e, 0x3a, 0xfa, 0x7d, 0x4b, 0xfb, 0xeb, 0xcc, 0x6a, 0x36, 0x7d, 0xf7, 0xdf, 0x01, + 0x00, 0x00, 0xff, 0xff, 0x8f, 0xff, 0x87, 0xe4, 0x10, 0x13, 0x00, 0x00, } func (m *ConsumerAdditionProposal) Marshal() (dAtA []byte, err error) { @@ -2727,6 +2782,43 @@ func (m *ConsumerValidator) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *ConsumerRewardsAllocation) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ConsumerRewardsAllocation) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ConsumerRewardsAllocation) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Rewards) > 0 { + for iNdEx := len(m.Rewards) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Rewards[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintProvider(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func encodeVarintProvider(dAtA []byte, offset int, v uint64) int { offset -= sovProvider(v) base := offset @@ -3221,6 +3313,21 @@ func (m *ConsumerValidator) Size() (n int) { return n } +func (m *ConsumerRewardsAllocation) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Rewards) > 0 { + for _, e := range m.Rewards { + l = e.Size() + n += 1 + l + sovProvider(uint64(l)) + } + } + return n +} + func sovProvider(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -6672,6 +6779,90 @@ func (m *ConsumerValidator) Unmarshal(dAtA []byte) error { } return nil } +func (m *ConsumerRewardsAllocation) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProvider + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ConsumerRewardsAllocation: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ConsumerRewardsAllocation: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Rewards", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProvider + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthProvider + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthProvider + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Rewards = append(m.Rewards, types2.DecCoin{}) + if err := m.Rewards[len(m.Rewards)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipProvider(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthProvider + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipProvider(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/ccv/types/expected_keepers.go b/x/ccv/types/expected_keepers.go index df531e09ca..761eca90d7 100644 --- a/x/ccv/types/expected_keepers.go +++ b/x/ccv/types/expected_keepers.go @@ -11,6 +11,7 @@ import ( ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" "cosmossdk.io/math" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" sdk "github.com/cosmos/cosmos-sdk/types" auth "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -109,6 +110,10 @@ type ClientKeeper interface { // DistributionKeeper defines the expected interface of the distribution keeper type DistributionKeeper interface { FundCommunityPool(ctx sdk.Context, amount sdk.Coins, sender sdk.AccAddress) error + GetFeePool(ctx sdk.Context) distrtypes.FeePool + SetFeePool(ctx sdk.Context, feePool distrtypes.FeePool) + GetCommunityTax(ctx sdk.Context) math.LegacyDec + AllocateTokensToValidator(ctx sdk.Context, validator stakingtypes.ValidatorI, reward sdk.DecCoins) } // ConsumerHooks event hooks for newly bonded cross-chain validators From 71315ef4cd53f88a347c6c683ecdc6b6c1bd1407 Mon Sep 17 00:00:00 2001 From: Simon Noetzlin Date: Fri, 23 Feb 2024 15:15:37 +0100 Subject: [PATCH 013/110] feat! use protos to serialize opted-in validators (#1659) move OptedInValidators to proto Co-authored-by: insumity --- .../ccv/provider/v1/provider.proto | 13 + x/ccv/provider/keeper/distribution_test.go | 9 +- x/ccv/provider/keeper/keeper.go | 38 +- x/ccv/provider/keeper/keeper_test.go | 56 +- x/ccv/provider/keeper/partial_set_security.go | 6 - .../keeper/partial_set_security_test.go | 7 +- x/ccv/provider/types/keys.go | 4 +- x/ccv/provider/types/provider.pb.go | 538 ++++++++++++++---- 8 files changed, 501 insertions(+), 170 deletions(-) diff --git a/proto/interchain_security/ccv/provider/v1/provider.proto b/proto/interchain_security/ccv/provider/v1/provider.proto index 1b5f7a515f..3576b03f55 100644 --- a/proto/interchain_security/ccv/provider/v1/provider.proto +++ b/proto/interchain_security/ccv/provider/v1/provider.proto @@ -326,3 +326,16 @@ message ConsumerRewardsAllocation { (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins" ]; } + +// OptedInValidator is used to store a opted-in validator +// to a consumer chain with the following mapping: (chainID, providerAddr) -> optedInValidator +message OptedInValidator { + // validator address + bytes provider_addr = 1; + // block height at which the validator opted-in + int64 block_height = 2; + // validator voting power at the block it opted-in + int64 power = 3; + // public key used by the validator on the consumer + bytes public_key = 4; +} diff --git a/x/ccv/provider/keeper/distribution_test.go b/x/ccv/provider/keeper/distribution_test.go index b8883177b1..52ac0e0a82 100644 --- a/x/ccv/provider/keeper/distribution_test.go +++ b/x/ccv/provider/keeper/distribution_test.go @@ -38,8 +38,12 @@ func TestComputeConsumerTotalVotingPower(t *testing.T) { keeper.SetOptedIn( ctx, chainID, - types.NewProviderConsAddress(sdk.ConsAddress(val.Address)), - 0, + types.OptedInValidator{ + ProviderAddr: val.Address, + BlockHeight: ctx.BlockHeight(), + Power: val.VotingPower, + PublicKey: val.PubKey.Bytes(), + }, ) validatorsVotes = append( @@ -65,7 +69,6 @@ func TestComputeConsumerTotalVotingPower(t *testing.T) { } func TestIdentifyConsumerChainIDFromIBCPacket(t *testing.T) { - var ( chainID = "consumer" ccvChannel = "channel-0" diff --git a/x/ccv/provider/keeper/keeper.go b/x/ccv/provider/keeper/keeper.go index 42bcb12ace..e6b1c589aa 100644 --- a/x/ccv/provider/keeper/keeper.go +++ b/x/ccv/provider/keeper/keeper.go @@ -1189,16 +1189,15 @@ func (k Keeper) IsOptIn(ctx sdk.Context, chainID string) bool { func (k Keeper) SetOptedIn( ctx sdk.Context, chainID string, - providerAddr types.ProviderConsAddress, - blockHeight uint64, + validator types.OptedInValidator, ) { store := ctx.KVStore(k.storeKey) + bz, err := validator.Marshal() + if err != nil { + panic(fmt.Errorf("failed to marshal OptedInValidator: %w", err)) + } - // validator is considered opted in - blockHeightBytes := make([]byte, 8) - binary.BigEndian.PutUint64(blockHeightBytes, blockHeight) - - store.Set(types.OptedInKey(chainID, providerAddr), blockHeightBytes) + store.Set(types.OptedInKey(chainID, validator.ProviderAddr), bz) } func (k Keeper) DeleteOptedIn( @@ -1207,7 +1206,7 @@ func (k Keeper) DeleteOptedIn( providerAddr types.ProviderConsAddress, ) { store := ctx.KVStore(k.storeKey) - store.Delete(types.OptedInKey(chainID, providerAddr)) + store.Delete(types.OptedInKey(chainID, providerAddr.ToSdkConsAddr())) } func (k Keeper) IsOptedIn( @@ -1216,22 +1215,25 @@ func (k Keeper) IsOptedIn( providerAddr types.ProviderConsAddress, ) bool { store := ctx.KVStore(k.storeKey) - return store.Get(types.OptedInKey(chainID, providerAddr)) != nil + return store.Get(types.OptedInKey(chainID, providerAddr.ToSdkConsAddr())) != nil } -func (k Keeper) GetOptedIn( +// GetAllOptedIn returns all the opted-in validators on chain `chainID` +func (k Keeper) GetAllOptedIn( ctx sdk.Context, - chainID string) (optedInValidators []OptedInValidator) { + chainID string) (optedInValidators []types.OptedInValidator) { store := ctx.KVStore(k.storeKey) key := types.ChainIdWithLenKey(types.OptedInBytePrefix, chainID) iterator := sdk.KVStorePrefixIterator(store, key) defer iterator.Close() for ; iterator.Valid(); iterator.Next() { - optedInValidators = append(optedInValidators, OptedInValidator{ - ProviderAddr: types.NewProviderConsAddress(iterator.Key()[len(key):]), - BlockHeight: binary.BigEndian.Uint64(iterator.Value()), - }) + iterator.Value() + var optedInValidator types.OptedInValidator + if err := optedInValidator.Unmarshal(iterator.Value()); err != nil { + panic(fmt.Errorf("failed to unmarshal OptedInValidator: %w", err)) + } + optedInValidators = append(optedInValidators, optedInValidator) } return optedInValidators @@ -1264,7 +1266,8 @@ func (k Keeper) IsToBeOptedIn( return store.Get(types.ToBeOptedInKey(chainID, providerAddr)) != nil } -func (k Keeper) GetToBeOptedIn( +// GetAllToBeOptedIn returns all the to-be-opted-in validators on chain `chainID` +func (k Keeper) GetAllToBeOptedIn( ctx sdk.Context, chainID string) (addresses []types.ProviderConsAddress) { @@ -1308,7 +1311,8 @@ func (k Keeper) IsToBeOptedOut( return store.Get(types.ToBeOptedOutKey(chainID, providerAddr)) != nil } -func (k Keeper) GetToBeOptedOut( +// GetAllToBeOptedOut returns all the to-be-opted-out validators on chain `chainID` +func (k Keeper) GetAllToBeOptedOut( ctx sdk.Context, chainID string) (addresses []types.ProviderConsAddress) { diff --git a/x/ccv/provider/keeper/keeper_test.go b/x/ccv/provider/keeper/keeper_test.go index 35380a67aa..a231eb4c0c 100644 --- a/x/ccv/provider/keeper/keeper_test.go +++ b/x/ccv/provider/keeper/keeper_test.go @@ -3,7 +3,6 @@ package keeper_test import ( "bytes" "fmt" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" "sort" "testing" "time" @@ -662,39 +661,49 @@ func TestTopN(t *testing.T) { } } -func TestGetOptedIn(t *testing.T) { +func TestGetAllOptedIn(t *testing.T) { providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - expectedOptedInValidators := []keeper.OptedInValidator{ + expectedOptedInValidators := []types.OptedInValidator{ { - ProviderAddr: types.NewProviderConsAddress([]byte("providerAddr1")), + ProviderAddr: []byte("providerAddr1"), BlockHeight: 1, + Power: 2, + PublicKey: []byte{3}, }, { - ProviderAddr: types.NewProviderConsAddress([]byte("providerAddr2")), + ProviderAddr: []byte("providerAddr2"), BlockHeight: 2, + Power: 3, + PublicKey: []byte{4}, }, { - ProviderAddr: types.NewProviderConsAddress([]byte("providerAddr3")), + ProviderAddr: []byte("providerAddr3"), BlockHeight: 3, + Power: 4, + PublicKey: []byte{5}, }, } for _, expectedOptedInValidator := range expectedOptedInValidators { providerKeeper.SetOptedIn(ctx, "chainID", - expectedOptedInValidator.ProviderAddr, expectedOptedInValidator.BlockHeight) + types.OptedInValidator{ + ProviderAddr: expectedOptedInValidator.ProviderAddr, + BlockHeight: expectedOptedInValidator.BlockHeight, + Power: expectedOptedInValidator.Power, + PublicKey: expectedOptedInValidator.PublicKey}) } - actualOptedInValidators := providerKeeper.GetOptedIn(ctx, "chainID") + actualOptedInValidators := providerKeeper.GetAllOptedIn(ctx, "chainID") // sort validators first to be able to compare - sortOptedInValidators := func(optedInValidators []keeper.OptedInValidator) { + sortOptedInValidators := func(optedInValidators []types.OptedInValidator) { sort.Slice(optedInValidators, func(i int, j int) bool { a := optedInValidators[i] b := optedInValidators[j] return a.BlockHeight < b.BlockHeight || - (a.BlockHeight == b.BlockHeight && bytes.Compare(a.ProviderAddr.ToSdkConsAddr(), b.ProviderAddr.ToSdkConsAddr()) < 0) + (a.BlockHeight == b.BlockHeight && bytes.Compare(a.ProviderAddr, b.ProviderAddr) < 0) }) } sortOptedInValidators(expectedOptedInValidators) @@ -707,19 +716,20 @@ func TestOptedIn(t *testing.T) { providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - optedInValidator := keeper.OptedInValidator{ - ProviderAddr: types.NewProviderConsAddress([]byte("providerAddr")), - BlockHeight: 1, + optedInValidator := types.OptedInValidator{ProviderAddr: []byte("providerAddr"), + BlockHeight: 1, + Power: 2, + PublicKey: []byte{3}, } - require.False(t, providerKeeper.IsOptedIn(ctx, "chainID", optedInValidator.ProviderAddr)) - providerKeeper.SetOptedIn(ctx, "chainID", optedInValidator.ProviderAddr, optedInValidator.BlockHeight) - require.True(t, providerKeeper.IsOptedIn(ctx, "chainID", optedInValidator.ProviderAddr)) - providerKeeper.DeleteOptedIn(ctx, "chainID", optedInValidator.ProviderAddr) - require.False(t, providerKeeper.IsOptedIn(ctx, "chainID", optedInValidator.ProviderAddr)) + require.False(t, providerKeeper.IsOptedIn(ctx, "chainID", types.NewProviderConsAddress(optedInValidator.ProviderAddr))) + providerKeeper.SetOptedIn(ctx, "chainID", optedInValidator) + require.True(t, providerKeeper.IsOptedIn(ctx, "chainID", types.NewProviderConsAddress(optedInValidator.ProviderAddr))) + providerKeeper.DeleteOptedIn(ctx, "chainID", types.NewProviderConsAddress(optedInValidator.ProviderAddr)) + require.False(t, providerKeeper.IsOptedIn(ctx, "chainID", types.NewProviderConsAddress(optedInValidator.ProviderAddr))) } -func TestGetToBeOptedIn(t *testing.T) { +func TestGetAllToBeOptedIn(t *testing.T) { providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() @@ -732,7 +742,7 @@ func TestGetToBeOptedIn(t *testing.T) { providerKeeper.SetToBeOptedIn(ctx, "chainID", addr) } - actualAddresses := providerKeeper.GetToBeOptedIn(ctx, "chainID") + actualAddresses := providerKeeper.GetAllToBeOptedIn(ctx, "chainID") // sort addresses first to be able to compare sortAddresses := func(addresses []types.ProviderConsAddress) { @@ -766,7 +776,7 @@ func TestBeOptedIn(t *testing.T) { providerKeeper.SetToBeOptedIn(ctx, "chainID", addr) } - actualAddresses := providerKeeper.GetToBeOptedIn(ctx, "chainID") + actualAddresses := providerKeeper.GetAllToBeOptedIn(ctx, "chainID") // sort addresses first to be able to compare sortAddresses := func(addresses []types.ProviderConsAddress) { @@ -801,7 +811,7 @@ func TestToBeOptedIn(t *testing.T) { require.False(t, providerKeeper.IsToBeOptedIn(ctx, "chainID", providerAddr)) } -func TestGetToBeOptedOut(t *testing.T) { +func TestGetAllToBeOptedOut(t *testing.T) { providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() @@ -814,7 +824,7 @@ func TestGetToBeOptedOut(t *testing.T) { providerKeeper.SetToBeOptedOut(ctx, "chainID", addr) } - actualAddresses := providerKeeper.GetToBeOptedOut(ctx, "chainID") + actualAddresses := providerKeeper.GetAllToBeOptedOut(ctx, "chainID") // sort addresses first to be able to compare sortAddresses := func(addresses []types.ProviderConsAddress) { diff --git a/x/ccv/provider/keeper/partial_set_security.go b/x/ccv/provider/keeper/partial_set_security.go index e1bf9cc14f..bf76e7d7c8 100644 --- a/x/ccv/provider/keeper/partial_set_security.go +++ b/x/ccv/provider/keeper/partial_set_security.go @@ -7,12 +7,6 @@ import ( "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" ) -type OptedInValidator struct { - ProviderAddr types.ProviderConsAddress - // block height the validator opted in at - BlockHeight uint64 -} - func (k Keeper) HandleOptIn(ctx sdk.Context, chainID string, providerAddr types.ProviderConsAddress, consumerKey *string) error { if !k.IsConsumerProposedOrRegistered(ctx, chainID) { return errorsmod.Wrapf( diff --git a/x/ccv/provider/keeper/partial_set_security_test.go b/x/ccv/provider/keeper/partial_set_security_test.go index 4831723bec..1af5f58c7c 100644 --- a/x/ccv/provider/keeper/partial_set_security_test.go +++ b/x/ccv/provider/keeper/partial_set_security_test.go @@ -1,6 +1,8 @@ package keeper_test import ( + "testing" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" sdk "github.com/cosmos/cosmos-sdk/types" @@ -10,7 +12,6 @@ import ( ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" - "testing" ) func TestHandleOptIn(t *testing.T) { @@ -32,7 +33,9 @@ func TestHandleOptIn(t *testing.T) { require.False(t, providerKeeper.IsToBeOptedOut(ctx, "chainID", providerAddr)) // if validator (`providerAddr`) is already opted in, then the validator cannot be opted in - providerKeeper.SetOptedIn(ctx, "chainID", providerAddr, 1) + + providerKeeper.SetOptedIn(ctx, "chainID", + types.OptedInValidator{ProviderAddr: providerAddr.ToSdkConsAddr(), BlockHeight: 1, Power: 1, PublicKey: []byte{1}}) providerKeeper.HandleOptIn(ctx, "chainID", providerAddr, nil) require.False(t, providerKeeper.IsToBeOptedIn(ctx, "chainID", providerAddr)) } diff --git a/x/ccv/provider/types/keys.go b/x/ccv/provider/types/keys.go index b82346b674..e0b25bf9a0 100644 --- a/x/ccv/provider/types/keys.go +++ b/x/ccv/provider/types/keys.go @@ -547,9 +547,9 @@ func TopNKey(chainID string) []byte { } // OptedInKey returns the key of consumer chain `chainID` and validator with `providerAddr` -func OptedInKey(chainID string, providerAddr ProviderConsAddress) []byte { +func OptedInKey(chainID string, providerAddr []byte) []byte { prefix := ChainIdWithLenKey(OptedInBytePrefix, chainID) - return append(prefix, providerAddr.ToSdkConsAddr().Bytes()...) + return append(prefix, providerAddr...) } // ToBeOptedInKey returns the key of consumer chain `chainID` and validator with `providerAddr` diff --git a/x/ccv/provider/types/provider.pb.go b/x/ccv/provider/types/provider.pb.go index dee8a9520a..c2771de119 100644 --- a/x/ccv/provider/types/provider.pb.go +++ b/x/ccv/provider/types/provider.pb.go @@ -1513,6 +1513,80 @@ func (m *ConsumerRewardsAllocation) GetRewards() github_com_cosmos_cosmos_sdk_ty return nil } +// OptedInValidator is used to store a opted-in validator +// to a consumer chain with the following mapping: (chainID, providerAddr) -> optedInValidator +type OptedInValidator struct { + // validator address + ProviderAddr []byte `protobuf:"bytes,1,opt,name=provider_addr,json=providerAddr,proto3" json:"provider_addr,omitempty"` + // block height at which the validator opted-in + BlockHeight int64 `protobuf:"varint,2,opt,name=block_height,json=blockHeight,proto3" json:"block_height,omitempty"` + // validator voting power at the block it opted-in + Power int64 `protobuf:"varint,3,opt,name=power,proto3" json:"power,omitempty"` + // public key used by the validator on the consumer + PublicKey []byte `protobuf:"bytes,4,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` +} + +func (m *OptedInValidator) Reset() { *m = OptedInValidator{} } +func (m *OptedInValidator) String() string { return proto.CompactTextString(m) } +func (*OptedInValidator) ProtoMessage() {} +func (*OptedInValidator) Descriptor() ([]byte, []int) { + return fileDescriptor_f22ec409a72b7b72, []int{24} +} +func (m *OptedInValidator) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *OptedInValidator) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_OptedInValidator.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *OptedInValidator) XXX_Merge(src proto.Message) { + xxx_messageInfo_OptedInValidator.Merge(m, src) +} +func (m *OptedInValidator) XXX_Size() int { + return m.Size() +} +func (m *OptedInValidator) XXX_DiscardUnknown() { + xxx_messageInfo_OptedInValidator.DiscardUnknown(m) +} + +var xxx_messageInfo_OptedInValidator proto.InternalMessageInfo + +func (m *OptedInValidator) GetProviderAddr() []byte { + if m != nil { + return m.ProviderAddr + } + return nil +} + +func (m *OptedInValidator) GetBlockHeight() int64 { + if m != nil { + return m.BlockHeight + } + return 0 +} + +func (m *OptedInValidator) GetPower() int64 { + if m != nil { + return m.Power + } + return 0 +} + +func (m *OptedInValidator) GetPublicKey() []byte { + if m != nil { + return m.PublicKey + } + return nil +} + func init() { proto.RegisterType((*ConsumerAdditionProposal)(nil), "interchain_security.ccv.provider.v1.ConsumerAdditionProposal") proto.RegisterType((*ConsumerRemovalProposal)(nil), "interchain_security.ccv.provider.v1.ConsumerRemovalProposal") @@ -1538,6 +1612,7 @@ func init() { proto.RegisterType((*ConsumerAddrsToPrune)(nil), "interchain_security.ccv.provider.v1.ConsumerAddrsToPrune") proto.RegisterType((*ConsumerValidator)(nil), "interchain_security.ccv.provider.v1.ConsumerValidator") proto.RegisterType((*ConsumerRewardsAllocation)(nil), "interchain_security.ccv.provider.v1.ConsumerRewardsAllocation") + proto.RegisterType((*OptedInValidator)(nil), "interchain_security.ccv.provider.v1.OptedInValidator") } func init() { @@ -1545,123 +1620,126 @@ func init() { } var fileDescriptor_f22ec409a72b7b72 = []byte{ - // 1852 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0x4d, 0x6f, 0x1c, 0xc7, - 0xd1, 0xe6, 0x70, 0x97, 0x1f, 0x5b, 0xcb, 0xcf, 0x21, 0x6d, 0x0d, 0xf5, 0xf2, 0x5d, 0x52, 0xe3, - 0xd8, 0x61, 0xa2, 0x68, 0x26, 0xa4, 0x13, 0x40, 0x10, 0x62, 0x18, 0xe4, 0x52, 0xb6, 0x28, 0xda, - 0x12, 0x3d, 0x64, 0x28, 0x24, 0x39, 0x0c, 0x7a, 0x7b, 0x5a, 0xbb, 0x0d, 0xce, 0x4e, 0x8f, 0xba, - 0x7b, 0x47, 0xde, 0x4b, 0xce, 0xb9, 0x04, 0x70, 0x6e, 0x46, 0x2e, 0x71, 0x02, 0x04, 0x08, 0x72, - 0x49, 0x7e, 0x86, 0x8f, 0x3e, 0xe6, 0x64, 0x07, 0xd2, 0x21, 0x87, 0x5c, 0xf3, 0x03, 0x82, 0xee, - 0xf9, 0xdc, 0x25, 0xa9, 0xac, 0xe0, 0xe4, 0x42, 0xce, 0x54, 0x57, 0x3d, 0x55, 0xdd, 0x55, 0xf5, - 0x54, 0xef, 0xc0, 0x1e, 0x8d, 0x24, 0xe1, 0xb8, 0x87, 0x68, 0xe4, 0x0b, 0x82, 0x07, 0x9c, 0xca, - 0xa1, 0x8b, 0x71, 0xe2, 0xc6, 0x9c, 0x25, 0x34, 0x20, 0xdc, 0x4d, 0x76, 0x8b, 0x67, 0x27, 0xe6, - 0x4c, 0x32, 0xf3, 0xad, 0x2b, 0x6c, 0x1c, 0x8c, 0x13, 0xa7, 0xd0, 0x4b, 0x76, 0x6f, 0xbe, 0x7d, - 0x1d, 0x70, 0xb2, 0xeb, 0x3e, 0xa7, 0x9c, 0xa4, 0x58, 0x37, 0xd7, 0xbb, 0xac, 0xcb, 0xf4, 0xa3, - 0xab, 0x9e, 0x32, 0xe9, 0x56, 0x97, 0xb1, 0x6e, 0x48, 0x5c, 0xfd, 0xd6, 0x19, 0x3c, 0x75, 0x25, - 0xed, 0x13, 0x21, 0x51, 0x3f, 0xce, 0x14, 0x5a, 0xe3, 0x0a, 0xc1, 0x80, 0x23, 0x49, 0x59, 0x94, - 0x03, 0xd0, 0x0e, 0x76, 0x31, 0xe3, 0xc4, 0xc5, 0x21, 0x25, 0x91, 0x54, 0x5e, 0xd3, 0xa7, 0x4c, - 0xc1, 0x55, 0x0a, 0x21, 0xed, 0xf6, 0x64, 0x2a, 0x16, 0xae, 0x24, 0x51, 0x40, 0x78, 0x9f, 0xa6, - 0xca, 0xe5, 0x5b, 0x66, 0xb0, 0x59, 0x59, 0xc7, 0x7c, 0x18, 0x4b, 0xe6, 0x5e, 0x90, 0xa1, 0xc8, - 0x56, 0xdf, 0xc1, 0x4c, 0xf4, 0x99, 0x70, 0x89, 0xda, 0x7f, 0x84, 0x89, 0x9b, 0xec, 0x76, 0x88, - 0x44, 0xbb, 0x85, 0x20, 0x8f, 0x3b, 0xd3, 0xeb, 0x20, 0x51, 0xea, 0x60, 0x46, 0xf3, 0xb8, 0x57, - 0x51, 0x9f, 0x46, 0xcc, 0xd5, 0x7f, 0x53, 0x91, 0xfd, 0xaf, 0x59, 0xb0, 0xda, 0x2c, 0x12, 0x83, - 0x3e, 0xe1, 0xfb, 0x41, 0x40, 0xd5, 0x2e, 0x4f, 0x38, 0x8b, 0x99, 0x40, 0xa1, 0xb9, 0x0e, 0x33, - 0x92, 0xca, 0x90, 0x58, 0xc6, 0xb6, 0xb1, 0xd3, 0xf0, 0xd2, 0x17, 0x73, 0x1b, 0x9a, 0x01, 0x11, - 0x98, 0xd3, 0x58, 0x29, 0x5b, 0xd3, 0x7a, 0xad, 0x2a, 0x32, 0x37, 0x60, 0x3e, 0x4d, 0x0d, 0x0d, - 0xac, 0x9a, 0x5e, 0x9e, 0xd3, 0xef, 0x47, 0x81, 0xf9, 0x21, 0x2c, 0xd1, 0x88, 0x4a, 0x8a, 0x42, - 0xbf, 0x47, 0xd4, 0x01, 0x59, 0xf5, 0x6d, 0x63, 0xa7, 0xb9, 0x77, 0xd3, 0xa1, 0x1d, 0xec, 0xa8, - 0x33, 0x75, 0xb2, 0x93, 0x4c, 0x76, 0x9d, 0x07, 0x5a, 0xe3, 0xa0, 0xfe, 0xe5, 0xd7, 0x5b, 0x53, - 0xde, 0x62, 0x66, 0x97, 0x0a, 0xcd, 0x5b, 0xb0, 0xd0, 0x25, 0x11, 0x11, 0x54, 0xf8, 0x3d, 0x24, - 0x7a, 0xd6, 0xcc, 0xb6, 0xb1, 0xb3, 0xe0, 0x35, 0x33, 0xd9, 0x03, 0x24, 0x7a, 0xe6, 0x16, 0x34, - 0x3b, 0x34, 0x42, 0x7c, 0x98, 0x6a, 0xcc, 0x6a, 0x0d, 0x48, 0x45, 0x5a, 0xa1, 0x0d, 0x20, 0x62, - 0xf4, 0x3c, 0xf2, 0x55, 0x01, 0x58, 0x73, 0x59, 0x20, 0x69, 0xf2, 0x9d, 0x3c, 0xf9, 0xce, 0x59, - 0x5e, 0x1d, 0x07, 0xf3, 0x2a, 0x90, 0xcf, 0xbe, 0xd9, 0x32, 0xbc, 0x86, 0xb6, 0x53, 0x2b, 0xe6, - 0x23, 0x58, 0x19, 0x44, 0x1d, 0x16, 0x05, 0x34, 0xea, 0xfa, 0x31, 0xe1, 0x94, 0x05, 0xd6, 0xbc, - 0x86, 0xda, 0xb8, 0x04, 0x75, 0x98, 0xd5, 0x51, 0x8a, 0xf4, 0xb9, 0x42, 0x5a, 0x2e, 0x8c, 0x4f, - 0xb4, 0xad, 0xf9, 0x09, 0x98, 0x18, 0x27, 0x3a, 0x24, 0x36, 0x90, 0x39, 0x62, 0x63, 0x72, 0xc4, - 0x15, 0x8c, 0x93, 0xb3, 0xd4, 0x3a, 0x83, 0xfc, 0x05, 0xdc, 0x90, 0x1c, 0x45, 0xe2, 0x29, 0xe1, - 0xe3, 0xb8, 0x30, 0x39, 0xee, 0x1b, 0x39, 0xc6, 0x28, 0xf8, 0x03, 0xd8, 0xc6, 0x59, 0x01, 0xf9, - 0x9c, 0x04, 0x54, 0x48, 0x4e, 0x3b, 0x03, 0x65, 0xeb, 0x3f, 0xe5, 0x08, 0xeb, 0x1a, 0x69, 0xea, - 0x22, 0x68, 0xe5, 0x7a, 0xde, 0x88, 0xda, 0x07, 0x99, 0x96, 0xf9, 0x18, 0xbe, 0xd3, 0x09, 0x19, - 0xbe, 0x10, 0x2a, 0x38, 0x7f, 0x04, 0x49, 0xbb, 0xee, 0x53, 0x21, 0x14, 0xda, 0xc2, 0xb6, 0xb1, - 0x53, 0xf3, 0x6e, 0xa5, 0xba, 0x27, 0x84, 0x1f, 0x56, 0x34, 0xcf, 0x2a, 0x8a, 0xe6, 0x1d, 0x30, - 0x7b, 0x54, 0x48, 0xc6, 0x29, 0x46, 0xa1, 0x4f, 0x22, 0xc9, 0x29, 0x11, 0xd6, 0xa2, 0x36, 0x5f, - 0x2d, 0x57, 0xee, 0xa7, 0x0b, 0xe6, 0x43, 0xb8, 0x75, 0xad, 0x53, 0x1f, 0xf7, 0x50, 0x14, 0x91, - 0xd0, 0x5a, 0xd2, 0x5b, 0xd9, 0x0a, 0xae, 0xf1, 0xd9, 0x4e, 0xd5, 0xcc, 0x35, 0x98, 0x91, 0x2c, - 0xf6, 0x1f, 0x59, 0xcb, 0xdb, 0xc6, 0xce, 0xa2, 0x57, 0x97, 0x2c, 0x7e, 0x74, 0x6f, 0xfe, 0x57, - 0x5f, 0x6c, 0x4d, 0x7d, 0xfe, 0xc5, 0xd6, 0x94, 0xfd, 0x17, 0x03, 0x6e, 0xb4, 0x8b, 0xd3, 0xe8, - 0xb3, 0x04, 0x85, 0xff, 0xcb, 0xae, 0xdb, 0x87, 0x86, 0x50, 0xe1, 0xe8, 0x3a, 0xaf, 0xbf, 0x46, - 0x9d, 0xcf, 0x2b, 0x33, 0xb5, 0x60, 0xff, 0xce, 0x80, 0xf5, 0xfb, 0xcf, 0x06, 0x34, 0x61, 0x18, - 0xfd, 0x57, 0x48, 0xe2, 0x18, 0x16, 0x49, 0x05, 0x4f, 0x58, 0xb5, 0xed, 0xda, 0x4e, 0x73, 0xef, - 0x6d, 0x27, 0x25, 0x31, 0xa7, 0xe0, 0xb6, 0x8c, 0xc8, 0x9c, 0xaa, 0x77, 0x6f, 0xd4, 0xf6, 0xde, - 0xb4, 0x65, 0xd8, 0x7f, 0x30, 0xe0, 0xa6, 0x3a, 0xfe, 0x2e, 0xf1, 0xc8, 0x73, 0xc4, 0x83, 0x43, - 0x12, 0xb1, 0xbe, 0xf8, 0xd6, 0x71, 0xda, 0xb0, 0x18, 0x68, 0x24, 0x5f, 0x32, 0x1f, 0x05, 0x81, - 0x8e, 0x53, 0xeb, 0x28, 0xe1, 0x19, 0xdb, 0x0f, 0x02, 0x73, 0x07, 0x56, 0x4a, 0x1d, 0xae, 0xf2, - 0xa9, 0x8e, 0x59, 0xa9, 0x2d, 0xe5, 0x6a, 0x3a, 0xcb, 0xc4, 0xfe, 0xa7, 0x01, 0x2b, 0x1f, 0x86, - 0xac, 0x83, 0xc2, 0xd3, 0x10, 0x89, 0x9e, 0x2a, 0xbd, 0xa1, 0x4a, 0x0f, 0x27, 0x59, 0xcf, 0xeb, - 0xf0, 0x26, 0x4e, 0x8f, 0x32, 0xd3, 0x2c, 0xf4, 0x3e, 0xac, 0x16, 0x5d, 0x58, 0x54, 0x81, 0xde, - 0xcd, 0xc1, 0xda, 0x8b, 0xaf, 0xb7, 0x96, 0xf3, 0x62, 0x6b, 0xeb, 0x8a, 0x38, 0xf4, 0x96, 0xf1, - 0x88, 0x20, 0x30, 0x5b, 0xd0, 0xa4, 0x1d, 0xec, 0x0b, 0xf2, 0xcc, 0x8f, 0x06, 0x7d, 0x5d, 0x40, - 0x75, 0xaf, 0x41, 0x3b, 0xf8, 0x94, 0x3c, 0x7b, 0x34, 0xe8, 0x9b, 0xef, 0xc2, 0x9b, 0xf9, 0x00, - 0xf6, 0x13, 0x14, 0xfa, 0xca, 0x5e, 0x1d, 0x07, 0xd7, 0xf5, 0xb4, 0xe0, 0xad, 0xe5, 0xab, 0xe7, - 0x28, 0x54, 0xce, 0xf6, 0x83, 0x80, 0xdb, 0x2f, 0x67, 0x60, 0xf6, 0x04, 0x71, 0xd4, 0x17, 0xe6, - 0x19, 0x2c, 0x4b, 0xd2, 0x8f, 0x43, 0x24, 0x89, 0x9f, 0x32, 0x7c, 0xb6, 0xd3, 0xdb, 0x9a, 0xf9, - 0xab, 0xc3, 0xd2, 0xa9, 0x8c, 0xc7, 0x64, 0xd7, 0x69, 0x6b, 0xe9, 0xa9, 0x44, 0x92, 0x78, 0x4b, - 0x39, 0x46, 0x2a, 0x34, 0xef, 0x82, 0x25, 0xf9, 0x40, 0xc8, 0x92, 0x7b, 0x4b, 0xd2, 0x49, 0x73, - 0xf9, 0x66, 0xbe, 0x9e, 0xd2, 0x55, 0x41, 0x36, 0x57, 0xd3, 0x6c, 0xed, 0xdb, 0xd0, 0xec, 0x29, - 0xac, 0xa9, 0x19, 0x35, 0x8e, 0x59, 0x9f, 0x1c, 0x73, 0x55, 0xd9, 0x8f, 0x82, 0x7e, 0x02, 0x66, - 0x22, 0xf0, 0x38, 0xe6, 0xcc, 0x6b, 0xc4, 0x99, 0x08, 0x3c, 0x0a, 0x19, 0xc0, 0xa6, 0x50, 0xc5, - 0xe7, 0xf7, 0x89, 0xd4, 0xa4, 0x1d, 0x87, 0x24, 0xa2, 0xa2, 0x97, 0x83, 0xcf, 0x4e, 0x0e, 0xbe, - 0xa1, 0x81, 0x3e, 0x56, 0x38, 0x5e, 0x0e, 0x93, 0x79, 0x69, 0x43, 0xeb, 0x6a, 0x2f, 0x45, 0x82, - 0xe6, 0x74, 0x82, 0xfe, 0xef, 0x0a, 0x88, 0x22, 0x4b, 0x02, 0xde, 0xa9, 0x0c, 0x17, 0xd5, 0xd5, - 0xbe, 0x6e, 0x28, 0x9f, 0x93, 0xae, 0x62, 0x60, 0x94, 0xce, 0x19, 0x42, 0x8a, 0x01, 0x99, 0xb1, - 0x87, 0xba, 0x02, 0x15, 0xcc, 0xd1, 0x66, 0x34, 0xca, 0x6e, 0x11, 0x76, 0x39, 0x83, 0x0a, 0x8e, - 0xf0, 0x2a, 0x58, 0x1f, 0x10, 0xa2, 0xba, 0xb9, 0x32, 0x87, 0x48, 0xcc, 0x70, 0x4f, 0xcf, 0xc9, - 0x9a, 0xb7, 0x54, 0xcc, 0x9c, 0xfb, 0x4a, 0xfa, 0xb0, 0x3e, 0x3f, 0xbf, 0xd2, 0xb0, 0xbf, 0x07, - 0x0d, 0xdd, 0xcc, 0xfb, 0xf8, 0x42, 0x98, 0x9b, 0xd0, 0x50, 0x5d, 0x41, 0x84, 0x20, 0xc2, 0x32, - 0x34, 0x07, 0x94, 0x02, 0x5b, 0xc2, 0xc6, 0x75, 0xb7, 0x2d, 0x61, 0x3e, 0x81, 0xb9, 0x98, 0xe8, - 0xab, 0x80, 0x36, 0x6c, 0xee, 0xbd, 0xe7, 0x4c, 0x70, 0x17, 0x76, 0xae, 0x03, 0xf4, 0x72, 0x34, - 0x9b, 0x97, 0x77, 0xbc, 0xb1, 0x61, 0x23, 0xcc, 0xf3, 0x71, 0xa7, 0x3f, 0x79, 0x2d, 0xa7, 0x63, - 0x78, 0xa5, 0xcf, 0xdb, 0xd0, 0xdc, 0x4f, 0xb7, 0xfd, 0x11, 0x15, 0xf2, 0xf2, 0xb1, 0x2c, 0x54, - 0x8f, 0xe5, 0x21, 0x2c, 0x65, 0x83, 0xf3, 0x8c, 0x69, 0x42, 0x32, 0xff, 0x1f, 0x20, 0x9b, 0xb8, - 0x8a, 0xc8, 0x52, 0xca, 0x6e, 0x64, 0x92, 0xa3, 0x60, 0x64, 0xd6, 0x4d, 0x8f, 0xcc, 0x3a, 0xdb, - 0x83, 0xe5, 0x73, 0x81, 0x7f, 0x9a, 0xdf, 0xaa, 0x1e, 0xc7, 0xc2, 0x7c, 0x03, 0x66, 0x55, 0x0f, - 0x65, 0x40, 0x75, 0x6f, 0x26, 0x11, 0xf8, 0x48, 0xb3, 0x76, 0x79, 0x73, 0x63, 0xb1, 0x4f, 0x03, - 0x61, 0x4d, 0x6f, 0xd7, 0x76, 0xea, 0xde, 0xd2, 0xa0, 0x34, 0x3f, 0x0a, 0x84, 0xfd, 0x33, 0x68, - 0x56, 0x00, 0xcd, 0x25, 0x98, 0x2e, 0xb0, 0xa6, 0x69, 0x60, 0xde, 0x83, 0x8d, 0x12, 0x68, 0x94, - 0x86, 0x53, 0xc4, 0x86, 0x77, 0xa3, 0x50, 0x18, 0x61, 0x62, 0x61, 0x3f, 0x86, 0xf5, 0xa3, 0xb2, - 0xe9, 0x0b, 0x92, 0x1f, 0xd9, 0xa1, 0x31, 0x3a, 0xcd, 0x37, 0xa1, 0x51, 0xfc, 0x62, 0xd1, 0xbb, - 0xaf, 0x7b, 0xa5, 0xc0, 0xee, 0xc3, 0xca, 0xb9, 0xc0, 0xa7, 0x24, 0x0a, 0x4a, 0xb0, 0x6b, 0x0e, - 0xe0, 0x60, 0x1c, 0x68, 0xe2, 0xeb, 0x6f, 0xe9, 0x8e, 0xc1, 0xc6, 0x39, 0x0a, 0x69, 0x80, 0x24, - 0xe3, 0xa7, 0x44, 0xa6, 0x03, 0xf8, 0x04, 0xe1, 0x0b, 0x22, 0x85, 0xe9, 0x41, 0x3d, 0xa4, 0x42, - 0x66, 0x95, 0x75, 0xf7, 0xda, 0xca, 0x4a, 0x76, 0x9d, 0xeb, 0x40, 0x0e, 0x91, 0x44, 0x59, 0xef, - 0x6a, 0x2c, 0xfb, 0xbb, 0xb0, 0xf6, 0x31, 0x92, 0x03, 0x4e, 0x82, 0x91, 0x1c, 0xaf, 0x40, 0x4d, - 0xe5, 0xcf, 0xd0, 0xf9, 0x53, 0x8f, 0xea, 0x3e, 0x60, 0xdd, 0xff, 0x34, 0x66, 0x5c, 0x92, 0xe0, - 0xd2, 0x89, 0xbc, 0xe2, 0x78, 0x2f, 0x60, 0x4d, 0x1d, 0x96, 0x20, 0x51, 0xe0, 0x17, 0xfb, 0x4c, - 0xf3, 0xd8, 0xdc, 0xfb, 0xf1, 0x44, 0xdd, 0x31, 0xee, 0x2e, 0xdb, 0xc0, 0x6a, 0x32, 0x26, 0x17, - 0xf6, 0x6f, 0x0c, 0xb0, 0x8e, 0xc9, 0x70, 0x5f, 0x08, 0xda, 0x8d, 0xfa, 0x24, 0x92, 0x8a, 0x03, - 0x11, 0x26, 0xea, 0xd1, 0x7c, 0x0b, 0x16, 0x8b, 0x99, 0xab, 0x47, 0xad, 0xa1, 0x47, 0xed, 0x42, - 0x2e, 0x54, 0x0d, 0x66, 0xde, 0x03, 0x88, 0x39, 0x49, 0x7c, 0xec, 0x5f, 0x90, 0x61, 0x96, 0xc5, - 0xcd, 0xea, 0x08, 0x4d, 0x7f, 0x4f, 0x3a, 0x27, 0x83, 0x4e, 0x48, 0xf1, 0x31, 0x19, 0x7a, 0xf3, - 0x4a, 0xbf, 0x7d, 0x4c, 0x86, 0xea, 0x4e, 0x14, 0xb3, 0xe7, 0x84, 0xeb, 0xb9, 0x57, 0xf3, 0xd2, - 0x17, 0xfb, 0xb7, 0x06, 0xdc, 0x28, 0xd2, 0x91, 0x97, 0xeb, 0xc9, 0xa0, 0xa3, 0x2c, 0x5e, 0x71, - 0x6e, 0x97, 0xa2, 0x9d, 0xbe, 0x22, 0xda, 0xf7, 0x61, 0xa1, 0x68, 0x10, 0x15, 0x6f, 0x6d, 0x82, - 0x78, 0x9b, 0xb9, 0xc5, 0x31, 0x19, 0xda, 0xbf, 0xac, 0xc4, 0x76, 0x30, 0xac, 0x70, 0x1f, 0xff, - 0x0f, 0xb1, 0x15, 0x6e, 0xab, 0xb1, 0xe1, 0xaa, 0xfd, 0xa5, 0x0d, 0xd4, 0x2e, 0x6f, 0xc0, 0xfe, - 0xbd, 0x01, 0xeb, 0x55, 0xaf, 0xe2, 0x8c, 0x9d, 0xf0, 0x41, 0x44, 0x5e, 0xe5, 0xbd, 0x6c, 0xbf, - 0xe9, 0x6a, 0xfb, 0x3d, 0x81, 0xa5, 0x91, 0xa0, 0x44, 0x76, 0x1a, 0x3f, 0x9c, 0xa8, 0xc6, 0x2a, - 0xec, 0xea, 0x2d, 0x56, 0xf7, 0x21, 0xec, 0x3f, 0x1a, 0xb0, 0x9a, 0xc7, 0x58, 0x1c, 0x96, 0xf9, - 0x03, 0x30, 0x8b, 0xed, 0x95, 0xb7, 0xb7, 0xb4, 0xa4, 0x56, 0xf2, 0x95, 0xfc, 0xea, 0x56, 0x96, - 0xc6, 0x74, 0xa5, 0x34, 0xcc, 0x8f, 0x60, 0xad, 0x08, 0x39, 0xd6, 0x09, 0x9a, 0x38, 0x8b, 0xc5, - 0xfd, 0xb4, 0x10, 0xd9, 0xbf, 0x36, 0xca, 0x71, 0x98, 0xce, 0x63, 0xb1, 0x1f, 0x86, 0xd9, 0xa5, - 0xde, 0x8c, 0x61, 0x2e, 0x1d, 0xf9, 0x22, 0xe3, 0x8f, 0xcd, 0x2b, 0x87, 0xfb, 0x21, 0xc1, 0x7a, - 0xbe, 0xdf, 0x55, 0x2d, 0xf6, 0xe7, 0x6f, 0xb6, 0x6e, 0x77, 0xa9, 0xec, 0x0d, 0x3a, 0x0e, 0x66, - 0x7d, 0x37, 0xfb, 0x1e, 0x92, 0xfe, 0xbb, 0x23, 0x82, 0x0b, 0x57, 0x0e, 0x63, 0x22, 0x72, 0x1b, - 0xf1, 0xa7, 0x7f, 0xfc, 0xf5, 0xfb, 0x86, 0x97, 0xbb, 0x39, 0x78, 0xf2, 0xe5, 0x8b, 0x96, 0xf1, - 0xd5, 0x8b, 0x96, 0xf1, 0xf7, 0x17, 0x2d, 0xe3, 0xb3, 0x97, 0xad, 0xa9, 0xaf, 0x5e, 0xb6, 0xa6, - 0xfe, 0xf6, 0xb2, 0x35, 0xf5, 0xf3, 0xf7, 0x2e, 0x83, 0x96, 0x39, 0xba, 0x53, 0x7c, 0x81, 0x4a, - 0x7e, 0xe4, 0x7e, 0x3a, 0xfa, 0x7d, 0x4b, 0xfb, 0xeb, 0xcc, 0x6a, 0x36, 0x7d, 0xf7, 0xdf, 0x01, - 0x00, 0x00, 0xff, 0xff, 0x8f, 0xff, 0x87, 0xe4, 0x10, 0x13, 0x00, 0x00, + // 1892 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0xcd, 0x73, 0x1c, 0x47, + 0x15, 0xd7, 0x68, 0x57, 0x1f, 0xfb, 0x56, 0x9f, 0x23, 0x25, 0x1e, 0x19, 0xb1, 0x92, 0x27, 0x24, + 0x08, 0x82, 0x67, 0x90, 0x02, 0x55, 0x2e, 0x17, 0xa9, 0x94, 0xb4, 0x72, 0x62, 0x59, 0x89, 0xad, + 0x8c, 0x84, 0x5c, 0xc0, 0x61, 0xaa, 0xb7, 0xa7, 0xbd, 0xdb, 0xa5, 0xd9, 0xe9, 0x71, 0x77, 0xef, + 0x38, 0x7b, 0xe1, 0xcc, 0x85, 0x22, 0xdc, 0x52, 0x5c, 0x08, 0x54, 0x51, 0x45, 0x71, 0x81, 0x3f, + 0x23, 0xc7, 0x1c, 0x39, 0x25, 0x94, 0x7d, 0xe0, 0xc0, 0x95, 0x3f, 0x80, 0xea, 0x9e, 0xcf, 0x5d, + 0x49, 0x66, 0x5d, 0x81, 0x8b, 0x34, 0xf3, 0xfa, 0xbd, 0xdf, 0x7b, 0xfd, 0xbe, 0x77, 0x60, 0x8f, + 0x46, 0x92, 0x70, 0xdc, 0x43, 0x34, 0xf2, 0x05, 0xc1, 0x03, 0x4e, 0xe5, 0xd0, 0xc5, 0x38, 0x71, + 0x63, 0xce, 0x12, 0x1a, 0x10, 0xee, 0x26, 0xbb, 0xc5, 0xb3, 0x13, 0x73, 0x26, 0x99, 0xf9, 0xc6, + 0x15, 0x32, 0x0e, 0xc6, 0x89, 0x53, 0xf0, 0x25, 0xbb, 0x37, 0xdf, 0xbc, 0x0e, 0x38, 0xd9, 0x75, + 0x9f, 0x51, 0x4e, 0x52, 0xac, 0x9b, 0xeb, 0x5d, 0xd6, 0x65, 0xfa, 0xd1, 0x55, 0x4f, 0x19, 0x75, + 0xab, 0xcb, 0x58, 0x37, 0x24, 0xae, 0x7e, 0xeb, 0x0c, 0x9e, 0xb8, 0x92, 0xf6, 0x89, 0x90, 0xa8, + 0x1f, 0x67, 0x0c, 0xad, 0x71, 0x86, 0x60, 0xc0, 0x91, 0xa4, 0x2c, 0xca, 0x01, 0x68, 0x07, 0xbb, + 0x98, 0x71, 0xe2, 0xe2, 0x90, 0x92, 0x48, 0x2a, 0xad, 0xe9, 0x53, 0xc6, 0xe0, 0x2a, 0x86, 0x90, + 0x76, 0x7b, 0x32, 0x25, 0x0b, 0x57, 0x92, 0x28, 0x20, 0xbc, 0x4f, 0x53, 0xe6, 0xf2, 0x2d, 0x13, + 0xd8, 0xac, 0x9c, 0x63, 0x3e, 0x8c, 0x25, 0x73, 0x2f, 0xc8, 0x50, 0x64, 0xa7, 0x6f, 0x61, 0x26, + 0xfa, 0x4c, 0xb8, 0x44, 0xdd, 0x3f, 0xc2, 0xc4, 0x4d, 0x76, 0x3b, 0x44, 0xa2, 0xdd, 0x82, 0x90, + 0xdb, 0x9d, 0xf1, 0x75, 0x90, 0x28, 0x79, 0x30, 0xa3, 0xb9, 0xdd, 0xab, 0xa8, 0x4f, 0x23, 0xe6, + 0xea, 0xbf, 0x29, 0xc9, 0xfe, 0xf7, 0x2c, 0x58, 0x6d, 0x16, 0x89, 0x41, 0x9f, 0xf0, 0xfd, 0x20, + 0xa0, 0xea, 0x96, 0x27, 0x9c, 0xc5, 0x4c, 0xa0, 0xd0, 0x5c, 0x87, 0x19, 0x49, 0x65, 0x48, 0x2c, + 0x63, 0xdb, 0xd8, 0x69, 0x78, 0xe9, 0x8b, 0xb9, 0x0d, 0xcd, 0x80, 0x08, 0xcc, 0x69, 0xac, 0x98, + 0xad, 0x69, 0x7d, 0x56, 0x25, 0x99, 0x1b, 0x30, 0x9f, 0x86, 0x86, 0x06, 0x56, 0x4d, 0x1f, 0xcf, + 0xe9, 0xf7, 0xa3, 0xc0, 0xfc, 0x00, 0x96, 0x68, 0x44, 0x25, 0x45, 0xa1, 0xdf, 0x23, 0xca, 0x41, + 0x56, 0x7d, 0xdb, 0xd8, 0x69, 0xee, 0xdd, 0x74, 0x68, 0x07, 0x3b, 0xca, 0xa7, 0x4e, 0xe6, 0xc9, + 0x64, 0xd7, 0xb9, 0xaf, 0x39, 0x0e, 0xea, 0x5f, 0x7c, 0xb5, 0x35, 0xe5, 0x2d, 0x66, 0x72, 0x29, + 0xd1, 0xbc, 0x05, 0x0b, 0x5d, 0x12, 0x11, 0x41, 0x85, 0xdf, 0x43, 0xa2, 0x67, 0xcd, 0x6c, 0x1b, + 0x3b, 0x0b, 0x5e, 0x33, 0xa3, 0xdd, 0x47, 0xa2, 0x67, 0x6e, 0x41, 0xb3, 0x43, 0x23, 0xc4, 0x87, + 0x29, 0xc7, 0xac, 0xe6, 0x80, 0x94, 0xa4, 0x19, 0xda, 0x00, 0x22, 0x46, 0xcf, 0x22, 0x5f, 0x25, + 0x80, 0x35, 0x97, 0x19, 0x92, 0x06, 0xdf, 0xc9, 0x83, 0xef, 0x9c, 0xe5, 0xd9, 0x71, 0x30, 0xaf, + 0x0c, 0xf9, 0xf4, 0xeb, 0x2d, 0xc3, 0x6b, 0x68, 0x39, 0x75, 0x62, 0x3e, 0x84, 0x95, 0x41, 0xd4, + 0x61, 0x51, 0x40, 0xa3, 0xae, 0x1f, 0x13, 0x4e, 0x59, 0x60, 0xcd, 0x6b, 0xa8, 0x8d, 0x4b, 0x50, + 0x87, 0x59, 0x1e, 0xa5, 0x48, 0x9f, 0x29, 0xa4, 0xe5, 0x42, 0xf8, 0x44, 0xcb, 0x9a, 0x1f, 0x83, + 0x89, 0x71, 0xa2, 0x4d, 0x62, 0x03, 0x99, 0x23, 0x36, 0x26, 0x47, 0x5c, 0xc1, 0x38, 0x39, 0x4b, + 0xa5, 0x33, 0xc8, 0x5f, 0xc0, 0x0d, 0xc9, 0x51, 0x24, 0x9e, 0x10, 0x3e, 0x8e, 0x0b, 0x93, 0xe3, + 0xbe, 0x96, 0x63, 0x8c, 0x82, 0xdf, 0x87, 0x6d, 0x9c, 0x25, 0x90, 0xcf, 0x49, 0x40, 0x85, 0xe4, + 0xb4, 0x33, 0x50, 0xb2, 0xfe, 0x13, 0x8e, 0xb0, 0xce, 0x91, 0xa6, 0x4e, 0x82, 0x56, 0xce, 0xe7, + 0x8d, 0xb0, 0xbd, 0x9f, 0x71, 0x99, 0x8f, 0xe0, 0x3b, 0x9d, 0x90, 0xe1, 0x0b, 0xa1, 0x8c, 0xf3, + 0x47, 0x90, 0xb4, 0xea, 0x3e, 0x15, 0x42, 0xa1, 0x2d, 0x6c, 0x1b, 0x3b, 0x35, 0xef, 0x56, 0xca, + 0x7b, 0x42, 0xf8, 0x61, 0x85, 0xf3, 0xac, 0xc2, 0x68, 0xde, 0x06, 0xb3, 0x47, 0x85, 0x64, 0x9c, + 0x62, 0x14, 0xfa, 0x24, 0x92, 0x9c, 0x12, 0x61, 0x2d, 0x6a, 0xf1, 0xd5, 0xf2, 0xe4, 0x5e, 0x7a, + 0x60, 0x3e, 0x80, 0x5b, 0xd7, 0x2a, 0xf5, 0x71, 0x0f, 0x45, 0x11, 0x09, 0xad, 0x25, 0x7d, 0x95, + 0xad, 0xe0, 0x1a, 0x9d, 0xed, 0x94, 0xcd, 0x5c, 0x83, 0x19, 0xc9, 0x62, 0xff, 0xa1, 0xb5, 0xbc, + 0x6d, 0xec, 0x2c, 0x7a, 0x75, 0xc9, 0xe2, 0x87, 0x77, 0xe7, 0x7f, 0xf5, 0xf9, 0xd6, 0xd4, 0x67, + 0x9f, 0x6f, 0x4d, 0xd9, 0x7f, 0x35, 0xe0, 0x46, 0xbb, 0xf0, 0x46, 0x9f, 0x25, 0x28, 0xfc, 0x7f, + 0x56, 0xdd, 0x3e, 0x34, 0x84, 0x32, 0x47, 0xe7, 0x79, 0xfd, 0x15, 0xf2, 0x7c, 0x5e, 0x89, 0xa9, + 0x03, 0xfb, 0xf7, 0x06, 0xac, 0xdf, 0x7b, 0x3a, 0xa0, 0x09, 0xc3, 0xe8, 0x7f, 0xd2, 0x24, 0x8e, + 0x61, 0x91, 0x54, 0xf0, 0x84, 0x55, 0xdb, 0xae, 0xed, 0x34, 0xf7, 0xde, 0x74, 0xd2, 0x26, 0xe6, + 0x14, 0xbd, 0x2d, 0x6b, 0x64, 0x4e, 0x55, 0xbb, 0x37, 0x2a, 0x7b, 0x77, 0xda, 0x32, 0xec, 0x3f, + 0x1a, 0x70, 0x53, 0xb9, 0xbf, 0x4b, 0x3c, 0xf2, 0x0c, 0xf1, 0xe0, 0x90, 0x44, 0xac, 0x2f, 0xbe, + 0xb1, 0x9d, 0x36, 0x2c, 0x06, 0x1a, 0xc9, 0x97, 0xcc, 0x47, 0x41, 0xa0, 0xed, 0xd4, 0x3c, 0x8a, + 0x78, 0xc6, 0xf6, 0x83, 0xc0, 0xdc, 0x81, 0x95, 0x92, 0x87, 0xab, 0x78, 0x2a, 0x37, 0x2b, 0xb6, + 0xa5, 0x9c, 0x4d, 0x47, 0x99, 0xd8, 0xff, 0x32, 0x60, 0xe5, 0x83, 0x90, 0x75, 0x50, 0x78, 0x1a, + 0x22, 0xd1, 0x53, 0xa9, 0x37, 0x54, 0xe1, 0xe1, 0x24, 0xab, 0x79, 0x6d, 0xde, 0xc4, 0xe1, 0x51, + 0x62, 0xba, 0x0b, 0xbd, 0x07, 0xab, 0x45, 0x15, 0x16, 0x59, 0xa0, 0x6f, 0x73, 0xb0, 0xf6, 0xfc, + 0xab, 0xad, 0xe5, 0x3c, 0xd9, 0xda, 0x3a, 0x23, 0x0e, 0xbd, 0x65, 0x3c, 0x42, 0x08, 0xcc, 0x16, + 0x34, 0x69, 0x07, 0xfb, 0x82, 0x3c, 0xf5, 0xa3, 0x41, 0x5f, 0x27, 0x50, 0xdd, 0x6b, 0xd0, 0x0e, + 0x3e, 0x25, 0x4f, 0x1f, 0x0e, 0xfa, 0xe6, 0x3b, 0xf0, 0x7a, 0x3e, 0x80, 0xfd, 0x04, 0x85, 0xbe, + 0x92, 0x57, 0xee, 0xe0, 0x3a, 0x9f, 0x16, 0xbc, 0xb5, 0xfc, 0xf4, 0x1c, 0x85, 0x4a, 0xd9, 0x7e, + 0x10, 0x70, 0xfb, 0xc5, 0x0c, 0xcc, 0x9e, 0x20, 0x8e, 0xfa, 0xc2, 0x3c, 0x83, 0x65, 0x49, 0xfa, + 0x71, 0x88, 0x24, 0xf1, 0xd3, 0x0e, 0x9f, 0xdd, 0xf4, 0x6d, 0xdd, 0xf9, 0xab, 0xc3, 0xd2, 0xa9, + 0x8c, 0xc7, 0x64, 0xd7, 0x69, 0x6b, 0xea, 0xa9, 0x44, 0x92, 0x78, 0x4b, 0x39, 0x46, 0x4a, 0x34, + 0xef, 0x80, 0x25, 0xf9, 0x40, 0xc8, 0xb2, 0xf7, 0x96, 0x4d, 0x27, 0x8d, 0xe5, 0xeb, 0xf9, 0x79, + 0xda, 0xae, 0x8a, 0x66, 0x73, 0x75, 0x9b, 0xad, 0x7d, 0x93, 0x36, 0x7b, 0x0a, 0x6b, 0x6a, 0x46, + 0x8d, 0x63, 0xd6, 0x27, 0xc7, 0x5c, 0x55, 0xf2, 0xa3, 0xa0, 0x1f, 0x83, 0x99, 0x08, 0x3c, 0x8e, + 0x39, 0xf3, 0x0a, 0x76, 0x26, 0x02, 0x8f, 0x42, 0x06, 0xb0, 0x29, 0x54, 0xf2, 0xf9, 0x7d, 0x22, + 0x75, 0xd3, 0x8e, 0x43, 0x12, 0x51, 0xd1, 0xcb, 0xc1, 0x67, 0x27, 0x07, 0xdf, 0xd0, 0x40, 0x1f, + 0x29, 0x1c, 0x2f, 0x87, 0xc9, 0xb4, 0xb4, 0xa1, 0x75, 0xb5, 0x96, 0x22, 0x40, 0x73, 0x3a, 0x40, + 0xdf, 0xba, 0x02, 0xa2, 0x88, 0x92, 0x80, 0xb7, 0x2a, 0xc3, 0x45, 0x55, 0xb5, 0xaf, 0x0b, 0xca, + 0xe7, 0xa4, 0xab, 0x3a, 0x30, 0x4a, 0xe7, 0x0c, 0x21, 0xc5, 0x80, 0xcc, 0xba, 0x87, 0x5a, 0x81, + 0x8a, 0xce, 0xd1, 0x66, 0x34, 0xca, 0xb6, 0x08, 0xbb, 0x9c, 0x41, 0x45, 0x8f, 0xf0, 0x2a, 0x58, + 0xef, 0x13, 0xa2, 0xaa, 0xb9, 0x32, 0x87, 0x48, 0xcc, 0x70, 0x4f, 0xcf, 0xc9, 0x9a, 0xb7, 0x54, + 0xcc, 0x9c, 0x7b, 0x8a, 0xfa, 0xa0, 0x3e, 0x3f, 0xbf, 0xd2, 0xb0, 0xbf, 0x07, 0x0d, 0x5d, 0xcc, + 0xfb, 0xf8, 0x42, 0x98, 0x9b, 0xd0, 0x50, 0x55, 0x41, 0x84, 0x20, 0xc2, 0x32, 0x74, 0x0f, 0x28, + 0x09, 0xb6, 0x84, 0x8d, 0xeb, 0xb6, 0x2d, 0x61, 0x3e, 0x86, 0xb9, 0x98, 0xe8, 0x55, 0x40, 0x0b, + 0x36, 0xf7, 0xde, 0x75, 0x26, 0xd8, 0x85, 0x9d, 0xeb, 0x00, 0xbd, 0x1c, 0xcd, 0xe6, 0xe5, 0x8e, + 0x37, 0x36, 0x6c, 0x84, 0x79, 0x3e, 0xae, 0xf4, 0x27, 0xaf, 0xa4, 0x74, 0x0c, 0xaf, 0xd4, 0xf9, + 0x36, 0x34, 0xf7, 0xd3, 0x6b, 0x7f, 0x48, 0x85, 0xbc, 0xec, 0x96, 0x85, 0xaa, 0x5b, 0x1e, 0xc0, + 0x52, 0x36, 0x38, 0xcf, 0x98, 0x6e, 0x48, 0xe6, 0xb7, 0x01, 0xb2, 0x89, 0xab, 0x1a, 0x59, 0xda, + 0xb2, 0x1b, 0x19, 0xe5, 0x28, 0x18, 0x99, 0x75, 0xd3, 0x23, 0xb3, 0xce, 0xf6, 0x60, 0xf9, 0x5c, + 0xe0, 0x9f, 0xe6, 0x5b, 0xd5, 0xa3, 0x58, 0x98, 0xaf, 0xc1, 0xac, 0xaa, 0xa1, 0x0c, 0xa8, 0xee, + 0xcd, 0x24, 0x02, 0x1f, 0xe9, 0xae, 0x5d, 0x6e, 0x6e, 0x2c, 0xf6, 0x69, 0x20, 0xac, 0xe9, 0xed, + 0xda, 0x4e, 0xdd, 0x5b, 0x1a, 0x94, 0xe2, 0x47, 0x81, 0xb0, 0x7f, 0x06, 0xcd, 0x0a, 0xa0, 0xb9, + 0x04, 0xd3, 0x05, 0xd6, 0x34, 0x0d, 0xcc, 0xbb, 0xb0, 0x51, 0x02, 0x8d, 0xb6, 0xe1, 0x14, 0xb1, + 0xe1, 0xdd, 0x28, 0x18, 0x46, 0x3a, 0xb1, 0xb0, 0x1f, 0xc1, 0xfa, 0x51, 0x59, 0xf4, 0x45, 0x93, + 0x1f, 0xb9, 0xa1, 0x31, 0x3a, 0xcd, 0x37, 0xa1, 0x51, 0xfc, 0x62, 0xd1, 0xb7, 0xaf, 0x7b, 0x25, + 0xc1, 0xee, 0xc3, 0xca, 0xb9, 0xc0, 0xa7, 0x24, 0x0a, 0x4a, 0xb0, 0x6b, 0x1c, 0x70, 0x30, 0x0e, + 0x34, 0xf1, 0xfa, 0x5b, 0xaa, 0x63, 0xb0, 0x71, 0x8e, 0x42, 0x1a, 0x20, 0xc9, 0xf8, 0x29, 0x91, + 0xe9, 0x00, 0x3e, 0x41, 0xf8, 0x82, 0x48, 0x61, 0x7a, 0x50, 0x0f, 0xa9, 0x90, 0x59, 0x66, 0xdd, + 0xb9, 0x36, 0xb3, 0x92, 0x5d, 0xe7, 0x3a, 0x90, 0x43, 0x24, 0x51, 0x56, 0xbb, 0x1a, 0xcb, 0xfe, + 0x2e, 0xac, 0x7d, 0x84, 0xe4, 0x80, 0x93, 0x60, 0x24, 0xc6, 0x2b, 0x50, 0x53, 0xf1, 0x33, 0x74, + 0xfc, 0xd4, 0xa3, 0xda, 0x07, 0xac, 0x7b, 0x9f, 0xc4, 0x8c, 0x4b, 0x12, 0x5c, 0xf2, 0xc8, 0x4b, + 0xdc, 0x7b, 0x01, 0x6b, 0xca, 0x59, 0x82, 0x44, 0x81, 0x5f, 0xdc, 0x33, 0x8d, 0x63, 0x73, 0xef, + 0xc7, 0x13, 0x55, 0xc7, 0xb8, 0xba, 0xec, 0x02, 0xab, 0xc9, 0x18, 0x5d, 0xd8, 0xbf, 0x35, 0xc0, + 0x3a, 0x26, 0xc3, 0x7d, 0x21, 0x68, 0x37, 0xea, 0x93, 0x48, 0xaa, 0x1e, 0x88, 0x30, 0x51, 0x8f, + 0xe6, 0x1b, 0xb0, 0x58, 0xcc, 0x5c, 0x3d, 0x6a, 0x0d, 0x3d, 0x6a, 0x17, 0x72, 0xa2, 0x2a, 0x30, + 0xf3, 0x2e, 0x40, 0xcc, 0x49, 0xe2, 0x63, 0xff, 0x82, 0x0c, 0xb3, 0x28, 0x6e, 0x56, 0x47, 0x68, + 0xfa, 0x7b, 0xd2, 0x39, 0x19, 0x74, 0x42, 0x8a, 0x8f, 0xc9, 0xd0, 0x9b, 0x57, 0xfc, 0xed, 0x63, + 0x32, 0x54, 0x3b, 0x51, 0xcc, 0x9e, 0x11, 0xae, 0xe7, 0x5e, 0xcd, 0x4b, 0x5f, 0xec, 0xdf, 0x19, + 0x70, 0xa3, 0x08, 0x47, 0x9e, 0xae, 0x27, 0x83, 0x8e, 0x92, 0x78, 0x89, 0xdf, 0x2e, 0x59, 0x3b, + 0x7d, 0x85, 0xb5, 0xef, 0xc1, 0x42, 0x51, 0x20, 0xca, 0xde, 0xda, 0x04, 0xf6, 0x36, 0x73, 0x89, + 0x63, 0x32, 0xb4, 0x7f, 0x59, 0xb1, 0xed, 0x60, 0x58, 0xe9, 0x7d, 0xfc, 0xbf, 0xd8, 0x56, 0xa8, + 0xad, 0xda, 0x86, 0xab, 0xf2, 0x97, 0x2e, 0x50, 0xbb, 0x7c, 0x01, 0xfb, 0x0f, 0x06, 0xac, 0x57, + 0xb5, 0x8a, 0x33, 0x76, 0xc2, 0x07, 0x11, 0x79, 0x99, 0xf6, 0xb2, 0xfc, 0xa6, 0xab, 0xe5, 0xf7, + 0x18, 0x96, 0x46, 0x8c, 0x12, 0x99, 0x37, 0x7e, 0x38, 0x51, 0x8e, 0x55, 0xba, 0xab, 0xb7, 0x58, + 0xbd, 0x87, 0xb0, 0xff, 0x64, 0xc0, 0x6a, 0x6e, 0x63, 0xe1, 0x2c, 0xf3, 0x07, 0x60, 0x16, 0xd7, + 0x2b, 0xb7, 0xb7, 0x34, 0xa5, 0x56, 0xf2, 0x93, 0x7c, 0x75, 0x2b, 0x53, 0x63, 0xba, 0x92, 0x1a, + 0xe6, 0x87, 0xb0, 0x56, 0x98, 0x1c, 0xeb, 0x00, 0x4d, 0x1c, 0xc5, 0x62, 0x3f, 0x2d, 0x48, 0xf6, + 0xaf, 0x8d, 0x72, 0x1c, 0xa6, 0xf3, 0x58, 0xec, 0x87, 0x61, 0xb6, 0xd4, 0x9b, 0x31, 0xcc, 0xa5, + 0x23, 0x5f, 0x64, 0xfd, 0x63, 0xf3, 0xca, 0xe1, 0x7e, 0x48, 0xb0, 0x9e, 0xef, 0x77, 0x54, 0x89, + 0xfd, 0xe5, 0xeb, 0xad, 0xb7, 0xbb, 0x54, 0xf6, 0x06, 0x1d, 0x07, 0xb3, 0xbe, 0x9b, 0x7d, 0x0f, + 0x49, 0xff, 0xdd, 0x16, 0xc1, 0x85, 0x2b, 0x87, 0x31, 0x11, 0xb9, 0x8c, 0xf8, 0xf3, 0x3f, 0xff, + 0xf6, 0x7d, 0xc3, 0xcb, 0xd5, 0xd8, 0xbf, 0x31, 0x60, 0xe5, 0x51, 0x2c, 0x49, 0x70, 0x14, 0x95, + 0x6e, 0x9b, 0xa8, 0x08, 0x6f, 0xc1, 0x82, 0x5e, 0x0d, 0xf2, 0x8f, 0x1a, 0xa9, 0xd3, 0x9a, 0x9a, + 0x96, 0x7d, 0xb0, 0xb8, 0xb2, 0xd6, 0xd4, 0x9c, 0xab, 0xf8, 0x31, 0x5d, 0xa5, 0x1b, 0x71, 0xee, + 0xa1, 0x83, 0xc7, 0x5f, 0x3c, 0x6f, 0x19, 0x5f, 0x3e, 0x6f, 0x19, 0xff, 0x78, 0xde, 0x32, 0x3e, + 0x7d, 0xd1, 0x9a, 0xfa, 0xf2, 0x45, 0x6b, 0xea, 0xef, 0x2f, 0x5a, 0x53, 0x3f, 0x7f, 0xf7, 0xf2, + 0x35, 0xcb, 0xac, 0xb9, 0x5d, 0x7c, 0x13, 0x4b, 0x7e, 0xe4, 0x7e, 0x32, 0xfa, 0xc5, 0x4d, 0x7b, + 0xa0, 0x33, 0xab, 0xfb, 0xfb, 0x3b, 0xff, 0x09, 0x00, 0x00, 0xff, 0xff, 0x5d, 0x12, 0x76, 0xb8, + 0xa2, 0x13, 0x00, 0x00, } func (m *ConsumerAdditionProposal) Marshal() (dAtA []byte, err error) { @@ -2819,6 +2897,53 @@ func (m *ConsumerRewardsAllocation) MarshalToSizedBuffer(dAtA []byte) (int, erro return len(dAtA) - i, nil } +func (m *OptedInValidator) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *OptedInValidator) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *OptedInValidator) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.PublicKey) > 0 { + i -= len(m.PublicKey) + copy(dAtA[i:], m.PublicKey) + i = encodeVarintProvider(dAtA, i, uint64(len(m.PublicKey))) + i-- + dAtA[i] = 0x22 + } + if m.Power != 0 { + i = encodeVarintProvider(dAtA, i, uint64(m.Power)) + i-- + dAtA[i] = 0x18 + } + if m.BlockHeight != 0 { + i = encodeVarintProvider(dAtA, i, uint64(m.BlockHeight)) + i-- + dAtA[i] = 0x10 + } + if len(m.ProviderAddr) > 0 { + i -= len(m.ProviderAddr) + copy(dAtA[i:], m.ProviderAddr) + i = encodeVarintProvider(dAtA, i, uint64(len(m.ProviderAddr))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintProvider(dAtA []byte, offset int, v uint64) int { offset -= sovProvider(v) base := offset @@ -3328,6 +3453,29 @@ func (m *ConsumerRewardsAllocation) Size() (n int) { return n } +func (m *OptedInValidator) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ProviderAddr) + if l > 0 { + n += 1 + l + sovProvider(uint64(l)) + } + if m.BlockHeight != 0 { + n += 1 + sovProvider(uint64(m.BlockHeight)) + } + if m.Power != 0 { + n += 1 + sovProvider(uint64(m.Power)) + } + l = len(m.PublicKey) + if l > 0 { + n += 1 + l + sovProvider(uint64(l)) + } + return n +} + func sovProvider(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -6863,6 +7011,162 @@ func (m *ConsumerRewardsAllocation) Unmarshal(dAtA []byte) error { } return nil } +func (m *OptedInValidator) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProvider + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: OptedInValidator: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: OptedInValidator: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProviderAddr", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProvider + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthProvider + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthProvider + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProviderAddr = append(m.ProviderAddr[:0], dAtA[iNdEx:postIndex]...) + if m.ProviderAddr == nil { + m.ProviderAddr = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field BlockHeight", wireType) + } + m.BlockHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProvider + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.BlockHeight |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Power", wireType) + } + m.Power = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProvider + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Power |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PublicKey", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProvider + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthProvider + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthProvider + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PublicKey = append(m.PublicKey[:0], dAtA[iNdEx:postIndex]...) + if m.PublicKey == nil { + m.PublicKey = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipProvider(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthProvider + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipProvider(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 From e8cd10036b5ced0b7bb9111b7722c2812bf29976 Mon Sep 17 00:00:00 2001 From: Simon Noetzlin Date: Fri, 8 Mar 2024 09:24:32 +0100 Subject: [PATCH 014/110] feat!: PSS enable per-consumer chain commission (#1657) * add draft commission * implement consumer commission draft * formatting * add msg handling * improve UT * nits * Update x/ccv/provider/keeper/keeper.go Co-authored-by: insumity * Update proto/interchain_security/ccv/provider/v1/tx.proto Co-authored-by: Marius Poke * optimize keys * Update x/ccv/provider/keeper/keeper.go Co-authored-by: insumity * address comments * address comments * remove unnecessary check * Revert "remove unnecessary check" This reverts commit 2951e9bace04f6436d6ad1e4a11efcedd0be8cb1. * fix minor bug in StopConsumerChain --------- Co-authored-by: insumity Co-authored-by: Marius Poke --- .../ccv/provider/v1/provider.proto | 2 +- .../ccv/provider/v1/tx.proto | 23 +- tests/integration/distribution.go | 121 +++-- testutil/integration/interfaces.go | 1 + testutil/keeper/mocks.go | 128 ----- testutil/keeper/unit_test_helpers.go | 5 + x/ccv/provider/keeper/distribution.go | 53 +- x/ccv/provider/keeper/keeper.go | 69 +++ x/ccv/provider/keeper/keeper_test.go | 41 +- x/ccv/provider/keeper/msg_server.go | 41 +- .../keeper/partial_set_security_test.go | 25 + x/ccv/provider/keeper/proposal.go | 6 + x/ccv/provider/keeper/proposal_test.go | 4 - x/ccv/provider/types/errors.go | 1 + x/ccv/provider/types/events.go | 3 + x/ccv/provider/types/keys.go | 13 + x/ccv/provider/types/keys_test.go | 1 + x/ccv/provider/types/msg.go | 44 ++ x/ccv/provider/types/tx.pb.go | 510 ++++++++++++++++-- 19 files changed, 864 insertions(+), 227 deletions(-) diff --git a/proto/interchain_security/ccv/provider/v1/provider.proto b/proto/interchain_security/ccv/provider/v1/provider.proto index 3576b03f55..8c70c9e428 100644 --- a/proto/interchain_security/ccv/provider/v1/provider.proto +++ b/proto/interchain_security/ccv/provider/v1/provider.proto @@ -338,4 +338,4 @@ message OptedInValidator { int64 power = 3; // public key used by the validator on the consumer bytes public_key = 4; -} +} \ No newline at end of file diff --git a/proto/interchain_security/ccv/provider/v1/tx.proto b/proto/interchain_security/ccv/provider/v1/tx.proto index 51003bdf05..96844c2e72 100644 --- a/proto/interchain_security/ccv/provider/v1/tx.proto +++ b/proto/interchain_security/ccv/provider/v1/tx.proto @@ -17,6 +17,7 @@ service Msg { rpc SubmitConsumerDoubleVoting(MsgSubmitConsumerDoubleVoting) returns (MsgSubmitConsumerDoubleVotingResponse); rpc OptIn(MsgOptIn) returns (MsgOptInResponse); rpc OptOut(MsgOptOut) returns (MsgOptOutResponse); + rpc SetConsumerCommissionRate(MsgSetConsumerCommissionRate) returns (MsgSetConsumerCommissionRateResponse); } message MsgAssignConsumerKey { @@ -88,4 +89,24 @@ message MsgOptOut { string provider_addr = 2 [ (gogoproto.moretags) = "yaml:\"address\"" ]; } -message MsgOptOutResponse {} \ No newline at end of file +message MsgOptOutResponse {} + +// MsgSetConsumerCommissionRate allows validators to set +// a per-consumer chain commission rate +message MsgSetConsumerCommissionRate { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + // The validator address on the provider + string provider_addr = 1 [ (gogoproto.moretags) = "yaml:\"address\"" ]; + // The chain id of the consumer chain to set a commission rate + string chain_id = 2; + // The rate to charge delegators on the consumer chain, as a fraction + string rate = 3 [ + (cosmos_proto.scalar) = "cosmos.Dec", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; +} + + +message MsgSetConsumerCommissionRateResponse {} \ No newline at end of file diff --git a/tests/integration/distribution.go b/tests/integration/distribution.go index d6dd6196ec..b047c2f523 100644 --- a/tests/integration/distribution.go +++ b/tests/integration/distribution.go @@ -6,7 +6,7 @@ import ( "cosmossdk.io/math" abci "github.com/cometbft/cometbft/abci/types" "github.com/cometbft/cometbft/libs/bytes" - "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" @@ -575,7 +575,7 @@ func (s *CCVTestSuite) TestIBCTransferMiddleware() { bankKeeper := s.providerApp.GetTestBankKeeper() amount := sdk.NewInt(100) - data = types.NewFungibleTokenPacketData( // can be explicitly changed in setup + data = transfertypes.NewFungibleTokenPacketData( // can be explicitly changed in setup sdk.DefaultBondDenom, amount.String(), authtypes.NewModuleAddress(consumertypes.ConsumerToSendToProviderName).String(), @@ -734,11 +734,11 @@ func (s *CCVTestSuite) TestAllocateTokens() { perValExpReward := validatorsExpRewards.QuoDec(sdk.NewDec(int64(valNum))) // verify the validator tokens allocation - // note all validators have the same voting power to keep things simple + // note that the validators have the same voting power to keep things simple for _, val := range s.providerChain.Vals.Validators { - valReward := distributionKeeper.GetValidatorOutstandingRewards(s.providerCtx(), sdk.ValAddress(val.Address)) + valRewards := distributionKeeper.GetValidatorOutstandingRewards(s.providerCtx(), sdk.ValAddress(val.Address)) s.Require().Equal( - valReward.Rewards, + valRewards.Rewards, lastValOutRewards[sdk.ValAddress(val.Address).String()].Add(perValExpReward...), ) } @@ -902,80 +902,133 @@ func (s *CCVTestSuite) prepareRewardDist() { } func (s *CCVTestSuite) TestAllocateTokensToValidator() { - - providerkeepr := s.providerApp.GetProviderKeeper() + providerKeeper := s.providerApp.GetProviderKeeper() + distributionKeeper := s.providerApp.GetTestDistributionKeeper() + bankKeeper := s.providerApp.GetTestBankKeeper() chainID := "consumer" - validators := []bytes.HexBytes{ s.providerChain.Vals.Validators[0].Address, s.providerChain.Vals.Validators[1].Address, } - votes := []abci.VoteInfo{ {Validator: abci.Validator{Address: validators[0], Power: 1}}, {Validator: abci.Validator{Address: validators[1], Power: 1}}, } testCases := []struct { - name string - votes []abci.VoteInfo - tokens sdk.DecCoins - expCoinTransferred sdk.DecCoins + name string + votes []abci.VoteInfo + tokens sdk.DecCoins + rate sdk.Dec + expAllocated sdk.DecCoins }{ { - name: "reward tokens are empty", + name: "tokens are empty", + tokens: sdk.DecCoins{}, + rate: sdk.ZeroDec(), + expAllocated: nil, }, { - name: "total voting power is zero", - tokens: sdk.DecCoins{sdk.NewDecCoin("uatom", math.NewInt(100_000))}, + name: "total voting power is zero", + tokens: sdk.DecCoins{sdk.NewDecCoin(sdk.DefaultBondDenom, math.NewInt(100_000))}, + rate: sdk.ZeroDec(), + expAllocated: nil, }, { - name: "expect all tokens to be allocated to a single validator", - votes: []abci.VoteInfo{votes[0]}, - tokens: sdk.DecCoins{sdk.NewDecCoin("uatom", math.NewInt(100_000))}, - expCoinTransferred: sdk.DecCoins{sdk.NewDecCoin("uatom", math.NewInt(100_000))}, + name: "expect all tokens to be allocated to a single validator", + votes: []abci.VoteInfo{votes[0]}, + tokens: sdk.DecCoins{sdk.NewDecCoin(sdk.DefaultBondDenom, math.NewInt(999))}, + rate: sdk.NewDecWithPrec(5, 1), + expAllocated: sdk.DecCoins{sdk.NewDecCoin(sdk.DefaultBondDenom, math.NewInt(999))}, }, { - name: "expect tokens to be allocated evenly between validators", - votes: []abci.VoteInfo{votes[0], votes[1]}, - tokens: sdk.DecCoins{sdk.NewDecCoin("uatom", math.NewInt(555_555))}, - expCoinTransferred: sdk.DecCoins{sdk.NewDecCoin("uatom", math.NewInt(555_555))}, + name: "expect tokens to be allocated evenly between validators", + votes: []abci.VoteInfo{votes[0], votes[1]}, + tokens: sdk.DecCoins{sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, math.LegacyNewDecFromIntWithPrec(math.NewInt(999), 2))}, + rate: sdk.OneDec(), + expAllocated: sdk.DecCoins{sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, math.LegacyNewDecFromIntWithPrec(math.NewInt(999), 2))}, }, } for _, tc := range testCases { s.Run(tc.name, func() { - // TODO: opt validators in and verify - // that rewards are solely allocated to them + // set the same consumer commission rate for all validators + for _, v := range s.providerChain.Vals.Validators { + provAddr := providertypes.NewProviderConsAddress(sdk.ConsAddress(v.Address)) + + providerKeeper.SetConsumerCommissionRate( + s.providerCtx(), + chainID, + provAddr, + tc.rate, + ) + } + + // TODO: opt validators in and verify + // that rewards are only allocated to them ctx, _ := s.providerCtx().CacheContext() // allocate tokens - res := providerkeepr.AllocateTokensToConsumerValidators( + res := providerKeeper.AllocateTokensToConsumerValidators( ctx, chainID, tc.votes, tc.tokens, ) - // check that the expect result is returned - s.Require().Equal(tc.expCoinTransferred, res) + // check that the expected result is returned + s.Require().Equal(tc.expAllocated, res) - if !tc.expCoinTransferred.Empty() { + if !tc.expAllocated.Empty() { // rewards are expected to be allocated evenly between validators - rewardsPerVal := tc.expCoinTransferred.QuoDec(sdk.NewDec(int64(len(tc.votes)))) + rewardsPerVal := tc.expAllocated.QuoDec(sdk.NewDec(int64(len(tc.votes)))) - // check that the rewards are allocated to validators as expected + // check that the rewards are allocated to validators for _, v := range tc.votes { + valAddr := sdk.ValAddress(v.Validator.Address) rewards := s.providerApp.GetTestDistributionKeeper().GetValidatorOutstandingRewards( ctx, - sdk.ValAddress(v.Validator.Address), + valAddr, ) s.Require().Equal(rewardsPerVal, rewards.Rewards) + + // send rewards to the distribution module + valRewardsTrunc, _ := rewards.Rewards.TruncateDecimal() + err := bankKeeper.SendCoinsFromAccountToModule( + ctx, + s.providerChain.SenderAccount.GetAddress(), + distrtypes.ModuleName, + valRewardsTrunc) + s.Require().NoError(err) + + // check that validators can withdraw their rewards + withdrawnCoins, err := distributionKeeper.WithdrawValidatorCommission( + ctx, + valAddr, + ) + s.Require().NoError(err) + + // check that the withdrawn coins is equal to the entire reward amount + // times the set consumer commission rate + commission := rewards.Rewards.MulDec(tc.rate) + c, _ := commission.TruncateDecimal() + s.Require().Equal(withdrawnCoins, c) + + // check that validators get rewards in their balance + s.Require().Equal(withdrawnCoins, bankKeeper.GetAllBalances(ctx, sdk.AccAddress(valAddr))) + } + } else { + for _, v := range tc.votes { + valAddr := sdk.ValAddress(v.Validator.Address) + rewards := s.providerApp.GetTestDistributionKeeper().GetValidatorOutstandingRewards( + ctx, + valAddr, + ) + s.Require().Zero(rewards.Rewards) } } - }) } } diff --git a/testutil/integration/interfaces.go b/testutil/integration/interfaces.go index 89d59904df..fe3382b524 100644 --- a/testutil/integration/interfaces.go +++ b/testutil/integration/interfaces.go @@ -142,6 +142,7 @@ type TestDistributionKeeper interface { GetValidatorOutstandingRewards(ctx sdk.Context, val sdk.ValAddress) (rewards distributiontypes.ValidatorOutstandingRewards) GetCommunityTax(ctx sdk.Context) (percent sdk.Dec) + WithdrawValidatorCommission(ctx sdk.Context, valAddr sdk.ValAddress) (sdk.Coins, error) } type TestMintKeeper interface { diff --git a/testutil/keeper/mocks.go b/testutil/keeper/mocks.go index a192765ec9..78c0fbedc9 100644 --- a/testutil/keeper/mocks.go +++ b/testutil/keeper/mocks.go @@ -1114,134 +1114,6 @@ func (m *MockIBCTransferKeeper) EXPECT() *MockIBCTransferKeeperMockRecorder { return m.recorder } -// OnAcknowledgementPacket mocks base method. -func (m *MockIBCTransferKeeper) OnAcknowledgementPacket(ctx types0.Context, packet types9.Packet, acknowledgement []byte, relayer types0.AccAddress) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnAcknowledgementPacket", ctx, packet, acknowledgement, relayer) - ret0, _ := ret[0].(error) - return ret0 -} - -// OnAcknowledgementPacket indicates an expected call of OnAcknowledgementPacket. -func (mr *MockIBCTransferKeeperMockRecorder) OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnAcknowledgementPacket", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnAcknowledgementPacket), ctx, packet, acknowledgement, relayer) -} - -// OnChanCloseConfirm mocks base method. -func (m *MockIBCTransferKeeper) OnChanCloseConfirm(ctx types0.Context, portID, channelID string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnChanCloseConfirm", ctx, portID, channelID) - ret0, _ := ret[0].(error) - return ret0 -} - -// OnChanCloseConfirm indicates an expected call of OnChanCloseConfirm. -func (mr *MockIBCTransferKeeperMockRecorder) OnChanCloseConfirm(ctx, portID, channelID interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnChanCloseConfirm", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnChanCloseConfirm), ctx, portID, channelID) -} - -// OnChanCloseInit mocks base method. -func (m *MockIBCTransferKeeper) OnChanCloseInit(ctx types0.Context, portID, channelID string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnChanCloseInit", ctx, portID, channelID) - ret0, _ := ret[0].(error) - return ret0 -} - -// OnChanCloseInit indicates an expected call of OnChanCloseInit. -func (mr *MockIBCTransferKeeperMockRecorder) OnChanCloseInit(ctx, portID, channelID interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnChanCloseInit", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnChanCloseInit), ctx, portID, channelID) -} - -// OnChanOpenAck mocks base method. -func (m *MockIBCTransferKeeper) OnChanOpenAck(ctx types0.Context, portID, channelID, counterpartyChannelID, counterpartyVersion string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnChanOpenAck", ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) - ret0, _ := ret[0].(error) - return ret0 -} - -// OnChanOpenAck indicates an expected call of OnChanOpenAck. -func (mr *MockIBCTransferKeeperMockRecorder) OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnChanOpenAck", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnChanOpenAck), ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) -} - -// OnChanOpenConfirm mocks base method. -func (m *MockIBCTransferKeeper) OnChanOpenConfirm(ctx types0.Context, portID, channelID string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnChanOpenConfirm", ctx, portID, channelID) - ret0, _ := ret[0].(error) - return ret0 -} - -// OnChanOpenConfirm indicates an expected call of OnChanOpenConfirm. -func (mr *MockIBCTransferKeeperMockRecorder) OnChanOpenConfirm(ctx, portID, channelID interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnChanOpenConfirm", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnChanOpenConfirm), ctx, portID, channelID) -} - -// OnChanOpenInit mocks base method. -func (m *MockIBCTransferKeeper) OnChanOpenInit(ctx types0.Context, order types9.Order, connectionHops []string, portID, channelID string, channelCap *types2.Capability, counterparty types9.Counterparty, version string) (string, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnChanOpenInit", ctx, order, connectionHops, portID, channelID, channelCap, counterparty, version) - ret0, _ := ret[0].(string) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// OnChanOpenInit indicates an expected call of OnChanOpenInit. -func (mr *MockIBCTransferKeeperMockRecorder) OnChanOpenInit(ctx, order, connectionHops, portID, channelID, channelCap, counterparty, version interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnChanOpenInit", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnChanOpenInit), ctx, order, connectionHops, portID, channelID, channelCap, counterparty, version) -} - -// OnChanOpenTry mocks base method. -func (m *MockIBCTransferKeeper) OnChanOpenTry(ctx types0.Context, order types9.Order, connectionHops []string, portID, channelID string, channelCap *types2.Capability, counterparty types9.Counterparty, counterpartyVersion string) (string, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnChanOpenTry", ctx, order, connectionHops, portID, channelID, channelCap, counterparty, counterpartyVersion) - ret0, _ := ret[0].(string) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// OnChanOpenTry indicates an expected call of OnChanOpenTry. -func (mr *MockIBCTransferKeeperMockRecorder) OnChanOpenTry(ctx, order, connectionHops, portID, channelID, channelCap, counterparty, counterpartyVersion interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnChanOpenTry", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnChanOpenTry), ctx, order, connectionHops, portID, channelID, channelCap, counterparty, counterpartyVersion) -} - -// OnRecvPacket mocks base method. -func (m *MockIBCTransferKeeper) OnRecvPacket(ctx types0.Context, packet types9.Packet, relayer types0.AccAddress) exported.Acknowledgement { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnRecvPacket", ctx, packet, relayer) - ret0, _ := ret[0].(exported.Acknowledgement) - return ret0 -} - -// OnRecvPacket indicates an expected call of OnRecvPacket. -func (mr *MockIBCTransferKeeperMockRecorder) OnRecvPacket(ctx, packet, relayer interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnRecvPacket", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnRecvPacket), ctx, packet, relayer) -} - -// OnTimeoutPacket mocks base method. -func (m *MockIBCTransferKeeper) OnTimeoutPacket(ctx types0.Context, packet types9.Packet, relayer types0.AccAddress) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnTimeoutPacket", ctx, packet, relayer) - ret0, _ := ret[0].(error) - return ret0 -} - -// OnTimeoutPacket indicates an expected call of OnTimeoutPacket. -func (mr *MockIBCTransferKeeperMockRecorder) OnTimeoutPacket(ctx, packet, relayer interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnTimeoutPacket", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnTimeoutPacket), ctx, packet, relayer) -} - // Transfer mocks base method. func (m *MockIBCTransferKeeper) Transfer(arg0 context.Context, arg1 *types6.MsgTransfer) (*types6.MsgTransferResponse, error) { m.ctrl.T.Helper() diff --git a/testutil/keeper/unit_test_helpers.go b/testutil/keeper/unit_test_helpers.go index 05bef232e3..1bb1f7f3ee 100644 --- a/testutil/keeper/unit_test_helpers.go +++ b/testutil/keeper/unit_test_helpers.go @@ -249,10 +249,15 @@ func TestProviderStateIsCleanedAfterConsumerChainIsStopped(t *testing.T, ctx sdk require.Empty(t, providerKeeper.GetAllVscSendTimestamps(ctx, expectedChainID)) + // in case the chain was successfully stopped, it should not contain a Top N associated to it + _, found = providerKeeper.GetTopN(ctx, expectedChainID) + require.False(t, found) + // test key assignment state is cleaned require.Empty(t, providerKeeper.GetAllValidatorConsumerPubKeys(ctx, &expectedChainID)) require.Empty(t, providerKeeper.GetAllValidatorsByConsumerAddr(ctx, &expectedChainID)) require.Empty(t, providerKeeper.GetAllConsumerAddrsToPrune(ctx, expectedChainID)) + require.Empty(t, providerKeeper.GetAllCommissionRateValidators(ctx, expectedChainID)) } func GetTestConsumerAdditionProp() *providertypes.ConsumerAdditionProposal { diff --git a/x/ccv/provider/keeper/distribution.go b/x/ccv/provider/keeper/distribution.go index 45af3eb262..16511f8bde 100644 --- a/x/ccv/provider/keeper/distribution.go +++ b/x/ccv/provider/keeper/distribution.go @@ -5,9 +5,9 @@ import ( "cosmossdk.io/math" abci "github.com/cometbft/cometbft/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" - channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" - distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" ) @@ -138,16 +138,17 @@ func (k Keeper) AllocateTokensToConsumerValidators( chainID string, bondedVotes []abci.VoteInfo, tokens sdk.DecCoins, -) (totalReward sdk.DecCoins) { +) (allocated sdk.DecCoins) { + // return early if the tokens are empty if tokens.Empty() { - return totalReward + return allocated } // get the consumer total voting power from the votes totalPower := k.ComputeConsumerTotalVotingPower(ctx, chainID, bondedVotes) if totalPower == 0 { - return totalReward + return allocated } for _, vote := range bondedVotes { @@ -157,19 +158,31 @@ func (k Keeper) AllocateTokensToConsumerValidators( powerFraction := math.LegacyNewDec(vote.Validator.Power).QuoTruncate(math.LegacyNewDec(totalPower)) tokensFraction := tokens.MulDecTruncate(powerFraction) + // get the validator type struct for the consensus address + val := k.stakingKeeper.ValidatorByConsAddr(ctx, consAddr).(stakingtypes.Validator) + + // check if the validator set a custom commission rate for the consumer chain + if cr, found := k.GetConsumerCommissionRate(ctx, chainID, types.NewProviderConsAddress(consAddr)); found { + // set the validator commission rate + val.Commission.CommissionRates.Rate = cr + } + + // allocate the consumer reward tokens to the validator k.distributionKeeper.AllocateTokensToValidator( ctx, - k.stakingKeeper.ValidatorByConsAddr(ctx, consAddr), + val, tokensFraction, ) - totalReward = totalReward.Add(tokensFraction...) + + // sum the tokens allocated + allocated = allocated.Add(tokensFraction...) } - return totalReward + return allocated } -// TransferConsumerRewardsToDistributionModule transfers the collected rewards of the given consumer chain -// from the consumer rewards pool module account to a the distribution module +// TransferConsumerRewardsToDistributionModule transfers the rewards allocation of the given consumer chain +// from the consumer rewards pool to a the distribution module func (k Keeper) TransferConsumerRewardsToDistributionModule( ctx sdk.Context, chainID string, @@ -267,3 +280,23 @@ func (k Keeper) IdentifyConsumerChainIDFromIBCPacket(ctx sdk.Context, packet cha return chainID, nil } + +// HandleSetConsumerCommissionRate sets a per-consumer chain commission rate for the given provider address +// on the condition that the given consumer chain exists. +func (k Keeper) HandleSetConsumerCommissionRate(ctx sdk.Context, chainID string, providerAddr types.ProviderConsAddress, commissionRate sdk.Dec) error { + // check that the consumer chain exists + if !k.IsConsumerProposedOrRegistered(ctx, chainID) { + return errorsmod.Wrapf( + types.ErrUnknownConsumerChainId, + "unknown consumer chain, with id: %s", chainID) + } + // set per-consumer chain commission rate for the validator address + k.SetConsumerCommissionRate( + ctx, + chainID, + providerAddr, + commissionRate, + ) + + return nil +} diff --git a/x/ccv/provider/keeper/keeper.go b/x/ccv/provider/keeper/keeper.go index e6b1c589aa..ec73d85383 100644 --- a/x/ccv/provider/keeper/keeper.go +++ b/x/ccv/provider/keeper/keeper.go @@ -1248,6 +1248,75 @@ func (k Keeper) SetToBeOptedIn( store.Set(types.ToBeOptedInKey(chainID, providerAddr), []byte{}) } +// SetConsumerCommissionRate sets a per-consumer chain commission rate +// for the given validator address +func (k Keeper) SetConsumerCommissionRate( + ctx sdk.Context, + chainID string, + providerAddr types.ProviderConsAddress, + commissionRate sdk.Dec, +) { + store := ctx.KVStore(k.storeKey) + bz, err := commissionRate.Marshal() + if err != nil { + panic(fmt.Errorf("consumer commission rate marshalling failed: %s", err)) + } + + store.Set(types.ConsumerCommissionRateKey(chainID, providerAddr), bz) +} + +// GetConsumerCommissionRate returns the per-consumer commission rate set +// for the given validator address +func (k Keeper) GetConsumerCommissionRate( + ctx sdk.Context, + chainID string, + providerAddr types.ProviderConsAddress, +) (sdk.Dec, bool) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.ConsumerCommissionRateKey(chainID, providerAddr)) + if bz == nil { + return sdk.ZeroDec(), false + } + + cr := sdk.Dec{} + if err := cr.Unmarshal(bz); err != nil { + k.Logger(ctx).Error("consumer commission rate unmarshalling failed: %s", err) + return sdk.ZeroDec(), false + } + + return cr, true +} + +// GetAllCommissionRateValidators returns all the validator address +// that set a commission rate for the given chain ID +func (k Keeper) GetAllCommissionRateValidators( + ctx sdk.Context, + chainID string) (addresses []types.ProviderConsAddress) { + + store := ctx.KVStore(k.storeKey) + key := types.ChainIdWithLenKey(types.ConsumerCommissionRatePrefix, chainID) + iterator := sdk.KVStorePrefixIterator(store, key) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + providerAddr := types.NewProviderConsAddress(iterator.Key()[len(key):]) + addresses = append(addresses, providerAddr) + } + + return addresses +} + +// DeleteConsumerCommissionRate the per-consumer chain commission rate +// associated to the given validator address +func (k Keeper) DeleteConsumerCommissionRate( + ctx sdk.Context, + chainID string, + providerAddr types.ProviderConsAddress, +) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.ConsumerCommissionRateKey(chainID, providerAddr)) +} + func (k Keeper) DeleteToBeOptedIn( ctx sdk.Context, chainID string, diff --git a/x/ccv/provider/keeper/keeper_test.go b/x/ccv/provider/keeper/keeper_test.go index a231eb4c0c..595e01100a 100644 --- a/x/ccv/provider/keeper/keeper_test.go +++ b/x/ccv/provider/keeper/keeper_test.go @@ -15,6 +15,7 @@ import ( abci "github.com/cometbft/cometbft/abci/types" tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" + sdk "github.com/cosmos/cosmos-sdk/types" cryptotestutil "github.com/cosmos/interchain-security/v4/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" @@ -692,7 +693,8 @@ func TestGetAllOptedIn(t *testing.T) { ProviderAddr: expectedOptedInValidator.ProviderAddr, BlockHeight: expectedOptedInValidator.BlockHeight, Power: expectedOptedInValidator.Power, - PublicKey: expectedOptedInValidator.PublicKey}) + PublicKey: expectedOptedInValidator.PublicKey, + }) } actualOptedInValidators := providerKeeper.GetAllOptedIn(ctx, "chainID") @@ -858,3 +860,40 @@ func TestToBeOptedOut(t *testing.T) { providerKeeper.DeleteToBeOptedOut(ctx, "chainID", providerAddr) require.False(t, providerKeeper.IsToBeOptedOut(ctx, "chainID", providerAddr)) } + +// TestToBeOptedOut tests the `SetConsumerCommissionRate`, `GetConsumerCommissionRate`, and `DeleteConsumerCommissionRate` methods +func TestConsumerCommissionRate(t *testing.T) { + providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + providerAddr1 := types.NewProviderConsAddress([]byte("providerAddr1")) + providerAddr2 := types.NewProviderConsAddress([]byte("providerAddr2")) + + cr, found := providerKeeper.GetConsumerCommissionRate(ctx, "chainID", providerAddr1) + require.False(t, found) + require.Equal(t, sdk.ZeroDec(), cr) + + providerKeeper.SetConsumerCommissionRate(ctx, "chainID", providerAddr1, sdk.OneDec()) + cr, found = providerKeeper.GetConsumerCommissionRate(ctx, "chainID", providerAddr1) + require.True(t, found) + require.Equal(t, sdk.OneDec(), cr) + + providerKeeper.SetConsumerCommissionRate(ctx, "chainID", providerAddr2, sdk.ZeroDec()) + cr, found = providerKeeper.GetConsumerCommissionRate(ctx, "chainID", providerAddr2) + require.True(t, found) + require.Equal(t, sdk.ZeroDec(), cr) + + provAddrs := providerKeeper.GetAllCommissionRateValidators(ctx, "chainID") + require.Len(t, provAddrs, 2) + + for _, addr := range provAddrs { + providerKeeper.DeleteConsumerCommissionRate(ctx, "chainID", addr) + } + + _, found = providerKeeper.GetConsumerCommissionRate(ctx, "chainID", providerAddr1) + require.False(t, found) + + _, found = providerKeeper.GetConsumerCommissionRate(ctx, "chainID", providerAddr2) + require.False(t, found) + +} diff --git a/x/ccv/provider/keeper/msg_server.go b/x/ccv/provider/keeper/msg_server.go index 4863cd0d66..9e019bcb22 100644 --- a/x/ccv/provider/keeper/msg_server.go +++ b/x/ccv/provider/keeper/msg_server.go @@ -2,14 +2,12 @@ package keeper import ( "context" - errorsmod "cosmossdk.io/errors" + errorsmod "cosmossdk.io/errors" + tmtypes "github.com/cometbft/cometbft/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - - tmtypes "github.com/cometbft/cometbft/types" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" ) @@ -195,3 +193,38 @@ func (k msgServer) OptOut(goCtx context.Context, msg *types.MsgOptOut) (*types.M return &types.MsgOptOutResponse{}, nil } + +func (k msgServer) SetConsumerCommissionRate(goCtx context.Context, msg *types.MsgSetConsumerCommissionRate) (*types.MsgSetConsumerCommissionRateResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + providerValidatorAddr, err := sdk.ValAddressFromBech32(msg.ProviderAddr) + if err != nil { + return nil, err + } + + // validator must already be registered + validator, found := k.stakingKeeper.GetValidator(ctx, providerValidatorAddr) + if !found { + return nil, stakingtypes.ErrNoValidatorFound + } + + consAddr, err := validator.GetConsAddr() + if err != nil { + return nil, err + } + + if err := k.HandleSetConsumerCommissionRate(ctx, msg.ChainId, types.NewProviderConsAddress(consAddr), msg.Rate); err != nil { + return nil, err + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeSetConsumerCommissionRate, + sdk.NewAttribute(types.AttributeConsumerChainID, msg.ChainId), + sdk.NewAttribute(types.AttributeProviderValidatorAddress, msg.ProviderAddr), + sdk.NewAttribute(types.AttributeConsumerCommissionRate, msg.Rate.String()), + ), + }) + + return &types.MsgSetConsumerCommissionRateResponse{}, nil +} diff --git a/x/ccv/provider/keeper/partial_set_security_test.go b/x/ccv/provider/keeper/partial_set_security_test.go index 1af5f58c7c..a6b2ec45e7 100644 --- a/x/ccv/provider/keeper/partial_set_security_test.go +++ b/x/ccv/provider/keeper/partial_set_security_test.go @@ -112,3 +112,28 @@ func TestHandleOptOut(t *testing.T) { require.NoError(t, err) require.False(t, providerKeeper.IsToBeOptedOut(ctx, "chainID", providerAddr)) } + +func TestHandleSetConsumerCommissionRate(t *testing.T) { + providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + providerAddr := types.NewProviderConsAddress([]byte("providerAddr")) + + // trying to set a commission rate to a unknown consumer chain + require.Error(t, providerKeeper.HandleSetConsumerCommissionRate(ctx, "unknownChainID", providerAddr, sdk.ZeroDec())) + + // setup a pending consumer chain + chainID := "pendingChainID" + providerKeeper.SetPendingConsumerAdditionProp(ctx, &types.ConsumerAdditionProposal{ChainId: chainID}) + + // check that there's no commission rate set for the validator yet + _, found := providerKeeper.GetConsumerCommissionRate(ctx, chainID, providerAddr) + require.False(t, found) + + require.NoError(t, providerKeeper.HandleSetConsumerCommissionRate(ctx, chainID, providerAddr, sdk.OneDec())) + + // check that the commission rate is now set + cr, found := providerKeeper.GetConsumerCommissionRate(ctx, chainID, providerAddr) + require.Equal(t, sdk.OneDec(), cr) + require.True(t, found) +} diff --git a/x/ccv/provider/keeper/proposal.go b/x/ccv/provider/keeper/proposal.go index f1af329d60..e8d50133ba 100644 --- a/x/ccv/provider/keeper/proposal.go +++ b/x/ccv/provider/keeper/proposal.go @@ -190,6 +190,12 @@ func (k Keeper) StopConsumerChain(ctx sdk.Context, chainID string, closeChan boo k.DeleteVscSendTimestampsForConsumer(ctx, chainID) } + // delete consumer commission rate + provAddrs := k.GetAllCommissionRateValidators(ctx, chainID) + for _, addr := range provAddrs { + k.DeleteConsumerCommissionRate(ctx, chainID, addr) + } + k.DeleteInitChainHeight(ctx, chainID) k.DeleteSlashAcks(ctx, chainID) k.DeletePendingVSCPackets(ctx, chainID) diff --git a/x/ccv/provider/keeper/proposal_test.go b/x/ccv/provider/keeper/proposal_test.go index 8de4282474..99e8c74e49 100644 --- a/x/ccv/provider/keeper/proposal_test.go +++ b/x/ccv/provider/keeper/proposal_test.go @@ -554,10 +554,6 @@ func TestStopConsumerChain(t *testing.T) { require.Error(t, err) } else { require.NoError(t, err) - - // in case the chain was successfully stopped, it should not contain a Top N associated to it - _, found := providerKeeper.GetTopN(ctx, "chainID") - require.False(t, found) } testkeeper.TestProviderStateIsCleanedAfterConsumerChainIsStopped(t, ctx, providerKeeper, "chainID", "channelID") diff --git a/x/ccv/provider/types/errors.go b/x/ccv/provider/types/errors.go index 6c19a7b396..271ea90329 100644 --- a/x/ccv/provider/types/errors.go +++ b/x/ccv/provider/types/errors.go @@ -24,4 +24,5 @@ var ( ErrInvalidConsumerClient = errorsmod.Register(ModuleName, 16, "ccv channel is not built on correct client") ErrDuplicateConsumerChain = errorsmod.Register(ModuleName, 17, "consumer chain already exists") ErrConsumerChainNotFound = errorsmod.Register(ModuleName, 18, "consumer chain not found") + ErrInvalidConsumerCommissionRate = errorsmod.Register(ModuleName, 19, "consumer commission rate is invalid") ) diff --git a/x/ccv/provider/types/events.go b/x/ccv/provider/types/events.go index 58d686020f..4838c1ba43 100644 --- a/x/ccv/provider/types/events.go +++ b/x/ccv/provider/types/events.go @@ -7,6 +7,7 @@ const ( EventTypeAddConsumerRewardDenom = "add_consumer_reward_denom" EventTypeRemoveConsumerRewardDenom = "remove_consumer_reward_denom" EventTypeExecuteConsumerChainSlash = "execute_consumer_chain_slash" + EventTypeSetConsumerCommissionRate = "set_consumer_commission_rate" AttributeInfractionHeight = "infraction_height" AttributeInitialHeight = "initial_height" AttributeInitializationTimeout = "initialization_timeout" @@ -15,4 +16,6 @@ const ( AttributeProviderValidatorAddress = "provider_validator_address" AttributeConsumerConsensusPubKey = "consumer_consensus_pub_key" AttributeConsumerRewardDenom = "consumer_reward_denom" + AttributeConsumerCommissionRate = "consumer_commission_rate" + AttributeConsumerChainID = "consumer_chain_id" ) diff --git a/x/ccv/provider/types/keys.go b/x/ccv/provider/types/keys.go index e0b25bf9a0..998608ef18 100644 --- a/x/ccv/provider/types/keys.go +++ b/x/ccv/provider/types/keys.go @@ -169,6 +169,10 @@ const ( // it allocated to the consumer rewards pool ConsumerRewardsAllocationBytePrefix + // ConsumerCommissionRatePrefix is the byte prefix used when storing a validator a per-consumer chain commission rate + // for a validator address + ConsumerCommissionRatePrefix + // NOTE: DO NOT ADD NEW BYTE PREFIXES HERE WITHOUT ADDING THEM TO getAllKeyPrefixes() IN keys_test.go ) @@ -569,6 +573,15 @@ func ConsumerRewardsAllocationKey(chainID string) []byte { return append([]byte{ConsumerRewardsAllocationBytePrefix}, []byte(chainID)...) } +// ConsumerCommissionRateKey returns the key of consumer chain `chainID` and validator with `providerAddr` +func ConsumerCommissionRateKey(chainID string, providerAddr ProviderConsAddress) []byte { + return ChainIdAndConsAddrKey( + ConsumerCommissionRatePrefix, + chainID, + providerAddr.ToSdkConsAddr(), + ) +} + // // End of generic helpers section // diff --git a/x/ccv/provider/types/keys_test.go b/x/ccv/provider/types/keys_test.go index 87864d67be..f24c6ec476 100644 --- a/x/ccv/provider/types/keys_test.go +++ b/x/ccv/provider/types/keys_test.go @@ -62,6 +62,7 @@ func getAllKeyPrefixes() []byte { providertypes.ToBeOptedInBytePrefix, providertypes.ToBeOptedOutBytePrefix, providertypes.ConsumerRewardsAllocationBytePrefix, + providertypes.ConsumerCommissionRatePrefix, } } diff --git a/x/ccv/provider/types/msg.go b/x/ccv/provider/types/msg.go index 20aae43f6c..1a8d6fa145 100644 --- a/x/ccv/provider/types/msg.go +++ b/x/ccv/provider/types/msg.go @@ -24,6 +24,7 @@ const ( TypeMsgSubmitConsumerDoubleVoting = "submit_consumer_double_vote" TypeMsgOptIn = "opt_in" TypeMsgOptOut = "opt_out" + TypeMsgSetConsumerCommissionRate = "set_consumer_commission_rate" ) var ( @@ -32,6 +33,7 @@ var ( _ sdk.Msg = &MsgSubmitConsumerDoubleVoting{} _ sdk.Msg = &MsgOptIn{} _ sdk.Msg = &MsgOptOut{} + _ sdk.Msg = &MsgSetConsumerCommissionRate{} ) // NewMsgAssignConsumerKey creates a new MsgAssignConsumerKey instance. @@ -316,3 +318,45 @@ func (msg MsgOptOut) ValidateBasic() error { func (msg MsgOptOut) Type() string { return TypeMsgOptOut } + +func (msg MsgSetConsumerCommissionRate) Route() string { + return RouterKey +} + +func (msg MsgSetConsumerCommissionRate) Type() string { + return TypeMsgSetConsumerCommissionRate +} + +func (msg MsgSetConsumerCommissionRate) ValidateBasic() error { + if strings.TrimSpace(msg.ChainId) == "" { + return errorsmod.Wrapf(ErrInvalidConsumerChainID, "chainId cannot be blank") + } + + if 128 < len(msg.ChainId) { + return errorsmod.Wrapf(ErrInvalidConsumerChainID, "chainId cannot exceed 128 length") + } + _, err := sdk.ValAddressFromBech32(msg.ProviderAddr) + if err != nil { + return ErrInvalidProviderAddress + } + + if msg.Rate.IsNegative() || msg.Rate.GT(sdk.OneDec()) { + return errorsmod.Wrapf(ErrInvalidConsumerCommissionRate, "consumer commission rate should be in the range [0, 1]") + } + + return nil +} + +func (msg MsgSetConsumerCommissionRate) GetSigners() []sdk.AccAddress { + valAddr, err := sdk.ValAddressFromBech32(msg.ProviderAddr) + if err != nil { + // same behavior as in cosmos-sdk + panic(err) + } + return []sdk.AccAddress{valAddr.Bytes()} +} + +func (msg MsgSetConsumerCommissionRate) GetSignBytes() []byte { + bz := ccvtypes.ModuleCdc.MustMarshalJSON(&msg) + return sdk.MustSortJSON(bz) +} diff --git a/x/ccv/provider/types/tx.pb.go b/x/ccv/provider/types/tx.pb.go index 647f5f49dc..7330433f5b 100644 --- a/x/ccv/provider/types/tx.pb.go +++ b/x/ccv/provider/types/tx.pb.go @@ -9,6 +9,7 @@ import ( types "github.com/cometbft/cometbft/proto/tendermint/types" _ "github.com/cosmos/cosmos-proto" _ "github.com/cosmos/cosmos-sdk/codec/types" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" _ "github.com/cosmos/gogoproto/gogoproto" grpc1 "github.com/cosmos/gogoproto/grpc" proto "github.com/cosmos/gogoproto/proto" @@ -426,6 +427,86 @@ func (m *MsgOptOutResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgOptOutResponse proto.InternalMessageInfo +// MsgSetConsumerCommissionRate allows validators to set +// a per-consumer chain commission rate +type MsgSetConsumerCommissionRate struct { + // The validator address on the provider + ProviderAddr string `protobuf:"bytes,1,opt,name=provider_addr,json=providerAddr,proto3" json:"provider_addr,omitempty" yaml:"address"` + // The chain id of the consumer chain to set a commission rate + ChainId string `protobuf:"bytes,2,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + // The rate to charge delegators on the consumer chain, as a fraction + Rate github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=rate,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"rate"` +} + +func (m *MsgSetConsumerCommissionRate) Reset() { *m = MsgSetConsumerCommissionRate{} } +func (m *MsgSetConsumerCommissionRate) String() string { return proto.CompactTextString(m) } +func (*MsgSetConsumerCommissionRate) ProtoMessage() {} +func (*MsgSetConsumerCommissionRate) Descriptor() ([]byte, []int) { + return fileDescriptor_43221a4391e9fbf4, []int{10} +} +func (m *MsgSetConsumerCommissionRate) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSetConsumerCommissionRate) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSetConsumerCommissionRate.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgSetConsumerCommissionRate) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSetConsumerCommissionRate.Merge(m, src) +} +func (m *MsgSetConsumerCommissionRate) XXX_Size() int { + return m.Size() +} +func (m *MsgSetConsumerCommissionRate) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSetConsumerCommissionRate.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSetConsumerCommissionRate proto.InternalMessageInfo + +type MsgSetConsumerCommissionRateResponse struct { +} + +func (m *MsgSetConsumerCommissionRateResponse) Reset() { *m = MsgSetConsumerCommissionRateResponse{} } +func (m *MsgSetConsumerCommissionRateResponse) String() string { return proto.CompactTextString(m) } +func (*MsgSetConsumerCommissionRateResponse) ProtoMessage() {} +func (*MsgSetConsumerCommissionRateResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_43221a4391e9fbf4, []int{11} +} +func (m *MsgSetConsumerCommissionRateResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSetConsumerCommissionRateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSetConsumerCommissionRateResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgSetConsumerCommissionRateResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSetConsumerCommissionRateResponse.Merge(m, src) +} +func (m *MsgSetConsumerCommissionRateResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgSetConsumerCommissionRateResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSetConsumerCommissionRateResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSetConsumerCommissionRateResponse proto.InternalMessageInfo + func init() { proto.RegisterType((*MsgAssignConsumerKey)(nil), "interchain_security.ccv.provider.v1.MsgAssignConsumerKey") proto.RegisterType((*MsgAssignConsumerKeyResponse)(nil), "interchain_security.ccv.provider.v1.MsgAssignConsumerKeyResponse") @@ -437,6 +518,8 @@ func init() { proto.RegisterType((*MsgOptInResponse)(nil), "interchain_security.ccv.provider.v1.MsgOptInResponse") proto.RegisterType((*MsgOptOut)(nil), "interchain_security.ccv.provider.v1.MsgOptOut") proto.RegisterType((*MsgOptOutResponse)(nil), "interchain_security.ccv.provider.v1.MsgOptOutResponse") + proto.RegisterType((*MsgSetConsumerCommissionRate)(nil), "interchain_security.ccv.provider.v1.MsgSetConsumerCommissionRate") + proto.RegisterType((*MsgSetConsumerCommissionRateResponse)(nil), "interchain_security.ccv.provider.v1.MsgSetConsumerCommissionRateResponse") } func init() { @@ -444,50 +527,57 @@ func init() { } var fileDescriptor_43221a4391e9fbf4 = []byte{ - // 683 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x55, 0x4d, 0x4f, 0xd4, 0x40, - 0x18, 0xde, 0x42, 0x40, 0x18, 0xd0, 0x48, 0x85, 0x00, 0x1b, 0xec, 0xea, 0x1a, 0xc5, 0x03, 0xcc, - 0x04, 0xfc, 0x8a, 0x24, 0x1e, 0x58, 0x31, 0x11, 0xcd, 0x06, 0xb3, 0x26, 0x98, 0x78, 0xb0, 0x69, - 0xa7, 0x43, 0x77, 0x42, 0x3b, 0xd3, 0xcc, 0x4c, 0x1b, 0xf6, 0x1f, 0x90, 0x78, 0xd1, 0x93, 0xf1, - 0xc6, 0x0f, 0xf0, 0x87, 0x78, 0xe4, 0xc8, 0xc9, 0x18, 0xb8, 0x78, 0xf6, 0x17, 0x98, 0x9d, 0x7e, - 0x6c, 0x89, 0x2b, 0x5f, 0xc6, 0x78, 0xeb, 0xbc, 0xef, 0x33, 0xcf, 0xf3, 0xbc, 0x6f, 0xe7, 0x9d, - 0x01, 0x0b, 0x94, 0x29, 0x22, 0x70, 0xdb, 0xa1, 0xcc, 0x96, 0x04, 0xc7, 0x82, 0xaa, 0x0e, 0xc2, - 0x38, 0x41, 0x91, 0xe0, 0x09, 0xf5, 0x88, 0x40, 0xc9, 0x12, 0x52, 0x3b, 0x30, 0x12, 0x5c, 0x71, - 0xf3, 0x56, 0x1f, 0x34, 0xc4, 0x38, 0x81, 0x39, 0x1a, 0x26, 0x4b, 0xd5, 0x49, 0x9f, 0xfb, 0x5c, - 0xe3, 0x51, 0xf7, 0x2b, 0xdd, 0x5a, 0x9d, 0xc5, 0x5c, 0x86, 0x5c, 0xda, 0x69, 0x22, 0x5d, 0xe4, - 0x29, 0x9f, 0x73, 0x3f, 0x20, 0x48, 0xaf, 0xdc, 0x78, 0x0b, 0x39, 0xac, 0x93, 0xa5, 0x10, 0x75, - 0x31, 0x0a, 0xa8, 0xdf, 0x56, 0x38, 0xa0, 0x84, 0x29, 0x89, 0x14, 0x61, 0x1e, 0x11, 0x21, 0x65, - 0x4a, 0x3b, 0x2b, 0x56, 0xd9, 0x86, 0x5a, 0x29, 0xaf, 0x3a, 0x11, 0x91, 0x88, 0x74, 0x8d, 0x31, - 0x4c, 0x52, 0x40, 0xfd, 0x93, 0x01, 0x26, 0x9b, 0xd2, 0x5f, 0x95, 0x92, 0xfa, 0xec, 0x29, 0x67, - 0x32, 0x0e, 0x89, 0x78, 0x49, 0x3a, 0xe6, 0x2c, 0x18, 0x49, 0x0b, 0xa3, 0xde, 0x8c, 0x71, 0xc3, - 0xb8, 0x3b, 0xda, 0xba, 0xa4, 0xd7, 0xeb, 0x9e, 0xf9, 0x08, 0x5c, 0xce, 0x0b, 0xb4, 0x1d, 0xcf, - 0x13, 0x33, 0x03, 0xdd, 0x7c, 0xc3, 0xfc, 0xf9, 0xad, 0x76, 0xa5, 0xe3, 0x84, 0xc1, 0x4a, 0xbd, - 0x1b, 0x25, 0x52, 0xd6, 0x5b, 0xe3, 0x39, 0x70, 0xd5, 0xf3, 0x84, 0x79, 0x13, 0x8c, 0xe3, 0x4c, - 0xc2, 0xde, 0x26, 0x9d, 0x99, 0x41, 0xcd, 0x3b, 0x86, 0x7b, 0xb2, 0x2b, 0x23, 0xbb, 0x7b, 0xb5, - 0xca, 0x8f, 0xbd, 0x5a, 0xa5, 0x6e, 0x81, 0xb9, 0x7e, 0xc6, 0x5a, 0x44, 0x46, 0x9c, 0x49, 0x52, - 0xff, 0x6c, 0x80, 0xeb, 0x4d, 0xe9, 0xbf, 0x8e, 0xdd, 0x90, 0xaa, 0x1c, 0xd0, 0xa4, 0xd2, 0x25, - 0x6d, 0x27, 0xa1, 0x3c, 0x16, 0xe6, 0x1c, 0x18, 0x95, 0x3a, 0xab, 0x88, 0xc8, 0x6a, 0xe8, 0x05, - 0xcc, 0x57, 0x60, 0x3c, 0x2c, 0xa1, 0x75, 0x11, 0x63, 0xcb, 0x0b, 0x90, 0xba, 0x18, 0x96, 0x5b, - 0x0c, 0x4b, 0x4d, 0x4d, 0x96, 0x60, 0x59, 0xa1, 0x75, 0x8c, 0xa1, 0xe4, 0x7d, 0x1e, 0xdc, 0x3e, - 0xd1, 0x5a, 0x51, 0xc4, 0xee, 0x40, 0x9f, 0x22, 0xd6, 0x78, 0xec, 0x06, 0x64, 0x93, 0x2b, 0xca, - 0xfc, 0x53, 0x8a, 0xb0, 0xc1, 0xb4, 0x17, 0x47, 0x01, 0xc5, 0x8e, 0x22, 0x76, 0xc2, 0x15, 0xb1, - 0xf3, 0xff, 0x9b, 0xd5, 0x33, 0x5f, 0xb6, 0xaf, 0x4f, 0x00, 0x5c, 0xcb, 0x37, 0x6c, 0x72, 0x45, - 0x9e, 0x65, 0xf0, 0xd6, 0x94, 0xd7, 0x2f, 0x6c, 0xbe, 0x03, 0xd3, 0x94, 0x6d, 0x09, 0x07, 0x2b, - 0xca, 0x99, 0xed, 0x06, 0x1c, 0x6f, 0xdb, 0x6d, 0xe2, 0x78, 0x44, 0xe8, 0xbf, 0x37, 0xb6, 0x7c, - 0xe7, 0xb4, 0x86, 0x3d, 0xd7, 0xe8, 0xd6, 0x54, 0x8f, 0xa6, 0xd1, 0x65, 0x49, 0xc3, 0xa7, 0xf4, - 0xac, 0xdc, 0x89, 0xa2, 0x67, 0xef, 0x0d, 0x30, 0xd2, 0x94, 0xfe, 0x46, 0xa4, 0xd6, 0xd9, 0xff, - 0x3f, 0xa6, 0x26, 0xb8, 0x9a, 0x9b, 0x29, 0x1c, 0x52, 0x30, 0x9a, 0xc6, 0x36, 0x62, 0xf5, 0x2f, - 0x1c, 0x96, 0xe4, 0xaf, 0x81, 0x89, 0x42, 0x2a, 0xd7, 0x5f, 0x3e, 0x18, 0x02, 0x83, 0x4d, 0xe9, - 0x9b, 0x1f, 0x0d, 0x30, 0xf1, 0xfb, 0x64, 0x3f, 0x86, 0x67, 0xb8, 0xb6, 0x60, 0xbf, 0xd9, 0xab, - 0xae, 0x5e, 0x78, 0x6b, 0xee, 0xcd, 0xfc, 0x62, 0x80, 0xea, 0x09, 0x33, 0xdb, 0x38, 0xab, 0xc2, - 0x9f, 0x39, 0xaa, 0x2f, 0xfe, 0x9e, 0xe3, 0x04, 0xbb, 0xc7, 0xa6, 0xf3, 0x82, 0x76, 0xcb, 0x1c, - 0x17, 0xb5, 0xdb, 0x6f, 0x36, 0xcc, 0x10, 0x0c, 0xa5, 0x73, 0xb1, 0x78, 0x56, 0x52, 0x0d, 0xaf, - 0x3e, 0x38, 0x17, 0xbc, 0x90, 0x8b, 0xc0, 0x70, 0x76, 0xca, 0xe1, 0x39, 0x08, 0x36, 0x62, 0x55, - 0x7d, 0x78, 0x3e, 0x7c, 0xae, 0xd8, 0x78, 0xf3, 0xf5, 0xd0, 0x32, 0xf6, 0x0f, 0x2d, 0xe3, 0xfb, - 0xa1, 0x65, 0x7c, 0x38, 0xb2, 0x2a, 0xfb, 0x47, 0x56, 0xe5, 0xe0, 0xc8, 0xaa, 0xbc, 0x7d, 0xe2, - 0x53, 0xd5, 0x8e, 0x5d, 0x88, 0x79, 0x98, 0xbd, 0xa7, 0xa8, 0x27, 0xb1, 0x58, 0x3c, 0xe6, 0xc9, - 0x7d, 0xb4, 0x73, 0xfc, 0x45, 0xd7, 0xb7, 0xa2, 0x3b, 0xac, 0xdf, 0xc3, 0x7b, 0xbf, 0x02, 0x00, - 0x00, 0xff, 0xff, 0x3b, 0x47, 0x43, 0x85, 0x02, 0x08, 0x00, 0x00, + // 787 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x56, 0xcd, 0x4f, 0xd4, 0x4e, + 0x18, 0xde, 0xc2, 0xef, 0xc7, 0xc7, 0x80, 0x46, 0x2a, 0x04, 0x68, 0x70, 0x57, 0x57, 0x05, 0x0f, + 0x6c, 0x1b, 0xf0, 0x2b, 0x12, 0x3d, 0xb0, 0x60, 0x22, 0x9a, 0x0d, 0xa4, 0x24, 0x98, 0x78, 0xb0, + 0x69, 0xa7, 0x43, 0x77, 0xc2, 0x76, 0xa6, 0xe9, 0x4c, 0x1b, 0xf6, 0xee, 0x81, 0xc4, 0x8b, 0x9e, + 0x8c, 0x37, 0xae, 0x26, 0x1e, 0xfd, 0x23, 0x38, 0x19, 0xe2, 0xc9, 0x78, 0x20, 0x06, 0x2e, 0x9e, + 0xfd, 0x0b, 0xcc, 0x4e, 0x3f, 0xb6, 0x1b, 0x96, 0x65, 0x81, 0x18, 0x4f, 0xbb, 0x33, 0xef, 0x33, + 0xcf, 0xfb, 0x3c, 0x6f, 0xa7, 0x4f, 0x0a, 0x66, 0x31, 0xe1, 0xc8, 0x87, 0x55, 0x13, 0x13, 0x83, + 0x21, 0x18, 0xf8, 0x98, 0xd7, 0x35, 0x08, 0x43, 0xcd, 0xf3, 0x69, 0x88, 0x6d, 0xe4, 0x6b, 0xe1, + 0x9c, 0xc6, 0xb7, 0x55, 0xcf, 0xa7, 0x9c, 0xca, 0x37, 0xdb, 0xa0, 0x55, 0x08, 0x43, 0x35, 0x41, + 0xab, 0xe1, 0x9c, 0x32, 0xea, 0x50, 0x87, 0x0a, 0xbc, 0xd6, 0xf8, 0x17, 0x1d, 0x55, 0x26, 0x21, + 0x65, 0x2e, 0x65, 0x46, 0x54, 0x88, 0x16, 0x49, 0xc9, 0xa1, 0xd4, 0xa9, 0x21, 0x4d, 0xac, 0xac, + 0x60, 0x53, 0x33, 0x49, 0x3d, 0x2e, 0x69, 0xd8, 0x82, 0x5a, 0x0d, 0x3b, 0x55, 0x0e, 0x6b, 0x18, + 0x11, 0xce, 0x34, 0x8e, 0x88, 0x8d, 0x7c, 0x17, 0x13, 0x2e, 0x94, 0xa5, 0xab, 0xf8, 0x40, 0x21, + 0x53, 0xe7, 0x75, 0x0f, 0x31, 0x0d, 0x35, 0x84, 0x11, 0x88, 0x22, 0x40, 0xf1, 0x83, 0x04, 0x46, + 0x2b, 0xcc, 0x59, 0x64, 0x0c, 0x3b, 0x64, 0x89, 0x12, 0x16, 0xb8, 0xc8, 0x7f, 0x81, 0xea, 0xf2, + 0x24, 0x18, 0x88, 0x8c, 0x61, 0x7b, 0x42, 0xba, 0x2e, 0xdd, 0x19, 0xd4, 0xfb, 0xc5, 0x7a, 0xc5, + 0x96, 0x1f, 0x82, 0x4b, 0x89, 0x41, 0xc3, 0xb4, 0x6d, 0x7f, 0xa2, 0xa7, 0x51, 0x2f, 0xcb, 0xbf, + 0x0f, 0x0a, 0x97, 0xeb, 0xa6, 0x5b, 0x5b, 0x28, 0x36, 0x76, 0x11, 0x63, 0x45, 0x7d, 0x38, 0x01, + 0x2e, 0xda, 0xb6, 0x2f, 0xdf, 0x00, 0xc3, 0x30, 0x6e, 0x61, 0x6c, 0xa1, 0xfa, 0x44, 0xaf, 0xe0, + 0x1d, 0x82, 0xcd, 0xb6, 0x0b, 0x03, 0x3b, 0xbb, 0x85, 0xdc, 0xaf, 0xdd, 0x42, 0xae, 0x98, 0x07, + 0x53, 0xed, 0x84, 0xe9, 0x88, 0x79, 0x94, 0x30, 0x54, 0xfc, 0x28, 0x81, 0x6b, 0x15, 0xe6, 0xac, + 0x07, 0x96, 0x8b, 0x79, 0x02, 0xa8, 0x60, 0x66, 0xa1, 0xaa, 0x19, 0x62, 0x1a, 0xf8, 0xf2, 0x14, + 0x18, 0x64, 0xa2, 0xca, 0x91, 0x1f, 0x7b, 0x68, 0x6e, 0xc8, 0x6b, 0x60, 0xd8, 0xcd, 0xa0, 0x85, + 0x89, 0xa1, 0xf9, 0x59, 0x15, 0x5b, 0x50, 0xcd, 0x8e, 0x58, 0xcd, 0x0c, 0x35, 0x9c, 0x53, 0xb3, + 0x1d, 0xf4, 0x16, 0x86, 0x8c, 0xf6, 0x19, 0x70, 0xbb, 0xa3, 0xb4, 0xd4, 0xc4, 0x4e, 0x4f, 0x1b, + 0x13, 0xcb, 0x34, 0xb0, 0x6a, 0x68, 0x83, 0x72, 0x4c, 0x9c, 0x53, 0x4c, 0x18, 0x60, 0xdc, 0x0e, + 0xbc, 0x1a, 0x86, 0x26, 0x47, 0x46, 0x48, 0x39, 0x32, 0x92, 0xe7, 0x1b, 0xfb, 0x99, 0xc9, 0xca, + 0x17, 0x37, 0x40, 0x5d, 0x4e, 0x0e, 0x6c, 0x50, 0x8e, 0x9e, 0xc6, 0x70, 0x7d, 0xcc, 0x6e, 0xb7, + 0x2d, 0xbf, 0x06, 0xe3, 0x98, 0x6c, 0xfa, 0x26, 0xe4, 0x98, 0x12, 0xc3, 0xaa, 0x51, 0xb8, 0x65, + 0x54, 0x91, 0x69, 0x23, 0x5f, 0x3c, 0xbd, 0xa1, 0xf9, 0xe9, 0xd3, 0x06, 0xf6, 0x4c, 0xa0, 0xf5, + 0xb1, 0x26, 0x4d, 0xb9, 0xc1, 0x12, 0x6d, 0x9f, 0x32, 0xb3, 0xec, 0x24, 0xd2, 0x99, 0xbd, 0x95, + 0xc0, 0x40, 0x85, 0x39, 0xab, 0x1e, 0x5f, 0x21, 0xff, 0xfe, 0x9a, 0xca, 0xe0, 0x4a, 0x22, 0x26, + 0x55, 0x88, 0xc1, 0x60, 0xb4, 0xb7, 0x1a, 0xf0, 0xbf, 0xa1, 0x30, 0xd3, 0xfe, 0x2a, 0x18, 0x49, + 0x5b, 0xa5, 0xfd, 0xbf, 0x4a, 0xe2, 0xdd, 0x59, 0x47, 0xe9, 0x20, 0x97, 0xa8, 0xeb, 0x62, 0xc6, + 0x30, 0x25, 0xba, 0xc9, 0xd1, 0xf1, 0xc6, 0x52, 0x97, 0xa3, 0xc9, 0x9a, 0xe9, 0x69, 0x35, 0xb3, + 0x06, 0xfe, 0xf3, 0x4d, 0x8e, 0xa2, 0x69, 0x95, 0x1f, 0xef, 0x1d, 0x14, 0x72, 0x3f, 0x0e, 0x0a, + 0xd3, 0x0e, 0xe6, 0xd5, 0xc0, 0x52, 0x21, 0x75, 0xe3, 0x94, 0x8b, 0x7f, 0x4a, 0xcc, 0xde, 0xd2, + 0xe2, 0x0b, 0x89, 0xe0, 0xb7, 0x2f, 0x25, 0x10, 0x87, 0xe0, 0x32, 0x82, 0xba, 0x60, 0xca, 0xb8, + 0x9c, 0x06, 0xb7, 0x3a, 0xf9, 0x49, 0x8c, 0xcf, 0xbf, 0xe9, 0x07, 0xbd, 0x15, 0xe6, 0xc8, 0xef, + 0x25, 0x30, 0x72, 0x3c, 0xd2, 0x1e, 0xa9, 0x5d, 0xe4, 0xb5, 0xda, 0x2e, 0x74, 0x94, 0xc5, 0x73, + 0x1f, 0x4d, 0xb4, 0xc9, 0x9f, 0x25, 0xa0, 0x74, 0x08, 0xab, 0x72, 0xb7, 0x1d, 0x4e, 0xe6, 0x50, + 0x9e, 0x5f, 0x9c, 0xa3, 0x83, 0xdc, 0x96, 0x58, 0x3a, 0xa7, 0xdc, 0x2c, 0xc7, 0x79, 0xe5, 0xb6, + 0x0b, 0x05, 0xd9, 0x05, 0xff, 0x47, 0x81, 0x50, 0xea, 0x96, 0x54, 0xc0, 0x95, 0xfb, 0x67, 0x82, + 0xa7, 0xed, 0x3c, 0xd0, 0x17, 0xbf, 0xde, 0xea, 0x19, 0x08, 0x56, 0x03, 0xae, 0x3c, 0x38, 0x1b, + 0x3e, 0xed, 0xf8, 0x49, 0x02, 0x93, 0x27, 0xbf, 0xd0, 0x5d, 0xdf, 0xcf, 0x13, 0x29, 0x94, 0x95, + 0x0b, 0x53, 0x24, 0x5a, 0xcb, 0x2f, 0xf7, 0x0e, 0xf3, 0xd2, 0xfe, 0x61, 0x5e, 0xfa, 0x79, 0x98, + 0x97, 0xde, 0x1d, 0xe5, 0x73, 0xfb, 0x47, 0xf9, 0xdc, 0xf7, 0xa3, 0x7c, 0xee, 0xd5, 0x93, 0xe3, + 0x71, 0xd0, 0xec, 0x5a, 0x4a, 0xbf, 0xb8, 0xc2, 0x7b, 0xda, 0x76, 0xeb, 0x67, 0x97, 0x48, 0x0a, + 0xab, 0x4f, 0x7c, 0xb4, 0xdc, 0xfd, 0x13, 0x00, 0x00, 0xff, 0xff, 0x76, 0xb7, 0xbf, 0x16, 0xa7, + 0x09, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -507,6 +597,7 @@ type MsgClient interface { SubmitConsumerDoubleVoting(ctx context.Context, in *MsgSubmitConsumerDoubleVoting, opts ...grpc.CallOption) (*MsgSubmitConsumerDoubleVotingResponse, error) OptIn(ctx context.Context, in *MsgOptIn, opts ...grpc.CallOption) (*MsgOptInResponse, error) OptOut(ctx context.Context, in *MsgOptOut, opts ...grpc.CallOption) (*MsgOptOutResponse, error) + SetConsumerCommissionRate(ctx context.Context, in *MsgSetConsumerCommissionRate, opts ...grpc.CallOption) (*MsgSetConsumerCommissionRateResponse, error) } type msgClient struct { @@ -562,6 +653,15 @@ func (c *msgClient) OptOut(ctx context.Context, in *MsgOptOut, opts ...grpc.Call return out, nil } +func (c *msgClient) SetConsumerCommissionRate(ctx context.Context, in *MsgSetConsumerCommissionRate, opts ...grpc.CallOption) (*MsgSetConsumerCommissionRateResponse, error) { + out := new(MsgSetConsumerCommissionRateResponse) + err := c.cc.Invoke(ctx, "/interchain_security.ccv.provider.v1.Msg/SetConsumerCommissionRate", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // MsgServer is the server API for Msg service. type MsgServer interface { AssignConsumerKey(context.Context, *MsgAssignConsumerKey) (*MsgAssignConsumerKeyResponse, error) @@ -569,6 +669,7 @@ type MsgServer interface { SubmitConsumerDoubleVoting(context.Context, *MsgSubmitConsumerDoubleVoting) (*MsgSubmitConsumerDoubleVotingResponse, error) OptIn(context.Context, *MsgOptIn) (*MsgOptInResponse, error) OptOut(context.Context, *MsgOptOut) (*MsgOptOutResponse, error) + SetConsumerCommissionRate(context.Context, *MsgSetConsumerCommissionRate) (*MsgSetConsumerCommissionRateResponse, error) } // UnimplementedMsgServer can be embedded to have forward compatible implementations. @@ -590,6 +691,9 @@ func (*UnimplementedMsgServer) OptIn(ctx context.Context, req *MsgOptIn) (*MsgOp func (*UnimplementedMsgServer) OptOut(ctx context.Context, req *MsgOptOut) (*MsgOptOutResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method OptOut not implemented") } +func (*UnimplementedMsgServer) SetConsumerCommissionRate(ctx context.Context, req *MsgSetConsumerCommissionRate) (*MsgSetConsumerCommissionRateResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SetConsumerCommissionRate not implemented") +} func RegisterMsgServer(s grpc1.Server, srv MsgServer) { s.RegisterService(&_Msg_serviceDesc, srv) @@ -685,6 +789,24 @@ func _Msg_OptOut_Handler(srv interface{}, ctx context.Context, dec func(interfac return interceptor(ctx, in, info, handler) } +func _Msg_SetConsumerCommissionRate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgSetConsumerCommissionRate) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).SetConsumerCommissionRate(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/interchain_security.ccv.provider.v1.Msg/SetConsumerCommissionRate", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).SetConsumerCommissionRate(ctx, req.(*MsgSetConsumerCommissionRate)) + } + return interceptor(ctx, in, info, handler) +} + var _Msg_serviceDesc = grpc.ServiceDesc{ ServiceName: "interchain_security.ccv.provider.v1.Msg", HandlerType: (*MsgServer)(nil), @@ -709,6 +831,10 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ MethodName: "OptOut", Handler: _Msg_OptOut_Handler, }, + { + MethodName: "SetConsumerCommissionRate", + Handler: _Msg_SetConsumerCommissionRate_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "interchain_security/ccv/provider/v1/tx.proto", @@ -1050,6 +1176,76 @@ func (m *MsgOptOutResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *MsgSetConsumerCommissionRate) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgSetConsumerCommissionRate) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSetConsumerCommissionRate) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.Rate.Size() + i -= size + if _, err := m.Rate.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if len(m.ChainId) > 0 { + i -= len(m.ChainId) + copy(dAtA[i:], m.ChainId) + i = encodeVarintTx(dAtA, i, uint64(len(m.ChainId))) + i-- + dAtA[i] = 0x12 + } + if len(m.ProviderAddr) > 0 { + i -= len(m.ProviderAddr) + copy(dAtA[i:], m.ProviderAddr) + i = encodeVarintTx(dAtA, i, uint64(len(m.ProviderAddr))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgSetConsumerCommissionRateResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgSetConsumerCommissionRateResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSetConsumerCommissionRateResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + func encodeVarintTx(dAtA []byte, offset int, v uint64) int { offset -= sovTx(v) base := offset @@ -1203,6 +1399,34 @@ func (m *MsgOptOutResponse) Size() (n int) { return n } +func (m *MsgSetConsumerCommissionRate) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ProviderAddr) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ChainId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Rate.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgSetConsumerCommissionRateResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + func sovTx(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -2137,6 +2361,204 @@ func (m *MsgOptOutResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *MsgSetConsumerCommissionRate) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgSetConsumerCommissionRate: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSetConsumerCommissionRate: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProviderAddr", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProviderAddr = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChainId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Rate", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Rate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgSetConsumerCommissionRateResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgSetConsumerCommissionRateResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSetConsumerCommissionRateResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipTx(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 From 93647fe2fa18921d1d13495e0318b53d382ac142 Mon Sep 17 00:00:00 2001 From: Simon Noetzlin Date: Fri, 8 Mar 2024 15:43:07 +0100 Subject: [PATCH 015/110] test: update integration test suite for PSS (#1687) * draft multi consumer transfer setup and test * format multi consumer distribution test * update test for democ consumer chains * nits * nit --- tests/integration/distribution.go | 92 +++++++++++++++++++++++++++ tests/integration/setup.go | 67 +++++++++++++++---- testutil/ibc_testing/generic_setup.go | 19 ++++++ testutil/integration/debug_test.go | 4 ++ 4 files changed, 168 insertions(+), 14 deletions(-) diff --git a/tests/integration/distribution.go b/tests/integration/distribution.go index b047c2f523..3a2d96b5f6 100644 --- a/tests/integration/distribution.go +++ b/tests/integration/distribution.go @@ -1032,3 +1032,95 @@ func (s *CCVTestSuite) TestAllocateTokensToValidator() { }) } } + +// TestMultiConsumerRewardsDistribution tests the rewards distribution of multiple consumers chains +func (s *CCVTestSuite) TestMultiConsumerRewardsDistribution() { + s.SetupAllCCVChannels() + s.SetupAllTransferChannels() + + providerBankKeeper := s.providerApp.GetTestBankKeeper() + providerAccountKeeper := s.providerApp.GetTestAccountKeeper() + + // check that the reward provider pool is empty + rewardPool := providerAccountKeeper.GetModuleAccount(s.providerCtx(), providertypes.ConsumerRewardsPool).GetAddress() + rewardCoins := providerBankKeeper.GetAllBalances(s.providerCtx(), rewardPool) + s.Require().Empty(rewardCoins) + + totalConsumerRewards := sdk.Coins{} + + // Iterate over the consumers and perform the reward distribution + // to the provider + for chainID := range s.consumerBundles { + bundle := s.consumerBundles[chainID] + consumerKeeper := bundle.App.GetConsumerKeeper() + bankKeeper := bundle.App.GetTestBankKeeper() + accountKeeper := bundle.App.GetTestAccountKeeper() + + // set the consumer reward denom and the block per distribution params + params := consumerKeeper.GetConsumerParams(bundle.GetCtx()) + params.RewardDenoms = []string{sdk.DefaultBondDenom} + // set the reward distribution to be performed during the next block + params.BlocksPerDistributionTransmission = int64(1) + consumerKeeper.SetParams(bundle.GetCtx(), params) + + // transfer the consumer reward pool to the provider + var rewardsPerConsumer sdk.Coin + + // check the consumer pool balance + // Note that for a democracy consumer chain the pool may already be filled + if pool := bankKeeper.GetAllBalances( + bundle.GetCtx(), + accountKeeper.GetModuleAccount(bundle.GetCtx(), consumertypes.ConsumerToSendToProviderName).GetAddress(), + ); pool.Empty() { + // if pool is empty, fill it with some tokens + rewardsPerConsumer = sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)) + err := bankKeeper.SendCoinsFromAccountToModule( + bundle.GetCtx(), + bundle.Chain.SenderAccount.GetAddress(), + consumertypes.ConsumerToSendToProviderName, + sdk.NewCoins(rewardsPerConsumer), + ) + s.Require().NoError(err) + } else { + // execute the internal rewards distribution + // to save the pool's balance before + // it gets transferred to the provider in EndBlock + consumerKeeper.DistributeRewardsInternally(bundle.GetCtx()) + pool = bankKeeper.GetAllBalances( + bundle.GetCtx(), + accountKeeper.GetModuleAccount(bundle.GetCtx(), consumertypes.ConsumerToSendToProviderName).GetAddress(), + ) + s.Require().Len(pool, 1, "consumer reward pool cannot have mutiple token denoms") + rewardsPerConsumer = pool[0] + } + + // perform the reward transfer + bundle.Chain.NextBlock() + + // relay IBC transfer packet from consumer to provider + relayAllCommittedPackets( + s, + bundle.Chain, + bundle.TransferPath, + transfertypes.PortID, + bundle.TransferPath.EndpointA.ChannelID, + 1, + ) + + // construct the denom of the reward tokens for the provider + prefixedDenom := ibctransfertypes.GetPrefixedDenom( + transfertypes.PortID, + bundle.TransferPath.EndpointB.ChannelID, + rewardsPerConsumer.Denom, + ) + provIBCDenom := ibctransfertypes.ParseDenomTrace(prefixedDenom).IBCDenom() + + // sum the total rewards transferred to the provider + totalConsumerRewards = totalConsumerRewards. + Add(sdk.NewCoin(provIBCDenom, rewardsPerConsumer.Amount)) + } + + // Check that the provider receives the rewards of each consumer + rewardCoins = providerBankKeeper.GetAllBalances(s.providerCtx(), rewardPool) + s.Require().Equal(totalConsumerRewards, rewardCoins, totalConsumerRewards.String(), rewardCoins.String()) +} diff --git a/tests/integration/setup.go b/tests/integration/setup.go index 03c63d5502..cb14f7bada 100644 --- a/tests/integration/setup.go +++ b/tests/integration/setup.go @@ -142,12 +142,16 @@ func (suite *CCVTestSuite) SetupTest() { preProposalKeyAssignment(suite, icstestingutils.FirstConsumerChainID) // start consumer chains - numConsumers := 5 suite.consumerBundles = make(map[string]*icstestingutils.ConsumerBundle) - for i := 0; i < numConsumers; i++ { + for i := 0; i < icstestingutils.NumConsumers; i++ { bundle := suite.setupConsumerCallback(&suite.Suite, suite.coordinator, i) suite.consumerBundles[bundle.Chain.ChainID] = bundle suite.registerPacketSniffer(bundle.Chain) + + // check that TopN is correctly set for the consumer + topN, found := providerKeeper.GetTopN(suite.providerCtx(), bundle.Chain.ChainID) + suite.Require().True(found) + suite.Require().Equal(bundle.TopN, topN) } // initialize each consumer chain with it's corresponding genesis state @@ -228,7 +232,6 @@ func initConsumerChain( ) s.Require().True(found, "provider endpoint clientID not found") bundle.Path.EndpointB.ClientID = providerEndpointClientID - // Set consumer endpoint's clientID consumerKeeper := bundle.GetKeeper() consumerEndpointClientID, found := consumerKeeper.GetProviderClientID(bundle.GetCtx()) @@ -308,34 +311,70 @@ func (suite *CCVTestSuite) ExecuteCCVChannelHandshake(path *ibctesting.Path) { // TODO: Make SetupTransferChannel functional for multiple consumers by pattern matching SetupCCVChannel. // See: https://github.com/cosmos/interchain-security/issues/506 +// SetupTransferChannel setup the transfer channel of the first consumer chain among multiple func (suite *CCVTestSuite) SetupTransferChannel() { - // transfer path will use the same connection as ccv path + suite.setupTransferChannel( + suite.transferPath, + suite.path, + suite.consumerApp.GetConsumerKeeper().GetDistributionTransmissionChannel( + suite.consumerChain.GetContext(), + ), + ) +} - suite.transferPath.EndpointA.ClientID = suite.path.EndpointA.ClientID - suite.transferPath.EndpointA.ConnectionID = suite.path.EndpointA.ConnectionID - suite.transferPath.EndpointB.ClientID = suite.path.EndpointB.ClientID - suite.transferPath.EndpointB.ConnectionID = suite.path.EndpointB.ConnectionID +func (suite *CCVTestSuite) setupTransferChannel( + transferPath *ibctesting.Path, + ccvPath *ibctesting.Path, + channelID string, +) { + // transfer path will use the same connection as ccv path + transferPath.EndpointA.ClientID = ccvPath.EndpointA.ClientID + transferPath.EndpointA.ConnectionID = ccvPath.EndpointA.ConnectionID + transferPath.EndpointB.ClientID = ccvPath.EndpointB.ClientID + transferPath.EndpointB.ConnectionID = ccvPath.EndpointB.ConnectionID // CCV channel handshake will automatically initiate transfer channel handshake on ACK // so transfer channel will be on stage INIT when CompleteSetupCCVChannel returns. - suite.transferPath.EndpointA.ChannelID = suite.consumerApp.GetConsumerKeeper().GetDistributionTransmissionChannel( - suite.consumerChain.GetContext()) + transferPath.EndpointA.ChannelID = channelID // Complete TRY, ACK, CONFIRM for transfer path - err := suite.transferPath.EndpointB.ChanOpenTry() + err := transferPath.EndpointB.ChanOpenTry() suite.Require().NoError(err) - err = suite.transferPath.EndpointA.ChanOpenAck() + err = transferPath.EndpointA.ChanOpenAck() suite.Require().NoError(err) - err = suite.transferPath.EndpointB.ChanOpenConfirm() + err = transferPath.EndpointB.ChanOpenConfirm() suite.Require().NoError(err) // ensure counterparty is up to date - err = suite.transferPath.EndpointA.UpdateClient() + err = transferPath.EndpointA.UpdateClient() suite.Require().NoError(err) } +// SetupAllTransferChannel setup all consumer chains transfer channel +func (suite *CCVTestSuite) SetupAllTransferChannels() { + // setup the first consumer transfer channel + suite.SetupTransferChannel() + + // setup all the remaining consumers transfer channels + for chainID := range suite.consumerBundles { + // skip fist consumer + if chainID == suite.consumerChain.ChainID { + continue + } + + // get the bundle for the chain ID + bundle := suite.consumerBundles[chainID] + // setup the transfer channel + suite.setupTransferChannel( + bundle.TransferPath, + bundle.Path, + bundle.App.GetConsumerKeeper().GetDistributionTransmissionChannel(bundle.GetCtx()), + ) + } +} + func (s CCVTestSuite) validateEndpointsClientConfig(consumerBundle icstestingutils.ConsumerBundle) { //nolint:govet // this is a test so we can copy locks consumerKeeper := consumerBundle.GetKeeper() providerStakingKeeper := s.providerApp.GetTestStakingKeeper() diff --git a/testutil/ibc_testing/generic_setup.go b/testutil/ibc_testing/generic_setup.go index 6d17337853..da00d76b85 100644 --- a/testutil/ibc_testing/generic_setup.go +++ b/testutil/ibc_testing/generic_setup.go @@ -30,10 +30,16 @@ type ( // and/or democracy consumer app.go implementation. You should not need to modify or replicate this file // to run integration tests against your app.go implementations! +const ( + // Default number of consumer chains + NumConsumers = 5 +) + var ( FirstConsumerChainID string provChainID string democConsumerChainID string + consumerTopNParams [NumConsumers]uint32 ) func init() { @@ -42,6 +48,9 @@ func init() { FirstConsumerChainID = ibctesting.GetChainID(2) provChainID = ibctesting.GetChainID(1) democConsumerChainID = ibctesting.GetChainID(5000) + // TopN parameter values per consumer chain initiated + // sorted in ascending order i.e. testchain2, testchain3, ..., testchain6 + consumerTopNParams = [NumConsumers]uint32{100, 100, 100, 100, 100} } // ConsumerBundle serves as a way to store useful in-mem consumer app chain state @@ -51,6 +60,7 @@ type ConsumerBundle struct { App testutil.ConsumerApp Path *ibctesting.Path TransferPath *ibctesting.Path + TopN uint32 } // GetCtx returns the context for the ConsumerBundle @@ -116,6 +126,9 @@ func AddConsumer[Tp testutil.ProviderApp, Tc testutil.ConsumerApp]( index int, appIniter ValSetAppIniter, ) *ConsumerBundle { + // check index isn't bigger that the number of consumers + s.Require().LessOrEqual(index, NumConsumers) + // consumer chain ID chainID := ibctesting.GetChainID(index + 2) @@ -126,6 +139,7 @@ func AddConsumer[Tp testutil.ProviderApp, Tc testutil.ConsumerApp]( prop := testkeeper.GetTestConsumerAdditionProp() prop.ChainId = chainID + prop.Top_N = consumerTopNParams[index] // isn't used in CreateConsumerClient // NOTE: the initial height passed to CreateConsumerClient // must be the height on the consumer when InitGenesis is called prop.InitialHeight = clienttypes.Height{RevisionNumber: 0, RevisionHeight: 3} @@ -135,6 +149,10 @@ func AddConsumer[Tp testutil.ProviderApp, Tc testutil.ConsumerApp]( ) s.Require().NoError(err) + // set the consumer TopN here since the test suite setup only used the consumer addition prop + // to create the consumer genesis, see BeginBlockInit in /x/ccv/provider/keeper/proposal.go. + providerKeeper.SetTopN(providerChain.GetContext(), chainID, prop.Top_N) + // commit the state on the provider chain coordinator.CommitBlock(providerChain) @@ -174,5 +192,6 @@ func AddConsumer[Tp testutil.ProviderApp, Tc testutil.ConsumerApp]( return &ConsumerBundle{ Chain: testChain, App: consumerToReturn, + TopN: prop.Top_N, } } diff --git a/testutil/integration/debug_test.go b/testutil/integration/debug_test.go index c370e8e701..2481e865ab 100644 --- a/testutil/integration/debug_test.go +++ b/testutil/integration/debug_test.go @@ -299,3 +299,7 @@ func TestTransferConsumerRewardsToDistributionModule(t *testing.T) { func TestAllocateTokensToValidator(t *testing.T) { runCCVTestByName(t, "TestAllocateTokensToValidator") } + +func TestMultiConsumerRewardsDistribution(t *testing.T) { + runCCVTestByName(t, "TestMultiConsumerRewardsDistribution") +} From d14cbacdb6b35a96e8e1cfb6f9128bc44e3130e8 Mon Sep 17 00:00:00 2001 From: Marius Poke Date: Thu, 11 Jan 2024 15:40:13 +0100 Subject: [PATCH 016/110] docs: changelog and release notes for v4.0.0 (#1564) * add v4.0.0 section to changelog * add release notes --- ...ble-opt-in-chains-through-gov-proposals.md | 0 .../provider/1516-introduce-epochs.md | 0 .../provider/1516-introduce-epochs.md | 0 CHANGELOG.md | 367 ++++++++++++++++-- 4 files changed, 337 insertions(+), 30 deletions(-) rename .changelog/{unreleased => v4.0.0}/features/1587-enable-opt-in-chains-through-gov-proposals.md (100%) rename .changelog/{unreleased => v4.0.0}/features/provider/1516-introduce-epochs.md (100%) rename .changelog/{unreleased => v4.0.0}/state-breaking/provider/1516-introduce-epochs.md (100%) diff --git a/.changelog/unreleased/features/1587-enable-opt-in-chains-through-gov-proposals.md b/.changelog/v4.0.0/features/1587-enable-opt-in-chains-through-gov-proposals.md similarity index 100% rename from .changelog/unreleased/features/1587-enable-opt-in-chains-through-gov-proposals.md rename to .changelog/v4.0.0/features/1587-enable-opt-in-chains-through-gov-proposals.md diff --git a/.changelog/unreleased/features/provider/1516-introduce-epochs.md b/.changelog/v4.0.0/features/provider/1516-introduce-epochs.md similarity index 100% rename from .changelog/unreleased/features/provider/1516-introduce-epochs.md rename to .changelog/v4.0.0/features/provider/1516-introduce-epochs.md diff --git a/.changelog/unreleased/state-breaking/provider/1516-introduce-epochs.md b/.changelog/v4.0.0/state-breaking/provider/1516-introduce-epochs.md similarity index 100% rename from .changelog/unreleased/state-breaking/provider/1516-introduce-epochs.md rename to .changelog/v4.0.0/state-breaking/provider/1516-introduce-epochs.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c88c0c722..9d46f32447 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,59 +56,366 @@ ## v3.3.0 -*January 11, 2024* +*January 5, 2024* ### API BREAKING -- [Consumer](x/ccv/consumer) - - Fix a bug in consmer genesis file transform CLI command. - ([\#1458](https://github.com/cosmos/interchain-security/pull/1458)) +- [Provider](x/ccv/provider) + - Deprecate equivocation proposals. + ([\#1340](https://github.com/cosmos/interchain-security/pull/1340)) -### BUG FIXES +### DEPENDENCIES + +- Bump [ibc-go](https://github.com/cosmos/ibc-go) to + [v7.3.1](https://github.com/cosmos/ibc-go/releases/tag/v7.3.1). + ([\#1373](https://github.com/cosmos/interchain-security/pull/1373)) + +### FEATURES - General - - Fix a bug in consmer genesis file transform CLI command. - ([\#1458](https://github.com/cosmos/interchain-security/pull/1458)) + - Add Quint model of Replicated Security. + ([\#1336](https://github.com/cosmos/interchain-security/pull/1336)) +- [Provider](x/ccv/provider) + - Update how consumer-assigned keys are checked when a validator is + created on the provider. + ([\#1339](https://github.com/cosmos/interchain-security/pull/1339)) + - Introduce the cryptographic verification of equivocation feature to the provider + (cf. [ADR-005](docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md) + & [ADR-013](docs/docs/adrs/adr-013-equivocation-slashing.md)). + ([\#1340](https://github.com/cosmos/interchain-security/pull/1340)) + +### IMPROVEMENTS + +- General + - Split out consumer genesis state to reduce shared data between provider and + consumer. ([\#1324](https://github.com/cosmos/interchain-security/pull/1324)) + - Note: This breaks json format used by augmenting Genesis files of consumer + chains with consumer genesis content exported from provider chain. Consumer + Genesis content exported from a provider chain using major version 1, 2 or 3 + of the provider module needs to be transformed with the transformation command + introduced by this PR: + ``` + Transform the consumer genesis file from a provider version v1, v2 or v3 to a version supported by this consumer. Result is printed to STDOUT. + + Example: + $ transform /path/to/ccv_consumer_genesis.json + + Usage: + interchain-security-cd genesis transform [genesis-file] [flags] + ``` + - Refactor shared events, codecs and errors assign to + consumer and provider dedicated types where possible. + ([\#1350](https://github.com/cosmos/interchain-security/pull/1350)) +- [Provider](x/ccv/provider) + - Add `QueryAllPairsValConAddrByConsumerChainID` method to get list of all pairs `valConsensus` address by `Consummer chainID`. ([\#1503](https://github.com/cosmos/interchain-security/pull/1503)) + +### STATE BREAKING + +- General + - Split out consumer genesis state to reduce shared data between provider and + consumer. ([\#1324](https://github.com/cosmos/interchain-security/pull/1324)) - Improve validation of IBC packet data and provider messages. Also, enable the provider to validate consumer packets before handling them. ([\#1460](https://github.com/cosmos/interchain-security/pull/1460)) +- [Provider](x/ccv/provider) + - Change the states by adding a consumer key for each chain that is + not yet registered meaning for which the gov proposal has not passed. + ([\#1339](https://github.com/cosmos/interchain-security/pull/1339)) + - Introduce the cryptographic verification of equivocation feature to the provider + (cf. [ADR-005](docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md) + & [ADR-013](docs/docs/adrs/adr-013-equivocation-slashing.md)). + ([\#1340](https://github.com/cosmos/interchain-security/pull/1340)) + +## v3.2.0 + +*November 24, 2023* + +### BUG FIXES + - [Consumer](x/ccv/consumer) - - Avoid jailing validators immediately once they can no longer opt-out from - validating consumer chains. - ([\#1549](https://github.com/cosmos/interchain-security/pull/1549)) - - Fix the validation of VSCPackets to not fail due to marshaling to string using Bech32. - ([\#1570](https://github.com/cosmos/interchain-security/pull/1570)) + - Fix deletion of pending packets that may cause duplicate sends + ([\#1146](https://github.com/cosmos/interchain-security/pull/1146)) + - Remove `idx` field from the `ccv.ConsumerPacketData` type as this would break the + wire ([\#1150](https://github.com/cosmos/interchain-security/pull/1150)) + - Validate token transfer messages before calling `Transfer()`. + ([\#1244](https://github.com/cosmos/interchain-security/pull/1244)) + - Remove incorrect address validation on `ProviderFeePoolAddrStr` param. + ([\#1262](https://github.com/cosmos/interchain-security/pull/1262)) + - Increment consumer consensus version and register consumer migration. + ([\#1295](https://github.com/cosmos/interchain-security/pull/1295)) ### DEPENDENCIES -- Bump Golang to v1.21 - ([\#1557](https://github.com/cosmos/interchain-security/pull/1557)) +- Bump [ibc-go](https://github.com/cosmos/ibc-go) to + [v7.2.0](https://github.com/cosmos/ibc-go/releases/tag/v7.2.0). + ([\#1196](https://github.com/cosmos/interchain-security/pull/1196)) - Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to - [v0.47.7](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.7). - ([\#1558](https://github.com/cosmos/interchain-security/pull/1558)) -- Bump [CometBFT](https://github.com/cometbft/cometbft) to - [v0.37.4](https://github.com/cometbft/cometbft/releases/tag/v0.37.4). - ([\#1558](https://github.com/cosmos/interchain-security/pull/1558)) + [v0.47.4](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.4). + ([\#1258](https://github.com/cosmos/interchain-security/pull/1258)) +- Bump [ibc-go](https://github.com/cosmos/ibc-go) to + [v7.3.0](https://github.com/cosmos/ibc-go/releases/tag/v7.3.0). + ([\#1258](https://github.com/cosmos/interchain-security/pull/1258)) +- Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to + [v0.47.5](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.5). + ([\#1259](https://github.com/cosmos/interchain-security/pull/1259)) ### FEATURES +- [Consumer](x/ccv/consumer) + - Add the consumer-side changes for jail throttling with retries (cf. ADR 008). + ([\#1024](https://github.com/cosmos/interchain-security/pull/1024)) + - Introduce the gRPC query `/interchain_security/ccv/consumer/provider- + info` and CLI command `interchain-security-cd q ccvconsumer + provider-info` to retrieve provider info from the consumer chain. + ([\#1164](https://github.com/cosmos/interchain-security/pull/1164)) - [Provider](x/ccv/provider) - - Add the provider-side changes for jail throttling with retries (cf. ADR 008). - ([\#1321](https://github.com/cosmos/interchain-security/pull/1321)) + - Add `InitTimeoutTimestamps` and `ExportedVscSendTimestamps` to exported + genesis. ([\#1076](https://github.com/cosmos/interchain-security/pull/1076)) + - Add a governance proposal for setting on the provider the denominations for + rewards from consumer chains. + ([\#1280](https://github.com/cosmos/interchain-security/pull/1280)) + +### IMPROVEMENTS + +- General + - Update the default consumer unbonding period to 2 weeks. + ([\#1244](https://github.com/cosmos/interchain-security/pull/1244)) +- [Consumer](x/ccv/consumer) + - Optimize pending packets storage on consumer, with migration. + ([\#1037](https://github.com/cosmos/interchain-security/pull/1037)) ### STATE BREAKING +- General + - Bump [ibc-go](https://github.com/cosmos/ibc-go) to + [v7.2.0](https://github.com/cosmos/ibc-go/releases/tag/v7.2.0). + ([\#1196](https://github.com/cosmos/interchain-security/pull/1196)) + - Update the default consumer unbonding period to 2 weeks. + ([\#1244](https://github.com/cosmos/interchain-security/pull/1244)) + - Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to + [v0.47.4](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.4). + ([\#1258](https://github.com/cosmos/interchain-security/pull/1258)) + - Bump [ibc-go](https://github.com/cosmos/ibc-go) to + [v7.3.0](https://github.com/cosmos/ibc-go/releases/tag/v7.3.0). + ([\#1258](https://github.com/cosmos/interchain-security/pull/1258)) + - Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to + [v0.47.5](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.5). + ([\#1259](https://github.com/cosmos/interchain-security/pull/1259)) - [Consumer](x/ccv/consumer) - - Avoid jailing validators immediately once they can no longer opt-out from - validating consumer chains. - ([\#1549](https://github.com/cosmos/interchain-security/pull/1549)) - - Fix the validation of VSCPackets to not fail due to marshaling to string using Bech32. - ([\#1570](https://github.com/cosmos/interchain-security/pull/1570)) + - Add the consumer-side changes for jail throttling with retries (cf. ADR 008). + ([\#1024](https://github.com/cosmos/interchain-security/pull/1024)) + - Optimize pending packets storage on consumer, with migration. + ([\#1037](https://github.com/cosmos/interchain-security/pull/1037)) + - Fix deletion of pending packets that may cause duplicate sends + ([\#1146](https://github.com/cosmos/interchain-security/pull/1146)) + - Remove `idx` field from the `ccv.ConsumerPacketData` type as this would break the + wire ([\#1150](https://github.com/cosmos/interchain-security/pull/1150)) + - Validate token transfer messages before calling `Transfer()`. + ([\#1244](https://github.com/cosmos/interchain-security/pull/1244)) + - Remove incorrect address validation on `ProviderFeePoolAddrStr` param. + ([\#1262](https://github.com/cosmos/interchain-security/pull/1262)) + - Increment consumer consensus version and register consumer migration. + ([\#1295](https://github.com/cosmos/interchain-security/pull/1295)) - [Provider](x/ccv/provider) - - Add the provider-side changes for jail throttling with retries (cf. ADR 008). - ([\#1321](https://github.com/cosmos/interchain-security/pull/1321)) + - Add a governance proposal for setting on the provider the denominations for + rewards from consumer chains. + ([\#1280](https://github.com/cosmos/interchain-security/pull/1280)) + +## v3.1.0 + +Date July 11th, 2023 + +A minor upgrade to v3.0.0, which removes the panic in the consumer ccv module which would occur in an emergency scenario where the ccv channel is closed. This release also fixes how a distribution related event is emitted, and bumps cometbft. + +* (feat) [#1127](https://github.com/cosmos/interchain-security/pull/1127) Remove consumer panic when ccv channel is closed +* (fix) [#720](https://github.com/cosmos/interchain-security/issues/720) Fix the attribute `AttributeDistributionTotal` value in `FeeDistribution` event emit. +* (deps) [#1119](https://github.com/cosmos/interchain-security/pull/1119) bump cometbft from `v0.37.1` to `0.37.2`. + +## v3.0.0 + +Date: June 21st, 2023 + +Interchain Security v3 uses SDK 0.47 and IBC 7. + +* (fix) [#1093](https://github.com/cosmos/interchain-security/pull/1093) Make SlashPacketData backward compatible when sending data over the wire +* (deps) [#1019](https://github.com/cosmos/interchain-security/pull/1019) Bump multiple dependencies. + * Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to [v0.47.3](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.3). + * Bump [ibc-go](https://github.com/cosmos/ibc-go) to [v7.1.0](https://github.com/cosmos/ibc-go/releases/tag/v7.1.0). + * Bump [CometBFT](https://github.com/cometbft/cometbft) to [v0.37.1](https://github.com/cometbft/cometbft/releases/tag/v0.37.1). +* `[x/ccv/provider]` (fix) [#945](https://github.com/cosmos/interchain-security/issues/945) Refactor `AfterUnbondingInitiated` to not panic when `PutUnbondingOnHold` returns error. +* `[x/ccv/provider]` (fix) [#977](https://github.com/cosmos/interchain-security/pull/977) Avoids panicking the provider when an unbonding delegation was removed through a `CancelUnbondingDelegation` message. +* `[x/ccv/democracy]` (feat) [#1019](https://github.com/cosmos/interchain-security/pull/1019) Whitelisting non-legacy params in the "democracy module" require the entire module to be whitelisted. + +## v2.4.0-lsm + +*November 20, 2023* + +* (fix) [#1439](https://github.com/cosmos/interchain-security/pull/1439) Fix unmarshaling for the CLI consumer double vote cmd. +* (feat!) [#1435](https://github.com/cosmos/interchain-security/pull/1435) Add height-base filter for consumer equivocation evidence. + +## v2.3.0-provider-lsm + +*November 15, 2023* + +❗ *This release is deprecated and should not be used in production.* + +* (fix!) [#1422](https://github.com/cosmos/interchain-security/pull/1422) Fix the misbehaviour handling by verifying the signatures of byzantine validators. + +## v2.2.0-provider-lsm + +❗ *This release is deprecated and should not be used in production.* + +### Cryptographic verification of equivocation +* New feature enabling the provider chain to verify equivocation evidence on its own instead of trusting consumer chains, see [EPIC](https://github.com/cosmos/interchain-security/issues/732). + +## v2.1.0-provider-lsm + +Date: September 15th, 2023 + +* (feature!) [#1280](https://github.com/cosmos/interchain-security/pull/1280) provider proposal for changing reward denoms + +## v2.0.0-lsm + +Date: August 18th, 2023 + +* (deps!) [#1120](https://github.com/cosmos/interchain-security/pull/1120) Bump [Cosmos SDK](https://github.com/cosmos/cosmos-sdk) to [v0.45.16-ics-lsm](https://github.com/cosmos/cosmos-sdk/tree/v0.45.16-ics-lsm). This requires adapting ICS to support this SDK release. Changes are state breaking. +* (fix) [#720](https://github.com/cosmos/interchain-security/issues/720) Fix the attribute `AttributeDistributionTotal` value in `FeeDistribution` event emit. + +## v2.0.0 + +Date: June 1st, 2023 + +Unlike prior releases, the ICS `v2.0.0` release will be based on the main branch. `v2.0.0` will contain all the accumulated PRs from the various releases below, along with other PRs that were merged, but not released to production. After `v2.0.0`, we plan to revamp release practices, and how we modularize the repo for consumer/provider. + +Upgrading a provider from `v1.1.0-multiden` to `v2.0.0` will require state migrations. See [migration.go](https://github.com/cosmos/interchain-security/blob/v2.0.0/x/ccv/provider/keeper/migration.go). + +Upgrading a consumer from `v1.2.0-multiden` to `v2.0.0` will NOT require state migrations. + +Some PRs from v2.0.0 may reappear from other releases below. This is due to the fact that ICS v1.1.0 deviates from the commit ordering of the main branch, and other releases thereafter are based on v1.1.0. + +### High level changes included in v2.0.0 + +* MVP for standalone to consumer changeover, see [EPIC](https://github.com/cosmos/interchain-security/issues/756) +* MVP for soft opt out, see [EPIC](https://github.com/cosmos/interchain-security/issues/851) +* Various fixes, critical and non-critical +* Docs updates which should not affect production code + +## Notable PRs included in v2.0.0 + +* (feat!) Add DistributionTransmissionChannel to ConsumerAdditionProposal [#965](https://github.com/cosmos/interchain-security/pull/965) +* (feat/fix) limit vsc matured packets handled per endblocker [#1004](https://github.com/cosmos/interchain-security/pull/1004) +* (fix) consumer key prefix order to avoid complex migrations [#963](https://github.com/cosmos/interchain-security/pull/963) and [#991](https://github.com/cosmos/interchain-security/pull/991). The latter PR is the proper fix. +* (feat) v1->v2 migrations to accommodate a bugfix having to do with store keys, introduce new params, and deal with consumer genesis state schema changes [#975](https://github.com/cosmos/interchain-security/pull/975) and [#997](https://github.com/cosmos/interchain-security/pull/997) +* (deps) Bump github.com/cosmos/ibc-go/v4 from 4.4.0 to 4.4.2 [#982](https://github.com/cosmos/interchain-security/pull/982) +* (fix) partially revert key assignment type safety PR [#980](https://github.com/cosmos/interchain-security/pull/980) +* (fix) Remove panics on failure to send IBC packets [#876](https://github.com/cosmos/interchain-security/pull/876) +* (fix) Prevent denom DOS [#931](https://github.com/cosmos/interchain-security/pull/931) +* (fix) multisig for assigning consumer key, use json [#916](https://github.com/cosmos/interchain-security/pull/916) +* (deps) Bump github.com/cosmos/ibc-go/v4 from 4.3.0 to 4.4.0 [#902](https://github.com/cosmos/interchain-security/pull/902) +* (feat) Add warnings when provider unbonding is shorter than consumer unbonding [#858](https://github.com/cosmos/interchain-security/pull/858) +* (chore) use go 1.19 [#899](https://github.com/cosmos/interchain-security/pull/899), [#840](https://github.com/cosmos/interchain-security/pull/840) +* (feat) Standalone to consumer changeover - recycle existing transfer channel [#832](https://github.com/cosmos/interchain-security/pull/832) +* (deps) Bump IBC [862](https://github.com/cosmos/interchain-security/pull/862) +* (testing) Add tests for soft opt out [#857](https://github.com/cosmos/interchain-security/pull/857) +* (feat) Standalone to consumer changeover - staking functionalities [#794](https://github.com/cosmos/interchain-security/pull/794) +* (fix) prevent provider from sending VSCPackets with multiple updates for the same validator [#850](https://github.com/cosmos/interchain-security/pull/850) +* (feat) Soft opt out [#833](https://github.com/cosmos/interchain-security/issues/833) +* (fix) Correctly handle VSC packet with duplicate val updates on consumer [#846](https://github.com/cosmos/interchain-security/pull/846) +* (deps) bump sdk to v0.45.15.ics [#805](https://github.com/cosmos/interchain-security/pull/805) +* (refactor) Remove spm module [#812](https://github.com/cosmos/interchain-security/pull/812) +* (feat) Standalone to consumer changeover part 1 [#757](https://github.com/cosmos/interchain-security/pull/757) +* (chore) Swap names of e2e and integration tests [#681](https://github.com/cosmos/interchain-security/pull/681) +* (fix) fix StopConsumerChain not running in cachedContext [#802](https://github.com/cosmos/interchain-security/pull/802). Also in earlier releases with different commit order! +* (docs) Introduce docs website [#759](https://github.com/cosmos/interchain-security/pull/759) +* (fix) Serialize correct byte prefix for SlashLogKey [#786](https://github.com/cosmos/interchain-security/pull/786) +* (feature) Improve keeper field validation [#766](https://github.com/cosmos/interchain-security/pull/766) +* (docs) Contributing guidelines [#744](https://github.com/cosmos/interchain-security/pull/744) +* (refactor) Key assignment type safety [#725](https://github.com/cosmos/interchain-security/pull/725) +* (fix) Update protos and fix deps [#752](https://github.com/cosmos/interchain-security/pull/752) +* (api) Add consumer QueryParams [#746](https://github.com/cosmos/interchain-security/pull/746) +* (feature) New validation for keeper fields [#740](https://github.com/cosmos/interchain-security/pull/740) + +## v1.2.0-multiden + +The first release candidate for a fix built on top of v1.2.0, intended for consumers. This release adds a list of denoms on the consumer that are allowed to be sent to the provider as rewards. This prevents a potential DOS attack that was discovered during the audit of Replicated Security performed by Oak Security and funded by the Cosmos Hub community through Proposal 687. In an effort to move quickly, this release also includes a multisig fix that is effective only for provider. It shouldn't affect the consumer module. + +Note PRs were made in a private security repo. + +[full diff](https://github.com/cosmos/interchain-security/compare/v1.2.0...v1.2.0-multiden-rc0) + +## v1.1.0-multiden + +This release combines two fixes on top of v1.1.0, that we judged were urgent to get onto the Cosmos Hub before the launch of the first ICS consumer chain. This is an emergency release intended for providers. + +The first fix is to enable the use of multisigs and Ledger devices when assigning keys for consumer chains. The second is to prevent a possible DOS vector involving the reward distribution system. + +Note PRs were made in a private security repo. + +[full diff](https://github.com/cosmos/interchain-security/compare/v1.1.0...release/v1.1.0-multiden) + +### Multisig fix + +On April 25th (a week and a half ago), we began receiving reports that validators using multisigs and Ledger devices were getting errors reading Error: unable to resolve type URL /interchain_security.ccv.provider.v1.MsgAssignConsumerKey: tx parse error when attempting to assign consensus keys for consumer chains. + +We quickly narrowed the problem down to issues having to do with using the PubKey type directly in the MsgAssignConsumerKey transaction, and Amino (a deprecated serialization library still used in Ledger devices and multisigs) not being able to handle this. We attempted to fix this with the assistance of the Cosmos-SDK team, but after making no headway for a few days, we decided to simply use a JSON representation of the PubKey in the transaction. This is how it is usually represented anyway. We have verified that this fixes the problem. + +### Distribution fix + +The ICS distribution system works by allowing consumer chains to send rewards to a module address on the provider called the FeePoolAddress. From here they are automatically distributed to all validators and delegators through the distribution system that already exists to distribute staking rewards. The FeePoolAddress is usually blocked so that no tokens can be sent to it, but to enable ICS distribution we had to unblock it. + +We recently realized that unblocking the FeePoolAddress could enable an attacker to send a huge number of different denoms into the distribution system. The distribution system would then attempt to distribute them all, leading to out of memory errors. Fixing a similar attack vector that existed in the distribution system before ICS led us to this realization. + +To fix this problem, we have re-blocked the FeePoolAddress and created a new address called the ConsumerRewardsPool. Consumer chains now send rewards to this new address. There is also a new transaction type called RegisterConsumerRewardDenom. This transaction allows people to register denoms to be used as rewards from consumer chains. It costs 10 Atoms to run this transaction.The Atoms are transferred to the community pool. Only denoms registered with this command are then transferred to the FeePoolAddress and distributed out to delegators and validators. + +## v1.2.1 + +* (fix) Remove SPM [#812](https://github.com/cosmos/interchain-security/pull/812) +* (refactor) Key assignment type safety [#725](https://github.com/cosmos/interchain-security/pull/725) + +## v1.2.0 + +Date: April 13th, 2023 + +* (feat) Soft opt-out [#833](https://github.com/cosmos/interchain-security/pull/833) +* (fix) Correctly handle VSC packet with duplicate val updates on consumer [#846](https://github.com/cosmos/interchain-security/pull/846) +* (chore) bump: sdk v0.45.15-ics [#805](https://github.com/cosmos/interchain-security/pull/805) +* (api) add interchain security consumer QueryParams [#746](https://github.com/cosmos/interchain-security/pull/746) + +## v1.1.1 + +* (fix) Remove SPM [#812](https://github.com/cosmos/interchain-security/pull/812) +* (refactor) Key assignment type safety [#725](https://github.com/cosmos/interchain-security/pull/725) + +## v1.1.0 + +Date: March 24th, 2023 + +* (fix) StopConsumerChain not running in cachedContext [#802](https://github.com/cosmos/interchain-security/pull/802) + +## v1.0.0 + +Date: February 6th, 2023 + +This is the first version of Interchain Security (ICS), also known as _Replicated Security_ (RS). +Replicated Security is a feature which will allow a chain -- referred to as the _provider_ -- to share security with other chains -- referred to as _consumers_. +This means that the provider's validator set will be granted the right to validate consumer chains. +The communication between the provider and the consumer chains is done through the IBC protocol over a unique, ordered channel (one for each consumer chain). Thus, RS is an IBC application. + +### Features / sub-protocols + +RS consist of the following core features: + +- **Channel Initialization**: Enables the provider to add new consumer chains. This process is governance-gated, i.e., to add a new consumer chain, a `ConsumerAdditionProposal` governance proposal must be sent to the provider and it must receive the necessary votes. +- **Validator Set Update**: Enables the provider to + (1) update the consumers on the voting power granted to validators (based on the changes in the active validator set on the provider chain), + and (2) ensure the timely completion of unbonding operations (e.g., undelegations). +- **Consumer Initiated Slashing**: Enables the provider to jail validators for downtime infractions on the consumer chains. +- **Reward Distribution**: Enables the consumers to transfer to the provider (over IBC) a portion of their block rewards as payment for the security provided. Once transferred, these rewards are distributed on the provider using the protocol in the [distribution module of Cosmos SDK](https://docs.cosmos.network/v0.45/modules/distribution/). +- **Consumer Chain Removal**: Enables the provider to remove a consumer either after a `ConsumerRemovalProposal` passes governance or after one of the timeout periods elapses -- `InitTimeoutPeriod`, `VscTimeoutPeriod`, `IBCTimeoutPeriod`. +- **Social Slashing**: Equivocation offenses (double signing etc.) on consumer chains are logged, and then can be used in a governance proposal to slash the validators responsible. -## Previous Versions +In addition, RS has the following features: -[CHANGELOG of previous versions](https://github.com/cosmos/interchain-security/blob/main/CHANGELOG.md) +- **Key Assignment**: Enables validator operators to use different consensus keys for each consumer chain validator node that they operate. +- **Jail Throttling**: Enables the provider to slow down a "worst case scenario" attack where a malicious consumer binary attempts to jail a significant amount (> 2/3) of the voting power, effectively taking control of the provider. From 5ccd9008c52369d303d8a6232f5f5e7908faba08 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Fri, 19 Jan 2024 19:25:23 +0100 Subject: [PATCH 017/110] fix!: Validation of SlashAcks fails due to marshaling to Bech32 (backport #1570) (#1577) fix!: Validation of SlashAcks fails due to marshaling to Bech32 (#1570) * add different Bech32Prefix for consumer and provider * separate app encoding and params * remove ConsumerValPubKey from ValidatorConfig * update addresses in tests * make SlashAcks consistent across chains * add comments for clarity * Regenerate traces * Fix argument order * set bech32prefix for provider to cosmos * add changelog entries * add consumer-double-downtime e2e test * update nightly-e2e workflow * fix typo * add consumer-double-downtime to testConfigs * remove changes on provider * skip invalid SlashAcks * seal the config * clear the outstanding downtime flag for new vals * add info on upgrading to v4.0.0 * fix upgrade handler * fix changeover e2e test * Update tests/e2e/config.go Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * Update tests/e2e/config.go Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * add AccountPrefix to ChainConfig * fix docstrings * update AccountAddressPrefix in app.go * fix consumer-misb e2e test --------- Co-authored-by: Philip Offtermatt Co-authored-by: Simon Noetzlin Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> (cherry picked from commit 86046926502f7b0ba795bebcdd1fdc97ac776573) Co-authored-by: Marius Poke --- .changelog/unreleased/state-breaking/1570-slashack-bech32.md | 2 ++ .changelog/v4.0.0/bug-fixes/1570-slashack-bech32.md | 2 ++ tests/e2e/actions.go | 1 - 3 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 .changelog/unreleased/state-breaking/1570-slashack-bech32.md create mode 100644 .changelog/v4.0.0/bug-fixes/1570-slashack-bech32.md diff --git a/.changelog/unreleased/state-breaking/1570-slashack-bech32.md b/.changelog/unreleased/state-breaking/1570-slashack-bech32.md new file mode 100644 index 0000000000..a0e9fe9262 --- /dev/null +++ b/.changelog/unreleased/state-breaking/1570-slashack-bech32.md @@ -0,0 +1,2 @@ +- Fix the validation of VSCPackets to not fail due to marshaling to string using Bech32. + ([\#1570](https://github.com/cosmos/interchain-security/pull/1570)) \ No newline at end of file diff --git a/.changelog/v4.0.0/bug-fixes/1570-slashack-bech32.md b/.changelog/v4.0.0/bug-fixes/1570-slashack-bech32.md new file mode 100644 index 0000000000..a0e9fe9262 --- /dev/null +++ b/.changelog/v4.0.0/bug-fixes/1570-slashack-bech32.md @@ -0,0 +1,2 @@ +- Fix the validation of VSCPackets to not fail due to marshaling to string using Bech32. + ([\#1570](https://github.com/cosmos/interchain-security/pull/1570)) \ No newline at end of file diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index 9db1bac2ca..600464af8b 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -1724,7 +1724,6 @@ func (tr TestConfig) redelegateTokens(action RedelegateTokensAction, target Exec cmd := target.ExecCommand( tr.chainConfigs[action.Chain].BinaryName, - "tx", "staking", "redelegate", redelegateSrc, redelegateDst, From f62d17cb885fa1163ede8d636dabf6e37cc1253a Mon Sep 17 00:00:00 2001 From: Marius Poke Date: Mon, 22 Jan 2024 09:39:42 +0100 Subject: [PATCH 018/110] docs: update changelog for v4.0.0 (#1578) update changelog --- .changelog/unreleased/state-breaking/1570-slashack-bech32.md | 2 -- .changelog/v4.0.0/bug-fixes/1570-slashack-bech32.md | 2 -- 2 files changed, 4 deletions(-) delete mode 100644 .changelog/unreleased/state-breaking/1570-slashack-bech32.md delete mode 100644 .changelog/v4.0.0/bug-fixes/1570-slashack-bech32.md diff --git a/.changelog/unreleased/state-breaking/1570-slashack-bech32.md b/.changelog/unreleased/state-breaking/1570-slashack-bech32.md deleted file mode 100644 index a0e9fe9262..0000000000 --- a/.changelog/unreleased/state-breaking/1570-slashack-bech32.md +++ /dev/null @@ -1,2 +0,0 @@ -- Fix the validation of VSCPackets to not fail due to marshaling to string using Bech32. - ([\#1570](https://github.com/cosmos/interchain-security/pull/1570)) \ No newline at end of file diff --git a/.changelog/v4.0.0/bug-fixes/1570-slashack-bech32.md b/.changelog/v4.0.0/bug-fixes/1570-slashack-bech32.md deleted file mode 100644 index a0e9fe9262..0000000000 --- a/.changelog/v4.0.0/bug-fixes/1570-slashack-bech32.md +++ /dev/null @@ -1,2 +0,0 @@ -- Fix the validation of VSCPackets to not fail due to marshaling to string using Bech32. - ([\#1570](https://github.com/cosmos/interchain-security/pull/1570)) \ No newline at end of file From a7b93a757fa0e4857c8532001acc24681bb38b8e Mon Sep 17 00:00:00 2001 From: insumity Date: Mon, 5 Feb 2024 09:27:26 +0100 Subject: [PATCH 019/110] feat!: enable Opt In and Top N chains through gov proposals (#1615) * init commit * added test * fixed tests * added changelog entry and comment * Update x/ccv/provider/keeper/proposal_test.go Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * Update .changelog/unreleased/features/1587-enable-opt-in-chains-through-gov-proposals.md Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * Update proto/interchain_security/ccv/provider/v1/provider.proto Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * Update proto/interchain_security/ccv/provider/v1/provider.proto Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * Update proto/interchain_security/ccv/provider/v1/provider.proto Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * Update proto/interchain_security/ccv/provider/v1/provider.proto Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * Update x/ccv/provider/keeper/keeper.go Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * changed to tabular test --------- Co-authored-by: insumity Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> --- .../1587-enable-opt-in-chains-through-gov-proposals.md | 2 ++ x/ccv/provider/keeper/proposal_test.go | 4 ++++ 2 files changed, 6 insertions(+) create mode 100644 .changelog/unreleased/features/1587-enable-opt-in-chains-through-gov-proposals.md diff --git a/.changelog/unreleased/features/1587-enable-opt-in-chains-through-gov-proposals.md b/.changelog/unreleased/features/1587-enable-opt-in-chains-through-gov-proposals.md new file mode 100644 index 0000000000..57f16adc9b --- /dev/null +++ b/.changelog/unreleased/features/1587-enable-opt-in-chains-through-gov-proposals.md @@ -0,0 +1,2 @@ +- Enable Opt In and Top N chains through gov proposals. + ([\#1587](https://github.com/cosmos/interchain-security/pull/1587)) \ No newline at end of file diff --git a/x/ccv/provider/keeper/proposal_test.go b/x/ccv/provider/keeper/proposal_test.go index 99e8c74e49..8de4282474 100644 --- a/x/ccv/provider/keeper/proposal_test.go +++ b/x/ccv/provider/keeper/proposal_test.go @@ -554,6 +554,10 @@ func TestStopConsumerChain(t *testing.T) { require.Error(t, err) } else { require.NoError(t, err) + + // in case the chain was successfully stopped, it should not contain a Top N associated to it + _, found := providerKeeper.GetTopN(ctx, "chainID") + require.False(t, found) } testkeeper.TestProviderStateIsCleanedAfterConsumerChainIsStopped(t, ctx, providerKeeper, "chainID", "channelID") From 6e2618b15ff39de6e7ecf983d1fb85d2d80143d1 Mon Sep 17 00:00:00 2001 From: insumity Date: Wed, 7 Feb 2024 11:35:28 +0100 Subject: [PATCH 020/110] feat!: introduce MsgOptIn and MsgOptOut (#1620) * init commit * cleaning up * changed cons to val address * Revert "changed cons to val address" This reverts commit a32e8829fee3cbbe50e363a0aa91ad62117a8a1d. * Update x/ccv/provider/keeper/keeper.go Co-authored-by: Simon Noetzlin * took into account comments * added key assignment * add contraint such that opt out only works if the chain is running --------- Co-authored-by: insumity Co-authored-by: Simon Noetzlin --- proto/interchain_security/ccv/provider/v1/tx.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proto/interchain_security/ccv/provider/v1/tx.proto b/proto/interchain_security/ccv/provider/v1/tx.proto index 96844c2e72..59590f7c5b 100644 --- a/proto/interchain_security/ccv/provider/v1/tx.proto +++ b/proto/interchain_security/ccv/provider/v1/tx.proto @@ -109,4 +109,4 @@ message MsgSetConsumerCommissionRate { } -message MsgSetConsumerCommissionRateResponse {} \ No newline at end of file +message MsgSetConsumerCommissionRateResponse {} From ee653997beebe141303cb9fd1a5c418b259d5739 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Date: Thu, 8 Feb 2024 10:39:49 +0100 Subject: [PATCH 021/110] test: MBT: Add partial set security to model (feature branch version) (#1627) * Port changes from branch to main * Add model analysis changes to Makefile --- tests/mbt/model/README.md | 4 ++++ tests/mbt/model/ccv_boundeddrift.qnt | 5 ----- tests/mbt/model/ccv_model.qnt | 4 ++-- tests/mbt/model/run_invariants.sh | 9 ++++++++- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/tests/mbt/model/README.md b/tests/mbt/model/README.md index df994b7f84..dac613337e 100644 --- a/tests/mbt/model/README.md +++ b/tests/mbt/model/README.md @@ -138,4 +138,8 @@ The available sanity checks are: - CanOptIn (only with `--step stepBoundedDriftKeyAndPSS` on `ccv_boundeddrift.qnt`) - CanOptOut (only with `--step stepBoundedDriftKeyAndPSS` on `ccv_boundeddrift.qnt`) - CanFailOptOut (only with `--step stepBoundedDriftKeyAndPSS` on `ccv_boundeddrift.qnt`) +<<<<<<< HEAD - CanHaveOptIn (only with `--step stepBoundedDriftKeyAndPSS` on `ccv_boundeddrift.qnt`) +======= +- CanHaveOptIn (only with `--step stepBoundedDriftKeyAndPSS` on `ccv_boundeddrift.qnt`) +>>>>>>> 6e075652 (test: MBT: Add partial set security to model (feature branch version) (#1627)) diff --git a/tests/mbt/model/ccv_boundeddrift.qnt b/tests/mbt/model/ccv_boundeddrift.qnt index b067ca79b2..37fcd5a15b 100644 --- a/tests/mbt/model/ccv_boundeddrift.qnt +++ b/tests/mbt/model/ccv_boundeddrift.qnt @@ -115,11 +115,6 @@ module ccv_boundeddrift { StepOptOut, } - action stepBoundedDriftKeyAssignment = any { - stepBoundedDrift, - nondetKeyAssignment, - } - // INVARIANT // The maxDrift between chains is never exceeded. // This *should* be ensured by the step function. diff --git a/tests/mbt/model/ccv_model.qnt b/tests/mbt/model/ccv_model.qnt index b3b487d113..3dc0ea1861 100644 --- a/tests/mbt/model/ccv_model.qnt +++ b/tests/mbt/model/ccv_model.qnt @@ -740,11 +740,11 @@ module ccv_model { // and the key assignment of each validator should be applied in that VSCPacket. val ValidatorUpdatesArePropagatedKeyAssignmentInv = // when the provider has just entered a validator set into a block... - ValUpdatePrecondition and CurrentBlockEndsEpoch + ValUpdatePrecondition and currentState.providerState.providerValidatorSetChangedInThisBlock implies val providerValSetInCurBlock = providerValidatorHistory.head() // ... for each consumer that is running then ... - currentState.providerState.consumersWithPowerChangesInThisEpoch.forall( + runningConsumers.forall( // ...the validator set under key assignment is in a sent packet... val providerState = currentState.providerState consumer => providerState.sentVscPacketsToConsumer.get(consumer).toSet().exists( diff --git a/tests/mbt/model/run_invariants.sh b/tests/mbt/model/run_invariants.sh index afe079387e..e232bcce8b 100755 --- a/tests/mbt/model/run_invariants.sh +++ b/tests/mbt/model/run_invariants.sh @@ -1,5 +1,6 @@ #!/bin/bash +<<<<<<< HEAD # to stop on any errors set -e @@ -38,4 +39,10 @@ run_invariant "CanSendVscPackets" "" '[violation]' run_invariant "CanSendVscMaturedPackets" "" '[violation]' run_invariant "CanAssignConsumerKey" "stepKeyAssignment" '[violation]' run_invariant "CanHaveConsumerAddresses" "stepKeyAssignment" '[violation]' -run_invariant "CanReceiveMaturations" "stepKeyAssignment" '[violation]' \ No newline at end of file +run_invariant "CanReceiveMaturations" "stepKeyAssignment" '[violation]' +======= +quint test ccv_model.qnt +quint test ccv_test.qnt +quint run --invariant "all{ValidatorUpdatesArePropagatedInv,ValidatorSetHasExistedInv,SameVscPacketsInv,MatureOnTimeInv,EventuallyMatureOnProviderInv}" ccv_model.qnt --max-steps 200 --max-samples 200 +quint run --invariant "all{ValidatorUpdatesArePropagatedKeyAssignmentInv,ValidatorSetHasExistedKeyAssignmentInv,SameVscPacketsKeyAssignmentInv,MatureOnTimeInv,EventuallyMatureOnProviderInv,KeyAssignmentRulesInv}" ccv_model.qnt --step stepKeyAssignment --max-steps 200 --max-samples 200 +>>>>>>> 6e075652 (test: MBT: Add partial set security to model (feature branch version) (#1627)) From 7497fc0079ac01bbaf457a822a0225c6afe0b49c Mon Sep 17 00:00:00 2001 From: Simon Noetzlin Date: Wed, 21 Feb 2024 17:16:15 +0100 Subject: [PATCH 022/110] feat!: add PSS reward distribution spike (#1632) * PSS reward distribution * "add optin mapping to test" * Update app/provider/app.go Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * docs * add TODO * fix Dos vector in IBCMiddlewarea * add reformat * fix DOS issue and make integration tests pass * doc * add integration test * doc * Compute total vp per consumer * add comments * remove opt-in comments and add TODOs * format * Update x/ccv/provider/keeper/distribution.go Co-authored-by: insumity * add UT + doc * Update tests/integration/distribution.go Co-authored-by: insumity * Update tests/integration/distribution.go Co-authored-by: insumity * nits * Update x/ccv/provider/ibc_middleware.go Co-authored-by: Marius Poke * add panics in IBC Middleware ICS4wrapper funcs * address comments --------- Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Co-authored-by: insumity Co-authored-by: Marius Poke --- .../ccv/provider/v1/provider.proto | 2 +- tests/integration/distribution.go | 9 +- testutil/keeper/mocks.go | 128 ++++++++++++++++++ 3 files changed, 133 insertions(+), 6 deletions(-) diff --git a/proto/interchain_security/ccv/provider/v1/provider.proto b/proto/interchain_security/ccv/provider/v1/provider.proto index 8c70c9e428..3576b03f55 100644 --- a/proto/interchain_security/ccv/provider/v1/provider.proto +++ b/proto/interchain_security/ccv/provider/v1/provider.proto @@ -338,4 +338,4 @@ message OptedInValidator { int64 power = 3; // public key used by the validator on the consumer bytes public_key = 4; -} \ No newline at end of file +} diff --git a/tests/integration/distribution.go b/tests/integration/distribution.go index 3a2d96b5f6..d61e81c796 100644 --- a/tests/integration/distribution.go +++ b/tests/integration/distribution.go @@ -14,7 +14,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" icstestingutils "github.com/cosmos/interchain-security/v4/testutil/integration" consumerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/consumer/keeper" consumertypes "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" @@ -482,7 +481,7 @@ func (s *CCVTestSuite) TestSendRewardsToProvider() { func (s *CCVTestSuite) TestIBCTransferMiddleware() { var ( - data ibctransfertypes.FungibleTokenPacketData + data transfertypes.FungibleTokenPacketData packet channeltypes.Packet getIBCDenom func(string, string) string ) @@ -614,7 +613,7 @@ func (s *CCVTestSuite) TestIBCTransferMiddleware() { tc.setup(s.providerCtx(), &providerKeeper, bankKeeper) - cbs, ok := s.providerChain.App.GetIBCKeeper().Router.GetRoute(ibctransfertypes.ModuleName) + cbs, ok := s.providerChain.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) s.Require().True(ok) // save the IBC transfer rewards transferred @@ -1108,12 +1107,12 @@ func (s *CCVTestSuite) TestMultiConsumerRewardsDistribution() { ) // construct the denom of the reward tokens for the provider - prefixedDenom := ibctransfertypes.GetPrefixedDenom( + prefixedDenom := transfertypes.GetPrefixedDenom( transfertypes.PortID, bundle.TransferPath.EndpointB.ChannelID, rewardsPerConsumer.Denom, ) - provIBCDenom := ibctransfertypes.ParseDenomTrace(prefixedDenom).IBCDenom() + provIBCDenom := transfertypes.ParseDenomTrace(prefixedDenom).IBCDenom() // sum the total rewards transferred to the provider totalConsumerRewards = totalConsumerRewards. diff --git a/testutil/keeper/mocks.go b/testutil/keeper/mocks.go index 78c0fbedc9..a192765ec9 100644 --- a/testutil/keeper/mocks.go +++ b/testutil/keeper/mocks.go @@ -1114,6 +1114,134 @@ func (m *MockIBCTransferKeeper) EXPECT() *MockIBCTransferKeeperMockRecorder { return m.recorder } +// OnAcknowledgementPacket mocks base method. +func (m *MockIBCTransferKeeper) OnAcknowledgementPacket(ctx types0.Context, packet types9.Packet, acknowledgement []byte, relayer types0.AccAddress) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnAcknowledgementPacket", ctx, packet, acknowledgement, relayer) + ret0, _ := ret[0].(error) + return ret0 +} + +// OnAcknowledgementPacket indicates an expected call of OnAcknowledgementPacket. +func (mr *MockIBCTransferKeeperMockRecorder) OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnAcknowledgementPacket", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnAcknowledgementPacket), ctx, packet, acknowledgement, relayer) +} + +// OnChanCloseConfirm mocks base method. +func (m *MockIBCTransferKeeper) OnChanCloseConfirm(ctx types0.Context, portID, channelID string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnChanCloseConfirm", ctx, portID, channelID) + ret0, _ := ret[0].(error) + return ret0 +} + +// OnChanCloseConfirm indicates an expected call of OnChanCloseConfirm. +func (mr *MockIBCTransferKeeperMockRecorder) OnChanCloseConfirm(ctx, portID, channelID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnChanCloseConfirm", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnChanCloseConfirm), ctx, portID, channelID) +} + +// OnChanCloseInit mocks base method. +func (m *MockIBCTransferKeeper) OnChanCloseInit(ctx types0.Context, portID, channelID string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnChanCloseInit", ctx, portID, channelID) + ret0, _ := ret[0].(error) + return ret0 +} + +// OnChanCloseInit indicates an expected call of OnChanCloseInit. +func (mr *MockIBCTransferKeeperMockRecorder) OnChanCloseInit(ctx, portID, channelID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnChanCloseInit", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnChanCloseInit), ctx, portID, channelID) +} + +// OnChanOpenAck mocks base method. +func (m *MockIBCTransferKeeper) OnChanOpenAck(ctx types0.Context, portID, channelID, counterpartyChannelID, counterpartyVersion string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnChanOpenAck", ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) + ret0, _ := ret[0].(error) + return ret0 +} + +// OnChanOpenAck indicates an expected call of OnChanOpenAck. +func (mr *MockIBCTransferKeeperMockRecorder) OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnChanOpenAck", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnChanOpenAck), ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) +} + +// OnChanOpenConfirm mocks base method. +func (m *MockIBCTransferKeeper) OnChanOpenConfirm(ctx types0.Context, portID, channelID string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnChanOpenConfirm", ctx, portID, channelID) + ret0, _ := ret[0].(error) + return ret0 +} + +// OnChanOpenConfirm indicates an expected call of OnChanOpenConfirm. +func (mr *MockIBCTransferKeeperMockRecorder) OnChanOpenConfirm(ctx, portID, channelID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnChanOpenConfirm", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnChanOpenConfirm), ctx, portID, channelID) +} + +// OnChanOpenInit mocks base method. +func (m *MockIBCTransferKeeper) OnChanOpenInit(ctx types0.Context, order types9.Order, connectionHops []string, portID, channelID string, channelCap *types2.Capability, counterparty types9.Counterparty, version string) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnChanOpenInit", ctx, order, connectionHops, portID, channelID, channelCap, counterparty, version) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// OnChanOpenInit indicates an expected call of OnChanOpenInit. +func (mr *MockIBCTransferKeeperMockRecorder) OnChanOpenInit(ctx, order, connectionHops, portID, channelID, channelCap, counterparty, version interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnChanOpenInit", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnChanOpenInit), ctx, order, connectionHops, portID, channelID, channelCap, counterparty, version) +} + +// OnChanOpenTry mocks base method. +func (m *MockIBCTransferKeeper) OnChanOpenTry(ctx types0.Context, order types9.Order, connectionHops []string, portID, channelID string, channelCap *types2.Capability, counterparty types9.Counterparty, counterpartyVersion string) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnChanOpenTry", ctx, order, connectionHops, portID, channelID, channelCap, counterparty, counterpartyVersion) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// OnChanOpenTry indicates an expected call of OnChanOpenTry. +func (mr *MockIBCTransferKeeperMockRecorder) OnChanOpenTry(ctx, order, connectionHops, portID, channelID, channelCap, counterparty, counterpartyVersion interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnChanOpenTry", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnChanOpenTry), ctx, order, connectionHops, portID, channelID, channelCap, counterparty, counterpartyVersion) +} + +// OnRecvPacket mocks base method. +func (m *MockIBCTransferKeeper) OnRecvPacket(ctx types0.Context, packet types9.Packet, relayer types0.AccAddress) exported.Acknowledgement { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnRecvPacket", ctx, packet, relayer) + ret0, _ := ret[0].(exported.Acknowledgement) + return ret0 +} + +// OnRecvPacket indicates an expected call of OnRecvPacket. +func (mr *MockIBCTransferKeeperMockRecorder) OnRecvPacket(ctx, packet, relayer interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnRecvPacket", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnRecvPacket), ctx, packet, relayer) +} + +// OnTimeoutPacket mocks base method. +func (m *MockIBCTransferKeeper) OnTimeoutPacket(ctx types0.Context, packet types9.Packet, relayer types0.AccAddress) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnTimeoutPacket", ctx, packet, relayer) + ret0, _ := ret[0].(error) + return ret0 +} + +// OnTimeoutPacket indicates an expected call of OnTimeoutPacket. +func (mr *MockIBCTransferKeeperMockRecorder) OnTimeoutPacket(ctx, packet, relayer interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnTimeoutPacket", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnTimeoutPacket), ctx, packet, relayer) +} + // Transfer mocks base method. func (m *MockIBCTransferKeeper) Transfer(arg0 context.Context, arg1 *types6.MsgTransfer) (*types6.MsgTransferResponse, error) { m.ctrl.T.Helper() From c6891116d7f79d8f32a55394f15a34ecb6f0fbcd Mon Sep 17 00:00:00 2001 From: Simon Noetzlin Date: Fri, 8 Mar 2024 09:24:32 +0100 Subject: [PATCH 023/110] feat!: PSS enable per-consumer chain commission (#1657) * add draft commission * implement consumer commission draft * formatting * add msg handling * improve UT * nits * Update x/ccv/provider/keeper/keeper.go Co-authored-by: insumity * Update proto/interchain_security/ccv/provider/v1/tx.proto Co-authored-by: Marius Poke * optimize keys * Update x/ccv/provider/keeper/keeper.go Co-authored-by: insumity * address comments * address comments * remove unnecessary check * Revert "remove unnecessary check" This reverts commit 2951e9bace04f6436d6ad1e4a11efcedd0be8cb1. * fix minor bug in StopConsumerChain --------- Co-authored-by: insumity Co-authored-by: Marius Poke --- .../features}/1516-introduce-epochs.md | 0 .../provider/1516-introduce-epochs.md | 0 ...ble-opt-in-chains-through-gov-proposals.md | 0 .../ccv/provider/v1/provider.proto | 2 +- tests/e2e/actions.go | 2 - tests/mbt/model/README.md | 4 - tests/mbt/model/ccv_boundeddrift.qnt | 5 + tests/mbt/model/run_invariants.sh | 42 ------ testutil/keeper/mocks.go | 128 ------------------ x/ccv/provider/keeper/proposal_test.go | 4 - 10 files changed, 6 insertions(+), 181 deletions(-) rename .changelog/{v4.0.0/features/provider => unreleased/features}/1516-introduce-epochs.md (100%) rename .changelog/{v4.0.0 => unreleased}/state-breaking/provider/1516-introduce-epochs.md (100%) rename .changelog/{v4.0.0/features => unreleased/state-breaking/provider}/1587-enable-opt-in-chains-through-gov-proposals.md (100%) diff --git a/.changelog/v4.0.0/features/provider/1516-introduce-epochs.md b/.changelog/unreleased/features/1516-introduce-epochs.md similarity index 100% rename from .changelog/v4.0.0/features/provider/1516-introduce-epochs.md rename to .changelog/unreleased/features/1516-introduce-epochs.md diff --git a/.changelog/v4.0.0/state-breaking/provider/1516-introduce-epochs.md b/.changelog/unreleased/state-breaking/provider/1516-introduce-epochs.md similarity index 100% rename from .changelog/v4.0.0/state-breaking/provider/1516-introduce-epochs.md rename to .changelog/unreleased/state-breaking/provider/1516-introduce-epochs.md diff --git a/.changelog/v4.0.0/features/1587-enable-opt-in-chains-through-gov-proposals.md b/.changelog/unreleased/state-breaking/provider/1587-enable-opt-in-chains-through-gov-proposals.md similarity index 100% rename from .changelog/v4.0.0/features/1587-enable-opt-in-chains-through-gov-proposals.md rename to .changelog/unreleased/state-breaking/provider/1587-enable-opt-in-chains-through-gov-proposals.md diff --git a/proto/interchain_security/ccv/provider/v1/provider.proto b/proto/interchain_security/ccv/provider/v1/provider.proto index 3576b03f55..8c70c9e428 100644 --- a/proto/interchain_security/ccv/provider/v1/provider.proto +++ b/proto/interchain_security/ccv/provider/v1/provider.proto @@ -338,4 +338,4 @@ message OptedInValidator { int64 power = 3; // public key used by the validator on the consumer bytes public_key = 4; -} +} \ No newline at end of file diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index 600464af8b..676c0566d7 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -1533,11 +1533,9 @@ func (tr TestConfig) delegateTokens( } cmd := target.ExecCommand(tr.chainConfigs[action.Chain].BinaryName, - "tx", "staking", "delegate", validatorAddress, fmt.Sprint(action.Amount)+`stake`, - `--from`, `validator`+fmt.Sprint(action.From), `--chain-id`, string(tr.chainConfigs[action.Chain].ChainId), `--home`, tr.getValidatorHome(action.Chain, action.From), diff --git a/tests/mbt/model/README.md b/tests/mbt/model/README.md index dac613337e..df994b7f84 100644 --- a/tests/mbt/model/README.md +++ b/tests/mbt/model/README.md @@ -138,8 +138,4 @@ The available sanity checks are: - CanOptIn (only with `--step stepBoundedDriftKeyAndPSS` on `ccv_boundeddrift.qnt`) - CanOptOut (only with `--step stepBoundedDriftKeyAndPSS` on `ccv_boundeddrift.qnt`) - CanFailOptOut (only with `--step stepBoundedDriftKeyAndPSS` on `ccv_boundeddrift.qnt`) -<<<<<<< HEAD - CanHaveOptIn (only with `--step stepBoundedDriftKeyAndPSS` on `ccv_boundeddrift.qnt`) -======= -- CanHaveOptIn (only with `--step stepBoundedDriftKeyAndPSS` on `ccv_boundeddrift.qnt`) ->>>>>>> 6e075652 (test: MBT: Add partial set security to model (feature branch version) (#1627)) diff --git a/tests/mbt/model/ccv_boundeddrift.qnt b/tests/mbt/model/ccv_boundeddrift.qnt index 37fcd5a15b..b067ca79b2 100644 --- a/tests/mbt/model/ccv_boundeddrift.qnt +++ b/tests/mbt/model/ccv_boundeddrift.qnt @@ -115,6 +115,11 @@ module ccv_boundeddrift { StepOptOut, } + action stepBoundedDriftKeyAssignment = any { + stepBoundedDrift, + nondetKeyAssignment, + } + // INVARIANT // The maxDrift between chains is never exceeded. // This *should* be ensured by the step function. diff --git a/tests/mbt/model/run_invariants.sh b/tests/mbt/model/run_invariants.sh index e232bcce8b..bda58d80f6 100755 --- a/tests/mbt/model/run_invariants.sh +++ b/tests/mbt/model/run_invariants.sh @@ -1,48 +1,6 @@ #!/bin/bash -<<<<<<< HEAD -# to stop on any errors -set -e - -quint test ccv_model.qnt -quint test ccv_test.qnt -quint run --invariant "all{ValidatorUpdatesArePropagatedInv,ValidatorSetHasExistedInv,SameVscPacketsInv,MatureOnTimeInv,EventuallyMatureOnProviderInv}" ccv_model.qnt --max-steps 200 --max-samples 200 -quint run --invariant "all{ValidatorUpdatesArePropagatedKeyAssignmentInv,ValidatorSetHasExistedKeyAssignmentInv,SameVscPacketsKeyAssignmentInv,MatureOnTimeInv,EventuallyMatureOnProviderInv,KeyAssignmentRulesInv}" ccv_model.qnt --step stepKeyAssignment --max-steps 200 --max-samples 200 - - -# do not stop on errors anymore, so we can give better output if we error -set +e - -run_invariant() { - local invariant=$1 - local step=$2 - local match=$3 - - if [[ -z "$step" ]]; then - quint run --invariant $invariant ccv_model.qnt | grep -q $match - else - quint run --invariant $invariant --step $step ccv_model.qnt | grep -q $match - fi - - if [[ $? -eq 0 ]]; then - echo "sanity check $invariant ok" - else - echo "sanity check $invariant not ok" - exit 1 - fi -} - -run_invariant "CanRunConsumer" "" '[violation]' -run_invariant "CanStopConsumer" "" '[violation]' -run_invariant "CanTimeoutConsumer" "" '[violation]' -run_invariant "CanSendVscPackets" "" '[violation]' -run_invariant "CanSendVscMaturedPackets" "" '[violation]' -run_invariant "CanAssignConsumerKey" "stepKeyAssignment" '[violation]' -run_invariant "CanHaveConsumerAddresses" "stepKeyAssignment" '[violation]' -run_invariant "CanReceiveMaturations" "stepKeyAssignment" '[violation]' -======= quint test ccv_model.qnt quint test ccv_test.qnt quint run --invariant "all{ValidatorUpdatesArePropagatedInv,ValidatorSetHasExistedInv,SameVscPacketsInv,MatureOnTimeInv,EventuallyMatureOnProviderInv}" ccv_model.qnt --max-steps 200 --max-samples 200 quint run --invariant "all{ValidatorUpdatesArePropagatedKeyAssignmentInv,ValidatorSetHasExistedKeyAssignmentInv,SameVscPacketsKeyAssignmentInv,MatureOnTimeInv,EventuallyMatureOnProviderInv,KeyAssignmentRulesInv}" ccv_model.qnt --step stepKeyAssignment --max-steps 200 --max-samples 200 ->>>>>>> 6e075652 (test: MBT: Add partial set security to model (feature branch version) (#1627)) diff --git a/testutil/keeper/mocks.go b/testutil/keeper/mocks.go index a192765ec9..78c0fbedc9 100644 --- a/testutil/keeper/mocks.go +++ b/testutil/keeper/mocks.go @@ -1114,134 +1114,6 @@ func (m *MockIBCTransferKeeper) EXPECT() *MockIBCTransferKeeperMockRecorder { return m.recorder } -// OnAcknowledgementPacket mocks base method. -func (m *MockIBCTransferKeeper) OnAcknowledgementPacket(ctx types0.Context, packet types9.Packet, acknowledgement []byte, relayer types0.AccAddress) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnAcknowledgementPacket", ctx, packet, acknowledgement, relayer) - ret0, _ := ret[0].(error) - return ret0 -} - -// OnAcknowledgementPacket indicates an expected call of OnAcknowledgementPacket. -func (mr *MockIBCTransferKeeperMockRecorder) OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnAcknowledgementPacket", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnAcknowledgementPacket), ctx, packet, acknowledgement, relayer) -} - -// OnChanCloseConfirm mocks base method. -func (m *MockIBCTransferKeeper) OnChanCloseConfirm(ctx types0.Context, portID, channelID string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnChanCloseConfirm", ctx, portID, channelID) - ret0, _ := ret[0].(error) - return ret0 -} - -// OnChanCloseConfirm indicates an expected call of OnChanCloseConfirm. -func (mr *MockIBCTransferKeeperMockRecorder) OnChanCloseConfirm(ctx, portID, channelID interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnChanCloseConfirm", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnChanCloseConfirm), ctx, portID, channelID) -} - -// OnChanCloseInit mocks base method. -func (m *MockIBCTransferKeeper) OnChanCloseInit(ctx types0.Context, portID, channelID string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnChanCloseInit", ctx, portID, channelID) - ret0, _ := ret[0].(error) - return ret0 -} - -// OnChanCloseInit indicates an expected call of OnChanCloseInit. -func (mr *MockIBCTransferKeeperMockRecorder) OnChanCloseInit(ctx, portID, channelID interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnChanCloseInit", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnChanCloseInit), ctx, portID, channelID) -} - -// OnChanOpenAck mocks base method. -func (m *MockIBCTransferKeeper) OnChanOpenAck(ctx types0.Context, portID, channelID, counterpartyChannelID, counterpartyVersion string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnChanOpenAck", ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) - ret0, _ := ret[0].(error) - return ret0 -} - -// OnChanOpenAck indicates an expected call of OnChanOpenAck. -func (mr *MockIBCTransferKeeperMockRecorder) OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnChanOpenAck", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnChanOpenAck), ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) -} - -// OnChanOpenConfirm mocks base method. -func (m *MockIBCTransferKeeper) OnChanOpenConfirm(ctx types0.Context, portID, channelID string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnChanOpenConfirm", ctx, portID, channelID) - ret0, _ := ret[0].(error) - return ret0 -} - -// OnChanOpenConfirm indicates an expected call of OnChanOpenConfirm. -func (mr *MockIBCTransferKeeperMockRecorder) OnChanOpenConfirm(ctx, portID, channelID interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnChanOpenConfirm", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnChanOpenConfirm), ctx, portID, channelID) -} - -// OnChanOpenInit mocks base method. -func (m *MockIBCTransferKeeper) OnChanOpenInit(ctx types0.Context, order types9.Order, connectionHops []string, portID, channelID string, channelCap *types2.Capability, counterparty types9.Counterparty, version string) (string, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnChanOpenInit", ctx, order, connectionHops, portID, channelID, channelCap, counterparty, version) - ret0, _ := ret[0].(string) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// OnChanOpenInit indicates an expected call of OnChanOpenInit. -func (mr *MockIBCTransferKeeperMockRecorder) OnChanOpenInit(ctx, order, connectionHops, portID, channelID, channelCap, counterparty, version interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnChanOpenInit", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnChanOpenInit), ctx, order, connectionHops, portID, channelID, channelCap, counterparty, version) -} - -// OnChanOpenTry mocks base method. -func (m *MockIBCTransferKeeper) OnChanOpenTry(ctx types0.Context, order types9.Order, connectionHops []string, portID, channelID string, channelCap *types2.Capability, counterparty types9.Counterparty, counterpartyVersion string) (string, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnChanOpenTry", ctx, order, connectionHops, portID, channelID, channelCap, counterparty, counterpartyVersion) - ret0, _ := ret[0].(string) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// OnChanOpenTry indicates an expected call of OnChanOpenTry. -func (mr *MockIBCTransferKeeperMockRecorder) OnChanOpenTry(ctx, order, connectionHops, portID, channelID, channelCap, counterparty, counterpartyVersion interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnChanOpenTry", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnChanOpenTry), ctx, order, connectionHops, portID, channelID, channelCap, counterparty, counterpartyVersion) -} - -// OnRecvPacket mocks base method. -func (m *MockIBCTransferKeeper) OnRecvPacket(ctx types0.Context, packet types9.Packet, relayer types0.AccAddress) exported.Acknowledgement { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnRecvPacket", ctx, packet, relayer) - ret0, _ := ret[0].(exported.Acknowledgement) - return ret0 -} - -// OnRecvPacket indicates an expected call of OnRecvPacket. -func (mr *MockIBCTransferKeeperMockRecorder) OnRecvPacket(ctx, packet, relayer interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnRecvPacket", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnRecvPacket), ctx, packet, relayer) -} - -// OnTimeoutPacket mocks base method. -func (m *MockIBCTransferKeeper) OnTimeoutPacket(ctx types0.Context, packet types9.Packet, relayer types0.AccAddress) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnTimeoutPacket", ctx, packet, relayer) - ret0, _ := ret[0].(error) - return ret0 -} - -// OnTimeoutPacket indicates an expected call of OnTimeoutPacket. -func (mr *MockIBCTransferKeeperMockRecorder) OnTimeoutPacket(ctx, packet, relayer interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnTimeoutPacket", reflect.TypeOf((*MockIBCTransferKeeper)(nil).OnTimeoutPacket), ctx, packet, relayer) -} - // Transfer mocks base method. func (m *MockIBCTransferKeeper) Transfer(arg0 context.Context, arg1 *types6.MsgTransfer) (*types6.MsgTransferResponse, error) { m.ctrl.T.Helper() diff --git a/x/ccv/provider/keeper/proposal_test.go b/x/ccv/provider/keeper/proposal_test.go index 8de4282474..99e8c74e49 100644 --- a/x/ccv/provider/keeper/proposal_test.go +++ b/x/ccv/provider/keeper/proposal_test.go @@ -554,10 +554,6 @@ func TestStopConsumerChain(t *testing.T) { require.Error(t, err) } else { require.NoError(t, err) - - // in case the chain was successfully stopped, it should not contain a Top N associated to it - _, found := providerKeeper.GetTopN(ctx, "chainID") - require.False(t, found) } testkeeper.TestProviderStateIsCleanedAfterConsumerChainIsStopped(t, ctx, providerKeeper, "chainID", "channelID") From 5d5470292aee4ad59571c7b4a8e122d19198739e Mon Sep 17 00:00:00 2001 From: Simon Noetzlin Date: Wed, 13 Mar 2024 09:35:02 +0100 Subject: [PATCH 024/110] fix nits in MBT model after merging #1676 from main --- tests/mbt/model/ccv_model.qnt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/mbt/model/ccv_model.qnt b/tests/mbt/model/ccv_model.qnt index 3dc0ea1861..a4f1ad4cf3 100644 --- a/tests/mbt/model/ccv_model.qnt +++ b/tests/mbt/model/ccv_model.qnt @@ -255,7 +255,7 @@ module ccv_model { // As a a `Run`, it is only used in tests, not during simulation or verification. run EndProviderEpoch( timeAdvancement: Time, - consumersToStart: Set[Chain], + consumersToStart: Set[ConsumerAdditionMsg], consumersToStop: Set[Chain] ): bool = epochLength.reps( From 24942e214ae17f0adc638dead0a1f447d2e4896b Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Wed, 13 Mar 2024 11:18:23 +0100 Subject: [PATCH 025/110] Fix merging ccv model --- tests/mbt/model/README.md | 3 +++ tests/mbt/model/ccv.qnt | 11 ++--------- tests/mbt/model/ccv_boundeddrift.qnt | 24 ++++++++++++++++++++++++ tests/mbt/model/ccv_model.qnt | 9 ++++----- 4 files changed, 33 insertions(+), 14 deletions(-) diff --git a/tests/mbt/model/README.md b/tests/mbt/model/README.md index df994b7f84..865fabe016 100644 --- a/tests/mbt/model/README.md +++ b/tests/mbt/model/README.md @@ -50,12 +50,15 @@ As an optional module, it can also include KeyAssignment. To run with key assignment, specify the step flag: `--step stepKeyAssignment`. KeyAssignment also needs some different invariants, see below. +<<<<<<< HEAD #### Partial Set Security To run with Partial Set Security, specify the step flag `--step stepBoundedDriftKeyAndPSS`. This runs both PSS and Key Assignment. It also requires running with `ccv_boundeddrift.qnt`, see below. +======= +>>>>>>> main #### ccv_boundeddrift.qnt This state machine layer is more restricted to generate more interesting traces: diff --git a/tests/mbt/model/ccv.qnt b/tests/mbt/model/ccv.qnt index 68d08e88a3..6941dc8a73 100644 --- a/tests/mbt/model/ccv.qnt +++ b/tests/mbt/model/ccv.qnt @@ -89,12 +89,6 @@ module ccv_types { // Stores VscPackets which have been sent but where the provider has *not received a response yet*. sentVscPacketsToConsumer: Chain -> List[VscPacket], - // stores whether, in this block, the validator set has changed. - // this is needed because the validator set might be considered to have changed, even though - // it is still technically identical at our level of abstraction, e.g. a validator power change on the provider - // might leave the validator set the same because a delegation and undelegation cancel each other out. - providerValidatorSetChangedInThisBlock: bool, - // stores for which consumer chains, in this epoch, the validator set is considered to have changed and we thus need to send a VscPacket to the consumer chains. consumersWithPowerChangesInThisEpoch: Set[Chain], @@ -147,7 +141,6 @@ module ccv_types { outstandingPacketsToConsumer: Map(), receivedMaturations: Set(), sentVscPacketsToConsumer: Map(), - providerValidatorSetChangedInThisBlock: false, consumersWithPowerChangesInThisEpoch: Set(), consumerStatus: Map(), runningVscId: 0, @@ -156,9 +149,9 @@ module ccv_types { consumerAddrToValidator: Map(), consumerAddrsToPrune: Map(), keyAssignmentsForVSCPackets: Map(), - consumersWithAddrAssignmentChangesInThisEpoch: Set(), optedInVals: Map(), topNByConsumer: Map(), + consumersWithAddrAssignmentChangesInThisEpoch: Set() } @@ -510,7 +503,7 @@ module ccv { consumersToStop, timedOutConsumers ) - val providerStateAfterConsumerAdvancement = res._1.with("providerValidatorSetChangedInThisBlock", false) + val providerStateAfterConsumerAdvancement = res._1 val err = res._2 val consumerAdditions = consumersToStart.map(consumer => consumer.chain) diff --git a/tests/mbt/model/ccv_boundeddrift.qnt b/tests/mbt/model/ccv_boundeddrift.qnt index b067ca79b2..125de8004e 100644 --- a/tests/mbt/model/ccv_boundeddrift.qnt +++ b/tests/mbt/model/ccv_boundeddrift.qnt @@ -104,6 +104,12 @@ module ccv_boundeddrift { nondet timeAdvancement = possibleAdvancements.oneOf() EndAndBeginBlockForConsumer(chain, timeAdvancement), } +<<<<<<< HEAD + } + + action stepBoundedDriftKeyAssignment = any { + stepBoundedDrift, + nondetKeyAssignment, } action stepBoundedDriftKeyAndPSS = any { @@ -113,6 +119,24 @@ module ccv_boundeddrift { nondetKeyAssignment, StepOptIn, StepOptOut, +======= + }, + + // advance a block for the provider + val maxAdv = findMaxTimeAdvancement(GetChainState(Ccvt::PROVIDER_CHAIN), GetOtherChainStates(Ccvt::PROVIDER_CHAIN), maxDrift) + val possibleAdvancements = timeAdvancements.filter(t => t <= maxAdv) + all { + possibleAdvancements.size() > 0, // ensure there is a possible advancement, otherwise this action does not make sense + // advance a block for the provider + val consumerStatus = currentState.providerState.consumerStatus + nondet consumersToStart = oneOf(nonConsumers.powerset()) + // make it so we stop consumers only with small likelihood: + nondet stopConsumersRand = oneOf(1.to(100)) + nondet consumersToStop = if (stopConsumersRand <= consumerStopChance) oneOf(runningConsumers.powerset()) else Set() + nondet timeAdvancement = oneOf(possibleAdvancements) + EndAndBeginBlockForProvider(timeAdvancement, consumersToStart, consumersToStop), + } +>>>>>>> main } action stepBoundedDriftKeyAssignment = any { diff --git a/tests/mbt/model/ccv_model.qnt b/tests/mbt/model/ccv_model.qnt index a4f1ad4cf3..3061f7039b 100644 --- a/tests/mbt/model/ccv_model.qnt +++ b/tests/mbt/model/ccv_model.qnt @@ -109,7 +109,7 @@ module ccv_model { val consumerStates = ConsumerChains.mapBy(chain => GetEmptyConsumerState) val providerStateWithConsumers = providerState.with( "consumerStatus", - ConsumerChains.mapBy(chain => NOT_CONSUMER) + ConsumerChains.mapBy(chain => NOT_CONSUMER) ).with( "outstandingPacketsToConsumer", ConsumerChains.mapBy(chain => List()) @@ -255,7 +255,7 @@ module ccv_model { // As a a `Run`, it is only used in tests, not during simulation or verification. run EndProviderEpoch( timeAdvancement: Time, - consumersToStart: Set[ConsumerAdditionMsg], + consumersToStart: Set[Chain], consumersToStop: Set[Chain] ): bool = epochLength.reps( @@ -270,7 +270,6 @@ module ccv_model { // ================== // UTILITY FUNCTIONS // ================== - pure def oldest(packets: Set[VscPacket]): VscPacket = val newestPossiblePacket: VscPacket = { id: 0, @@ -740,11 +739,11 @@ module ccv_model { // and the key assignment of each validator should be applied in that VSCPacket. val ValidatorUpdatesArePropagatedKeyAssignmentInv = // when the provider has just entered a validator set into a block... - ValUpdatePrecondition and currentState.providerState.providerValidatorSetChangedInThisBlock + ValUpdatePrecondition and CurrentBlockEndsEpoch implies val providerValSetInCurBlock = providerValidatorHistory.head() // ... for each consumer that is running then ... - runningConsumers.forall( + currentState.providerState.consumersWithPowerChangesInThisEpoch.forall( // ...the validator set under key assignment is in a sent packet... val providerState = currentState.providerState consumer => providerState.sentVscPacketsToConsumer.get(consumer).toSet().exists( From b30b6be88a2e4a6e555d4f41dda970ef976772e7 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Wed, 13 Mar 2024 11:23:23 +0100 Subject: [PATCH 026/110] Remove conflict markers --- tests/mbt/model/README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/mbt/model/README.md b/tests/mbt/model/README.md index 865fabe016..df994b7f84 100644 --- a/tests/mbt/model/README.md +++ b/tests/mbt/model/README.md @@ -50,15 +50,12 @@ As an optional module, it can also include KeyAssignment. To run with key assignment, specify the step flag: `--step stepKeyAssignment`. KeyAssignment also needs some different invariants, see below. -<<<<<<< HEAD #### Partial Set Security To run with Partial Set Security, specify the step flag `--step stepBoundedDriftKeyAndPSS`. This runs both PSS and Key Assignment. It also requires running with `ccv_boundeddrift.qnt`, see below. -======= ->>>>>>> main #### ccv_boundeddrift.qnt This state machine layer is more restricted to generate more interesting traces: From 18e7f254cbd6ecf15231f5b161cce652caef3521 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Wed, 13 Mar 2024 11:25:06 +0100 Subject: [PATCH 027/110] Remove more conflict markers --- tests/mbt/model/ccv_boundeddrift.qnt | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/tests/mbt/model/ccv_boundeddrift.qnt b/tests/mbt/model/ccv_boundeddrift.qnt index 125de8004e..eb59781124 100644 --- a/tests/mbt/model/ccv_boundeddrift.qnt +++ b/tests/mbt/model/ccv_boundeddrift.qnt @@ -104,7 +104,6 @@ module ccv_boundeddrift { nondet timeAdvancement = possibleAdvancements.oneOf() EndAndBeginBlockForConsumer(chain, timeAdvancement), } -<<<<<<< HEAD } action stepBoundedDriftKeyAssignment = any { @@ -119,8 +118,6 @@ module ccv_boundeddrift { nondetKeyAssignment, StepOptIn, StepOptOut, -======= - }, // advance a block for the provider val maxAdv = findMaxTimeAdvancement(GetChainState(Ccvt::PROVIDER_CHAIN), GetOtherChainStates(Ccvt::PROVIDER_CHAIN), maxDrift) @@ -136,14 +133,8 @@ module ccv_boundeddrift { nondet timeAdvancement = oneOf(possibleAdvancements) EndAndBeginBlockForProvider(timeAdvancement, consumersToStart, consumersToStop), } ->>>>>>> main } - - action stepBoundedDriftKeyAssignment = any { - stepBoundedDrift, - nondetKeyAssignment, - } - + // INVARIANT // The maxDrift between chains is never exceeded. // This *should* be ensured by the step function. From 581a9832253a4c7ec354c7c1b58a8a559a051476 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Wed, 13 Mar 2024 11:26:06 +0100 Subject: [PATCH 028/110] EndProviderEpoch takes ConsumerAdditionMsg --- tests/mbt/model/ccv_model.qnt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/mbt/model/ccv_model.qnt b/tests/mbt/model/ccv_model.qnt index 3061f7039b..fcd7897de1 100644 --- a/tests/mbt/model/ccv_model.qnt +++ b/tests/mbt/model/ccv_model.qnt @@ -255,7 +255,7 @@ module ccv_model { // As a a `Run`, it is only used in tests, not during simulation or verification. run EndProviderEpoch( timeAdvancement: Time, - consumersToStart: Set[Chain], + consumersToStart: Set[ConsumerAdditionMsg], consumersToStop: Set[Chain] ): bool = epochLength.reps( From 955528c471da474a8be08e403d98e4a45743bd92 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Wed, 13 Mar 2024 11:32:49 +0100 Subject: [PATCH 029/110] Fix using consumer addition msgs instead of chain names in boundeddrift.qnt --- tests/mbt/model/ccv_boundeddrift.qnt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/mbt/model/ccv_boundeddrift.qnt b/tests/mbt/model/ccv_boundeddrift.qnt index eb59781124..2552304816 100644 --- a/tests/mbt/model/ccv_boundeddrift.qnt +++ b/tests/mbt/model/ccv_boundeddrift.qnt @@ -111,7 +111,7 @@ module ccv_boundeddrift { nondetKeyAssignment, } - action stepBoundedDriftKeyAndPSS = any { + action stepBoundedDriftKeyAndPSS: bool = any { stepCommon, stepBoundedDriftProviderPSS, stepBoundedDriftConsumer, @@ -127,14 +127,16 @@ module ccv_boundeddrift { // advance a block for the provider val consumerStatus = currentState.providerState.consumerStatus nondet consumersToStart = oneOf(nonConsumers.powerset()) + nondet topN = oneOf(variousPossibleTopN) + nondet consumerAdditions = consumersToStart.map(c => Ccvt::NewTopNConsumer(c, topN)) // make it so we stop consumers only with small likelihood: nondet stopConsumersRand = oneOf(1.to(100)) nondet consumersToStop = if (stopConsumersRand <= consumerStopChance) oneOf(runningConsumers.powerset()) else Set() nondet timeAdvancement = oneOf(possibleAdvancements) - EndAndBeginBlockForProvider(timeAdvancement, consumersToStart, consumersToStop), + EndAndBeginBlockForProvider(timeAdvancement, consumerAdditions, consumersToStop), } } - + // INVARIANT // The maxDrift between chains is never exceeded. // This *should* be ensured by the step function. From ef56ccf3fab308e54e524367a725966b77d329ab Mon Sep 17 00:00:00 2001 From: Simon Noetzlin Date: Mon, 18 Mar 2024 15:31:34 +0100 Subject: [PATCH 030/110] lint --- app/consumer/genesis.go | 3 +- app/consumer/genesis_test.go | 4 +-- app/sovereign/app.go | 1 - tests/e2e/actions.go | 4 +-- tests/e2e/builder.go | 4 +-- tests/e2e/config.go | 2 +- tests/e2e/main.go | 11 ++++--- tests/e2e/steps_compatibility.go | 4 +-- tests/e2e/test_runner.go | 4 +-- tests/e2e/test_target.go | 2 +- tests/integration/distribution.go | 12 +++---- tests/integration/soft_opt_out.go | 4 ++- tests/mbt/driver/core.go | 2 +- tests/mbt/driver/mbt_test.go | 7 ++-- .../consumer/migrations/v2/migration_test.go | 1 + x/ccv/provider/client/cli/query.go | 1 - x/ccv/provider/client/cli/tx.go | 1 - x/ccv/provider/ibc_middleware.go | 14 ++++---- x/ccv/provider/ibc_middleware_test.go | 3 +- x/ccv/provider/keeper/distribution.go | 10 +++--- x/ccv/provider/keeper/distribution_test.go | 14 ++++---- x/ccv/provider/keeper/hooks.go | 6 +++- x/ccv/provider/keeper/hooks_test.go | 15 +++++---- x/ccv/provider/keeper/keeper.go | 15 +++++---- x/ccv/provider/keeper/keeper_test.go | 29 +++++++++-------- x/ccv/provider/keeper/key_assignment_test.go | 4 ++- x/ccv/provider/keeper/msg_server.go | 5 ++- x/ccv/provider/keeper/partial_set_security.go | 2 ++ .../keeper/partial_set_security_test.go | 6 ++-- x/ccv/provider/keeper/relay_test.go | 5 +-- x/ccv/provider/keeper/validator_set_update.go | 15 ++++++--- .../keeper/validator_set_update_test.go | 13 +++++--- .../provider/migrations/v3/migration_test.go | 32 +++++++++---------- x/ccv/provider/migrations/v3/migrations.go | 4 +-- x/ccv/provider/types/codec.go | 5 +-- x/ccv/provider/types/consumer.go | 1 + x/ccv/types/expected_keepers.go | 2 +- 37 files changed, 151 insertions(+), 116 deletions(-) diff --git a/app/consumer/genesis.go b/app/consumer/genesis.go index bf7ba81c95..7f49df7579 100644 --- a/app/consumer/genesis.go +++ b/app/consumer/genesis.go @@ -15,6 +15,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" + consumerTypes "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" "github.com/cosmos/interchain-security/v4/x/ccv/types" ) @@ -149,7 +150,6 @@ func transformToV33(jsonRaw []byte, ctx client.Context) ([]byte, error) { // to a format readable by consumer implementation of version v2.x // Use removePreHashKey to remove prehash_key_before_comparison from result. func transformToV2(jsonRaw []byte, ctx client.Context, removePreHashKey bool) (json.RawMessage, error) { - // populate deprecated fields of GenesisState used by version v2.x srcConGen := consumerTypes.GenesisState{} err := ctx.Codec.UnmarshalJSON(jsonRaw, &srcConGen) @@ -284,7 +284,6 @@ func transformGenesis(ctx client.Context, targetVersion IcsVersion, jsonRaw []by // // Result will be written to defined output. func TransformConsumerGenesis(cmd *cobra.Command, args []string) error { - sourceFile := args[0] jsonRaw, err := os.ReadFile(filepath.Clean(sourceFile)) if err != nil { diff --git a/app/consumer/genesis_test.go b/app/consumer/genesis_test.go index f5aa3208b1..c9b9b578ff 100644 --- a/app/consumer/genesis_test.go +++ b/app/consumer/genesis_test.go @@ -502,7 +502,6 @@ func TestConsumerGenesisTransformationFromV2ToCurrent(t *testing.T) { require.Equal(t, "", resultGenesis.ProviderChannelId) require.Equal(t, srcGenesis.InitialValSet, resultGenesis.Provider.InitialValSet) require.Empty(t, resultGenesis.InitialValSet) - } // Check transformation of provider v3.3.x implementation to consumer V2 @@ -530,7 +529,6 @@ func TestConsumerGenesisTransformationV330ToV2(t *testing.T) { require.Equal(t, srcGenesis.NewChain, resultGenesis.NewChain) require.Equal(t, "", resultGenesis.ProviderClientId) require.Equal(t, "", resultGenesis.ProviderChannelId) - } // Check transformation of provider v3.3.x implementation to current consumer version @@ -638,7 +636,7 @@ func TestConsumerGenesisTransformationV4ToV33(t *testing.T) { targetVersion := "v3.3.x" result, err := transformConsumerGenesis(filePath, &targetVersion) require.NoError(t, err) - resultGenesis := consumerTypes.GenesisState{} //Only difference to v33 is no RetryDelayPeriod + err = ctx.Codec.UnmarshalJSON(result, &resultGenesis) require.NoError(t, err) diff --git a/app/sovereign/app.go b/app/sovereign/app.go index 4017ca9d4f..3d1a981e83 100644 --- a/app/sovereign/app.go +++ b/app/sovereign/app.go @@ -79,7 +79,6 @@ import ( govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" - // add mint mint "github.com/cosmos/cosmos-sdk/x/mint" mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper" diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index 676c0566d7..34f6e9eaa0 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -559,7 +559,6 @@ func (tr *TestConfig) getConsumerGenesis(providerChain, consumerChain ChainID, t // needsGenesisTransform tries to identify if a genesis transformation should be performed func needsGenesisTransform(cfg TargetConfig) bool { - // no genesis transformation needed for same versions if cfg.consumerVersion == cfg.providerVersion { return false @@ -673,7 +672,7 @@ func (tr *TestConfig) transformConsumerGenesis(consumerChain ChainID, genesis [] panic(fmt.Sprintf("failed writing ccv consumer file : %v", err)) } defer file.Close() - err = os.WriteFile(file.Name(), genesis, 0600) + err = os.WriteFile(file.Name(), genesis, 0o600) if err != nil { log.Fatalf("Failed writing consumer genesis to file: %v", err) } @@ -954,7 +953,6 @@ func (tr TestConfig) addChainToHermes( target ExecutionTarget, verbose bool, ) { - bz, err := target.ExecCommand("bash", "-c", "hermes", "version").CombinedOutput() if err != nil { log.Fatal(err, "\n error getting hermes version", string(bz)) diff --git a/tests/e2e/builder.go b/tests/e2e/builder.go index 79800d0c23..4321b36729 100644 --- a/tests/e2e/builder.go +++ b/tests/e2e/builder.go @@ -82,7 +82,7 @@ func generateImageName(version string, cfg TargetConfig) (string, error) { tagName = "local" // this refers to build from local workspace } else { // use git hash of rev as docker image tag - //cmd := exec.Command("git", "rev-parse", "--verify", "--short", version) + cmd := exec.Command("git", "log", "--pretty=format:%h", "-n", "1", version) out, err := cmd.CombinedOutput() if err != nil { @@ -179,7 +179,7 @@ func pullDockerImage(tag string, targetConfig TargetConfig) (string, error) { // bootstrapSDK in workspace to use custom SDK setup if required func bootstrapSDK(workSpace string, targetCfg TargetConfig) error { sdkPath := strings.Join([]string{workSpace, "cosmos-sdk"}, string(os.PathSeparator)) - err := os.RemoveAll(sdkPath) //delete old SDK directory + if err != nil { return fmt.Errorf("error deleting SDK directory from workspace: %v", err) } diff --git a/tests/e2e/config.go b/tests/e2e/config.go index e530ca3a9d..bb36a4af28 100644 --- a/tests/e2e/config.go +++ b/tests/e2e/config.go @@ -236,7 +236,7 @@ func getIcsVersion(reference string) string { log.Printf("error identifying config version to use '%v': %s", err, string(out)) return "" } - //reference is not part of this tag, try next one + } } return semver.Canonical(icsVersion) diff --git a/tests/e2e/main.go b/tests/e2e/main.go index 8245b601b6..c1f7005bfa 100644 --- a/tests/e2e/main.go +++ b/tests/e2e/main.go @@ -36,7 +36,7 @@ func (vs *VersionSet) Set(value string) error { func (vs *VersionSet) String() string { keys := []string{} - for k, _ := range *vs { + for k := range *vs { keys = append(keys, k) } return fmt.Sprint(keys) @@ -233,7 +233,8 @@ type testStepsWithConfig struct { } func getTestCases(selectedPredefinedTests, selectedTestFiles TestSet, providerVersions, - consumerVersions VersionSet) (tests []testStepsWithConfig) { + consumerVersions VersionSet, +) (tests []testStepsWithConfig) { // Run default tests if no test cases were selected if len(selectedPredefinedTests) == 0 && len(selectedTestFiles) == 0 { selectedPredefinedTests = TestSet{ @@ -319,10 +320,10 @@ func createTargets(providerVersions, consumerVersions VersionSet) ([]ExecutionTa } // Create targets as a combination of "provider versions" with "consumer version" - for provider, _ := range providerVersions { + for provider := range providerVersions { targetCfg := TargetConfig{useGaia: *useGaia, localSdkPath: *localSdkPath, gaiaTag: *gaiaTag} targetCfg.providerVersion = provider - for consumer, _ := range consumerVersions { + for consumer := range consumerVersions { // Skip target creation for same version of provider and consumer // if multiple versions need to be tested. // This is to reduce the tests to be run for compatibility testing. @@ -376,7 +377,7 @@ func executeTests(runners []TestRunner) error { var wg sync.WaitGroup var err error = nil - for idx, _ := range runners { + for idx := range runners { if parallel != nil && *parallel { wg.Add(1) go func(runner *TestRunner) { diff --git a/tests/e2e/steps_compatibility.go b/tests/e2e/steps_compatibility.go index 1fc6ced315..ef3cab4e73 100644 --- a/tests/e2e/steps_compatibility.go +++ b/tests/e2e/steps_compatibility.go @@ -58,7 +58,7 @@ func compstepsStartConsumerChain(consumerName string, proposalIndex, chainIndex }, }, // not supported across major versions - //ProposedConsumerChains: &[]string{consumerName}, + // ProposedConsumerChains: &[]string{consumerName}, }, }, }, @@ -169,7 +169,7 @@ func compstepsStartConsumerChain(consumerName string, proposalIndex, chainIndex ValidatorID("carol"): 9500000000, }, // not supported - //ProposedConsumerChains: &[]string{}, + // ProposedConsumerChains: &[]string{}, }, ChainID(consumerName): ChainState{ ValBalances: &map[ValidatorID]uint{ diff --git a/tests/e2e/test_runner.go b/tests/e2e/test_runner.go index af4ea51eb3..d368f9d3e5 100644 --- a/tests/e2e/test_runner.go +++ b/tests/e2e/test_runner.go @@ -103,6 +103,7 @@ func (tr *TestRunner) checkConfig() error { tr.config.validateStringLiterals() return nil } + func (tr *TestRunner) setupEnvironment(target ExecutionTarget) error { tr.target = target return target.Start() @@ -118,7 +119,7 @@ func (tr *TestRunner) Setup(testCfg TestConfig) error { } func CreateTestRunner(config TestConfig, steps []Step, target ExecutionTarget, verbose bool) (error, TestRunner) { - //targetConfig := target.GetTargetConfig() + switch target.(type) { case *DockerContainer: target.(*DockerContainer).containerCfg = config.containerConfig @@ -143,7 +144,6 @@ Target: %s tr.config.name, tr.target.Info(), ) - } func (tr *TestRunner) Report() string { diff --git a/tests/e2e/test_target.go b/tests/e2e/test_target.go index 845ede8481..419242633e 100644 --- a/tests/e2e/test_target.go +++ b/tests/e2e/test_target.go @@ -28,7 +28,7 @@ type ExecutionTarget interface { type DockerContainer struct { targetConfig TargetConfig containerCfg ContainerConfig - images []string //images needed to build the target container + ImageName string } diff --git a/tests/integration/distribution.go b/tests/integration/distribution.go index d61e81c796..9f85b29f28 100644 --- a/tests/integration/distribution.go +++ b/tests/integration/distribution.go @@ -3,16 +3,18 @@ package integration import ( "strings" - "cosmossdk.io/math" - abci "github.com/cometbft/cometbft/abci/types" - "github.com/cometbft/cometbft/libs/bytes" - distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/libs/bytes" icstestingutils "github.com/cosmos/interchain-security/v4/testutil/integration" consumerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/consumer/keeper" @@ -479,7 +481,6 @@ func (s *CCVTestSuite) TestSendRewardsToProvider() { // TestIBCTransferMiddleware tests the logic of the IBC transfer OnRecvPacket callback func (s *CCVTestSuite) TestIBCTransferMiddleware() { - var ( data transfertypes.FungibleTokenPacketData packet channeltypes.Packet @@ -952,7 +953,6 @@ func (s *CCVTestSuite) TestAllocateTokensToValidator() { for _, tc := range testCases { s.Run(tc.name, func() { - // set the same consumer commission rate for all validators for _, v := range s.providerChain.Vals.Validators { provAddr := providertypes.NewProviderConsAddress(sdk.ConsAddress(v.Address)) diff --git a/tests/integration/soft_opt_out.go b/tests/integration/soft_opt_out.go index a9508118bd..bce2e1d77c 100644 --- a/tests/integration/soft_opt_out.go +++ b/tests/integration/soft_opt_out.go @@ -4,10 +4,12 @@ import ( "bytes" "sort" - abci "github.com/cometbft/cometbft/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + abci "github.com/cometbft/cometbft/abci/types" + consumerKeeper "github.com/cosmos/interchain-security/v4/x/ccv/consumer/keeper" ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" ) diff --git a/tests/mbt/driver/core.go b/tests/mbt/driver/core.go index 0e074c6580..b8eeb95540 100644 --- a/tests/mbt/driver/core.go +++ b/tests/mbt/driver/core.go @@ -18,9 +18,9 @@ import ( stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" abcitypes "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/proto/tendermint/crypto" cmttypes "github.com/cometbft/cometbft/types" - "github.com/cometbft/cometbft/proto/tendermint/crypto" appConsumer "github.com/cosmos/interchain-security/v4/app/consumer" appProvider "github.com/cosmos/interchain-security/v4/app/provider" simibc "github.com/cosmos/interchain-security/v4/testutil/simibc" diff --git a/tests/mbt/driver/mbt_test.go b/tests/mbt/driver/mbt_test.go index c31ec28359..a48d79d0c6 100644 --- a/tests/mbt/driver/mbt_test.go +++ b/tests/mbt/driver/mbt_test.go @@ -15,13 +15,12 @@ import ( "github.com/kylelemons/godebug/pretty" "github.com/stretchr/testify/require" - cmttypes "github.com/cometbft/cometbft/types" + sdktypes "github.com/cosmos/cosmos-sdk/types" tmencoding "github.com/cometbft/cometbft/crypto/encoding" - "github.com/cosmos/interchain-security/v4/testutil/integration" - - sdktypes "github.com/cosmos/cosmos-sdk/types" + cmttypes "github.com/cometbft/cometbft/types" + "github.com/cosmos/interchain-security/v4/testutil/integration" providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" ) diff --git a/x/ccv/consumer/migrations/v2/migration_test.go b/x/ccv/consumer/migrations/v2/migration_test.go index 5df453d7cf..a99a2be0fb 100644 --- a/x/ccv/consumer/migrations/v2/migration_test.go +++ b/x/ccv/consumer/migrations/v2/migration_test.go @@ -8,6 +8,7 @@ import ( storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" + testutil "github.com/cosmos/interchain-security/v4/testutil/keeper" v2 "github.com/cosmos/interchain-security/v4/x/ccv/consumer/migrations/v2" consumertypes "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" diff --git a/x/ccv/provider/client/cli/query.go b/x/ccv/provider/client/cli/query.go index f554ed6a8e..10b33322c6 100644 --- a/x/ccv/provider/client/cli/query.go +++ b/x/ccv/provider/client/cli/query.go @@ -408,5 +408,4 @@ $ %s query provider params flags.AddQueryFlagsToCmd(cmd) return cmd - } diff --git a/x/ccv/provider/client/cli/tx.go b/x/ccv/provider/client/cli/tx.go index 2d55b602dd..be77ecf6d8 100644 --- a/x/ccv/provider/client/cli/tx.go +++ b/x/ccv/provider/client/cli/tx.go @@ -233,7 +233,6 @@ func NewOptInCmd() *cobra.Command { consumerPubKey = "" } msg, err := types.NewMsgOptIn(args[0], sdk.ValAddress(providerValAddr), consumerPubKey) - if err != nil { return err } diff --git a/x/ccv/provider/ibc_middleware.go b/x/ccv/provider/ibc_middleware.go index 1c1b1ce824..5a3331df2e 100644 --- a/x/ccv/provider/ibc_middleware.go +++ b/x/ccv/provider/ibc_middleware.go @@ -1,17 +1,19 @@ package provider import ( - "cosmossdk.io/math" - sdk "github.com/cosmos/cosmos-sdk/types" - capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" "github.com/cosmos/ibc-go/v7/modules/core/exported" + + "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + + "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" + "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" ) var _ porttypes.Middleware = &IBCMiddleware{} diff --git a/x/ccv/provider/ibc_middleware_test.go b/x/ccv/provider/ibc_middleware_test.go index 3701a65402..347cdc66cb 100644 --- a/x/ccv/provider/ibc_middleware_test.go +++ b/x/ccv/provider/ibc_middleware_test.go @@ -5,8 +5,9 @@ import ( clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" - "github.com/cosmos/interchain-security/v4/x/ccv/provider" "github.com/stretchr/testify/require" + + "github.com/cosmos/interchain-security/v4/x/ccv/provider" ) func TestGetProviderDenom(t *testing.T) { diff --git a/x/ccv/provider/keeper/distribution.go b/x/ccv/provider/keeper/distribution.go index 16511f8bde..aa7195cf4b 100644 --- a/x/ccv/provider/keeper/distribution.go +++ b/x/ccv/provider/keeper/distribution.go @@ -1,19 +1,22 @@ package keeper import ( + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + errorsmod "cosmossdk.io/errors" "cosmossdk.io/math" - abci "github.com/cometbft/cometbft/abci/types" + sdk "github.com/cosmos/cosmos-sdk/types" distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" ) // BeginBlockRD executes BeginBlock logic for the Reward Distribution sub-protocol. func (k Keeper) BeginBlockRD(ctx sdk.Context, req abci.RequestBeginBlock) { - // determine the total power signing the block var previousTotalPower int64 for _, voteInfo := range req.LastCommitInfo.GetVotes() { @@ -139,7 +142,6 @@ func (k Keeper) AllocateTokensToConsumerValidators( bondedVotes []abci.VoteInfo, tokens sdk.DecCoins, ) (allocated sdk.DecCoins) { - // return early if the tokens are empty if tokens.Empty() { return allocated diff --git a/x/ccv/provider/keeper/distribution_test.go b/x/ccv/provider/keeper/distribution_test.go index 52ac0e0a82..d12b2c910a 100644 --- a/x/ccv/provider/keeper/distribution_test.go +++ b/x/ccv/provider/keeper/distribution_test.go @@ -3,17 +3,20 @@ package keeper_test import ( "testing" - abci "github.com/cometbft/cometbft/abci/types" - tmtypes "github.com/cometbft/cometbft/types" - sdk "github.com/cosmos/cosmos-sdk/types" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" conntypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" + + abci "github.com/cometbft/cometbft/abci/types" + tmtypes "github.com/cometbft/cometbft/types" + + testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" + "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" ) func TestComputeConsumerTotalVotingPower(t *testing.T) { @@ -217,7 +220,6 @@ func TestIdentifyConsumerChainIDFromIBCPacket(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - keeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() diff --git a/x/ccv/provider/keeper/hooks.go b/x/ccv/provider/keeper/hooks.go index fcf8339187..37680a37b1 100644 --- a/x/ccv/provider/keeper/hooks.go +++ b/x/ccv/provider/keeper/hooks.go @@ -1,8 +1,12 @@ package keeper import ( - "cosmossdk.io/math" "fmt" + + "fmt" + + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" sdkgov "github.com/cosmos/cosmos-sdk/x/gov/types" v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" diff --git a/x/ccv/provider/keeper/hooks_test.go b/x/ccv/provider/keeper/hooks_test.go index 140bb8a4ce..f82b3ec129 100644 --- a/x/ccv/provider/keeper/hooks_test.go +++ b/x/ccv/provider/keeper/hooks_test.go @@ -1,27 +1,28 @@ package keeper_test import ( - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" "testing" "time" + "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" "cosmossdk.io/math" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" cryptotestutil "github.com/cosmos/interchain-security/v4/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" providerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" + "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" ) func TestValidatorConsensusKeyInUse(t *testing.T) { @@ -264,7 +265,8 @@ func TestAfterProposalVoteWithNoVote(t *testing.T) { "Weighted vote with 100% NO", []*v1.WeightedVoteOption{{Option: v1.OptionNo, Weight: "1"}}, func(ctx sdk.Context, options []*v1.WeightedVoteOption, - mocks testkeeper.MockedKeepers, pubKey *codectypes.Any) { + mocks testkeeper.MockedKeepers, pubKey *codectypes.Any, + ) { gomock.InOrder( mocks.MockStakingKeeper.EXPECT().GetValidator(ctx, gomock.Any()).Return( stakingtypes.Validator{ConsensusPubkey: pubKey}, true), @@ -278,7 +280,8 @@ func TestAfterProposalVoteWithNoVote(t *testing.T) { "Weighted vote with 99.9% YES and 0.1% NO", []*v1.WeightedVoteOption{{Option: v1.OptionYes, Weight: "0.999"}, {Option: v1.OptionNo, Weight: "0.001"}}, func(ctx sdk.Context, options []*v1.WeightedVoteOption, - mocks testkeeper.MockedKeepers, pubKey *codectypes.Any) { + mocks testkeeper.MockedKeepers, pubKey *codectypes.Any, + ) { gomock.InOrder( mocks.MockStakingKeeper.EXPECT().GetValidator(ctx, gomock.Any()).Return( stakingtypes.Validator{ConsensusPubkey: pubKey}, true), diff --git a/x/ccv/provider/keeper/keeper.go b/x/ccv/provider/keeper/keeper.go index ec73d85383..2ec0a13603 100644 --- a/x/ccv/provider/keeper/keeper.go +++ b/x/ccv/provider/keeper/keeper.go @@ -1221,7 +1221,8 @@ func (k Keeper) IsOptedIn( // GetAllOptedIn returns all the opted-in validators on chain `chainID` func (k Keeper) GetAllOptedIn( ctx sdk.Context, - chainID string) (optedInValidators []types.OptedInValidator) { + chainID string, +) (optedInValidators []types.OptedInValidator) { store := ctx.KVStore(k.storeKey) key := types.ChainIdWithLenKey(types.OptedInBytePrefix, chainID) iterator := sdk.KVStorePrefixIterator(store, key) @@ -1291,8 +1292,8 @@ func (k Keeper) GetConsumerCommissionRate( // that set a commission rate for the given chain ID func (k Keeper) GetAllCommissionRateValidators( ctx sdk.Context, - chainID string) (addresses []types.ProviderConsAddress) { - + chainID string, +) (addresses []types.ProviderConsAddress) { store := ctx.KVStore(k.storeKey) key := types.ChainIdWithLenKey(types.ConsumerCommissionRatePrefix, chainID) iterator := sdk.KVStorePrefixIterator(store, key) @@ -1338,8 +1339,8 @@ func (k Keeper) IsToBeOptedIn( // GetAllToBeOptedIn returns all the to-be-opted-in validators on chain `chainID` func (k Keeper) GetAllToBeOptedIn( ctx sdk.Context, - chainID string) (addresses []types.ProviderConsAddress) { - + chainID string, +) (addresses []types.ProviderConsAddress) { store := ctx.KVStore(k.storeKey) key := types.ChainIdWithLenKey(types.ToBeOptedInBytePrefix, chainID) iterator := sdk.KVStorePrefixIterator(store, key) @@ -1383,8 +1384,8 @@ func (k Keeper) IsToBeOptedOut( // GetAllToBeOptedOut returns all the to-be-opted-out validators on chain `chainID` func (k Keeper) GetAllToBeOptedOut( ctx sdk.Context, - chainID string) (addresses []types.ProviderConsAddress) { - + chainID string, +) (addresses []types.ProviderConsAddress) { store := ctx.KVStore(k.storeKey) key := types.ChainIdWithLenKey(types.ToBeOptedOutBytePrefix, chainID) iterator := sdk.KVStorePrefixIterator(store, key) diff --git a/x/ccv/provider/keeper/keeper_test.go b/x/ccv/provider/keeper/keeper_test.go index 595e01100a..feb87490c6 100644 --- a/x/ccv/provider/keeper/keeper_test.go +++ b/x/ccv/provider/keeper/keeper_test.go @@ -11,11 +11,11 @@ import ( "github.com/stretchr/testify/require" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + sdk "github.com/cosmos/cosmos-sdk/types" abci "github.com/cometbft/cometbft/abci/types" tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" - sdk "github.com/cosmos/cosmos-sdk/types" cryptotestutil "github.com/cosmos/interchain-security/v4/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" @@ -701,7 +701,7 @@ func TestGetAllOptedIn(t *testing.T) { // sort validators first to be able to compare sortOptedInValidators := func(optedInValidators []types.OptedInValidator) { - sort.Slice(optedInValidators, func(i int, j int) bool { + sort.Slice(optedInValidators, func(i, j int) bool { a := optedInValidators[i] b := optedInValidators[j] return a.BlockHeight < b.BlockHeight || @@ -718,10 +718,11 @@ func TestOptedIn(t *testing.T) { providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - optedInValidator := types.OptedInValidator{ProviderAddr: []byte("providerAddr"), - BlockHeight: 1, - Power: 2, - PublicKey: []byte{3}, + optedInValidator := types.OptedInValidator{ + ProviderAddr: []byte("providerAddr"), + BlockHeight: 1, + Power: 2, + PublicKey: []byte{3}, } require.False(t, providerKeeper.IsOptedIn(ctx, "chainID", types.NewProviderConsAddress(optedInValidator.ProviderAddr))) @@ -738,7 +739,8 @@ func TestGetAllToBeOptedIn(t *testing.T) { expectedAddresses := []types.ProviderConsAddress{ types.NewProviderConsAddress([]byte("providerAddr1")), types.NewProviderConsAddress([]byte("providerAddr2")), - types.NewProviderConsAddress([]byte("providerAddr3"))} + types.NewProviderConsAddress([]byte("providerAddr3")), + } for _, addr := range expectedAddresses { providerKeeper.SetToBeOptedIn(ctx, "chainID", addr) @@ -748,7 +750,7 @@ func TestGetAllToBeOptedIn(t *testing.T) { // sort addresses first to be able to compare sortAddresses := func(addresses []types.ProviderConsAddress) { - sort.Slice(addresses, func(i int, j int) bool { + sort.Slice(addresses, func(i, j int) bool { a := addresses[i] b := addresses[j] return bytes.Compare(a.Address.Bytes(), b.Address.Bytes()) < 0 @@ -772,7 +774,8 @@ func TestBeOptedIn(t *testing.T) { expectedAddresses := []types.ProviderConsAddress{ types.NewProviderConsAddress([]byte("providerAddr1")), types.NewProviderConsAddress([]byte("providerAddr2")), - types.NewProviderConsAddress([]byte("providerAddr3"))} + types.NewProviderConsAddress([]byte("providerAddr3")), + } for _, addr := range expectedAddresses { providerKeeper.SetToBeOptedIn(ctx, "chainID", addr) @@ -782,7 +785,7 @@ func TestBeOptedIn(t *testing.T) { // sort addresses first to be able to compare sortAddresses := func(addresses []types.ProviderConsAddress) { - sort.Slice(addresses, func(i int, j int) bool { + sort.Slice(addresses, func(i, j int) bool { a := addresses[i] b := addresses[j] return bytes.Compare(a.Address.Bytes(), b.Address.Bytes()) < 0 @@ -820,7 +823,8 @@ func TestGetAllToBeOptedOut(t *testing.T) { expectedAddresses := []types.ProviderConsAddress{ types.NewProviderConsAddress([]byte("providerAddr1")), types.NewProviderConsAddress([]byte("providerAddr2")), - types.NewProviderConsAddress([]byte("providerAddr3"))} + types.NewProviderConsAddress([]byte("providerAddr3")), + } for _, addr := range expectedAddresses { providerKeeper.SetToBeOptedOut(ctx, "chainID", addr) @@ -830,7 +834,7 @@ func TestGetAllToBeOptedOut(t *testing.T) { // sort addresses first to be able to compare sortAddresses := func(addresses []types.ProviderConsAddress) { - sort.Slice(addresses, func(i int, j int) bool { + sort.Slice(addresses, func(i, j int) bool { a := addresses[i] b := addresses[j] return bytes.Compare(a.Address.Bytes(), b.Address.Bytes()) < 0 @@ -895,5 +899,4 @@ func TestConsumerCommissionRate(t *testing.T) { _, found = providerKeeper.GetConsumerCommissionRate(ctx, "chainID", providerAddr2) require.False(t, found) - } diff --git a/x/ccv/provider/keeper/key_assignment_test.go b/x/ccv/provider/keeper/key_assignment_test.go index 7cb222a3be..0868b5443f 100644 --- a/x/ccv/provider/keeper/key_assignment_test.go +++ b/x/ccv/provider/keeper/key_assignment_test.go @@ -2,15 +2,17 @@ package keeper_test import ( "bytes" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" "math/rand" "sort" "testing" "time" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" diff --git a/x/ccv/provider/keeper/msg_server.go b/x/ccv/provider/keeper/msg_server.go index 9e019bcb22..a595b5fbc2 100644 --- a/x/ccv/provider/keeper/msg_server.go +++ b/x/ccv/provider/keeper/msg_server.go @@ -4,10 +4,13 @@ import ( "context" errorsmod "cosmossdk.io/errors" - tmtypes "github.com/cometbft/cometbft/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + tmtypes "github.com/cometbft/cometbft/types" + "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" ) diff --git a/x/ccv/provider/keeper/partial_set_security.go b/x/ccv/provider/keeper/partial_set_security.go index bf76e7d7c8..4034687d21 100644 --- a/x/ccv/provider/keeper/partial_set_security.go +++ b/x/ccv/provider/keeper/partial_set_security.go @@ -2,8 +2,10 @@ package keeper import ( errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" ) diff --git a/x/ccv/provider/keeper/partial_set_security_test.go b/x/ccv/provider/keeper/partial_set_security_test.go index a6b2ec45e7..651bfc311d 100644 --- a/x/ccv/provider/keeper/partial_set_security_test.go +++ b/x/ccv/provider/keeper/partial_set_security_test.go @@ -3,15 +3,17 @@ package keeper_test import ( "testing" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" - "github.com/golang/mock/gomock" - "github.com/stretchr/testify/require" ) func TestHandleOptIn(t *testing.T) { diff --git a/x/ccv/provider/keeper/relay_test.go b/x/ccv/provider/keeper/relay_test.go index b7e89b3dc2..540cad64bf 100644 --- a/x/ccv/provider/keeper/relay_test.go +++ b/x/ccv/provider/keeper/relay_test.go @@ -1,18 +1,19 @@ package keeper_test import ( - cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" - ibctesting "github.com/cosmos/ibc-go/v7/testing" "strings" "testing" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v7/testing" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" "cosmossdk.io/math" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" diff --git a/x/ccv/provider/keeper/validator_set_update.go b/x/ccv/provider/keeper/validator_set_update.go index 71238d210d..da07aea352 100644 --- a/x/ccv/provider/keeper/validator_set_update.go +++ b/x/ccv/provider/keeper/validator_set_update.go @@ -2,9 +2,13 @@ package keeper import ( "fmt" - abci "github.com/cometbft/cometbft/abci/types" + + sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" ) @@ -36,7 +40,8 @@ func (k Keeper) DeleteConsumerValidator( // DeleteConsumerValSet deletes all the stored consumer validators for chain `chainID` func (k Keeper) DeleteConsumerValSet( ctx sdk.Context, - chainID string) { + chainID string, +) { store := ctx.KVStore(k.storeKey) key := types.ChainIdWithLenKey(types.ConsumerValidatorBytePrefix, chainID) iterator := sdk.KVStorePrefixIterator(store, key) @@ -65,7 +70,8 @@ func (k Keeper) IsConsumerValidator( // GetConsumerValSet returns all the consumer validators for chain `chainID` func (k Keeper) GetConsumerValSet( ctx sdk.Context, - chainID string) (validators []types.ConsumerValidator) { + chainID string, +) (validators []types.ConsumerValidator) { store := ctx.KVStore(k.storeKey) key := types.ChainIdWithLenKey(types.ConsumerValidatorBytePrefix, chainID) iterator := sdk.KVStorePrefixIterator(store, key) @@ -132,7 +138,8 @@ func (k Keeper) ComputeNextEpochConsumerValSet( // needed by CometBFT to update the validator set on a chain. func DiffValidators( currentValidators []types.ConsumerValidator, - nextValidators []types.ConsumerValidator) []abci.ValidatorUpdate { + nextValidators []types.ConsumerValidator, +) []abci.ValidatorUpdate { var updates []abci.ValidatorUpdate isCurrentValidator := make(map[string]types.ConsumerValidator) diff --git a/x/ccv/provider/keeper/validator_set_update_test.go b/x/ccv/provider/keeper/validator_set_update_test.go index 8505158816..dce307a135 100644 --- a/x/ccv/provider/keeper/validator_set_update_test.go +++ b/x/ccv/provider/keeper/validator_set_update_test.go @@ -5,18 +5,21 @@ import ( "sort" "testing" - abci "github.com/cometbft/cometbft/abci/types" - "github.com/cometbft/cometbft/crypto/ed25519" - "github.com/cometbft/cometbft/proto/tendermint/crypto" + "github.com/stretchr/testify/require" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/crypto/ed25519" + "github.com/cometbft/cometbft/proto/tendermint/crypto" + cryptotestutil "github.com/cosmos/interchain-security/v4/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - "github.com/stretchr/testify/require" ) // TestConsumerValidator tests the `SetConsumerValidator`, `IsConsumerValidator`, and `DeleteConsumerValidator` methods @@ -85,7 +88,7 @@ func TestGetConsumerValSet(t *testing.T) { // sort validators first to be able to compare sortValidators := func(validators []types.ConsumerValidator) { - sort.Slice(validators, func(i int, j int) bool { + sort.Slice(validators, func(i, j int) bool { return bytes.Compare(validators[i].ProviderConsAddr, validators[j].ProviderConsAddr) < 0 }) } diff --git a/x/ccv/provider/migrations/v3/migration_test.go b/x/ccv/provider/migrations/v3/migration_test.go index 189c75e271..e486bab910 100644 --- a/x/ccv/provider/migrations/v3/migration_test.go +++ b/x/ccv/provider/migrations/v3/migration_test.go @@ -19,41 +19,41 @@ func TestMigrate2To3(t *testing.T) { providerKeeper.SetConsumerClientId(ctx, "chain-3", "client-3") // Queue some data for chain-1 - providerKeeper.LegacyQueueThrottledPacketData( //nolint:staticcheck // SA1019: used in migration tests + providerKeeper.LegacyQueueThrottledPacketData( ctx, "chain-1", 66, testutil.GetNewSlashPacketData()) - providerKeeper.LegacyQueueThrottledPacketData( //nolint:staticcheck // SA1019: used in migration tests + providerKeeper.LegacyQueueThrottledPacketData( ctx, "chain-1", 67, testutil.GetNewVSCMaturedPacketData()) - providerKeeper.LegacyQueueThrottledPacketData( //nolint:staticcheck // SA1019: used in migration tests + providerKeeper.LegacyQueueThrottledPacketData( ctx, "chain-1", 68, testutil.GetNewSlashPacketData()) - providerKeeper.LegacyQueueThrottledPacketData( //nolint:staticcheck // SA1019: used in migration tests + providerKeeper.LegacyQueueThrottledPacketData( ctx, "chain-1", 69, testutil.GetNewVSCMaturedPacketData()) // Queue some data for chain-2 - providerKeeper.LegacyQueueThrottledPacketData( //nolint:staticcheck // SA1019: used in migration tests + providerKeeper.LegacyQueueThrottledPacketData( ctx, "chain-2", 789, testutil.GetNewVSCMaturedPacketData()) - providerKeeper.LegacyQueueThrottledPacketData( //nolint:staticcheck // SA1019: used in migration tests + providerKeeper.LegacyQueueThrottledPacketData( ctx, "chain-2", 790, testutil.GetNewSlashPacketData()) - providerKeeper.LegacyQueueThrottledPacketData( //nolint:staticcheck // SA1019: used in migration tests + providerKeeper.LegacyQueueThrottledPacketData( ctx, "chain-2", 791, testutil.GetNewVSCMaturedPacketData()) // Queue some data for chain-3 - providerKeeper.LegacyQueueThrottledPacketData( //nolint:staticcheck // SA1019: used in migration tests + providerKeeper.LegacyQueueThrottledPacketData( ctx, "chain-3", 123, testutil.GetNewSlashPacketData()) - providerKeeper.LegacyQueueThrottledPacketData( //nolint:staticcheck // SA1019: used in migration tests + providerKeeper.LegacyQueueThrottledPacketData( ctx, "chain-3", 124, testutil.GetNewVSCMaturedPacketData()) - providerKeeper.LegacyQueueThrottledPacketData( //nolint:staticcheck // SA1019: used in migration tests + providerKeeper.LegacyQueueThrottledPacketData( ctx, "chain-3", 125, testutil.GetNewVSCMaturedPacketData()) // Confirm getter methods return expected values - slash1, vscm1 := providerKeeper.LegacyGetAllThrottledPacketData(ctx, "chain-1") //nolint:staticcheck // SA1019: used in migration tests + slash1, vscm1 := providerKeeper.LegacyGetAllThrottledPacketData(ctx, "chain-1") require.Len(t, slash1, 2) require.Len(t, vscm1, 2) - slash2, vscm2 := providerKeeper.LegacyGetAllThrottledPacketData(ctx, "chain-2") //nolint:staticcheck // SA1019: used in migration tests + slash2, vscm2 := providerKeeper.LegacyGetAllThrottledPacketData(ctx, "chain-2") require.Len(t, slash2, 1) require.Len(t, vscm2, 2) - slash3, vscm3 := providerKeeper.LegacyGetAllThrottledPacketData(ctx, "chain-3") //nolint:staticcheck // SA1019: used in migration tests + slash3, vscm3 := providerKeeper.LegacyGetAllThrottledPacketData(ctx, "chain-3") require.Len(t, slash3, 1) require.Len(t, vscm3, 2) @@ -91,13 +91,13 @@ func TestMigrate2To3(t *testing.T) { require.NoError(t, err) // Confirm throttled data is now deleted - slash1, vscm1 = providerKeeper.LegacyGetAllThrottledPacketData(ctx, "chain-1") //nolint:staticcheck // SA1019: used in migration tests + slash1, vscm1 = providerKeeper.LegacyGetAllThrottledPacketData(ctx, "chain-1") require.Empty(t, slash1) require.Empty(t, vscm1) - slash2, vscm2 = providerKeeper.LegacyGetAllThrottledPacketData(ctx, "chain-2") //nolint:staticcheck // SA1019: used in migration tests + slash2, vscm2 = providerKeeper.LegacyGetAllThrottledPacketData(ctx, "chain-2") require.Empty(t, slash2) require.Empty(t, vscm2) - slash3, vscm3 = providerKeeper.LegacyGetAllThrottledPacketData(ctx, "chain-3") //nolint:staticcheck // SA1019: used in migration tests + slash3, vscm3 = providerKeeper.LegacyGetAllThrottledPacketData(ctx, "chain-3") require.Empty(t, slash3) require.Empty(t, vscm3) diff --git a/x/ccv/provider/migrations/v3/migrations.go b/x/ccv/provider/migrations/v3/migrations.go index c2cd9054ba..808da63ea2 100644 --- a/x/ccv/provider/migrations/v3/migrations.go +++ b/x/ccv/provider/migrations/v3/migrations.go @@ -12,14 +12,14 @@ import ( // on the provider in the v2 consensus version (jail throttling v1). func MigrateQueuedPackets(ctx sdk.Context, k providerkeeper.Keeper) error { for _, consumer := range k.GetAllConsumerChains(ctx) { - slashData, vscmData := k.LegacyGetAllThrottledPacketData(ctx, consumer.ChainId) //nolint:staticcheck // SA1019: function used for migration + slashData, vscmData := k.LegacyGetAllThrottledPacketData(ctx, consumer.ChainId) if len(slashData) > 0 { k.Logger(ctx).Error(fmt.Sprintf("slash data being dropped: %v", slashData)) } for _, data := range vscmData { k.HandleVSCMaturedPacket(ctx, consumer.ChainId, data) } - k.LegacyDeleteThrottledPacketDataForConsumer(ctx, consumer.ChainId) //nolint:staticcheck // SA1019: function used for migration + k.LegacyDeleteThrottledPacketDataForConsumer(ctx, consumer.ChainId) } return nil } diff --git a/x/ccv/provider/types/codec.go b/x/ccv/provider/types/codec.go index c0ab4f5aea..5f45c43fdf 100644 --- a/x/ccv/provider/types/codec.go +++ b/x/ccv/provider/types/codec.go @@ -1,13 +1,14 @@ package types import ( + "github.com/cosmos/ibc-go/v7/modules/core/exported" + tendermint "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/msgservice" govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" - "github.com/cosmos/ibc-go/v7/modules/core/exported" - tendermint "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" ) // RegisterLegacyAminoCodec registers the necessary x/ibc transfer interfaces and concrete types diff --git a/x/ccv/provider/types/consumer.go b/x/ccv/provider/types/consumer.go index 2a89859a36..da23cb2970 100644 --- a/x/ccv/provider/types/consumer.go +++ b/x/ccv/provider/types/consumer.go @@ -2,6 +2,7 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" + ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" ) diff --git a/x/ccv/types/expected_keepers.go b/x/ccv/types/expected_keepers.go index 761eca90d7..aaff34d878 100644 --- a/x/ccv/types/expected_keepers.go +++ b/x/ccv/types/expected_keepers.go @@ -11,11 +11,11 @@ import ( ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" "cosmossdk.io/math" - distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" sdk "github.com/cosmos/cosmos-sdk/types" auth "github.com/cosmos/cosmos-sdk/x/auth/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" From 3947a69bb526065cddde9fc1871c0683dfccc9fa Mon Sep 17 00:00:00 2001 From: Simon Noetzlin Date: Mon, 18 Mar 2024 17:44:30 +0100 Subject: [PATCH 031/110] chore: rebase PSS branch with main (#1689) * Update tests/mbt/driver/mbt_test.go * nits * revert unwanted line deletion from linter --------- Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> --- tests/e2e/builder.go | 1 - tests/e2e/test_target.go | 2 +- tests/mbt/driver/mbt_test.go | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/e2e/builder.go b/tests/e2e/builder.go index 7ac5763aee..ef0b94bcfe 100644 --- a/tests/e2e/builder.go +++ b/tests/e2e/builder.go @@ -82,7 +82,6 @@ func generateImageName(version string, cfg TargetConfig) (string, error) { tagName = "local" // this refers to build from local workspace } else { // use git hash of rev as docker image tag - cmd := exec.Command("git", "log", "--pretty=format:%h", "-n", "1", version) out, err := cmd.CombinedOutput() if err != nil { diff --git a/tests/e2e/test_target.go b/tests/e2e/test_target.go index 6fcec7de1b..421be1d1fa 100644 --- a/tests/e2e/test_target.go +++ b/tests/e2e/test_target.go @@ -28,7 +28,7 @@ type ExecutionTarget interface { type DockerContainer struct { targetConfig TargetConfig containerCfg ContainerConfig - images []string //images needed to build the target container + images []string // images needed to build the target container ImageName string } diff --git a/tests/mbt/driver/mbt_test.go b/tests/mbt/driver/mbt_test.go index a48d79d0c6..67923b76da 100644 --- a/tests/mbt/driver/mbt_test.go +++ b/tests/mbt/driver/mbt_test.go @@ -129,7 +129,7 @@ func RunItfTrace(t *testing.T, path string) { // consumerAddrNames are the human readable names of consumer addresses in the model // "realAddrs" are the addresses of the consumer keys on chain // these maps relate the consumerAddrNames to the priv validators (from which one can get the real address) - // and from the real ddresses to the consumerAddrNames to allow converting between the two easily + // and from the real addresses to the consumerAddrNames to allow converting between the two easily consumerAddrNamesToPrivVals := make(map[string]cmttypes.PrivValidator, len(consumerAddressesExpr)) realAddrsToModelConsAddrs := make(map[string]string, len(consumerAddressesExpr)) i := 0 From 31a9ee30a5265ededef7855c0ce4bab29db3cfe0 Mon Sep 17 00:00:00 2001 From: Simon Noetzlin Date: Tue, 19 Mar 2024 09:37:34 +0100 Subject: [PATCH 032/110] feat!: complete the PSS reward distribution (#1709) * update compute consumer total power for reward distribution * update distribution logic to work with epochcs * Adapt reward distribution mem test to epochs * doc * nits * other nits * nits * Update tests/integration/distribution.go --- tests/integration/distribution.go | 135 ++++++++++++--------- x/ccv/provider/keeper/distribution.go | 56 ++++----- x/ccv/provider/keeper/distribution_test.go | 36 +++--- 3 files changed, 117 insertions(+), 110 deletions(-) diff --git a/tests/integration/distribution.go b/tests/integration/distribution.go index 9f85b29f28..d3111a39a5 100644 --- a/tests/integration/distribution.go +++ b/tests/integration/distribution.go @@ -14,7 +14,6 @@ import ( distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" abci "github.com/cometbft/cometbft/abci/types" - "github.com/cometbft/cometbft/libs/bytes" icstestingutils "github.com/cosmos/interchain-security/v4/testutil/integration" consumerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/consumer/keeper" @@ -51,6 +50,8 @@ func (s *CCVTestSuite) TestRewardsDistribution() { providerAccountKeeper := s.providerApp.GetTestAccountKeeper() consumerBankKeeper := s.consumerApp.GetTestBankKeeper() providerBankKeeper := s.providerApp.GetTestBankKeeper() + providerKeeper := s.providerApp.GetProviderKeeper() + providerDistributionKeeper := s.providerApp.GetTestDistributionKeeper() // send coins to the fee pool which is used for reward distribution consumerFeePoolAddr := consumerAccountKeeper.GetModuleAccount(s.consumerCtx(), authtypes.FeeCollectorName).GetAddress() @@ -79,7 +80,6 @@ func (s *CCVTestSuite) TestRewardsDistribution() { s.Require().Equal(providerExpectedRewards.AmountOf(sdk.DefaultBondDenom), providerTokens.AmountOf(sdk.DefaultBondDenom)) // send the reward to provider chain after 2 blocks - s.consumerChain.NextBlock() providerTokens = consumerBankKeeper.GetAllBalances(s.consumerCtx(), providerRedistributeAddr) s.Require().Equal(0, len(providerTokens)) @@ -91,52 +91,85 @@ func (s *CCVTestSuite) TestRewardsDistribution() { rewardPool := providerAccountKeeper.GetModuleAccount(s.providerCtx(), providertypes.ConsumerRewardsPool).GetAddress() rewardCoins := providerBankKeeper.GetAllBalances(s.providerCtx(), rewardPool) - ibcCoinIndex := -1 - for i, coin := range rewardCoins { + // Check that the reward pool contains a coin with an IBC denom + rewardsIBCdenom := "" + for _, coin := range rewardCoins { if strings.HasPrefix(coin.Denom, "ibc") { - ibcCoinIndex = i + rewardsIBCdenom = coin.Denom } } - - // Check that we found an ibc denom in the reward pool - s.Require().Greater(ibcCoinIndex, -1) + s.Require().NotZero(rewardsIBCdenom) // Check that the coins got into the ConsumerRewardsPool - s.Require().Equal(rewardCoins[ibcCoinIndex].Amount, (providerExpectedRewards[0].Amount)) + providerExpRewardsAmount := providerExpectedRewards.AmountOf(sdk.DefaultBondDenom) + s.Require().Equal(rewardCoins.AmountOf(rewardsIBCdenom), providerExpRewardsAmount) // Advance a block and check that the coins are still in the ConsumerRewardsPool s.providerChain.NextBlock() rewardCoins = providerBankKeeper.GetAllBalances(s.providerCtx(), rewardPool) - s.Require().Equal(rewardCoins[ibcCoinIndex].Amount, (providerExpectedRewards[0].Amount)) + s.Require().Equal(rewardCoins.AmountOf(rewardsIBCdenom), providerExpRewardsAmount) - // Set the consumer reward denom. This would be done by a governance proposal in prod - s.providerApp.GetProviderKeeper().SetConsumerRewardDenom(s.providerCtx(), rewardCoins[ibcCoinIndex].Denom) + // Set the consumer reward denom. This would be done by a governance proposal in prod. + providerKeeper.SetConsumerRewardDenom(s.providerCtx(), rewardsIBCdenom) // Refill the consumer fee pool - err = consumerBankKeeper.SendCoinsFromAccountToModule(s.consumerCtx(), s.consumerChain.SenderAccount.GetAddress(), authtypes.FeeCollectorName, fees) + err = consumerBankKeeper.SendCoinsFromAccountToModule( + s.consumerCtx(), + s.consumerChain.SenderAccount.GetAddress(), + authtypes.FeeCollectorName, + fees, + ) s.Require().NoError(err) - // pass two blocks + // Pass two blocks s.consumerChain.NextBlock() s.consumerChain.NextBlock() - // transfer rewards from consumer to provider - relayAllCommittedPackets(s, s.consumerChain, s.transferPath, transfertypes.PortID, s.transferPath.EndpointA.ChannelID, 1) + // Save the consumer validators total outstanding rewards on the provider + consumerValsOutstandingRewardsFunc := func(ctx sdk.Context) sdk.DecCoins { + totalRewards := sdk.DecCoins{} + for _, v := range providerKeeper.GetConsumerValSet(ctx, s.consumerChain.ChainID) { + val, ok := s.providerApp.GetTestStakingKeeper().GetValidatorByConsAddr(ctx, sdk.ConsAddress(v.ProviderConsAddr)) + s.Require().True(ok) + valReward := providerDistributionKeeper.GetValidatorOutstandingRewards(ctx, val.GetOperator()) + totalRewards = totalRewards.Add(valReward.Rewards...) + } + return totalRewards + } + consuValsRewards := consumerValsOutstandingRewardsFunc(s.providerCtx()) + + // Save community pool balance + communityPool := providerDistributionKeeper.GetFeePoolCommunityCoins(s.providerCtx()) + + // Transfer rewards from consumer to provider + relayAllCommittedPackets( + s, + s.consumerChain, + s.transferPath, + transfertypes.PortID, + s.transferPath.EndpointA.ChannelID, + 1, + ) - // check that the consumer rewards allocation are empty since relayAllCommittedPackets call BeginBlock - rewardsAlloc := s.providerApp.GetProviderKeeper().GetConsumerRewardsAllocation(s.providerCtx(), s.consumerChain.ChainID) + // Check that the consumer rewards allocation are empty since relayAllCommittedPackets calls BeginBlockRD, + // which in turns calls AllocateTokens. + rewardsAlloc := providerKeeper.GetConsumerRewardsAllocation(s.providerCtx(), s.consumerChain.ChainID) s.Require().Empty(rewardsAlloc.Rewards) - // Check that the reward pool still has the first coins transferred that were never allocated + // Check that the reward pool still holds the coins from the first transfer, + // which were never allocated since they were not whitelisted rewardCoins = providerBankKeeper.GetAllBalances(s.providerCtx(), rewardPool) - s.Require().Equal(rewardCoins[ibcCoinIndex].Amount, (providerExpectedRewards[0].Amount)) - - // check that the fee pool has the expected amount of coins - // Note that all rewards are allocated to the community pool since - // BeginBlock is called without the validators' votes in ibctesting. - // See NextBlock() in https://github.com/cosmos/ibc-go/blob/release/v7.3.x/testing/chain.go#L281 - communityCoins := s.providerApp.GetTestDistributionKeeper().GetFeePoolCommunityCoins(s.providerCtx()) - s.Require().Equal(communityCoins[ibcCoinIndex].Amount, (sdk.NewDecCoinFromCoin(providerExpectedRewards[0]).Amount)) + s.Require().Equal(rewardCoins.AmountOf(rewardsIBCdenom), providerExpRewardsAmount) + + // Check that summing the rewards received by the consumer validators and the community pool + // is equal to the expected provider rewards + consuValsRewardsReceived := consumerValsOutstandingRewardsFunc(s.providerCtx()).Sub(consuValsRewards) + communityPoolDelta := providerDistributionKeeper.GetFeePoolCommunityCoins(s.providerCtx()).Sub(communityPool) + + s.Require().Equal( + sdk.NewDecFromInt(providerExpRewardsAmount), + consuValsRewardsReceived.AmountOf(rewardsIBCdenom).Add(communityPoolDelta.AmountOf(rewardsIBCdenom)), + ) } // TestSendRewardsRetries tests that failed reward transmissions are retried every BlocksPerDistributionTransmission blocks @@ -906,19 +939,11 @@ func (s *CCVTestSuite) TestAllocateTokensToValidator() { distributionKeeper := s.providerApp.GetTestDistributionKeeper() bankKeeper := s.providerApp.GetTestBankKeeper() - chainID := "consumer" - validators := []bytes.HexBytes{ - s.providerChain.Vals.Validators[0].Address, - s.providerChain.Vals.Validators[1].Address, - } - votes := []abci.VoteInfo{ - {Validator: abci.Validator{Address: validators[0], Power: 1}}, - {Validator: abci.Validator{Address: validators[1], Power: 1}}, - } + chainID := s.consumerChain.ChainID testCases := []struct { name string - votes []abci.VoteInfo + consuValLen int tokens sdk.DecCoins rate sdk.Dec expAllocated sdk.DecCoins @@ -930,21 +955,21 @@ func (s *CCVTestSuite) TestAllocateTokensToValidator() { expAllocated: nil, }, { - name: "total voting power is zero", + name: "consumer valset is empty - total voting power is zero", tokens: sdk.DecCoins{sdk.NewDecCoin(sdk.DefaultBondDenom, math.NewInt(100_000))}, rate: sdk.ZeroDec(), expAllocated: nil, }, { name: "expect all tokens to be allocated to a single validator", - votes: []abci.VoteInfo{votes[0]}, + consuValLen: 1, tokens: sdk.DecCoins{sdk.NewDecCoin(sdk.DefaultBondDenom, math.NewInt(999))}, rate: sdk.NewDecWithPrec(5, 1), expAllocated: sdk.DecCoins{sdk.NewDecCoin(sdk.DefaultBondDenom, math.NewInt(999))}, }, { name: "expect tokens to be allocated evenly between validators", - votes: []abci.VoteInfo{votes[0], votes[1]}, + consuValLen: 2, tokens: sdk.DecCoins{sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, math.LegacyNewDecFromIntWithPrec(math.NewInt(999), 2))}, rate: sdk.OneDec(), expAllocated: sdk.DecCoins{sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, math.LegacyNewDecFromIntWithPrec(math.NewInt(999), 2))}, @@ -953,27 +978,29 @@ func (s *CCVTestSuite) TestAllocateTokensToValidator() { for _, tc := range testCases { s.Run(tc.name, func() { - // set the same consumer commission rate for all validators - for _, v := range s.providerChain.Vals.Validators { - provAddr := providertypes.NewProviderConsAddress(sdk.ConsAddress(v.Address)) + ctx, _ := s.providerCtx().CacheContext() + // change the consumer valset + consuVals := providerKeeper.GetConsumerValSet(ctx, chainID) + providerKeeper.DeleteConsumerValSet(ctx, chainID) + providerKeeper.SetConsumerValSet(ctx, chainID, consuVals[0:tc.consuValLen]) + consuVals = providerKeeper.GetConsumerValSet(ctx, chainID) + + // set the same consumer commission rate for all consumer validators + for _, v := range consuVals { + provAddr := providertypes.NewProviderConsAddress(sdk.ConsAddress(v.ProviderConsAddr)) providerKeeper.SetConsumerCommissionRate( - s.providerCtx(), + ctx, chainID, provAddr, tc.rate, ) } - // TODO: opt validators in and verify - // that rewards are only allocated to them - ctx, _ := s.providerCtx().CacheContext() - // allocate tokens res := providerKeeper.AllocateTokensToConsumerValidators( ctx, chainID, - tc.votes, tc.tokens, ) @@ -982,11 +1009,11 @@ func (s *CCVTestSuite) TestAllocateTokensToValidator() { if !tc.expAllocated.Empty() { // rewards are expected to be allocated evenly between validators - rewardsPerVal := tc.expAllocated.QuoDec(sdk.NewDec(int64(len(tc.votes)))) + rewardsPerVal := tc.expAllocated.QuoDec(sdk.NewDec(int64(len(consuVals)))) // check that the rewards are allocated to validators - for _, v := range tc.votes { - valAddr := sdk.ValAddress(v.Validator.Address) + for _, v := range consuVals { + valAddr := sdk.ValAddress(v.ProviderConsAddr) rewards := s.providerApp.GetTestDistributionKeeper().GetValidatorOutstandingRewards( ctx, valAddr, @@ -1019,8 +1046,8 @@ func (s *CCVTestSuite) TestAllocateTokensToValidator() { s.Require().Equal(withdrawnCoins, bankKeeper.GetAllBalances(ctx, sdk.AccAddress(valAddr))) } } else { - for _, v := range tc.votes { - valAddr := sdk.ValAddress(v.Validator.Address) + for _, v := range consuVals { + valAddr := sdk.ValAddress(v.ProviderConsAddr) rewards := s.providerApp.GetTestDistributionKeeper().GetValidatorOutstandingRewards( ctx, valAddr, diff --git a/x/ccv/provider/keeper/distribution.go b/x/ccv/provider/keeper/distribution.go index aa7195cf4b..cd7755ac3e 100644 --- a/x/ccv/provider/keeper/distribution.go +++ b/x/ccv/provider/keeper/distribution.go @@ -17,16 +17,11 @@ import ( // BeginBlockRD executes BeginBlock logic for the Reward Distribution sub-protocol. func (k Keeper) BeginBlockRD(ctx sdk.Context, req abci.RequestBeginBlock) { - // determine the total power signing the block - var previousTotalPower int64 - for _, voteInfo := range req.LastCommitInfo.GetVotes() { - previousTotalPower += voteInfo.Validator.Power - } // TODO this is Tendermint-dependent // ref https://github.com/cosmos/cosmos-sdk/issues/3095 if ctx.BlockHeight() > 1 { - k.AllocateTokens(ctx, previousTotalPower, req.LastCommitInfo.GetVotes()) + k.AllocateTokens(ctx) } } @@ -75,7 +70,7 @@ func (k Keeper) GetAllConsumerRewardDenoms(ctx sdk.Context) (consumerRewardDenom // 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, totalPreviousPower int64, bondedVotes []abci.VoteInfo) { +func (k Keeper) AllocateTokens(ctx sdk.Context) { // return if there is no coins in the consumer rewards pool if k.GetConsumerRewardsPool(ctx).IsZero() { return @@ -95,6 +90,9 @@ func (k Keeper) AllocateTokens(ctx sdk.Context, totalPreviousPower int64, bonded continue } + // note that it's possible that no rewards are collected even though the + // reward pool isn't empty. This can happen if the reward pool holds some tokens + // of non-whitelisted denominations. if rewardsCollected.IsZero() { continue } @@ -104,13 +102,13 @@ func (k Keeper) AllocateTokens(ctx sdk.Context, totalPreviousPower int64, bonded // temporary workaround to keep CanWithdrawInvariant happy // general discussions here: https://github.com/cosmos/cosmos-sdk/issues/2906#issuecomment-441867634 feePool := k.distributionKeeper.GetFeePool(ctx) - if k.ComputeConsumerTotalVotingPower(ctx, consumer.ChainId, bondedVotes) == 0 { + if k.ComputeConsumerTotalVotingPower(ctx, consumer.ChainId) == 0 { feePool.CommunityPool = feePool.CommunityPool.Add(rewardsCollectedDec...) k.distributionKeeper.SetFeePool(ctx, feePool) return } - // Calculate the reward allocations + // calculate the reward allocations remaining := rewardsCollectedDec communityTax := k.distributionKeeper.GetCommunityTax(ctx) voteMultiplier := math.LegacyOneDec().Sub(communityTax) @@ -120,7 +118,6 @@ func (k Keeper) AllocateTokens(ctx sdk.Context, totalPreviousPower int64, bonded feeAllocated := k.AllocateTokensToConsumerValidators( ctx, consumer.ChainId, - bondedVotes, feeMultiplier, ) remaining = remaining.Sub(feeAllocated) @@ -131,15 +128,11 @@ func (k Keeper) AllocateTokens(ctx sdk.Context, totalPreviousPower int64, bonded } } -// TODO: allocate tokens to validators that opted-in and for long enough e.g. 1000 blocks -// once the opt-in logic is integrated QueueVSCPackets() -// -// AllocateTokensToConsumerValidators allocates the given tokens from the -// from consumer rewards pool to validator according to their voting power +// AllocateTokensToConsumerValidators allocates tokens +// to the given consumer chain's validator set func (k Keeper) AllocateTokensToConsumerValidators( ctx sdk.Context, chainID string, - bondedVotes []abci.VoteInfo, tokens sdk.DecCoins, ) (allocated sdk.DecCoins) { // return early if the tokens are empty @@ -147,17 +140,18 @@ func (k Keeper) AllocateTokensToConsumerValidators( return allocated } - // get the consumer total voting power from the votes - totalPower := k.ComputeConsumerTotalVotingPower(ctx, chainID, bondedVotes) + // get the total voting power of the consumer valset + totalPower := k.ComputeConsumerTotalVotingPower(ctx, chainID) if totalPower == 0 { return allocated } - for _, vote := range bondedVotes { - // TODO: should check if validator IsOptIn or continue here - consAddr := sdk.ConsAddress(vote.Validator.Address) + // Allocate tokens by iterating over the consumer validators + for _, consumerVal := range k.GetConsumerValSet(ctx, chainID) { + consAddr := sdk.ConsAddress(consumerVal.ProviderConsAddr) - powerFraction := math.LegacyNewDec(vote.Validator.Power).QuoTruncate(math.LegacyNewDec(totalPower)) + // get the validator tokens fraction using its voting power + powerFraction := math.LegacyNewDec(consumerVal.Power).QuoTruncate(math.LegacyNewDec(totalPower)) tokensFraction := tokens.MulDecTruncate(powerFraction) // get the validator type struct for the consensus address @@ -242,21 +236,15 @@ func (k Keeper) GetConsumerRewardsPool(ctx sdk.Context) sdk.Coins { ) } -// ComputeConsumerTotalVotingPower returns the total voting power for a given consumer chain -// by summing its opted-in validators votes -func (k Keeper) ComputeConsumerTotalVotingPower(ctx sdk.Context, chainID string, votes []abci.VoteInfo) int64 { - // TODO: create a optedIn set from the OptedIn validators - // and sum their validator power - var totalPower int64 - +// ComputeConsumerTotalVotingPower returns the validator set total voting power +// for the given consumer chain +func (k Keeper) ComputeConsumerTotalVotingPower(ctx sdk.Context, chainID string) (totalPower int64) { // sum the opted-in validators set voting powers - for _, vote := range votes { - // TODO: check that val is in the optedIn set - - totalPower += vote.Validator.Power + for _, v := range k.GetConsumerValSet(ctx, chainID) { + totalPower += v.Power } - return totalPower + return } // IdentifyConsumerChainIDFromIBCPacket checks if the packet destination matches a registered consumer chain. diff --git a/x/ccv/provider/keeper/distribution_test.go b/x/ccv/provider/keeper/distribution_test.go index d12b2c910a..1e37b1112e 100644 --- a/x/ccv/provider/keeper/distribution_test.go +++ b/x/ccv/provider/keeper/distribution_test.go @@ -12,7 +12,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - abci "github.com/cometbft/cometbft/abci/types" tmtypes "github.com/cometbft/cometbft/types" testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" @@ -30,44 +29,37 @@ func TestComputeConsumerTotalVotingPower(t *testing.T) { } chainID := "consumer" - validatorsVotes := make([]abci.VoteInfo, 5) - expTotalPower := int64(0) - // create validators, opt them in and use them - // to create block votes + // verify that the total power returned is equal to zero + // when the consumer doesn't exist or has no validators. + require.Zero(t, keeper.ComputeConsumerTotalVotingPower( + ctx, + chainID, + )) + + // set 5 validators to the consumer chain for i := 0; i < 5; i++ { val := createVal(int64(i)) - keeper.SetOptedIn( + keeper.SetConsumerValidator( ctx, chainID, - types.OptedInValidator{ - ProviderAddr: val.Address, - BlockHeight: ctx.BlockHeight(), - Power: val.VotingPower, - PublicKey: val.PubKey.Bytes(), - }, - ) - - validatorsVotes = append( - validatorsVotes, - abci.VoteInfo{ - Validator: abci.Validator{ - Address: val.Address, - Power: val.VotingPower, - }, + types.ConsumerValidator{ + ProviderConsAddr: val.Address, + Power: val.VotingPower, }, ) expTotalPower += val.VotingPower } + // compute the total power of opted-in validators res := keeper.ComputeConsumerTotalVotingPower( ctx, chainID, - validatorsVotes, ) + // check the total power returned require.Equal(t, expTotalPower, res) } From 3ca33ecc9d3aec2533104e3b4b1ae0e2dd9be032 Mon Sep 17 00:00:00 2001 From: Simon Noetzlin Date: Wed, 20 Mar 2024 10:09:54 +0100 Subject: [PATCH 033/110] feat!: Add slashing logic for PSS (#1710) * add check for consumer validators in downtime logic * fix UT * try to fix weird errors in gh worfklow * fix silly merge bug * nits --- x/ccv/provider/keeper/keeper_test.go | 1 - x/ccv/provider/keeper/relay.go | 8 ++++ x/ccv/provider/keeper/relay_test.go | 65 +++++++++++++++++++--------- 3 files changed, 52 insertions(+), 22 deletions(-) diff --git a/x/ccv/provider/keeper/keeper_test.go b/x/ccv/provider/keeper/keeper_test.go index feb87490c6..90faec1c85 100644 --- a/x/ccv/provider/keeper/keeper_test.go +++ b/x/ccv/provider/keeper/keeper_test.go @@ -9,7 +9,6 @@ import ( ibctesting "github.com/cosmos/ibc-go/v7/testing" "github.com/stretchr/testify/require" - cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/x/ccv/provider/keeper/relay.go b/x/ccv/provider/keeper/relay.go index 939f6d3995..1644ce263a 100644 --- a/x/ccv/provider/keeper/relay.go +++ b/x/ccv/provider/keeper/relay.go @@ -391,6 +391,14 @@ func (k Keeper) HandleSlashPacket(ctx sdk.Context, chainID string, data ccv.Slas "infractionType", data.Infraction, ) + // Check that the validator belongs to the consumer chain valset + if !k.IsConsumerValidator(ctx, chainID, providerConsAddr) { + k.Logger(ctx).Error("cannot jail validator %s that does not belong to consumer %s valset", + providerConsAddr.String(), chainID) + // drop packet + return + } + // Obtain validator from staking keeper validator, found := k.stakingKeeper.GetValidatorByConsAddr(ctx, providerConsAddr.ToSdkConsAddr()) diff --git a/x/ccv/provider/keeper/relay_test.go b/x/ccv/provider/keeper/relay_test.go index 2c5a24cab8..bb5a5227c6 100644 --- a/x/ccv/provider/keeper/relay_test.go +++ b/x/ccv/provider/keeper/relay_test.go @@ -22,6 +22,7 @@ import ( cryptotestutil "github.com/cosmos/interchain-security/v4/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" + "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" ) @@ -136,6 +137,9 @@ func TestOnRecvDowntimeSlashPacket(t *testing.T) { // Now set slash meter to positive value and assert slash packet handled result is returned providerKeeper.SetSlashMeter(ctx, math.NewInt(5)) + // Set the consumer validator + providerKeeper.SetConsumerValidator(ctx, "chain-1", types.ConsumerValidator{ProviderConsAddr: packetData.Validator.Address}) + // Mock call to GetEffectiveValPower, so that it returns 2. providerAddr := providertypes.NewProviderConsAddress(packetData.Validator.Address) calls := []*gomock.Call{ @@ -289,8 +293,11 @@ func TestValidateSlashPacket(t *testing.T) { func TestHandleSlashPacket(t *testing.T) { chainId := "consumer-id" validVscID := uint64(234) + providerConsAddr := cryptotestutil.NewCryptoIdentityFromIntSeed(7842334).ProviderConsAddress() consumerConsAddr := cryptotestutil.NewCryptoIdentityFromIntSeed(784987634).ConsumerConsAddress() + // this "dummy" consensus address won't be stored on the provider states + dummyConsAddr := cryptotestutil.NewCryptoIdentityFromIntSeed(784987639).ConsumerConsAddress() testCases := []struct { name string @@ -299,6 +306,20 @@ func TestHandleSlashPacket(t *testing.T) { expectedCalls func(sdk.Context, testkeeper.MockedKeepers, ccv.SlashPacketData) []*gomock.Call expectedSlashAcksLen int }{ + { + "validator isn't a consumer validator", + ccv.SlashPacketData{ + Validator: abci.Validator{Address: dummyConsAddr.ToSdkConsAddr()}, + ValsetUpdateId: validVscID, + Infraction: stakingtypes.Infraction_INFRACTION_DOWNTIME, + }, + func(ctx sdk.Context, mocks testkeeper.MockedKeepers, + expectedPacketData ccv.SlashPacketData, + ) []*gomock.Call { + return []*gomock.Call{} + }, + 0, + }, { "unfound validator", ccv.SlashPacketData{ @@ -403,34 +424,36 @@ func TestHandleSlashPacket(t *testing.T) { } for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + providerKeeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx( + t, testkeeper.NewInMemKeeperParams(t)) - providerKeeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx( - t, testkeeper.NewInMemKeeperParams(t)) - - // Setup expected mock calls - gomock.InOrder(tc.expectedCalls(ctx, mocks, tc.packetData)...) + // Setup expected mock calls + gomock.InOrder(tc.expectedCalls(ctx, mocks, tc.packetData)...) - // Setup init chain height and a single valid valset update ID to block height mapping. - providerKeeper.SetInitChainHeight(ctx, chainId, 5) - providerKeeper.SetValsetUpdateBlockHeight(ctx, validVscID, 99) + // Setup init chain height and a single valid valset update ID to block height mapping. + providerKeeper.SetInitChainHeight(ctx, chainId, 5) + providerKeeper.SetValsetUpdateBlockHeight(ctx, validVscID, 99) - // Setup consumer address to provider address mapping. - require.NotEmpty(t, tc.packetData.Validator.Address) - providerKeeper.SetValidatorByConsumerAddr(ctx, chainId, consumerConsAddr, providerConsAddr) + // Setup consumer address to provider address mapping. + require.NotEmpty(t, tc.packetData.Validator.Address) + providerKeeper.SetValidatorByConsumerAddr(ctx, chainId, consumerConsAddr, providerConsAddr) + providerKeeper.SetConsumerValidator(ctx, chainId, types.ConsumerValidator{ProviderConsAddr: providerConsAddr.Address.Bytes()}) - // Execute method and assert expected mock calls. - providerKeeper.HandleSlashPacket(ctx, chainId, tc.packetData) + // Execute method and assert expected mock calls. + providerKeeper.HandleSlashPacket(ctx, chainId, tc.packetData) - require.Equal(t, tc.expectedSlashAcksLen, len(providerKeeper.GetSlashAcks(ctx, chainId))) + require.Equal(t, tc.expectedSlashAcksLen, len(providerKeeper.GetSlashAcks(ctx, chainId))) - if tc.expectedSlashAcksLen == 1 { - // must match the consumer address - require.Equal(t, consumerConsAddr.String(), providerKeeper.GetSlashAcks(ctx, chainId)[0]) - require.NotEqual(t, providerConsAddr.String(), providerKeeper.GetSlashAcks(ctx, chainId)[0]) - require.NotEqual(t, providerConsAddr.String(), consumerConsAddr.String()) - } + if tc.expectedSlashAcksLen == 1 { + // must match the consumer address + require.Equal(t, consumerConsAddr.String(), providerKeeper.GetSlashAcks(ctx, chainId)[0]) + require.NotEqual(t, providerConsAddr.String(), providerKeeper.GetSlashAcks(ctx, chainId)[0]) + require.NotEqual(t, providerConsAddr.String(), consumerConsAddr.String()) + } - ctrl.Finish() + ctrl.Finish() + }) } } From 79abc145c21d55b0a1ce6063779e5a09d4019e5b Mon Sep 17 00:00:00 2001 From: insumity Date: Thu, 21 Mar 2024 14:39:21 +0100 Subject: [PATCH 034/110] ci: do not scan the tests for security issues (#1717) init commit --- .github/workflows/gosec.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gosec.yml b/.github/workflows/gosec.yml index 3955b92323..90f1379eb1 100644 --- a/.github/workflows/gosec.yml +++ b/.github/workflows/gosec.yml @@ -28,4 +28,4 @@ jobs: - name: Run Gosec Security Scanner uses: securego/gosec@master with: - args: -exclude-dir=legacy_ibc_testing ./... -exclude-generated ./... + args: -exclude-dir=tests ./... -exclude-generated ./... From b25114105ceb728c20bb06eb341d67ee8955adcf Mon Sep 17 00:00:00 2001 From: insumity Date: Mon, 25 Mar 2024 18:00:10 +0100 Subject: [PATCH 035/110] feat!: compute partial sets (#1702) * init commit * nit change * cleaning up * clean up * fix distribution test * Update x/ccv/provider/keeper/hooks.go Co-authored-by: Simon Noetzlin * took into Simon's comments * took into rest of the comments * nit change * return an error if validator cannot opt out from a Top N chain * removed automatic opt-in for validators that vote Yes on proposals * tiny fix for E2E tests * nit change to remove unecessary else * fixed topN == 0 issue --------- Co-authored-by: Simon Noetzlin --- .../ccv/provider/v1/provider.proto | 13 - tests/e2e/actions.go | 1 + tests/mbt/driver/setup.go | 3 +- testutil/keeper/mocks.go | 29 - x/ccv/provider/keeper/hooks.go | 56 -- x/ccv/provider/keeper/hooks_test.go | 89 --- x/ccv/provider/keeper/keeper.go | 121 +--- x/ccv/provider/keeper/keeper_test.go | 192 +------ x/ccv/provider/keeper/key_assignment_test.go | 5 +- x/ccv/provider/keeper/msg_server.go | 30 +- x/ccv/provider/keeper/partial_set_security.go | 112 +++- .../keeper/partial_set_security_test.go | 213 ++++++- x/ccv/provider/keeper/proposal.go | 11 +- x/ccv/provider/keeper/relay.go | 12 +- x/ccv/provider/keeper/relay_test.go | 22 +- x/ccv/provider/keeper/validator_set_update.go | 124 ++-- .../keeper/validator_set_update_test.go | 223 ++++++-- x/ccv/provider/types/errors.go | 1 + x/ccv/provider/types/keys.go | 32 +- x/ccv/provider/types/keys_test.go | 4 +- x/ccv/provider/types/provider.pb.go | 538 ++++-------------- x/ccv/types/expected_keepers.go | 2 - 22 files changed, 727 insertions(+), 1106 deletions(-) diff --git a/proto/interchain_security/ccv/provider/v1/provider.proto b/proto/interchain_security/ccv/provider/v1/provider.proto index 8c70c9e428..1b5f7a515f 100644 --- a/proto/interchain_security/ccv/provider/v1/provider.proto +++ b/proto/interchain_security/ccv/provider/v1/provider.proto @@ -326,16 +326,3 @@ message ConsumerRewardsAllocation { (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins" ]; } - -// OptedInValidator is used to store a opted-in validator -// to a consumer chain with the following mapping: (chainID, providerAddr) -> optedInValidator -message OptedInValidator { - // validator address - bytes provider_addr = 1; - // block height at which the validator opted-in - int64 block_height = 2; - // validator voting power at the block it opted-in - int64 power = 3; - // public key used by the validator on the consumer - bytes public_key = 4; -} \ No newline at end of file diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index 5fea89ec12..e49c37ae71 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -278,6 +278,7 @@ func (tr TestConfig) submitConsumerAdditionProposal( UnbondingPeriod: params.UnbondingPeriod, Deposit: fmt.Sprint(action.Deposit) + `stake`, DistributionTransmissionChannel: action.DistributionChannel, + TopN: 100, } bz, err := json.Marshal(prop) diff --git a/tests/mbt/driver/setup.go b/tests/mbt/driver/setup.go index 6408f0e873..deeae01f6b 100644 --- a/tests/mbt/driver/setup.go +++ b/tests/mbt/driver/setup.go @@ -373,7 +373,8 @@ func (s *Driver) ConfigureNewPath(consumerChain, providerChain *ibctesting.TestC stakingValidators = append(stakingValidators, v) } - nextValidators := s.providerKeeper().ComputeNextEpochConsumerValSet(s.providerCtx(), string(consumerChainId), stakingValidators) + considerAll := func(validator stakingtypes.Validator) bool { return true } + nextValidators := s.providerKeeper().ComputeNextEpochConsumerValSet(s.providerCtx(), string(consumerChainId), stakingValidators, considerAll) s.providerKeeper().SetConsumerValSet(s.providerCtx(), string(consumerChainId), nextValidators) err = s.providerKeeper().SetConsumerGenesis( diff --git a/testutil/keeper/mocks.go b/testutil/keeper/mocks.go index 78c0fbedc9..e588f51e30 100644 --- a/testutil/keeper/mocks.go +++ b/testutil/keeper/mocks.go @@ -1270,32 +1270,3 @@ func (mr *MockGovKeeperMockRecorder) GetProposal(ctx, proposalID interface{}) *g mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetProposal", reflect.TypeOf((*MockGovKeeper)(nil).GetProposal), ctx, proposalID) } - -// GetProposals mocks base method. -func (m *MockGovKeeper) GetProposals(ctx types0.Context) v1.Proposals { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetProposals", ctx) - ret0, _ := ret[0].(v1.Proposals) - return ret0 -} - -// GetProposals indicates an expected call of GetProposals. -func (mr *MockGovKeeperMockRecorder) GetProposals(ctx interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetProposals", reflect.TypeOf((*MockGovKeeper)(nil).GetProposals), ctx) -} - -// GetVote mocks base method. -func (m *MockGovKeeper) GetVote(ctx types0.Context, proposalID uint64, voterAddr types0.AccAddress) (v1.Vote, bool) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetVote", ctx, proposalID, voterAddr) - ret0, _ := ret[0].(v1.Vote) - ret1, _ := ret[1].(bool) - return ret0, ret1 -} - -// GetVote indicates an expected call of GetVote. -func (mr *MockGovKeeperMockRecorder) GetVote(ctx, proposalID, voterAddr interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetVote", reflect.TypeOf((*MockGovKeeper)(nil).GetVote), ctx, proposalID, voterAddr) -} diff --git a/x/ccv/provider/keeper/hooks.go b/x/ccv/provider/keeper/hooks.go index 13cf0cc382..88590a9875 100644 --- a/x/ccv/provider/keeper/hooks.go +++ b/x/ccv/provider/keeper/hooks.go @@ -3,8 +3,6 @@ package keeper import ( "fmt" - "cosmossdk.io/math" - sdk "github.com/cosmos/cosmos-sdk/types" sdkgov "github.com/cosmos/cosmos-sdk/x/gov/types" v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" @@ -177,61 +175,7 @@ func (h Hooks) AfterProposalVotingPeriodEnded(ctx sdk.Context, proposalID uint64 func (h Hooks) AfterProposalDeposit(ctx sdk.Context, proposalID uint64, depositorAddr sdk.AccAddress) { } -// AfterProposalVote opts in validators that vote YES (with 100% weight) on a `ConsumerAdditionProposal`. If a -// validator votes multiple times, only the last vote would be considered on whether the validator is opted in or not. func (h Hooks) AfterProposalVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress) { - validator, found := h.k.stakingKeeper.GetValidator(ctx, voterAddr.Bytes()) - if !found { - return - } - - consAddr, err := validator.GetConsAddr() - if err != nil { - h.k.Logger(ctx).Error("could not extract validator's consensus address", - "error", err.Error(), - "validator acc addr", voterAddr, - ) - return - } - - chainID, found := h.k.GetProposedConsumerChain(ctx, proposalID) - if !found { - return - } - - vote, found := h.k.govKeeper.GetVote(ctx, proposalID, voterAddr) - if !found { - h.k.Logger(ctx).Error("could not find vote for validator", - "validator acc addr", voterAddr, - "proposalID", proposalID, - ) - return - } - - if len(vote.Options) == 1 && vote.Options[0].Option == v1.VoteOption_VOTE_OPTION_YES { - // only consider votes that vote YES with 100% weight - weight, err := sdk.NewDecFromStr(vote.Options[0].Weight) - if err != nil { - h.k.Logger(ctx).Error("could not extract decimal value from vote's weight", - "vote", vote, - "error", err.Error(), - ) - return - } - if !weight.Equal(math.LegacyNewDec(1)) { - h.k.Logger(ctx).Error("single vote does not have a weight of 1", - "vote", vote, - ) - return - } - - // in the validator is already to-be-opted in, the `SetToBeOptedIn` is a no-op - h.k.SetToBeOptedIn(ctx, chainID, providertypes.NewProviderConsAddress(consAddr)) - } else { - // if vote is not a YES vote with 100% weight, we delete the validator from to-be-opted in - // if the validator is not to-be-opted in, the `DeleteToBeOptedIn` is a no-op - h.k.DeleteToBeOptedIn(ctx, chainID, providertypes.NewProviderConsAddress(consAddr)) - } } func (h Hooks) AfterProposalFailedMinDeposit(ctx sdk.Context, proposalID uint64) { diff --git a/x/ccv/provider/keeper/hooks_test.go b/x/ccv/provider/keeper/hooks_test.go index c2c8df36e2..a9cf69b350 100644 --- a/x/ccv/provider/keeper/hooks_test.go +++ b/x/ccv/provider/keeper/hooks_test.go @@ -9,19 +9,14 @@ import ( "cosmossdk.io/math" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - cryptotestutil "github.com/cosmos/interchain-security/v4/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" providerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" ) func TestValidatorConsensusKeyInUse(t *testing.T) { @@ -229,87 +224,3 @@ func TestGetConsumerAdditionLegacyPropFromProp(t *testing.T) { }) } } - -func TestAfterProposalVoteWithYesVote(t *testing.T) { - k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) - defer ctrl.Finish() - - providerConsPubKey := ed25519.GenPrivKeyFromSecret([]byte{1}).PubKey() - pkAny, _ := codectypes.NewAnyWithValue(providerConsPubKey) - providerAddr := types.NewProviderConsAddress(providerConsPubKey.Address().Bytes()) - - options := []*v1.WeightedVoteOption{{Option: v1.OptionYes, Weight: "1"}} - k.SetProposedConsumerChain(ctx, "chainID", 1) - - gomock.InOrder( - mocks.MockStakingKeeper.EXPECT().GetValidator(ctx, gomock.Any()).Return( - stakingtypes.Validator{ConsensusPubkey: pkAny}, true), - mocks.MockGovKeeper.EXPECT().GetVote(ctx, gomock.Any(), gomock.Any()).Return( - v1.Vote{ProposalId: 1, Voter: "voter", Options: options}, true, - ), - ) - - require.False(t, k.IsToBeOptedIn(ctx, "chainID", providerAddr)) - k.Hooks().AfterProposalVote(ctx, 1, sdk.AccAddress{}) - require.True(t, k.IsToBeOptedIn(ctx, "chainID", providerAddr)) -} - -func TestAfterProposalVoteWithNoVote(t *testing.T) { - testCases := []struct { - name string - options []*v1.WeightedVoteOption - setup func(sdk.Context, []*v1.WeightedVoteOption, testkeeper.MockedKeepers, *codectypes.Any) - }{ - { - "Weighted vote with 100% NO", - []*v1.WeightedVoteOption{{Option: v1.OptionNo, Weight: "1"}}, - func(ctx sdk.Context, options []*v1.WeightedVoteOption, - mocks testkeeper.MockedKeepers, pubKey *codectypes.Any, - ) { - gomock.InOrder( - mocks.MockStakingKeeper.EXPECT().GetValidator(ctx, gomock.Any()).Return( - stakingtypes.Validator{ConsensusPubkey: pubKey}, true), - mocks.MockGovKeeper.EXPECT().GetVote(ctx, gomock.Any(), gomock.Any()).Return( - v1.Vote{ProposalId: 1, Voter: "voter", Options: options}, true, - ), - ) - }, - }, - { - "Weighted vote with 99.9% YES and 0.1% NO", - []*v1.WeightedVoteOption{{Option: v1.OptionYes, Weight: "0.999"}, {Option: v1.OptionNo, Weight: "0.001"}}, - func(ctx sdk.Context, options []*v1.WeightedVoteOption, - mocks testkeeper.MockedKeepers, pubKey *codectypes.Any, - ) { - gomock.InOrder( - mocks.MockStakingKeeper.EXPECT().GetValidator(ctx, gomock.Any()).Return( - stakingtypes.Validator{ConsensusPubkey: pubKey}, true), - mocks.MockGovKeeper.EXPECT().GetVote(ctx, gomock.Any(), gomock.Any()).Return( - v1.Vote{ProposalId: 1, Voter: "voter", Options: options}, true, - ), - ) - }, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) - defer ctrl.Finish() - - providerConsPubKey := ed25519.GenPrivKeyFromSecret([]byte{1}).PubKey() - pkAny, _ := codectypes.NewAnyWithValue(providerConsPubKey) - providerAddr := types.NewProviderConsAddress(providerConsPubKey.Address().Bytes()) - - k.SetProposedConsumerChain(ctx, "chainID", 1) - - tc.setup(ctx, tc.options, mocks, pkAny) - - // set the validator to-be-opted in first to assert that a NO vote removes the validator from to-be-opted in - k.SetToBeOptedIn(ctx, "chainID", providerAddr) - require.True(t, k.IsToBeOptedIn(ctx, "chainID", providerAddr)) - k.Hooks().AfterProposalVote(ctx, 1, sdk.AccAddress{}) - require.False(t, k.IsToBeOptedIn(ctx, "chainID", providerAddr)) - }) - } -} diff --git a/x/ccv/provider/keeper/keeper.go b/x/ccv/provider/keeper/keeper.go index 2ec0a13603..7e79bf4f6c 100644 --- a/x/ccv/provider/keeper/keeper.go +++ b/x/ccv/provider/keeper/keeper.go @@ -1174,13 +1174,13 @@ func (k Keeper) GetTopN( return binary.BigEndian.Uint32(buf), true } -// IsTopN returns true if chain with `chainID` is a Top N chain (i.e., enforces at least one validator to validate chain `chainID`) +// IsTopN returns true if chain with `chainID` is a Top-N chain (i.e., enforces at least one validator to validate chain `chainID`) func (k Keeper) IsTopN(ctx sdk.Context, chainID string) bool { topN, found := k.GetTopN(ctx, chainID) return found && topN > 0 } -// IsOptIn returns true if chain with `chainID` is an Opt In chain (i.e., no validator is forced to validate chain `chainID`) +// IsOptIn returns true if chain with `chainID` is an Opt-In chain (i.e., no validator is forced to validate chain `chainID`) func (k Keeper) IsOptIn(ctx sdk.Context, chainID string) bool { topN, found := k.GetTopN(ctx, chainID) return !found || topN == 0 @@ -1189,15 +1189,10 @@ func (k Keeper) IsOptIn(ctx sdk.Context, chainID string) bool { func (k Keeper) SetOptedIn( ctx sdk.Context, chainID string, - validator types.OptedInValidator, + providerConsAddress types.ProviderConsAddress, ) { store := ctx.KVStore(k.storeKey) - bz, err := validator.Marshal() - if err != nil { - panic(fmt.Errorf("failed to marshal OptedInValidator: %w", err)) - } - - store.Set(types.OptedInKey(chainID, validator.ProviderAddr), bz) + store.Set(types.OptedInKey(chainID, providerConsAddress), []byte{}) } func (k Keeper) DeleteOptedIn( @@ -1206,7 +1201,7 @@ func (k Keeper) DeleteOptedIn( providerAddr types.ProviderConsAddress, ) { store := ctx.KVStore(k.storeKey) - store.Delete(types.OptedInKey(chainID, providerAddr.ToSdkConsAddr())) + store.Delete(types.OptedInKey(chainID, providerAddr)) } func (k Keeper) IsOptedIn( @@ -1215,38 +1210,23 @@ func (k Keeper) IsOptedIn( providerAddr types.ProviderConsAddress, ) bool { store := ctx.KVStore(k.storeKey) - return store.Get(types.OptedInKey(chainID, providerAddr.ToSdkConsAddr())) != nil + return store.Get(types.OptedInKey(chainID, providerAddr)) != nil } // GetAllOptedIn returns all the opted-in validators on chain `chainID` func (k Keeper) GetAllOptedIn( ctx sdk.Context, - chainID string, -) (optedInValidators []types.OptedInValidator) { + chainID string) (providerConsAddresses []types.ProviderConsAddress) { store := ctx.KVStore(k.storeKey) key := types.ChainIdWithLenKey(types.OptedInBytePrefix, chainID) iterator := sdk.KVStorePrefixIterator(store, key) defer iterator.Close() for ; iterator.Valid(); iterator.Next() { - iterator.Value() - var optedInValidator types.OptedInValidator - if err := optedInValidator.Unmarshal(iterator.Value()); err != nil { - panic(fmt.Errorf("failed to unmarshal OptedInValidator: %w", err)) - } - optedInValidators = append(optedInValidators, optedInValidator) + providerConsAddresses = append(providerConsAddresses, types.NewProviderConsAddress(iterator.Key()[len(key):])) } - return optedInValidators -} - -func (k Keeper) SetToBeOptedIn( - ctx sdk.Context, - chainID string, - providerAddr types.ProviderConsAddress, -) { - store := ctx.KVStore(k.storeKey) - store.Set(types.ToBeOptedInKey(chainID, providerAddr), []byte{}) + return providerConsAddresses } // SetConsumerCommissionRate sets a per-consumer chain commission rate @@ -1316,85 +1296,4 @@ func (k Keeper) DeleteConsumerCommissionRate( ) { store := ctx.KVStore(k.storeKey) store.Delete(types.ConsumerCommissionRateKey(chainID, providerAddr)) -} - -func (k Keeper) DeleteToBeOptedIn( - ctx sdk.Context, - chainID string, - providerAddr types.ProviderConsAddress, -) { - store := ctx.KVStore(k.storeKey) - store.Delete(types.ToBeOptedInKey(chainID, providerAddr)) -} - -func (k Keeper) IsToBeOptedIn( - ctx sdk.Context, - chainID string, - providerAddr types.ProviderConsAddress, -) bool { - store := ctx.KVStore(k.storeKey) - return store.Get(types.ToBeOptedInKey(chainID, providerAddr)) != nil -} - -// GetAllToBeOptedIn returns all the to-be-opted-in validators on chain `chainID` -func (k Keeper) GetAllToBeOptedIn( - ctx sdk.Context, - chainID string, -) (addresses []types.ProviderConsAddress) { - store := ctx.KVStore(k.storeKey) - key := types.ChainIdWithLenKey(types.ToBeOptedInBytePrefix, chainID) - iterator := sdk.KVStorePrefixIterator(store, key) - defer iterator.Close() - - for ; iterator.Valid(); iterator.Next() { - providerAddr := types.NewProviderConsAddress(iterator.Key()[len(key):]) - addresses = append(addresses, providerAddr) - } - - return addresses -} - -func (k Keeper) SetToBeOptedOut( - ctx sdk.Context, - chainID string, - providerAddr types.ProviderConsAddress, -) { - store := ctx.KVStore(k.storeKey) - store.Set(types.ToBeOptedOutKey(chainID, providerAddr), []byte{}) -} - -func (k Keeper) DeleteToBeOptedOut( - ctx sdk.Context, - chainID string, - providerAddr types.ProviderConsAddress, -) { - store := ctx.KVStore(k.storeKey) - store.Delete(types.ToBeOptedOutKey(chainID, providerAddr)) -} - -func (k Keeper) IsToBeOptedOut( - ctx sdk.Context, - chainID string, - providerAddr types.ProviderConsAddress, -) bool { - store := ctx.KVStore(k.storeKey) - return store.Get(types.ToBeOptedOutKey(chainID, providerAddr)) != nil -} - -// GetAllToBeOptedOut returns all the to-be-opted-out validators on chain `chainID` -func (k Keeper) GetAllToBeOptedOut( - ctx sdk.Context, - chainID string, -) (addresses []types.ProviderConsAddress) { - store := ctx.KVStore(k.storeKey) - key := types.ChainIdWithLenKey(types.ToBeOptedOutBytePrefix, chainID) - iterator := sdk.KVStorePrefixIterator(store, key) - defer iterator.Close() - - for ; iterator.Valid(); iterator.Next() { - providerAddr := types.NewProviderConsAddress(iterator.Key()[len(key):]) - addresses = append(addresses, providerAddr) - } - - return addresses -} +} \ No newline at end of file diff --git a/x/ccv/provider/keeper/keeper_test.go b/x/ccv/provider/keeper/keeper_test.go index 90faec1c85..640b2ac70d 100644 --- a/x/ccv/provider/keeper/keeper_test.go +++ b/x/ccv/provider/keeper/keeper_test.go @@ -665,46 +665,22 @@ func TestGetAllOptedIn(t *testing.T) { providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - expectedOptedInValidators := []types.OptedInValidator{ - { - ProviderAddr: []byte("providerAddr1"), - BlockHeight: 1, - Power: 2, - PublicKey: []byte{3}, - }, - { - ProviderAddr: []byte("providerAddr2"), - BlockHeight: 2, - Power: 3, - PublicKey: []byte{4}, - }, - { - ProviderAddr: []byte("providerAddr3"), - BlockHeight: 3, - Power: 4, - PublicKey: []byte{5}, - }, - } + expectedOptedInValidators := []types.ProviderConsAddress{ + types.NewProviderConsAddress([]byte("providerAddr1")), + types.NewProviderConsAddress([]byte("providerAddr2")), + types.NewProviderConsAddress([]byte("providerAddr3"))} for _, expectedOptedInValidator := range expectedOptedInValidators { - providerKeeper.SetOptedIn(ctx, "chainID", - types.OptedInValidator{ - ProviderAddr: expectedOptedInValidator.ProviderAddr, - BlockHeight: expectedOptedInValidator.BlockHeight, - Power: expectedOptedInValidator.Power, - PublicKey: expectedOptedInValidator.PublicKey, - }) + providerKeeper.SetOptedIn(ctx, "chainID", expectedOptedInValidator) + } actualOptedInValidators := providerKeeper.GetAllOptedIn(ctx, "chainID") // sort validators first to be able to compare - sortOptedInValidators := func(optedInValidators []types.OptedInValidator) { - sort.Slice(optedInValidators, func(i, j int) bool { - a := optedInValidators[i] - b := optedInValidators[j] - return a.BlockHeight < b.BlockHeight || - (a.BlockHeight == b.BlockHeight && bytes.Compare(a.ProviderAddr, b.ProviderAddr) < 0) + sortOptedInValidators := func(addressess []types.ProviderConsAddress) { + sort.Slice(addressess, func(i int, j int) bool { + return bytes.Compare(addressess[i].ToSdkConsAddr(), addressess[j].ToSdkConsAddr()) < 0 }) } sortOptedInValidators(expectedOptedInValidators) @@ -717,154 +693,16 @@ func TestOptedIn(t *testing.T) { providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - optedInValidator := types.OptedInValidator{ - ProviderAddr: []byte("providerAddr"), - BlockHeight: 1, - Power: 2, - PublicKey: []byte{3}, - } + optedInValidator := types.NewProviderConsAddress([]byte("providerAddr")) - require.False(t, providerKeeper.IsOptedIn(ctx, "chainID", types.NewProviderConsAddress(optedInValidator.ProviderAddr))) + require.False(t, providerKeeper.IsOptedIn(ctx, "chainID", optedInValidator)) providerKeeper.SetOptedIn(ctx, "chainID", optedInValidator) - require.True(t, providerKeeper.IsOptedIn(ctx, "chainID", types.NewProviderConsAddress(optedInValidator.ProviderAddr))) - providerKeeper.DeleteOptedIn(ctx, "chainID", types.NewProviderConsAddress(optedInValidator.ProviderAddr)) - require.False(t, providerKeeper.IsOptedIn(ctx, "chainID", types.NewProviderConsAddress(optedInValidator.ProviderAddr))) -} - -func TestGetAllToBeOptedIn(t *testing.T) { - providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) - defer ctrl.Finish() - - expectedAddresses := []types.ProviderConsAddress{ - types.NewProviderConsAddress([]byte("providerAddr1")), - types.NewProviderConsAddress([]byte("providerAddr2")), - types.NewProviderConsAddress([]byte("providerAddr3")), - } - - for _, addr := range expectedAddresses { - providerKeeper.SetToBeOptedIn(ctx, "chainID", addr) - } - - actualAddresses := providerKeeper.GetAllToBeOptedIn(ctx, "chainID") - - // sort addresses first to be able to compare - sortAddresses := func(addresses []types.ProviderConsAddress) { - sort.Slice(addresses, func(i, j int) bool { - a := addresses[i] - b := addresses[j] - return bytes.Compare(a.Address.Bytes(), b.Address.Bytes()) < 0 - }) - } - sortAddresses(expectedAddresses) - sortAddresses(actualAddresses) - require.Equal(t, expectedAddresses, actualAddresses) - - for _, addr := range expectedAddresses { - require.True(t, providerKeeper.IsToBeOptedIn(ctx, "chainID", addr)) - providerKeeper.DeleteToBeOptedIn(ctx, "chainID", addr) - require.False(t, providerKeeper.IsToBeOptedIn(ctx, "chainID", addr)) - } -} - -func TestBeOptedIn(t *testing.T) { - providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) - defer ctrl.Finish() - - expectedAddresses := []types.ProviderConsAddress{ - types.NewProviderConsAddress([]byte("providerAddr1")), - types.NewProviderConsAddress([]byte("providerAddr2")), - types.NewProviderConsAddress([]byte("providerAddr3")), - } - - for _, addr := range expectedAddresses { - providerKeeper.SetToBeOptedIn(ctx, "chainID", addr) - } - - actualAddresses := providerKeeper.GetAllToBeOptedIn(ctx, "chainID") - - // sort addresses first to be able to compare - sortAddresses := func(addresses []types.ProviderConsAddress) { - sort.Slice(addresses, func(i, j int) bool { - a := addresses[i] - b := addresses[j] - return bytes.Compare(a.Address.Bytes(), b.Address.Bytes()) < 0 - }) - } - sortAddresses(expectedAddresses) - sortAddresses(actualAddresses) - require.Equal(t, expectedAddresses, actualAddresses) - - for _, addr := range expectedAddresses { - require.True(t, providerKeeper.IsToBeOptedIn(ctx, "chainID", addr)) - providerKeeper.DeleteToBeOptedIn(ctx, "chainID", addr) - require.False(t, providerKeeper.IsToBeOptedIn(ctx, "chainID", addr)) - } -} - -// TestToBeOptedIn tests the `SetToBeOptedIn`, `IsToBeOptedIn`, and `DeleteToBeOptedIn` methods -func TestToBeOptedIn(t *testing.T) { - providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) - defer ctrl.Finish() - - providerAddr := types.NewProviderConsAddress([]byte("providerAddr1")) - - require.False(t, providerKeeper.IsToBeOptedIn(ctx, "chainID", providerAddr)) - providerKeeper.SetToBeOptedIn(ctx, "chainID", providerAddr) - require.True(t, providerKeeper.IsToBeOptedIn(ctx, "chainID", providerAddr)) - providerKeeper.DeleteToBeOptedIn(ctx, "chainID", providerAddr) - require.False(t, providerKeeper.IsToBeOptedIn(ctx, "chainID", providerAddr)) -} - -func TestGetAllToBeOptedOut(t *testing.T) { - providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) - defer ctrl.Finish() - - expectedAddresses := []types.ProviderConsAddress{ - types.NewProviderConsAddress([]byte("providerAddr1")), - types.NewProviderConsAddress([]byte("providerAddr2")), - types.NewProviderConsAddress([]byte("providerAddr3")), - } - - for _, addr := range expectedAddresses { - providerKeeper.SetToBeOptedOut(ctx, "chainID", addr) - } - - actualAddresses := providerKeeper.GetAllToBeOptedOut(ctx, "chainID") - - // sort addresses first to be able to compare - sortAddresses := func(addresses []types.ProviderConsAddress) { - sort.Slice(addresses, func(i, j int) bool { - a := addresses[i] - b := addresses[j] - return bytes.Compare(a.Address.Bytes(), b.Address.Bytes()) < 0 - }) - } - sortAddresses(expectedAddresses) - sortAddresses(actualAddresses) - require.Equal(t, expectedAddresses, actualAddresses) - - for _, addr := range expectedAddresses { - require.True(t, providerKeeper.IsToBeOptedOut(ctx, "chainID", addr)) - providerKeeper.DeleteToBeOptedOut(ctx, "chainID", addr) - require.False(t, providerKeeper.IsToBeOptedOut(ctx, "chainID", addr)) - } -} - -// TestToBeOptedOut tests the `SetToBeOptedOut`, `IsToBeOptedOut`, and `DeleteToBeOptedOut` methods -func TestToBeOptedOut(t *testing.T) { - providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) - defer ctrl.Finish() - - providerAddr := types.NewProviderConsAddress([]byte("providerAddr1")) - - require.False(t, providerKeeper.IsToBeOptedOut(ctx, "chainID", providerAddr)) - providerKeeper.SetToBeOptedOut(ctx, "chainID", providerAddr) - require.True(t, providerKeeper.IsToBeOptedOut(ctx, "chainID", providerAddr)) - providerKeeper.DeleteToBeOptedOut(ctx, "chainID", providerAddr) - require.False(t, providerKeeper.IsToBeOptedOut(ctx, "chainID", providerAddr)) + require.True(t, providerKeeper.IsOptedIn(ctx, "chainID", optedInValidator)) + providerKeeper.DeleteOptedIn(ctx, "chainID", optedInValidator) + require.False(t, providerKeeper.IsOptedIn(ctx, "chainID", optedInValidator)) } -// TestToBeOptedOut tests the `SetConsumerCommissionRate`, `GetConsumerCommissionRate`, and `DeleteConsumerCommissionRate` methods +// TestConsumerCommissionRate tests the `SetConsumerCommissionRate`, `GetConsumerCommissionRate`, and `DeleteConsumerCommissionRate` methods func TestConsumerCommissionRate(t *testing.T) { providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() diff --git a/x/ccv/provider/keeper/key_assignment_test.go b/x/ccv/provider/keeper/key_assignment_test.go index 53a428d0dc..1ea4080d2f 100644 --- a/x/ccv/provider/keeper/key_assignment_test.go +++ b/x/ccv/provider/keeper/key_assignment_test.go @@ -766,7 +766,10 @@ func TestSimulatedAssignmentsAndUpdateApplication(t *testing.T) { }) } - nextValidators := k.ComputeNextEpochConsumerValSet(ctx, CHAINID, bondedValidators) + nextValidators := k.ComputeNextEpochConsumerValSet(ctx, CHAINID, bondedValidators, + func(validator stakingtypes.Validator) bool { + return true + }) updates = providerkeeper.DiffValidators(k.GetConsumerValSet(ctx, CHAINID), nextValidators) k.SetConsumerValSet(ctx, CHAINID, nextValidators) diff --git a/x/ccv/provider/keeper/msg_server.go b/x/ccv/provider/keeper/msg_server.go index a595b5fbc2..7bbf270ef9 100644 --- a/x/ccv/provider/keeper/msg_server.go +++ b/x/ccv/provider/keeper/msg_server.go @@ -140,19 +140,27 @@ func (k msgServer) SubmitConsumerDoubleVoting(goCtx context.Context, msg *types. func (k msgServer) OptIn(goCtx context.Context, msg *types.MsgOptIn) (*types.MsgOptInResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - valAddress, err := sdk.ConsAddressFromBech32(msg.ProviderAddr) + valAddress, err := sdk.ValAddressFromBech32(msg.ProviderAddr) if err != nil { return nil, err } - providerAddr := types.NewProviderConsAddress(valAddress) + + // validator must already be registered + validator, found := k.stakingKeeper.GetValidator(ctx, valAddress) + if !found { + return nil, stakingtypes.ErrNoValidatorFound + } + + consAddrTmp, err := validator.GetConsAddr() if err != nil { return nil, err } + providerConsAddr := types.NewProviderConsAddress(consAddrTmp) if msg.ConsumerKey != "" { - err = k.Keeper.HandleOptIn(ctx, msg.ChainId, providerAddr, &msg.ConsumerKey) + err = k.Keeper.HandleOptIn(ctx, msg.ChainId, providerConsAddr, &msg.ConsumerKey) } else { - err = k.Keeper.HandleOptIn(ctx, msg.ChainId, providerAddr, nil) + err = k.Keeper.HandleOptIn(ctx, msg.ChainId, providerConsAddr, nil) } if err != nil { @@ -173,16 +181,24 @@ func (k msgServer) OptIn(goCtx context.Context, msg *types.MsgOptIn) (*types.Msg func (k msgServer) OptOut(goCtx context.Context, msg *types.MsgOptOut) (*types.MsgOptOutResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - valAddress, err := sdk.ConsAddressFromBech32(msg.ProviderAddr) + valAddress, err := sdk.ValAddressFromBech32(msg.ProviderAddr) if err != nil { return nil, err } - providerAddr := types.NewProviderConsAddress(valAddress) + + // validator must already be registered + validator, found := k.stakingKeeper.GetValidator(ctx, valAddress) + if !found { + return nil, stakingtypes.ErrNoValidatorFound + } + + consAddrTmp, err := validator.GetConsAddr() if err != nil { return nil, err } + providerConsAddr := types.NewProviderConsAddress(consAddrTmp) - err = k.Keeper.HandleOptOut(ctx, msg.ChainId, providerAddr) + err = k.Keeper.HandleOptOut(ctx, msg.ChainId, providerConsAddr) if err != nil { return nil, err } diff --git a/x/ccv/provider/keeper/partial_set_security.go b/x/ccv/provider/keeper/partial_set_security.go index 4034687d21..c34885e117 100644 --- a/x/ccv/provider/keeper/partial_set_security.go +++ b/x/ccv/provider/keeper/partial_set_security.go @@ -2,13 +2,15 @@ package keeper import ( errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + "math" + "sort" ) +// HandleOptIn prepares validator `providerAddr` to opt in to `chainID` with an optional `consumerKey` consumer public key. +// Note that the validator only opts in at the end of an epoch. func (k Keeper) HandleOptIn(ctx sdk.Context, chainID string, providerAddr types.ProviderConsAddress, consumerKey *string) error { if !k.IsConsumerProposedOrRegistered(ctx, chainID) { return errorsmod.Wrapf( @@ -16,13 +18,7 @@ func (k Keeper) HandleOptIn(ctx sdk.Context, chainID string, providerAddr types. "opting in to an unknown consumer chain, with id: %s", chainID) } - if k.IsToBeOptedOut(ctx, chainID, providerAddr) { - // a validator to be opted in cancels out with a validator to be opted out - k.DeleteToBeOptedOut(ctx, chainID, providerAddr) - } else if !k.IsToBeOptedIn(ctx, chainID, providerAddr) && !k.IsOptedIn(ctx, chainID, providerAddr) { - // a validator can only be set for opt in if it is not opted in and not already set for opt in - k.SetToBeOptedIn(ctx, chainID, providerAddr) - } + k.SetOptedIn(ctx, chainID, providerAddr) if consumerKey != nil { consumerTMPublicKey, err := k.ParseConsumerKey(*consumerKey) @@ -44,6 +40,8 @@ func (k Keeper) HandleOptIn(ctx sdk.Context, chainID string, providerAddr types. return nil } +// HandleOptOut prepares validator `providerAddr` to opt out from running `chainID`. +// Note that the validator only opts out at the end of an epoch. func (k Keeper) HandleOptOut(ctx sdk.Context, chainID string, providerAddr types.ProviderConsAddress) error { if _, found := k.GetConsumerClientId(ctx, chainID); !found { // A validator can only opt out from a running chain. We check this by checking the consumer client id, because @@ -53,13 +51,97 @@ func (k Keeper) HandleOptOut(ctx sdk.Context, chainID string, providerAddr types "opting out of an unknown or not running consumer chain, with id: %s", chainID) } - if k.IsToBeOptedIn(ctx, chainID, providerAddr) { - // a validator to be opted out cancels out a validator to be opted in - k.DeleteToBeOptedIn(ctx, chainID, providerAddr) - } else if !k.IsToBeOptedOut(ctx, chainID, providerAddr) && k.IsOptedIn(ctx, chainID, providerAddr) { - // a validator can only be set for opt out if it is opted in and not already set for opt out - k.SetToBeOptedOut(ctx, chainID, providerAddr) + if topN, found := k.GetTopN(ctx, chainID); found && topN > 0 { + // a validator cannot opt out from a Top N chain if the validator is in the Top N validators + validator, validatorFound := k.stakingKeeper.GetValidatorByConsAddr(ctx, providerAddr.ToSdkConsAddr()) + if !validatorFound { + return errorsmod.Wrapf( + stakingtypes.ErrNoValidatorFound, + "validator with consensus address %s could not be found", providerAddr.ToSdkConsAddr()) + } + power := k.stakingKeeper.GetLastValidatorPower(ctx, validator.GetOperator()) + minPowerToOptIn := k.ComputeMinPowerToOptIn(ctx, chainID, k.stakingKeeper.GetLastValidators(ctx), topN) + + if power >= minPowerToOptIn { + return errorsmod.Wrapf( + types.ErrCannotOptOutFromTopN, + "validator with power (%d) cannot opt out from Top N chain because all validators"+ + "with at least %d power have to validate", power, minPowerToOptIn) + } } + k.DeleteOptedIn(ctx, chainID, providerAddr) return nil } + +// OptInTopNValidators opts in to `chainID` all the `bondedValidators` that have at least `minPowerToOptIn` power +func (k Keeper) OptInTopNValidators(ctx sdk.Context, chainID string, bondedValidators []stakingtypes.Validator, minPowerToOptIn int64) { + for _, val := range bondedValidators { + power := k.stakingKeeper.GetLastValidatorPower(ctx, val.GetOperator()) + if power >= minPowerToOptIn { + consAddr, err := val.GetConsAddr() + if err != nil { + k.Logger(ctx).Error("could not retrieve validators consensus address", + "validator", val, + "error", err) + continue + } + + // if validator already exists it gets overwritten + k.SetOptedIn(ctx, chainID, types.NewProviderConsAddress(consAddr)) + } // else validators that do not belong to the top N validators but were opted in, remain opted in + } +} + +// ComputeMinPowerToOptIn returns the minimum power needed for a validator (from the bonded validators) +// to belong to the `topN` validators. `chainID` is only used for logging purposes. +func (k Keeper) ComputeMinPowerToOptIn(ctx sdk.Context, chainID string, bondedValidators []stakingtypes.Validator, topN uint32) int64 { + if topN == 0 { + // This should never happen but because `ComputeMinPowerToOptIn` is called during an `EndBlock` we do want + // to `panic` here. Instead, we log an error and return the maximum possible `int64`. + k.Logger(ctx).Error("trying to compute minimum power to opt in for a non-Top-N chain", + "chainID", chainID) + return math.MaxInt64 + } + + totalPower := sdk.ZeroDec() + var powers []int64 + + for _, val := range bondedValidators { + power := k.stakingKeeper.GetLastValidatorPower(ctx, val.GetOperator()) + powers = append(powers, power) + totalPower = totalPower.Add(sdk.NewDecFromInt(sdk.NewInt(power))) + } + + // sort by powers descending + sort.Slice(powers, func(i, j int) bool { + return powers[i] > powers[j] + }) + + topNThreshold := sdk.NewDecFromInt(sdk.NewInt(int64(topN))).QuoInt64(int64(100)) + powerSum := sdk.ZeroDec() + for _, power := range powers { + powerSum = powerSum.Add(sdk.NewDecFromInt(sdk.NewInt(power))) + if powerSum.Quo(totalPower).GTE(topNThreshold) { + return power + } + } + + // We should never reach this point because the topN can be up to 1.0 (100%) and in the above `for` loop we + // perform an equal comparison as well (`GTE`). In any case, we do not have to panic here because we can return 0 + // as the smallest possible power. + k.Logger(ctx).Error("should never reach this point", + "topN", topN, + "totalPower", totalPower, + "powerSum", powerSum) + return 0 +} + +// ShouldConsiderOnlyOptIn returns true if `validator` is opted in, in `chainID. +func (k Keeper) ShouldConsiderOnlyOptIn(ctx sdk.Context, chainID string, validator stakingtypes.Validator) bool { + consAddr, err := validator.GetConsAddr() + if err != nil { + return false + } + return k.IsOptedIn(ctx, chainID, types.NewProviderConsAddress(consAddr)) +} diff --git a/x/ccv/provider/keeper/partial_set_security_test.go b/x/ccv/provider/keeper/partial_set_security_test.go index 651bfc311d..303bdd633f 100644 --- a/x/ccv/provider/keeper/partial_set_security_test.go +++ b/x/ccv/provider/keeper/partial_set_security_test.go @@ -1,6 +1,9 @@ package keeper_test import ( + "bytes" + "math" + "sort" "testing" "github.com/golang/mock/gomock" @@ -25,21 +28,10 @@ func TestHandleOptIn(t *testing.T) { // trying to opt in to a non-proposed and non-registered chain returns an error require.Error(t, providerKeeper.HandleOptIn(ctx, "unknownChainID", providerAddr, nil)) - // if validator (`providerAddr`) is to be opted out, then we cancel that the validator is about - // to be opted out and do not consider the validator to opt in - providerKeeper.SetToBeOptedOut(ctx, "chainID", providerAddr) providerKeeper.SetProposedConsumerChain(ctx, "chainID", 1) - require.True(t, providerKeeper.IsToBeOptedOut(ctx, "chainID", providerAddr)) + require.False(t, providerKeeper.IsOptedIn(ctx, "chainID", providerAddr)) providerKeeper.HandleOptIn(ctx, "chainID", providerAddr, nil) - require.False(t, providerKeeper.IsToBeOptedIn(ctx, "chainID", providerAddr)) - require.False(t, providerKeeper.IsToBeOptedOut(ctx, "chainID", providerAddr)) - - // if validator (`providerAddr`) is already opted in, then the validator cannot be opted in - - providerKeeper.SetOptedIn(ctx, "chainID", - types.OptedInValidator{ProviderAddr: providerAddr.ToSdkConsAddr(), BlockHeight: 1, Power: 1, PublicKey: []byte{1}}) - providerKeeper.HandleOptIn(ctx, "chainID", providerAddr, nil) - require.False(t, providerKeeper.IsToBeOptedIn(ctx, "chainID", providerAddr)) + require.True(t, providerKeeper.IsOptedIn(ctx, "chainID", providerAddr)) } func TestHandleOptInWithConsumerKey(t *testing.T) { @@ -98,21 +90,64 @@ func TestHandleOptOut(t *testing.T) { // trying to opt out from a not running chain returns an error require.Error(t, providerKeeper.HandleOptOut(ctx, "unknownChainID", providerAddr)) - // if validator (`providerAddr`) is to be opted in, then we cancel that the validator is about - // to be opted out and do not consider the validator to opt out - providerKeeper.SetToBeOptedIn(ctx, "chainID", providerAddr) + // set a consumer client so that the chain is considered running providerKeeper.SetConsumerClientId(ctx, "chainID", "clientID") - require.True(t, providerKeeper.IsToBeOptedIn(ctx, "chainID", providerAddr)) - err := providerKeeper.HandleOptOut(ctx, "chainID", providerAddr) - require.NoError(t, err) - require.False(t, providerKeeper.IsToBeOptedOut(ctx, "chainID", providerAddr)) - require.False(t, providerKeeper.IsToBeOptedIn(ctx, "chainID", providerAddr)) - // if validator (`providerAddr`) is not opted in, then the validator cannot be opted out - providerKeeper.DeleteOptedIn(ctx, "chainID", providerAddr) - err = providerKeeper.HandleOptOut(ctx, "chainID", providerAddr) - require.NoError(t, err) - require.False(t, providerKeeper.IsToBeOptedOut(ctx, "chainID", providerAddr)) + // if validator (`providerAddr`) is already opted in, then an opt-out would remove this validator + providerKeeper.SetOptedIn(ctx, "chainID", providerAddr) + require.True(t, providerKeeper.IsOptedIn(ctx, "chainID", providerAddr)) + providerKeeper.HandleOptOut(ctx, "chainID", providerAddr) + require.False(t, providerKeeper.IsOptedIn(ctx, "chainID", providerAddr)) +} + +func TestHandleOptOutFromTopNChain(t *testing.T) { + providerKeeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + chainID := "chainID" + + // set a consumer client so that the chain is considered running + providerKeeper.SetConsumerClientId(ctx, chainID, "clientID") + + // set the chain as Top 50 and create 4 validators with 10%, 20%, 30%, and 40% of the total voting power + // respectively + providerKeeper.SetTopN(ctx, "chainID", 50) + valA := createStakingValidator(ctx, mocks, 1, 1) // 10% of the total voting power (can opt out) + valAConsAddr, _ := valA.GetConsAddr() + mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, valAConsAddr).Return(valA, true).AnyTimes() + valB := createStakingValidator(ctx, mocks, 2, 2) // 20% of the total voting power (can opt out) + valBConsAddr, _ := valB.GetConsAddr() + mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, valBConsAddr).Return(valB, true).AnyTimes() + valC := createStakingValidator(ctx, mocks, 3, 3) // 30% of the total voting power (cannot opt out) + valCConsAddr, _ := valC.GetConsAddr() + mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, valCConsAddr).Return(valC, true).AnyTimes() + valD := createStakingValidator(ctx, mocks, 4, 4) // 40% of the total voting power (cannot opt out) + valDConsAddr, _ := valD.GetConsAddr() + mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, valDConsAddr).Return(valD, true).AnyTimes() + + mocks.MockStakingKeeper.EXPECT().GetLastValidators(ctx).Return([]stakingtypes.Validator{valA, valB, valC, valD}).AnyTimes() + + // opt in all validators + providerKeeper.SetOptedIn(ctx, chainID, types.NewProviderConsAddress(valAConsAddr)) + providerKeeper.SetOptedIn(ctx, chainID, types.NewProviderConsAddress(valBConsAddr)) + providerKeeper.SetOptedIn(ctx, chainID, types.NewProviderConsAddress(valCConsAddr)) + providerKeeper.SetOptedIn(ctx, chainID, types.NewProviderConsAddress(valDConsAddr)) + + // validators A and B can opt out because they belong the bottom 30% of validators + require.NoError(t, providerKeeper.HandleOptOut(ctx, chainID, types.NewProviderConsAddress(valAConsAddr))) + require.NoError(t, providerKeeper.HandleOptOut(ctx, chainID, types.NewProviderConsAddress(valBConsAddr))) + + // validators C and D cannot opt out because C has 30% of the voting power and D has 40% of the voting power + // and hence both are needed to keep validating a Top 50 chain + require.Error(t, providerKeeper.HandleOptOut(ctx, chainID, types.NewProviderConsAddress(valCConsAddr))) + require.Error(t, providerKeeper.HandleOptOut(ctx, chainID, types.NewProviderConsAddress(valDConsAddr))) + + // opting out a validator that cannot be found from a Top N chain should also return an error + notFoundValidator := createStakingValidator(ctx, mocks, 5, 5) + notFoundValidatorConsAddr, _ := notFoundValidator.GetConsAddr() + mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, notFoundValidatorConsAddr). + Return(stakingtypes.Validator{}, false) + require.Error(t, providerKeeper.HandleOptOut(ctx, chainID, types.NewProviderConsAddress(notFoundValidatorConsAddr))) } func TestHandleSetConsumerCommissionRate(t *testing.T) { @@ -139,3 +174,129 @@ func TestHandleSetConsumerCommissionRate(t *testing.T) { require.Equal(t, sdk.OneDec(), cr) require.True(t, found) } + +func TestOptInTopNValidators(t *testing.T) { + providerKeeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + // create 4 validators with powers 1, 2, 3, and 1 respectively + valA := createStakingValidator(ctx, mocks, 1, 1) + valAConsAddr, _ := valA.GetConsAddr() + valB := createStakingValidator(ctx, mocks, 2, 2) + valBConsAddr, _ := valB.GetConsAddr() + valC := createStakingValidator(ctx, mocks, 3, 3) + valCConsAddr, _ := valC.GetConsAddr() + valD := createStakingValidator(ctx, mocks, 4, 1) + valDConsAddr, _ := valD.GetConsAddr() + + // Start Test 1: opt in all validators with power >= 0 + providerKeeper.OptInTopNValidators(ctx, "chainID", []stakingtypes.Validator{valA, valB, valC, valD}, 0) + expectedOptedInValidators := []types.ProviderConsAddress{ + types.NewProviderConsAddress(valAConsAddr), + types.NewProviderConsAddress(valBConsAddr), + types.NewProviderConsAddress(valCConsAddr), + types.NewProviderConsAddress(valDConsAddr)} + actualOptedInValidators := providerKeeper.GetAllOptedIn(ctx, "chainID") + + // sort validators first to be able to compare + sortUpdates := func(addresses []types.ProviderConsAddress) { + sort.Slice(addresses, func(i, j int) bool { + return bytes.Compare(addresses[i].ToSdkConsAddr(), addresses[j].ToSdkConsAddr()) < 0 + }) + } + + sortUpdates(expectedOptedInValidators) + sortUpdates(actualOptedInValidators) + require.Equal(t, expectedOptedInValidators, actualOptedInValidators) + + // reset state for the upcoming checks + providerKeeper.DeleteOptedIn(ctx, "chainID", types.NewProviderConsAddress(valAConsAddr)) + providerKeeper.DeleteOptedIn(ctx, "chainID", types.NewProviderConsAddress(valBConsAddr)) + providerKeeper.DeleteOptedIn(ctx, "chainID", types.NewProviderConsAddress(valCConsAddr)) + providerKeeper.DeleteOptedIn(ctx, "chainID", types.NewProviderConsAddress(valDConsAddr)) + + // Start Test 2: opt in all validators with power >= 1 + // We expect the same `expectedOptedInValidators` as when we opted in all validators with power >= 0 because the + // validators with the smallest power have power == 1 + providerKeeper.OptInTopNValidators(ctx, "chainID", []stakingtypes.Validator{valA, valB, valC, valD}, 0) + actualOptedInValidators = providerKeeper.GetAllOptedIn(ctx, "chainID") + sortUpdates(actualOptedInValidators) + require.Equal(t, expectedOptedInValidators, actualOptedInValidators) + + providerKeeper.DeleteOptedIn(ctx, "chainID", types.NewProviderConsAddress(valAConsAddr)) + providerKeeper.DeleteOptedIn(ctx, "chainID", types.NewProviderConsAddress(valBConsAddr)) + providerKeeper.DeleteOptedIn(ctx, "chainID", types.NewProviderConsAddress(valCConsAddr)) + providerKeeper.DeleteOptedIn(ctx, "chainID", types.NewProviderConsAddress(valDConsAddr)) + + // Start Test 3: opt in all validators with power >= 2 and hence we do not expect to opt in validator A + providerKeeper.OptInTopNValidators(ctx, "chainID", []stakingtypes.Validator{valA, valB, valC, valD}, 2) + expectedOptedInValidators = []types.ProviderConsAddress{ + types.NewProviderConsAddress(valBConsAddr), + types.NewProviderConsAddress(valCConsAddr)} + actualOptedInValidators = providerKeeper.GetAllOptedIn(ctx, "chainID") + + // sort validators first to be able to compare + sortUpdates(expectedOptedInValidators) + sortUpdates(actualOptedInValidators) + require.Equal(t, expectedOptedInValidators, actualOptedInValidators) + + // reset state for the upcoming checks + providerKeeper.DeleteOptedIn(ctx, "chainID", types.NewProviderConsAddress(valAConsAddr)) + providerKeeper.DeleteOptedIn(ctx, "chainID", types.NewProviderConsAddress(valBConsAddr)) + providerKeeper.DeleteOptedIn(ctx, "chainID", types.NewProviderConsAddress(valCConsAddr)) + providerKeeper.DeleteOptedIn(ctx, "chainID", types.NewProviderConsAddress(valDConsAddr)) + + // Start Test 4: opt in all validators with power >= 4 and hence we do not expect any opted-in validators + providerKeeper.OptInTopNValidators(ctx, "chainID", []stakingtypes.Validator{valA, valB, valC, valD}, 4) + require.Empty(t, providerKeeper.GetAllOptedIn(ctx, "chainID")) +} + +func TestComputeMinPowerToOptIn(t *testing.T) { + providerKeeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + // create 5 validators with powers 1, 3, 5, 6, 10 (not in that order) with total power of 25 (= 1 + 3 + 5 + 6 + 10) + // such that: + // validator power => cumulative share + // 10 => 40% + // 6 => 64% + // 5 => 84% + // 3 => 96% + // 1 => 100% + + bondedValidators := []stakingtypes.Validator{ + createStakingValidator(ctx, mocks, 1, 5), + createStakingValidator(ctx, mocks, 2, 10), + createStakingValidator(ctx, mocks, 3, 3), + createStakingValidator(ctx, mocks, 4, 1), + createStakingValidator(ctx, mocks, 5, 6), + } + + require.Equal(t, int64(1), providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 100)) + require.Equal(t, int64(1), providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 97)) + require.Equal(t, int64(3), providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 96)) + require.Equal(t, int64(3), providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 85)) + require.Equal(t, int64(5), providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 84)) + require.Equal(t, int64(5), providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 65)) + require.Equal(t, int64(6), providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 64)) + require.Equal(t, int64(6), providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 41)) + require.Equal(t, int64(10), providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 40)) + require.Equal(t, int64(10), providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 1)) + + // exceptional case when we erroneously call with `topN == 0` + require.Equal(t, int64(math.MaxInt64), providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 0)) +} + +// TestShouldConsiderOnlyOptIn returns true if `validator` is opted in, in `chainID. +func TestShouldConsiderOnlyOptIn(t *testing.T) { + providerKeeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + validator := createStakingValidator(ctx, mocks, 0, 1) + consAddr, _ := validator.GetConsAddr() + + require.False(t, providerKeeper.IsOptedIn(ctx, "chainID", types.NewProviderConsAddress(consAddr))) + providerKeeper.SetOptedIn(ctx, "chainID", types.NewProviderConsAddress(consAddr)) + require.True(t, providerKeeper.IsOptedIn(ctx, "chainID", types.NewProviderConsAddress(consAddr))) + +} diff --git a/x/ccv/provider/keeper/proposal.go b/x/ccv/provider/keeper/proposal.go index e8d50133ba..360ff8f9d2 100644 --- a/x/ccv/provider/keeper/proposal.go +++ b/x/ccv/provider/keeper/proposal.go @@ -289,7 +289,16 @@ func (k Keeper) MakeConsumerGenesis( bondedValidators = append(bondedValidators, val) } - nextValidators := k.ComputeNextEpochConsumerValSet(ctx, chainID, bondedValidators) + if prop.Top_N > 0 { + // in a Top-N chain, we automatically opt in all validators that belong to the top N + minPower := k.ComputeMinPowerToOptIn(ctx, chainID, bondedValidators, prop.Top_N) + k.OptInTopNValidators(ctx, chainID, bondedValidators, minPower) + } + + nextValidators := k.ComputeNextEpochConsumerValSet(ctx, chainID, bondedValidators, + func(validator stakingtypes.Validator) bool { + return k.ShouldConsiderOnlyOptIn(ctx, chainID, validator) + }) k.SetConsumerValSet(ctx, chainID, nextValidators) // get the initial updates with the latest set consumer public keys diff --git a/x/ccv/provider/keeper/relay.go b/x/ccv/provider/keeper/relay.go index 1644ce263a..1ef8547243 100644 --- a/x/ccv/provider/keeper/relay.go +++ b/x/ccv/provider/keeper/relay.go @@ -222,7 +222,17 @@ func (k Keeper) QueueVSCPackets(ctx sdk.Context) { for _, chain := range k.GetAllConsumerChains(ctx) { currentValidators := k.GetConsumerValSet(ctx, chain.ChainId) - nextValidators := k.ComputeNextEpochConsumerValSet(ctx, chain.ChainId, bondedValidators) + + if topN, found := k.GetTopN(ctx, chain.ChainId); found && topN > 0 { + // in a Top-N chain, we automatically opt in all validators that belong to the top N + minPower := k.ComputeMinPowerToOptIn(ctx, chain.ChainId, bondedValidators, topN) + k.OptInTopNValidators(ctx, chain.ChainId, bondedValidators, minPower) + } + + nextValidators := k.ComputeNextEpochConsumerValSet(ctx, chain.ChainId, bondedValidators, + func(validator stakingtypes.Validator) bool { + return k.ShouldConsiderOnlyOptIn(ctx, chain.ChainId, validator) + }) valUpdates := DiffValidators(currentValidators, nextValidators) k.SetConsumerValSet(ctx, chain.ChainId, nextValidators) diff --git a/x/ccv/provider/keeper/relay_test.go b/x/ccv/provider/keeper/relay_test.go index bb5a5227c6..594783a9a1 100644 --- a/x/ccv/provider/keeper/relay_test.go +++ b/x/ccv/provider/keeper/relay_test.go @@ -682,6 +682,10 @@ func TestEndBlockVSU(t *testing.T) { providerKeeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() + chainID := "chainID" + + providerKeeper.SetTopN(ctx, chainID, 100) + // 10 blocks constitute an epoch params := providertypes.DefaultParams() params.BlocksPerEpoch = 10 @@ -689,34 +693,38 @@ func TestEndBlockVSU(t *testing.T) { // create 4 sample lastValidators var lastValidators []stakingtypes.Validator + var valAddresses []sdk.ValAddress for i := 0; i < 4; i++ { - lastValidators = append(lastValidators, crypto.NewCryptoIdentityFromIntSeed(i).SDKStakingValidator()) + validator := crypto.NewCryptoIdentityFromIntSeed(i).SDKStakingValidator() + lastValidators = append(lastValidators, validator) + valAddresses = append(valAddresses, validator.GetOperator()) + mocks.MockStakingKeeper.EXPECT().GetLastValidatorPower(gomock.Any(), validator.GetOperator()).Return(int64(i + 1)).AnyTimes() } + mocks.MockStakingKeeper.EXPECT().GetLastValidators(gomock.Any()).Return(lastValidators).AnyTimes() - mocks.MockStakingKeeper.EXPECT().GetLastValidatorPower(gomock.Any(), gomock.Any()).Return(int64(2)).AnyTimes() // set a sample client for a consumer chain so that `GetAllConsumerChains` in `QueueVSCPackets` iterates at least once - providerKeeper.SetConsumerClientId(ctx, "chainID", "clientID") + providerKeeper.SetConsumerClientId(ctx, chainID, "clientID") // with block height of 1 we do not expect any queueing of VSC packets ctx = ctx.WithBlockHeight(1) providerKeeper.EndBlockVSU(ctx) - require.Equal(t, 0, len(providerKeeper.GetPendingVSCPackets(ctx, "chainID"))) + require.Equal(t, 0, len(providerKeeper.GetPendingVSCPackets(ctx, chainID))) // with block height of 5 we do not expect any queueing of VSC packets ctx = ctx.WithBlockHeight(5) providerKeeper.EndBlockVSU(ctx) - require.Equal(t, 0, len(providerKeeper.GetPendingVSCPackets(ctx, "chainID"))) + require.Equal(t, 0, len(providerKeeper.GetPendingVSCPackets(ctx, chainID))) // with block height of 10 we expect the queueing of one VSC packet ctx = ctx.WithBlockHeight(10) providerKeeper.EndBlockVSU(ctx) - require.Equal(t, 1, len(providerKeeper.GetPendingVSCPackets(ctx, "chainID"))) + require.Equal(t, 1, len(providerKeeper.GetPendingVSCPackets(ctx, chainID))) // With block height of 15 we expect no additional queueing of a VSC packet. // Note that the pending VSC packet is still there because `SendVSCPackets` does not send the packet. We // need to mock channels, etc. for this to work, and it's out of scope for this test. ctx = ctx.WithBlockHeight(15) providerKeeper.EndBlockVSU(ctx) - require.Equal(t, 1, len(providerKeeper.GetPendingVSCPackets(ctx, "chainID"))) + require.Equal(t, 1, len(providerKeeper.GetPendingVSCPackets(ctx, chainID))) } diff --git a/x/ccv/provider/keeper/validator_set_update.go b/x/ccv/provider/keeper/validator_set_update.go index adaee853e8..b9dc741d1b 100644 --- a/x/ccv/provider/keeper/validator_set_update.go +++ b/x/ccv/provider/keeper/validator_set_update.go @@ -26,6 +26,15 @@ func (k Keeper) SetConsumerValidator( store.Set(types.ConsumerValidatorKey(chainID, validator.ProviderConsAddr), bz) } +// SetConsumerValSet resets the current consumer validators with the `nextValidators` computed by +// `ComputeNextEpochConsumerValSet` and hence this method should only be called after `ComputeNextEpochConsumerValSet` has completed. +func (k Keeper) SetConsumerValSet(ctx sdk.Context, chainID string, nextValidators []types.ConsumerValidator) { + k.DeleteConsumerValSet(ctx, chainID) + for _, val := range nextValidators { + k.SetConsumerValidator(ctx, chainID, val) + } +} + // DeleteConsumerValidator removes consumer validator with `providerAddr` address func (k Keeper) DeleteConsumerValidator( ctx sdk.Context, @@ -37,10 +46,7 @@ func (k Keeper) DeleteConsumerValidator( } // DeleteConsumerValSet deletes all the stored consumer validators for chain `chainID` -func (k Keeper) DeleteConsumerValSet( - ctx sdk.Context, - chainID string, -) { +func (k Keeper) DeleteConsumerValSet(ctx sdk.Context, chainID string) { store := ctx.KVStore(k.storeKey) key := types.ChainIdWithLenKey(types.ConsumerValidatorBytePrefix, chainID) iterator := sdk.KVStorePrefixIterator(store, key) @@ -57,20 +63,13 @@ func (k Keeper) DeleteConsumerValSet( // IsConsumerValidator returns `true` if the consumer validator with `providerAddr` exists for chain `chainID` // and `false` otherwise -func (k Keeper) IsConsumerValidator( - ctx sdk.Context, - chainID string, - providerAddr types.ProviderConsAddress, -) bool { +func (k Keeper) IsConsumerValidator(ctx sdk.Context, chainID string, providerAddr types.ProviderConsAddress) bool { store := ctx.KVStore(k.storeKey) return store.Get(types.ConsumerValidatorKey(chainID, providerAddr.ToSdkConsAddr())) != nil } // GetConsumerValSet returns all the consumer validators for chain `chainID` -func (k Keeper) GetConsumerValSet( - ctx sdk.Context, - chainID string, -) (validators []types.ConsumerValidator) { +func (k Keeper) GetConsumerValSet(ctx sdk.Context, chainID string) (validators []types.ConsumerValidator) { store := ctx.KVStore(k.storeKey) key := types.ChainIdWithLenKey(types.ConsumerValidatorBytePrefix, chainID) iterator := sdk.KVStorePrefixIterator(store, key) @@ -88,51 +87,6 @@ func (k Keeper) GetConsumerValSet( return validators } -// ComputeNextEpochConsumerValSet returns the next validator set that is responsible for validating consumer -// chain `chainID`, based on the bonded validators. -func (k Keeper) ComputeNextEpochConsumerValSet( - ctx sdk.Context, - chainID string, - bondedValidators []stakingtypes.Validator, -) []types.ConsumerValidator { - var nextValidators []types.ConsumerValidator - for _, val := range bondedValidators { - // get next voting power and the next consumer public key - nextPower := k.stakingKeeper.GetLastValidatorPower(ctx, val.GetOperator()) - consAddr, err := val.GetConsAddr() - if err != nil { - // this should never happen but is recoverable if we exclude this validator from the `nextValidators` - k.Logger(ctx).Error("could not get consensus address of validator", - "validator", val.GetOperator().String(), - "error", err) - continue - } - nextConsumerPublicKey, foundConsumerPublicKey := k.GetValidatorConsumerPubKey(ctx, chainID, types.NewProviderConsAddress(consAddr)) - if !foundConsumerPublicKey { - // if no consumer key assigned then use the validator's key itself - k.Logger(ctx).Info("could not retrieve public key for validator on consumer chain because"+ - " the validator did not assign a new consumer key", - "validator", val.GetOperator().String(), - "chainID", chainID) - nextConsumerPublicKey, err = val.TmConsPublicKey() - if err != nil { - // this should never happen and might not be recoverable because without the public key - // we cannot generate a validator update - panic(fmt.Errorf("could not retrieve validator's (%+v) public key: %w", val, err)) - } - } - - nextValidator := types.ConsumerValidator{ - ProviderConsAddr: consAddr, - Power: nextPower, - ConsumerPublicKey: &nextConsumerPublicKey, - } - nextValidators = append(nextValidators, nextValidator) - } - - return nextValidators -} - // DiffValidators compares the current and the next epoch's consumer validators and returns the `ValidatorUpdate` diff // needed by CometBFT to update the validator set on a chain. func DiffValidators( @@ -174,11 +128,53 @@ func DiffValidators( return updates } -// SetConsumerValSet resets the current consumer validators with the `nextValidators` computed by -// `ComputeNextEpochConsumerValSet` and hence this method should only be called after `ComputeNextEpochConsumerValSet` has completed. -func (k Keeper) SetConsumerValSet(ctx sdk.Context, chainID string, nextValidators []types.ConsumerValidator) { - k.DeleteConsumerValSet(ctx, chainID) - for _, val := range nextValidators { - k.SetConsumerValidator(ctx, chainID, val) +// CreateConsumerValidator creates a consumer validator for `chainID` from the given staking `validator` +func (k Keeper) CreateConsumerValidator(ctx sdk.Context, chainID string, validator stakingtypes.Validator) (types.ConsumerValidator, error) { + power := k.stakingKeeper.GetLastValidatorPower(ctx, validator.GetOperator()) + consAddr, err := validator.GetConsAddr() + if err != nil { + return types.ConsumerValidator{}, fmt.Errorf("could not retrieve validator's (%+v) consensus address: %w", + validator, err) + } + + consumerPublicKey, foundConsumerPublicKey := k.GetValidatorConsumerPubKey(ctx, chainID, types.NewProviderConsAddress(consAddr)) + if !foundConsumerPublicKey { + consumerPublicKey, err = validator.TmConsPublicKey() + if err != nil { + return types.ConsumerValidator{}, fmt.Errorf("could not retrieve validator's (%+v) public key: %w", validator, err) + } + } + + return types.ConsumerValidator{ + ProviderConsAddr: consAddr, + Power: power, + ConsumerPublicKey: &consumerPublicKey, + }, nil +} + +// ComputeNextEpochConsumerValSet returns the next validator set that is responsible for validating consumer +// chain `chainID`. The next validator set corresponds to the `bondedValidator`s that `shouldConsider` evaluates to `true`. +func (k Keeper) ComputeNextEpochConsumerValSet( + ctx sdk.Context, + chainID string, + bondedValidators []stakingtypes.Validator, + shouldConsider func(validator stakingtypes.Validator) bool, +) []types.ConsumerValidator { + var nextValidators []types.ConsumerValidator + for _, val := range bondedValidators { + if shouldConsider(val) { + nextValidator, err := k.CreateConsumerValidator(ctx, chainID, val) + if err != nil { + // this should never happen but is recoverable if we exclude this validator from the next validator set + k.Logger(ctx).Error("could not create consumer validator", + "validator", val.GetOperator().String(), + "error", err) + continue + } + + nextValidators = append(nextValidators, nextValidator) + } } + + return nextValidators } diff --git a/x/ccv/provider/keeper/validator_set_update_test.go b/x/ccv/provider/keeper/validator_set_update_test.go index dce307a135..1de54fbbde 100644 --- a/x/ccv/provider/keeper/validator_set_update_test.go +++ b/x/ccv/provider/keeper/validator_set_update_test.go @@ -110,65 +110,25 @@ func createConsumerValidator(index int, power int64, seed int) (types.ConsumerVa }, publicKey } -func TestComputeNextEpochConsumerValSet(t *testing.T) { - providerKeeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) - defer ctrl.Finish() - - chainID := "chainID" - - // helper function to generate a validator with the given power and with a provider address based on index - createStakingValidator := func(ctx sdk.Context, mocks testkeeper.MockedKeepers, index int, power int64) stakingtypes.Validator { - providerConsPubKey := ed25519.GenPrivKeyFromSecret([]byte{byte(index)}).PubKey() - consAddr := sdk.ConsAddress(providerConsPubKey.Address()) - providerAddr := types.NewProviderConsAddress(consAddr) - pk, _ := cryptocodec.FromTmPubKeyInterface(providerConsPubKey) - pkAny, _ := codectypes.NewAnyWithValue(pk) - - var providerValidatorAddr sdk.ValAddress - providerValidatorAddr = providerAddr.Address.Bytes() - - mocks.MockStakingKeeper.EXPECT(). - GetLastValidatorPower(ctx, providerValidatorAddr).Return(power).AnyTimes() - - return stakingtypes.Validator{ - OperatorAddress: providerValidatorAddr.String(), - ConsensusPubkey: pkAny, - } +// createStakingValidator helper function to generate a validator with the given power and with a provider address based on index +func createStakingValidator(ctx sdk.Context, mocks testkeeper.MockedKeepers, index int, power int64) stakingtypes.Validator { + providerConsPubKey := ed25519.GenPrivKeyFromSecret([]byte{byte(index)}).PubKey() + consAddr := sdk.ConsAddress(providerConsPubKey.Address()) + providerAddr := types.NewProviderConsAddress(consAddr) + pk, _ := cryptocodec.FromTmPubKeyInterface(providerConsPubKey) + pkAny, _ := codectypes.NewAnyWithValue(pk) + + var providerValidatorAddr sdk.ValAddress + providerValidatorAddr = providerAddr.Address.Bytes() + + mocks.MockStakingKeeper.EXPECT(). + GetLastValidatorPower(ctx, providerValidatorAddr).Return(power).AnyTimes() + + return stakingtypes.Validator{ + OperatorAddress: providerValidatorAddr.String(), + ConsensusPubkey: pkAny, } - - // no consumer validators returned if we have no bonded validators - require.Empty(t, providerKeeper.ComputeNextEpochConsumerValSet(ctx, chainID, []stakingtypes.Validator{})) - - var expectedValidators []types.ConsumerValidator - - // create a staking validator A that has not set a consumer public key - valA := createStakingValidator(ctx, mocks, 1, 1) - // because validator A has no consumer key set, the `ConsumerPublicKey` we expect is the key on the provider chain - valAConsAddr, _ := valA.GetConsAddr() - valAPublicKey, _ := valA.TmConsPublicKey() - expectedValidators = append(expectedValidators, types.ConsumerValidator{ - ProviderConsAddr: types.NewProviderConsAddress(valAConsAddr).Address.Bytes(), - Power: 1, - ConsumerPublicKey: &valAPublicKey, - }) - - // create a staking validator B that has set a consumer public key - valB := createStakingValidator(ctx, mocks, 2, 2) - // validator B has set a consumer key, the `ConsumerPublicKey` we expect is the key set by `SetValidatorConsumerPubKey` - valBConsumerKey := cryptotestutil.NewCryptoIdentityFromIntSeed(1).TMProtoCryptoPublicKey() - valBConsAddr, _ := valB.GetConsAddr() - providerKeeper.SetValidatorConsumerPubKey(ctx, chainID, types.NewProviderConsAddress(valBConsAddr), valBConsumerKey) - expectedValidators = append(expectedValidators, types.ConsumerValidator{ - ProviderConsAddr: types.NewProviderConsAddress(valBConsAddr).Address.Bytes(), - Power: 2, - ConsumerPublicKey: &valBConsumerKey, - }) - - bondedValidators := []stakingtypes.Validator{valA, valB} - actualValidators := providerKeeper.ComputeNextEpochConsumerValSet(ctx, "chainID", bondedValidators) - require.Equal(t, expectedValidators, actualValidators) } - func TestDiff(t *testing.T) { // In what follows we create 6 validators: A, B, C, D, E, and F where currentValidators = {A, B, C, D, E} // and nextValidators = {B, C, D, E, F}. For the validators {B, C, D, E} in the intersection we have: @@ -356,3 +316,152 @@ func TestSetConsumerValSet(t *testing.T) { sortValidators(nextCurrentValidators) require.Equal(t, nextValidators, nextCurrentValidators) } + +func TestComputeNextEpochConsumerValSetConsiderAll(t *testing.T) { + providerKeeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + chainID := "chainID" + + // no consumer validators returned if we have no bonded validators + considerAll := func(validator stakingtypes.Validator) bool { return true } + require.Empty(t, providerKeeper.ComputeNextEpochConsumerValSet(ctx, chainID, []stakingtypes.Validator{}, considerAll)) + + var expectedValidators []types.ConsumerValidator + + // create a staking validator A that has not set a consumer public key + valA := createStakingValidator(ctx, mocks, 1, 1) + // because validator A has no consumer key set, the `ConsumerPublicKey` we expect is the key on the provider chain + valAConsAddr, _ := valA.GetConsAddr() + valAPublicKey, _ := valA.TmConsPublicKey() + expectedValidators = append(expectedValidators, types.ConsumerValidator{ + ProviderConsAddr: types.NewProviderConsAddress(valAConsAddr).Address.Bytes(), + Power: 1, + ConsumerPublicKey: &valAPublicKey, + }) + + // create a staking validator B that has set a consumer public key + valB := createStakingValidator(ctx, mocks, 2, 2) + // validator B has set a consumer key, the `ConsumerPublicKey` we expect is the key set by `SetValidatorConsumerPubKey` + valBConsumerKey := cryptotestutil.NewCryptoIdentityFromIntSeed(1).TMProtoCryptoPublicKey() + valBConsAddr, _ := valB.GetConsAddr() + providerKeeper.SetValidatorConsumerPubKey(ctx, chainID, types.NewProviderConsAddress(valBConsAddr), valBConsumerKey) + expectedValidators = append(expectedValidators, types.ConsumerValidator{ + ProviderConsAddr: types.NewProviderConsAddress(valBConsAddr).Address.Bytes(), + Power: 2, + ConsumerPublicKey: &valBConsumerKey, + }) + + bondedValidators := []stakingtypes.Validator{valA, valB} + actualValidators := providerKeeper.ComputeNextEpochConsumerValSet(ctx, chainID, bondedValidators, considerAll) + require.Equal(t, expectedValidators, actualValidators) +} + +func TestComputeNextEpochConsumerValSetConsiderOnlyOptIn(t *testing.T) { + providerKeeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + chainID := "chainID" + + // no consumer validators returned if we have no opted-in validators + require.Empty(t, providerKeeper.ComputeNextEpochConsumerValSet(ctx, chainID, []stakingtypes.Validator{}, + func(validator stakingtypes.Validator) bool { + return providerKeeper.ShouldConsiderOnlyOptIn(ctx, chainID, validator) + })) + + var expectedValidators []types.ConsumerValidator + + // create a staking validator A that has not set a consumer public key + valA := createStakingValidator(ctx, mocks, 1, 1) + // because validator A has no consumer key set, the `ConsumerPublicKey` we expect is the key on the provider chain + valAConsAddr, _ := valA.GetConsAddr() + valAPublicKey, _ := valA.TmConsPublicKey() + expectedValAConsumerValidator := types.ConsumerValidator{ + ProviderConsAddr: types.NewProviderConsAddress(valAConsAddr).Address.Bytes(), + Power: 1, + ConsumerPublicKey: &valAPublicKey} + expectedValidators = append(expectedValidators, expectedValAConsumerValidator) + + // create a staking validator B that has set a consumer public key + valB := createStakingValidator(ctx, mocks, 2, 2) + // validator B has set a consumer key, the `ConsumerPublicKey` we expect is the key set by `SetValidatorConsumerPubKey` + valBConsumerKey := cryptotestutil.NewCryptoIdentityFromIntSeed(1).TMProtoCryptoPublicKey() + valBConsAddr, _ := valB.GetConsAddr() + providerKeeper.SetValidatorConsumerPubKey(ctx, chainID, types.NewProviderConsAddress(valBConsAddr), valBConsumerKey) + expectedValBConsumerValidator := types.ConsumerValidator{ + ProviderConsAddr: types.NewProviderConsAddress(valBConsAddr).Address.Bytes(), + Power: 2, + ConsumerPublicKey: &valBConsumerKey, + } + expectedValidators = append(expectedValidators, expectedValBConsumerValidator) + + // opt in validators A and B with 0 power and no consumer public keys + providerKeeper.SetOptedIn(ctx, chainID, types.NewProviderConsAddress(valAConsAddr)) + providerKeeper.SetOptedIn(ctx, chainID, types.NewProviderConsAddress(valBConsAddr)) + + // the expected actual validators are the opted-in validators but with the correct power and consumer public keys set + bondedValidators := []stakingtypes.Validator{valA, valB} + actualValidators := providerKeeper.ComputeNextEpochConsumerValSet(ctx, "chainID", bondedValidators, + func(validator stakingtypes.Validator) bool { + return providerKeeper.ShouldConsiderOnlyOptIn(ctx, "chainID", validator) + }) + + // sort validators first to be able to compare + sortValidators := func(validators []types.ConsumerValidator) { + sort.Slice(validators, func(i, j int) bool { + return bytes.Compare(validators[i].ProviderConsAddr, validators[j].ProviderConsAddr) < 0 + }) + } + + sortValidators(actualValidators) + sortValidators(expectedValidators) + require.Equal(t, expectedValidators, actualValidators) + + // create a staking validator C that is not opted in, hence `expectedValidators` remains the same + valC := createStakingValidator(ctx, mocks, 3, 3) + bondedValidators = []stakingtypes.Validator{valA, valB, valC} + actualValidators = providerKeeper.ComputeNextEpochConsumerValSet(ctx, "chainID", bondedValidators, + func(validator stakingtypes.Validator) bool { + return providerKeeper.ShouldConsiderOnlyOptIn(ctx, "chainID", validator) + }) + + sortValidators(actualValidators) + sortValidators(expectedValidators) + require.Equal(t, expectedValidators, actualValidators) +} + +func TestCreateConsumerValidator(t *testing.T) { + providerKeeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + chainID := "chainID" + + // create a validator which has set a consumer public key + valA := createStakingValidator(ctx, mocks, 0, 1) + valAConsumerKey := cryptotestutil.NewCryptoIdentityFromIntSeed(1).TMProtoCryptoPublicKey() + valAConsAddr, _ := valA.GetConsAddr() + valAProviderConsAddr := types.NewProviderConsAddress(valAConsAddr) + providerKeeper.SetValidatorConsumerPubKey(ctx, chainID, valAProviderConsAddr, valAConsumerKey) + actualConsumerValidatorA, err := providerKeeper.CreateConsumerValidator(ctx, chainID, valA) + expectedConsumerValidatorA := types.ConsumerValidator{ + ProviderConsAddr: valAProviderConsAddr.ToSdkConsAddr(), + Power: 1, + ConsumerPublicKey: &valAConsumerKey, + } + require.Equal(t, expectedConsumerValidatorA, actualConsumerValidatorA) + require.NoError(t, err) + + // create a validator which has not set a consumer public key + valB := createStakingValidator(ctx, mocks, 1, 2) + valBConsAddr, _ := valB.GetConsAddr() + valBProviderConsAddr := types.NewProviderConsAddress(valBConsAddr) + valBPublicKey, _ := valB.TmConsPublicKey() + actualConsumerValidatorB, err := providerKeeper.CreateConsumerValidator(ctx, chainID, valB) + expectedConsumerValidatorB := types.ConsumerValidator{ + ProviderConsAddr: valBProviderConsAddr.ToSdkConsAddr(), + Power: 2, + ConsumerPublicKey: &valBPublicKey, + } + require.Equal(t, expectedConsumerValidatorB, actualConsumerValidatorB) + require.NoError(t, err) +} diff --git a/x/ccv/provider/types/errors.go b/x/ccv/provider/types/errors.go index 271ea90329..1e7dd7dd3d 100644 --- a/x/ccv/provider/types/errors.go +++ b/x/ccv/provider/types/errors.go @@ -25,4 +25,5 @@ var ( ErrDuplicateConsumerChain = errorsmod.Register(ModuleName, 17, "consumer chain already exists") ErrConsumerChainNotFound = errorsmod.Register(ModuleName, 18, "consumer chain not found") ErrInvalidConsumerCommissionRate = errorsmod.Register(ModuleName, 19, "consumer commission rate is invalid") + ErrCannotOptOutFromTopN = errorsmod.Register(ModuleName, 20, "cannot opt out from a Top N chain") ) diff --git a/x/ccv/provider/types/keys.go b/x/ccv/provider/types/keys.go index 998608ef18..1e2516ba07 100644 --- a/x/ccv/provider/types/keys.go +++ b/x/ccv/provider/types/keys.go @@ -147,24 +147,18 @@ const ( // ProposedConsumerChainByteKey is the byte prefix storing the consumer chainId in consumerAddition gov proposal submitted before voting finishes ProposedConsumerChainByteKey - // ConsumerValidatorBytePrefix is the byte prefix used when storing for each consumer chain all the consumer validators in this epoch + // OptedInBytePrefix is the byte prefix used when storing for each consumer chain the validators that + // are opted in but not necessarily the ones that are validating. + OptedInBytePrefix + + // ConsumerValidatorBytePrefix is the byte prefix used when storing for each consumer chain all the consumer + // validators in this epoch that are validating the consumer chain ConsumerValidatorBytePrefix // TopNBytePrefix is the byte prefix storing the mapping from a consumer chain to the N value of this chain, // that corresponds to the N% of the top validators that have to validate this consumer chain TopNBytePrefix - // OptedInBytePrefix is the byte prefix used when storing for each consumer chain all the opted in validators - OptedInBytePrefix - - // ToBeOptedInBytePrefix is the byte prefix used when storing for each consumer chain the validators that - // are about to be opted in - ToBeOptedInBytePrefix - - // ToBeOptedOutBytePrefix is the byte prefix used when storing for each consumer chain the validators that - // are about to be opted out - ToBeOptedOutBytePrefix - // ConsumerRewardsAllocationBytePrefix is the byte prefix used when storing for each consumer the rewards // it allocated to the consumer rewards pool ConsumerRewardsAllocationBytePrefix @@ -551,20 +545,8 @@ func TopNKey(chainID string) []byte { } // OptedInKey returns the key of consumer chain `chainID` and validator with `providerAddr` -func OptedInKey(chainID string, providerAddr []byte) []byte { +func OptedInKey(chainID string, providerAddr ProviderConsAddress) []byte { prefix := ChainIdWithLenKey(OptedInBytePrefix, chainID) - return append(prefix, providerAddr...) -} - -// ToBeOptedInKey returns the key of consumer chain `chainID` and validator with `providerAddr` -func ToBeOptedInKey(chainID string, providerAddr ProviderConsAddress) []byte { - prefix := ChainIdWithLenKey(ToBeOptedInBytePrefix, chainID) - return append(prefix, providerAddr.ToSdkConsAddr().Bytes()...) -} - -// ToBeOptedOutKey returns the key of consumer chain `chainID` and validator with `providerAddr` -func ToBeOptedOutKey(chainID string, providerAddr ProviderConsAddress) []byte { - prefix := ChainIdWithLenKey(ToBeOptedOutBytePrefix, chainID) return append(prefix, providerAddr.ToSdkConsAddr().Bytes()...) } diff --git a/x/ccv/provider/types/keys_test.go b/x/ccv/provider/types/keys_test.go index f24c6ec476..d37482e50e 100644 --- a/x/ccv/provider/types/keys_test.go +++ b/x/ccv/provider/types/keys_test.go @@ -56,11 +56,9 @@ func getAllKeyPrefixes() []byte { providertypes.VSCMaturedHandledThisBlockBytePrefix, providertypes.EquivocationEvidenceMinHeightBytePrefix, providertypes.ProposedConsumerChainByteKey, + providertypes.OptedInBytePrefix, providertypes.ConsumerValidatorBytePrefix, providertypes.TopNBytePrefix, - providertypes.OptedInBytePrefix, - providertypes.ToBeOptedInBytePrefix, - providertypes.ToBeOptedOutBytePrefix, providertypes.ConsumerRewardsAllocationBytePrefix, providertypes.ConsumerCommissionRatePrefix, } diff --git a/x/ccv/provider/types/provider.pb.go b/x/ccv/provider/types/provider.pb.go index c2771de119..dee8a9520a 100644 --- a/x/ccv/provider/types/provider.pb.go +++ b/x/ccv/provider/types/provider.pb.go @@ -1513,80 +1513,6 @@ func (m *ConsumerRewardsAllocation) GetRewards() github_com_cosmos_cosmos_sdk_ty return nil } -// OptedInValidator is used to store a opted-in validator -// to a consumer chain with the following mapping: (chainID, providerAddr) -> optedInValidator -type OptedInValidator struct { - // validator address - ProviderAddr []byte `protobuf:"bytes,1,opt,name=provider_addr,json=providerAddr,proto3" json:"provider_addr,omitempty"` - // block height at which the validator opted-in - BlockHeight int64 `protobuf:"varint,2,opt,name=block_height,json=blockHeight,proto3" json:"block_height,omitempty"` - // validator voting power at the block it opted-in - Power int64 `protobuf:"varint,3,opt,name=power,proto3" json:"power,omitempty"` - // public key used by the validator on the consumer - PublicKey []byte `protobuf:"bytes,4,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` -} - -func (m *OptedInValidator) Reset() { *m = OptedInValidator{} } -func (m *OptedInValidator) String() string { return proto.CompactTextString(m) } -func (*OptedInValidator) ProtoMessage() {} -func (*OptedInValidator) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{24} -} -func (m *OptedInValidator) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *OptedInValidator) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_OptedInValidator.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *OptedInValidator) XXX_Merge(src proto.Message) { - xxx_messageInfo_OptedInValidator.Merge(m, src) -} -func (m *OptedInValidator) XXX_Size() int { - return m.Size() -} -func (m *OptedInValidator) XXX_DiscardUnknown() { - xxx_messageInfo_OptedInValidator.DiscardUnknown(m) -} - -var xxx_messageInfo_OptedInValidator proto.InternalMessageInfo - -func (m *OptedInValidator) GetProviderAddr() []byte { - if m != nil { - return m.ProviderAddr - } - return nil -} - -func (m *OptedInValidator) GetBlockHeight() int64 { - if m != nil { - return m.BlockHeight - } - return 0 -} - -func (m *OptedInValidator) GetPower() int64 { - if m != nil { - return m.Power - } - return 0 -} - -func (m *OptedInValidator) GetPublicKey() []byte { - if m != nil { - return m.PublicKey - } - return nil -} - func init() { proto.RegisterType((*ConsumerAdditionProposal)(nil), "interchain_security.ccv.provider.v1.ConsumerAdditionProposal") proto.RegisterType((*ConsumerRemovalProposal)(nil), "interchain_security.ccv.provider.v1.ConsumerRemovalProposal") @@ -1612,7 +1538,6 @@ func init() { proto.RegisterType((*ConsumerAddrsToPrune)(nil), "interchain_security.ccv.provider.v1.ConsumerAddrsToPrune") proto.RegisterType((*ConsumerValidator)(nil), "interchain_security.ccv.provider.v1.ConsumerValidator") proto.RegisterType((*ConsumerRewardsAllocation)(nil), "interchain_security.ccv.provider.v1.ConsumerRewardsAllocation") - proto.RegisterType((*OptedInValidator)(nil), "interchain_security.ccv.provider.v1.OptedInValidator") } func init() { @@ -1620,126 +1545,123 @@ func init() { } var fileDescriptor_f22ec409a72b7b72 = []byte{ - // 1892 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0xcd, 0x73, 0x1c, 0x47, - 0x15, 0xd7, 0x68, 0x57, 0x1f, 0xfb, 0x56, 0x9f, 0x23, 0x25, 0x1e, 0x19, 0xb1, 0x92, 0x27, 0x24, - 0x08, 0x82, 0x67, 0x90, 0x02, 0x55, 0x2e, 0x17, 0xa9, 0x94, 0xb4, 0x72, 0x62, 0x59, 0x89, 0xad, - 0x8c, 0x84, 0x5c, 0xc0, 0x61, 0xaa, 0xb7, 0xa7, 0xbd, 0xdb, 0xa5, 0xd9, 0xe9, 0x71, 0x77, 0xef, - 0x38, 0x7b, 0xe1, 0xcc, 0x85, 0x22, 0xdc, 0x52, 0x5c, 0x08, 0x54, 0x51, 0x45, 0x71, 0x81, 0x3f, - 0x23, 0xc7, 0x1c, 0x39, 0x25, 0x94, 0x7d, 0xe0, 0xc0, 0x95, 0x3f, 0x80, 0xea, 0x9e, 0xcf, 0x5d, - 0x49, 0x66, 0x5d, 0x81, 0x8b, 0x34, 0xf3, 0xfa, 0xbd, 0xdf, 0x7b, 0xfd, 0xbe, 0x77, 0x60, 0x8f, - 0x46, 0x92, 0x70, 0xdc, 0x43, 0x34, 0xf2, 0x05, 0xc1, 0x03, 0x4e, 0xe5, 0xd0, 0xc5, 0x38, 0x71, - 0x63, 0xce, 0x12, 0x1a, 0x10, 0xee, 0x26, 0xbb, 0xc5, 0xb3, 0x13, 0x73, 0x26, 0x99, 0xf9, 0xc6, - 0x15, 0x32, 0x0e, 0xc6, 0x89, 0x53, 0xf0, 0x25, 0xbb, 0x37, 0xdf, 0xbc, 0x0e, 0x38, 0xd9, 0x75, - 0x9f, 0x51, 0x4e, 0x52, 0xac, 0x9b, 0xeb, 0x5d, 0xd6, 0x65, 0xfa, 0xd1, 0x55, 0x4f, 0x19, 0x75, - 0xab, 0xcb, 0x58, 0x37, 0x24, 0xae, 0x7e, 0xeb, 0x0c, 0x9e, 0xb8, 0x92, 0xf6, 0x89, 0x90, 0xa8, - 0x1f, 0x67, 0x0c, 0xad, 0x71, 0x86, 0x60, 0xc0, 0x91, 0xa4, 0x2c, 0xca, 0x01, 0x68, 0x07, 0xbb, - 0x98, 0x71, 0xe2, 0xe2, 0x90, 0x92, 0x48, 0x2a, 0xad, 0xe9, 0x53, 0xc6, 0xe0, 0x2a, 0x86, 0x90, - 0x76, 0x7b, 0x32, 0x25, 0x0b, 0x57, 0x92, 0x28, 0x20, 0xbc, 0x4f, 0x53, 0xe6, 0xf2, 0x2d, 0x13, - 0xd8, 0xac, 0x9c, 0x63, 0x3e, 0x8c, 0x25, 0x73, 0x2f, 0xc8, 0x50, 0x64, 0xa7, 0x6f, 0x61, 0x26, - 0xfa, 0x4c, 0xb8, 0x44, 0xdd, 0x3f, 0xc2, 0xc4, 0x4d, 0x76, 0x3b, 0x44, 0xa2, 0xdd, 0x82, 0x90, - 0xdb, 0x9d, 0xf1, 0x75, 0x90, 0x28, 0x79, 0x30, 0xa3, 0xb9, 0xdd, 0xab, 0xa8, 0x4f, 0x23, 0xe6, - 0xea, 0xbf, 0x29, 0xc9, 0xfe, 0xf7, 0x2c, 0x58, 0x6d, 0x16, 0x89, 0x41, 0x9f, 0xf0, 0xfd, 0x20, - 0xa0, 0xea, 0x96, 0x27, 0x9c, 0xc5, 0x4c, 0xa0, 0xd0, 0x5c, 0x87, 0x19, 0x49, 0x65, 0x48, 0x2c, - 0x63, 0xdb, 0xd8, 0x69, 0x78, 0xe9, 0x8b, 0xb9, 0x0d, 0xcd, 0x80, 0x08, 0xcc, 0x69, 0xac, 0x98, - 0xad, 0x69, 0x7d, 0x56, 0x25, 0x99, 0x1b, 0x30, 0x9f, 0x86, 0x86, 0x06, 0x56, 0x4d, 0x1f, 0xcf, - 0xe9, 0xf7, 0xa3, 0xc0, 0xfc, 0x00, 0x96, 0x68, 0x44, 0x25, 0x45, 0xa1, 0xdf, 0x23, 0xca, 0x41, - 0x56, 0x7d, 0xdb, 0xd8, 0x69, 0xee, 0xdd, 0x74, 0x68, 0x07, 0x3b, 0xca, 0xa7, 0x4e, 0xe6, 0xc9, - 0x64, 0xd7, 0xb9, 0xaf, 0x39, 0x0e, 0xea, 0x5f, 0x7c, 0xb5, 0x35, 0xe5, 0x2d, 0x66, 0x72, 0x29, - 0xd1, 0xbc, 0x05, 0x0b, 0x5d, 0x12, 0x11, 0x41, 0x85, 0xdf, 0x43, 0xa2, 0x67, 0xcd, 0x6c, 0x1b, - 0x3b, 0x0b, 0x5e, 0x33, 0xa3, 0xdd, 0x47, 0xa2, 0x67, 0x6e, 0x41, 0xb3, 0x43, 0x23, 0xc4, 0x87, - 0x29, 0xc7, 0xac, 0xe6, 0x80, 0x94, 0xa4, 0x19, 0xda, 0x00, 0x22, 0x46, 0xcf, 0x22, 0x5f, 0x25, - 0x80, 0x35, 0x97, 0x19, 0x92, 0x06, 0xdf, 0xc9, 0x83, 0xef, 0x9c, 0xe5, 0xd9, 0x71, 0x30, 0xaf, - 0x0c, 0xf9, 0xf4, 0xeb, 0x2d, 0xc3, 0x6b, 0x68, 0x39, 0x75, 0x62, 0x3e, 0x84, 0x95, 0x41, 0xd4, - 0x61, 0x51, 0x40, 0xa3, 0xae, 0x1f, 0x13, 0x4e, 0x59, 0x60, 0xcd, 0x6b, 0xa8, 0x8d, 0x4b, 0x50, - 0x87, 0x59, 0x1e, 0xa5, 0x48, 0x9f, 0x29, 0xa4, 0xe5, 0x42, 0xf8, 0x44, 0xcb, 0x9a, 0x1f, 0x83, - 0x89, 0x71, 0xa2, 0x4d, 0x62, 0x03, 0x99, 0x23, 0x36, 0x26, 0x47, 0x5c, 0xc1, 0x38, 0x39, 0x4b, - 0xa5, 0x33, 0xc8, 0x5f, 0xc0, 0x0d, 0xc9, 0x51, 0x24, 0x9e, 0x10, 0x3e, 0x8e, 0x0b, 0x93, 0xe3, - 0xbe, 0x96, 0x63, 0x8c, 0x82, 0xdf, 0x87, 0x6d, 0x9c, 0x25, 0x90, 0xcf, 0x49, 0x40, 0x85, 0xe4, - 0xb4, 0x33, 0x50, 0xb2, 0xfe, 0x13, 0x8e, 0xb0, 0xce, 0x91, 0xa6, 0x4e, 0x82, 0x56, 0xce, 0xe7, - 0x8d, 0xb0, 0xbd, 0x9f, 0x71, 0x99, 0x8f, 0xe0, 0x3b, 0x9d, 0x90, 0xe1, 0x0b, 0xa1, 0x8c, 0xf3, - 0x47, 0x90, 0xb4, 0xea, 0x3e, 0x15, 0x42, 0xa1, 0x2d, 0x6c, 0x1b, 0x3b, 0x35, 0xef, 0x56, 0xca, - 0x7b, 0x42, 0xf8, 0x61, 0x85, 0xf3, 0xac, 0xc2, 0x68, 0xde, 0x06, 0xb3, 0x47, 0x85, 0x64, 0x9c, - 0x62, 0x14, 0xfa, 0x24, 0x92, 0x9c, 0x12, 0x61, 0x2d, 0x6a, 0xf1, 0xd5, 0xf2, 0xe4, 0x5e, 0x7a, - 0x60, 0x3e, 0x80, 0x5b, 0xd7, 0x2a, 0xf5, 0x71, 0x0f, 0x45, 0x11, 0x09, 0xad, 0x25, 0x7d, 0x95, - 0xad, 0xe0, 0x1a, 0x9d, 0xed, 0x94, 0xcd, 0x5c, 0x83, 0x19, 0xc9, 0x62, 0xff, 0xa1, 0xb5, 0xbc, - 0x6d, 0xec, 0x2c, 0x7a, 0x75, 0xc9, 0xe2, 0x87, 0x77, 0xe7, 0x7f, 0xf5, 0xf9, 0xd6, 0xd4, 0x67, - 0x9f, 0x6f, 0x4d, 0xd9, 0x7f, 0x35, 0xe0, 0x46, 0xbb, 0xf0, 0x46, 0x9f, 0x25, 0x28, 0xfc, 0x7f, - 0x56, 0xdd, 0x3e, 0x34, 0x84, 0x32, 0x47, 0xe7, 0x79, 0xfd, 0x15, 0xf2, 0x7c, 0x5e, 0x89, 0xa9, - 0x03, 0xfb, 0xf7, 0x06, 0xac, 0xdf, 0x7b, 0x3a, 0xa0, 0x09, 0xc3, 0xe8, 0x7f, 0xd2, 0x24, 0x8e, - 0x61, 0x91, 0x54, 0xf0, 0x84, 0x55, 0xdb, 0xae, 0xed, 0x34, 0xf7, 0xde, 0x74, 0xd2, 0x26, 0xe6, - 0x14, 0xbd, 0x2d, 0x6b, 0x64, 0x4e, 0x55, 0xbb, 0x37, 0x2a, 0x7b, 0x77, 0xda, 0x32, 0xec, 0x3f, - 0x1a, 0x70, 0x53, 0xb9, 0xbf, 0x4b, 0x3c, 0xf2, 0x0c, 0xf1, 0xe0, 0x90, 0x44, 0xac, 0x2f, 0xbe, - 0xb1, 0x9d, 0x36, 0x2c, 0x06, 0x1a, 0xc9, 0x97, 0xcc, 0x47, 0x41, 0xa0, 0xed, 0xd4, 0x3c, 0x8a, - 0x78, 0xc6, 0xf6, 0x83, 0xc0, 0xdc, 0x81, 0x95, 0x92, 0x87, 0xab, 0x78, 0x2a, 0x37, 0x2b, 0xb6, - 0xa5, 0x9c, 0x4d, 0x47, 0x99, 0xd8, 0xff, 0x32, 0x60, 0xe5, 0x83, 0x90, 0x75, 0x50, 0x78, 0x1a, - 0x22, 0xd1, 0x53, 0xa9, 0x37, 0x54, 0xe1, 0xe1, 0x24, 0xab, 0x79, 0x6d, 0xde, 0xc4, 0xe1, 0x51, - 0x62, 0xba, 0x0b, 0xbd, 0x07, 0xab, 0x45, 0x15, 0x16, 0x59, 0xa0, 0x6f, 0x73, 0xb0, 0xf6, 0xfc, - 0xab, 0xad, 0xe5, 0x3c, 0xd9, 0xda, 0x3a, 0x23, 0x0e, 0xbd, 0x65, 0x3c, 0x42, 0x08, 0xcc, 0x16, - 0x34, 0x69, 0x07, 0xfb, 0x82, 0x3c, 0xf5, 0xa3, 0x41, 0x5f, 0x27, 0x50, 0xdd, 0x6b, 0xd0, 0x0e, - 0x3e, 0x25, 0x4f, 0x1f, 0x0e, 0xfa, 0xe6, 0x3b, 0xf0, 0x7a, 0x3e, 0x80, 0xfd, 0x04, 0x85, 0xbe, - 0x92, 0x57, 0xee, 0xe0, 0x3a, 0x9f, 0x16, 0xbc, 0xb5, 0xfc, 0xf4, 0x1c, 0x85, 0x4a, 0xd9, 0x7e, - 0x10, 0x70, 0xfb, 0xc5, 0x0c, 0xcc, 0x9e, 0x20, 0x8e, 0xfa, 0xc2, 0x3c, 0x83, 0x65, 0x49, 0xfa, - 0x71, 0x88, 0x24, 0xf1, 0xd3, 0x0e, 0x9f, 0xdd, 0xf4, 0x6d, 0xdd, 0xf9, 0xab, 0xc3, 0xd2, 0xa9, - 0x8c, 0xc7, 0x64, 0xd7, 0x69, 0x6b, 0xea, 0xa9, 0x44, 0x92, 0x78, 0x4b, 0x39, 0x46, 0x4a, 0x34, - 0xef, 0x80, 0x25, 0xf9, 0x40, 0xc8, 0xb2, 0xf7, 0x96, 0x4d, 0x27, 0x8d, 0xe5, 0xeb, 0xf9, 0x79, - 0xda, 0xae, 0x8a, 0x66, 0x73, 0x75, 0x9b, 0xad, 0x7d, 0x93, 0x36, 0x7b, 0x0a, 0x6b, 0x6a, 0x46, - 0x8d, 0x63, 0xd6, 0x27, 0xc7, 0x5c, 0x55, 0xf2, 0xa3, 0xa0, 0x1f, 0x83, 0x99, 0x08, 0x3c, 0x8e, - 0x39, 0xf3, 0x0a, 0x76, 0x26, 0x02, 0x8f, 0x42, 0x06, 0xb0, 0x29, 0x54, 0xf2, 0xf9, 0x7d, 0x22, - 0x75, 0xd3, 0x8e, 0x43, 0x12, 0x51, 0xd1, 0xcb, 0xc1, 0x67, 0x27, 0x07, 0xdf, 0xd0, 0x40, 0x1f, - 0x29, 0x1c, 0x2f, 0x87, 0xc9, 0xb4, 0xb4, 0xa1, 0x75, 0xb5, 0x96, 0x22, 0x40, 0x73, 0x3a, 0x40, - 0xdf, 0xba, 0x02, 0xa2, 0x88, 0x92, 0x80, 0xb7, 0x2a, 0xc3, 0x45, 0x55, 0xb5, 0xaf, 0x0b, 0xca, - 0xe7, 0xa4, 0xab, 0x3a, 0x30, 0x4a, 0xe7, 0x0c, 0x21, 0xc5, 0x80, 0xcc, 0xba, 0x87, 0x5a, 0x81, - 0x8a, 0xce, 0xd1, 0x66, 0x34, 0xca, 0xb6, 0x08, 0xbb, 0x9c, 0x41, 0x45, 0x8f, 0xf0, 0x2a, 0x58, - 0xef, 0x13, 0xa2, 0xaa, 0xb9, 0x32, 0x87, 0x48, 0xcc, 0x70, 0x4f, 0xcf, 0xc9, 0x9a, 0xb7, 0x54, - 0xcc, 0x9c, 0x7b, 0x8a, 0xfa, 0xa0, 0x3e, 0x3f, 0xbf, 0xd2, 0xb0, 0xbf, 0x07, 0x0d, 0x5d, 0xcc, - 0xfb, 0xf8, 0x42, 0x98, 0x9b, 0xd0, 0x50, 0x55, 0x41, 0x84, 0x20, 0xc2, 0x32, 0x74, 0x0f, 0x28, - 0x09, 0xb6, 0x84, 0x8d, 0xeb, 0xb6, 0x2d, 0x61, 0x3e, 0x86, 0xb9, 0x98, 0xe8, 0x55, 0x40, 0x0b, - 0x36, 0xf7, 0xde, 0x75, 0x26, 0xd8, 0x85, 0x9d, 0xeb, 0x00, 0xbd, 0x1c, 0xcd, 0xe6, 0xe5, 0x8e, - 0x37, 0x36, 0x6c, 0x84, 0x79, 0x3e, 0xae, 0xf4, 0x27, 0xaf, 0xa4, 0x74, 0x0c, 0xaf, 0xd4, 0xf9, - 0x36, 0x34, 0xf7, 0xd3, 0x6b, 0x7f, 0x48, 0x85, 0xbc, 0xec, 0x96, 0x85, 0xaa, 0x5b, 0x1e, 0xc0, - 0x52, 0x36, 0x38, 0xcf, 0x98, 0x6e, 0x48, 0xe6, 0xb7, 0x01, 0xb2, 0x89, 0xab, 0x1a, 0x59, 0xda, - 0xb2, 0x1b, 0x19, 0xe5, 0x28, 0x18, 0x99, 0x75, 0xd3, 0x23, 0xb3, 0xce, 0xf6, 0x60, 0xf9, 0x5c, - 0xe0, 0x9f, 0xe6, 0x5b, 0xd5, 0xa3, 0x58, 0x98, 0xaf, 0xc1, 0xac, 0xaa, 0xa1, 0x0c, 0xa8, 0xee, - 0xcd, 0x24, 0x02, 0x1f, 0xe9, 0xae, 0x5d, 0x6e, 0x6e, 0x2c, 0xf6, 0x69, 0x20, 0xac, 0xe9, 0xed, - 0xda, 0x4e, 0xdd, 0x5b, 0x1a, 0x94, 0xe2, 0x47, 0x81, 0xb0, 0x7f, 0x06, 0xcd, 0x0a, 0xa0, 0xb9, - 0x04, 0xd3, 0x05, 0xd6, 0x34, 0x0d, 0xcc, 0xbb, 0xb0, 0x51, 0x02, 0x8d, 0xb6, 0xe1, 0x14, 0xb1, - 0xe1, 0xdd, 0x28, 0x18, 0x46, 0x3a, 0xb1, 0xb0, 0x1f, 0xc1, 0xfa, 0x51, 0x59, 0xf4, 0x45, 0x93, - 0x1f, 0xb9, 0xa1, 0x31, 0x3a, 0xcd, 0x37, 0xa1, 0x51, 0xfc, 0x62, 0xd1, 0xb7, 0xaf, 0x7b, 0x25, - 0xc1, 0xee, 0xc3, 0xca, 0xb9, 0xc0, 0xa7, 0x24, 0x0a, 0x4a, 0xb0, 0x6b, 0x1c, 0x70, 0x30, 0x0e, - 0x34, 0xf1, 0xfa, 0x5b, 0xaa, 0x63, 0xb0, 0x71, 0x8e, 0x42, 0x1a, 0x20, 0xc9, 0xf8, 0x29, 0x91, - 0xe9, 0x00, 0x3e, 0x41, 0xf8, 0x82, 0x48, 0x61, 0x7a, 0x50, 0x0f, 0xa9, 0x90, 0x59, 0x66, 0xdd, - 0xb9, 0x36, 0xb3, 0x92, 0x5d, 0xe7, 0x3a, 0x90, 0x43, 0x24, 0x51, 0x56, 0xbb, 0x1a, 0xcb, 0xfe, - 0x2e, 0xac, 0x7d, 0x84, 0xe4, 0x80, 0x93, 0x60, 0x24, 0xc6, 0x2b, 0x50, 0x53, 0xf1, 0x33, 0x74, - 0xfc, 0xd4, 0xa3, 0xda, 0x07, 0xac, 0x7b, 0x9f, 0xc4, 0x8c, 0x4b, 0x12, 0x5c, 0xf2, 0xc8, 0x4b, - 0xdc, 0x7b, 0x01, 0x6b, 0xca, 0x59, 0x82, 0x44, 0x81, 0x5f, 0xdc, 0x33, 0x8d, 0x63, 0x73, 0xef, - 0xc7, 0x13, 0x55, 0xc7, 0xb8, 0xba, 0xec, 0x02, 0xab, 0xc9, 0x18, 0x5d, 0xd8, 0xbf, 0x35, 0xc0, - 0x3a, 0x26, 0xc3, 0x7d, 0x21, 0x68, 0x37, 0xea, 0x93, 0x48, 0xaa, 0x1e, 0x88, 0x30, 0x51, 0x8f, - 0xe6, 0x1b, 0xb0, 0x58, 0xcc, 0x5c, 0x3d, 0x6a, 0x0d, 0x3d, 0x6a, 0x17, 0x72, 0xa2, 0x2a, 0x30, - 0xf3, 0x2e, 0x40, 0xcc, 0x49, 0xe2, 0x63, 0xff, 0x82, 0x0c, 0xb3, 0x28, 0x6e, 0x56, 0x47, 0x68, - 0xfa, 0x7b, 0xd2, 0x39, 0x19, 0x74, 0x42, 0x8a, 0x8f, 0xc9, 0xd0, 0x9b, 0x57, 0xfc, 0xed, 0x63, - 0x32, 0x54, 0x3b, 0x51, 0xcc, 0x9e, 0x11, 0xae, 0xe7, 0x5e, 0xcd, 0x4b, 0x5f, 0xec, 0xdf, 0x19, - 0x70, 0xa3, 0x08, 0x47, 0x9e, 0xae, 0x27, 0x83, 0x8e, 0x92, 0x78, 0x89, 0xdf, 0x2e, 0x59, 0x3b, - 0x7d, 0x85, 0xb5, 0xef, 0xc1, 0x42, 0x51, 0x20, 0xca, 0xde, 0xda, 0x04, 0xf6, 0x36, 0x73, 0x89, - 0x63, 0x32, 0xb4, 0x7f, 0x59, 0xb1, 0xed, 0x60, 0x58, 0xe9, 0x7d, 0xfc, 0xbf, 0xd8, 0x56, 0xa8, - 0xad, 0xda, 0x86, 0xab, 0xf2, 0x97, 0x2e, 0x50, 0xbb, 0x7c, 0x01, 0xfb, 0x0f, 0x06, 0xac, 0x57, - 0xb5, 0x8a, 0x33, 0x76, 0xc2, 0x07, 0x11, 0x79, 0x99, 0xf6, 0xb2, 0xfc, 0xa6, 0xab, 0xe5, 0xf7, - 0x18, 0x96, 0x46, 0x8c, 0x12, 0x99, 0x37, 0x7e, 0x38, 0x51, 0x8e, 0x55, 0xba, 0xab, 0xb7, 0x58, - 0xbd, 0x87, 0xb0, 0xff, 0x64, 0xc0, 0x6a, 0x6e, 0x63, 0xe1, 0x2c, 0xf3, 0x07, 0x60, 0x16, 0xd7, - 0x2b, 0xb7, 0xb7, 0x34, 0xa5, 0x56, 0xf2, 0x93, 0x7c, 0x75, 0x2b, 0x53, 0x63, 0xba, 0x92, 0x1a, - 0xe6, 0x87, 0xb0, 0x56, 0x98, 0x1c, 0xeb, 0x00, 0x4d, 0x1c, 0xc5, 0x62, 0x3f, 0x2d, 0x48, 0xf6, - 0xaf, 0x8d, 0x72, 0x1c, 0xa6, 0xf3, 0x58, 0xec, 0x87, 0x61, 0xb6, 0xd4, 0x9b, 0x31, 0xcc, 0xa5, - 0x23, 0x5f, 0x64, 0xfd, 0x63, 0xf3, 0xca, 0xe1, 0x7e, 0x48, 0xb0, 0x9e, 0xef, 0x77, 0x54, 0x89, - 0xfd, 0xe5, 0xeb, 0xad, 0xb7, 0xbb, 0x54, 0xf6, 0x06, 0x1d, 0x07, 0xb3, 0xbe, 0x9b, 0x7d, 0x0f, - 0x49, 0xff, 0xdd, 0x16, 0xc1, 0x85, 0x2b, 0x87, 0x31, 0x11, 0xb9, 0x8c, 0xf8, 0xf3, 0x3f, 0xff, - 0xf6, 0x7d, 0xc3, 0xcb, 0xd5, 0xd8, 0xbf, 0x31, 0x60, 0xe5, 0x51, 0x2c, 0x49, 0x70, 0x14, 0x95, - 0x6e, 0x9b, 0xa8, 0x08, 0x6f, 0xc1, 0x82, 0x5e, 0x0d, 0xf2, 0x8f, 0x1a, 0xa9, 0xd3, 0x9a, 0x9a, - 0x96, 0x7d, 0xb0, 0xb8, 0xb2, 0xd6, 0xd4, 0x9c, 0xab, 0xf8, 0x31, 0x5d, 0xa5, 0x1b, 0x71, 0xee, - 0xa1, 0x83, 0xc7, 0x5f, 0x3c, 0x6f, 0x19, 0x5f, 0x3e, 0x6f, 0x19, 0xff, 0x78, 0xde, 0x32, 0x3e, - 0x7d, 0xd1, 0x9a, 0xfa, 0xf2, 0x45, 0x6b, 0xea, 0xef, 0x2f, 0x5a, 0x53, 0x3f, 0x7f, 0xf7, 0xf2, - 0x35, 0xcb, 0xac, 0xb9, 0x5d, 0x7c, 0x13, 0x4b, 0x7e, 0xe4, 0x7e, 0x32, 0xfa, 0xc5, 0x4d, 0x7b, - 0xa0, 0x33, 0xab, 0xfb, 0xfb, 0x3b, 0xff, 0x09, 0x00, 0x00, 0xff, 0xff, 0x5d, 0x12, 0x76, 0xb8, - 0xa2, 0x13, 0x00, 0x00, + // 1852 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0x4d, 0x6f, 0x1c, 0xc7, + 0xd1, 0xe6, 0x70, 0x97, 0x1f, 0x5b, 0xcb, 0xcf, 0x21, 0x6d, 0x0d, 0xf5, 0xf2, 0x5d, 0x52, 0xe3, + 0xd8, 0x61, 0xa2, 0x68, 0x26, 0xa4, 0x13, 0x40, 0x10, 0x62, 0x18, 0xe4, 0x52, 0xb6, 0x28, 0xda, + 0x12, 0x3d, 0x64, 0x28, 0x24, 0x39, 0x0c, 0x7a, 0x7b, 0x5a, 0xbb, 0x0d, 0xce, 0x4e, 0x8f, 0xba, + 0x7b, 0x47, 0xde, 0x4b, 0xce, 0xb9, 0x04, 0x70, 0x6e, 0x46, 0x2e, 0x71, 0x02, 0x04, 0x08, 0x72, + 0x49, 0x7e, 0x86, 0x8f, 0x3e, 0xe6, 0x64, 0x07, 0xd2, 0x21, 0x87, 0x5c, 0xf3, 0x03, 0x82, 0xee, + 0xf9, 0xdc, 0x25, 0xa9, 0xac, 0xe0, 0xe4, 0x42, 0xce, 0x54, 0x57, 0x3d, 0x55, 0xdd, 0x55, 0xf5, + 0x54, 0xef, 0xc0, 0x1e, 0x8d, 0x24, 0xe1, 0xb8, 0x87, 0x68, 0xe4, 0x0b, 0x82, 0x07, 0x9c, 0xca, + 0xa1, 0x8b, 0x71, 0xe2, 0xc6, 0x9c, 0x25, 0x34, 0x20, 0xdc, 0x4d, 0x76, 0x8b, 0x67, 0x27, 0xe6, + 0x4c, 0x32, 0xf3, 0xad, 0x2b, 0x6c, 0x1c, 0x8c, 0x13, 0xa7, 0xd0, 0x4b, 0x76, 0x6f, 0xbe, 0x7d, + 0x1d, 0x70, 0xb2, 0xeb, 0x3e, 0xa7, 0x9c, 0xa4, 0x58, 0x37, 0xd7, 0xbb, 0xac, 0xcb, 0xf4, 0xa3, + 0xab, 0x9e, 0x32, 0xe9, 0x56, 0x97, 0xb1, 0x6e, 0x48, 0x5c, 0xfd, 0xd6, 0x19, 0x3c, 0x75, 0x25, + 0xed, 0x13, 0x21, 0x51, 0x3f, 0xce, 0x14, 0x5a, 0xe3, 0x0a, 0xc1, 0x80, 0x23, 0x49, 0x59, 0x94, + 0x03, 0xd0, 0x0e, 0x76, 0x31, 0xe3, 0xc4, 0xc5, 0x21, 0x25, 0x91, 0x54, 0x5e, 0xd3, 0xa7, 0x4c, + 0xc1, 0x55, 0x0a, 0x21, 0xed, 0xf6, 0x64, 0x2a, 0x16, 0xae, 0x24, 0x51, 0x40, 0x78, 0x9f, 0xa6, + 0xca, 0xe5, 0x5b, 0x66, 0xb0, 0x59, 0x59, 0xc7, 0x7c, 0x18, 0x4b, 0xe6, 0x5e, 0x90, 0xa1, 0xc8, + 0x56, 0xdf, 0xc1, 0x4c, 0xf4, 0x99, 0x70, 0x89, 0xda, 0x7f, 0x84, 0x89, 0x9b, 0xec, 0x76, 0x88, + 0x44, 0xbb, 0x85, 0x20, 0x8f, 0x3b, 0xd3, 0xeb, 0x20, 0x51, 0xea, 0x60, 0x46, 0xf3, 0xb8, 0x57, + 0x51, 0x9f, 0x46, 0xcc, 0xd5, 0x7f, 0x53, 0x91, 0xfd, 0xaf, 0x59, 0xb0, 0xda, 0x2c, 0x12, 0x83, + 0x3e, 0xe1, 0xfb, 0x41, 0x40, 0xd5, 0x2e, 0x4f, 0x38, 0x8b, 0x99, 0x40, 0xa1, 0xb9, 0x0e, 0x33, + 0x92, 0xca, 0x90, 0x58, 0xc6, 0xb6, 0xb1, 0xd3, 0xf0, 0xd2, 0x17, 0x73, 0x1b, 0x9a, 0x01, 0x11, + 0x98, 0xd3, 0x58, 0x29, 0x5b, 0xd3, 0x7a, 0xad, 0x2a, 0x32, 0x37, 0x60, 0x3e, 0x4d, 0x0d, 0x0d, + 0xac, 0x9a, 0x5e, 0x9e, 0xd3, 0xef, 0x47, 0x81, 0xf9, 0x21, 0x2c, 0xd1, 0x88, 0x4a, 0x8a, 0x42, + 0xbf, 0x47, 0xd4, 0x01, 0x59, 0xf5, 0x6d, 0x63, 0xa7, 0xb9, 0x77, 0xd3, 0xa1, 0x1d, 0xec, 0xa8, + 0x33, 0x75, 0xb2, 0x93, 0x4c, 0x76, 0x9d, 0x07, 0x5a, 0xe3, 0xa0, 0xfe, 0xe5, 0xd7, 0x5b, 0x53, + 0xde, 0x62, 0x66, 0x97, 0x0a, 0xcd, 0x5b, 0xb0, 0xd0, 0x25, 0x11, 0x11, 0x54, 0xf8, 0x3d, 0x24, + 0x7a, 0xd6, 0xcc, 0xb6, 0xb1, 0xb3, 0xe0, 0x35, 0x33, 0xd9, 0x03, 0x24, 0x7a, 0xe6, 0x16, 0x34, + 0x3b, 0x34, 0x42, 0x7c, 0x98, 0x6a, 0xcc, 0x6a, 0x0d, 0x48, 0x45, 0x5a, 0xa1, 0x0d, 0x20, 0x62, + 0xf4, 0x3c, 0xf2, 0x55, 0x01, 0x58, 0x73, 0x59, 0x20, 0x69, 0xf2, 0x9d, 0x3c, 0xf9, 0xce, 0x59, + 0x5e, 0x1d, 0x07, 0xf3, 0x2a, 0x90, 0xcf, 0xbe, 0xd9, 0x32, 0xbc, 0x86, 0xb6, 0x53, 0x2b, 0xe6, + 0x23, 0x58, 0x19, 0x44, 0x1d, 0x16, 0x05, 0x34, 0xea, 0xfa, 0x31, 0xe1, 0x94, 0x05, 0xd6, 0xbc, + 0x86, 0xda, 0xb8, 0x04, 0x75, 0x98, 0xd5, 0x51, 0x8a, 0xf4, 0xb9, 0x42, 0x5a, 0x2e, 0x8c, 0x4f, + 0xb4, 0xad, 0xf9, 0x09, 0x98, 0x18, 0x27, 0x3a, 0x24, 0x36, 0x90, 0x39, 0x62, 0x63, 0x72, 0xc4, + 0x15, 0x8c, 0x93, 0xb3, 0xd4, 0x3a, 0x83, 0xfc, 0x05, 0xdc, 0x90, 0x1c, 0x45, 0xe2, 0x29, 0xe1, + 0xe3, 0xb8, 0x30, 0x39, 0xee, 0x1b, 0x39, 0xc6, 0x28, 0xf8, 0x03, 0xd8, 0xc6, 0x59, 0x01, 0xf9, + 0x9c, 0x04, 0x54, 0x48, 0x4e, 0x3b, 0x03, 0x65, 0xeb, 0x3f, 0xe5, 0x08, 0xeb, 0x1a, 0x69, 0xea, + 0x22, 0x68, 0xe5, 0x7a, 0xde, 0x88, 0xda, 0x07, 0x99, 0x96, 0xf9, 0x18, 0xbe, 0xd3, 0x09, 0x19, + 0xbe, 0x10, 0x2a, 0x38, 0x7f, 0x04, 0x49, 0xbb, 0xee, 0x53, 0x21, 0x14, 0xda, 0xc2, 0xb6, 0xb1, + 0x53, 0xf3, 0x6e, 0xa5, 0xba, 0x27, 0x84, 0x1f, 0x56, 0x34, 0xcf, 0x2a, 0x8a, 0xe6, 0x1d, 0x30, + 0x7b, 0x54, 0x48, 0xc6, 0x29, 0x46, 0xa1, 0x4f, 0x22, 0xc9, 0x29, 0x11, 0xd6, 0xa2, 0x36, 0x5f, + 0x2d, 0x57, 0xee, 0xa7, 0x0b, 0xe6, 0x43, 0xb8, 0x75, 0xad, 0x53, 0x1f, 0xf7, 0x50, 0x14, 0x91, + 0xd0, 0x5a, 0xd2, 0x5b, 0xd9, 0x0a, 0xae, 0xf1, 0xd9, 0x4e, 0xd5, 0xcc, 0x35, 0x98, 0x91, 0x2c, + 0xf6, 0x1f, 0x59, 0xcb, 0xdb, 0xc6, 0xce, 0xa2, 0x57, 0x97, 0x2c, 0x7e, 0x74, 0x6f, 0xfe, 0x57, + 0x5f, 0x6c, 0x4d, 0x7d, 0xfe, 0xc5, 0xd6, 0x94, 0xfd, 0x17, 0x03, 0x6e, 0xb4, 0x8b, 0xd3, 0xe8, + 0xb3, 0x04, 0x85, 0xff, 0xcb, 0xae, 0xdb, 0x87, 0x86, 0x50, 0xe1, 0xe8, 0x3a, 0xaf, 0xbf, 0x46, + 0x9d, 0xcf, 0x2b, 0x33, 0xb5, 0x60, 0xff, 0xce, 0x80, 0xf5, 0xfb, 0xcf, 0x06, 0x34, 0x61, 0x18, + 0xfd, 0x57, 0x48, 0xe2, 0x18, 0x16, 0x49, 0x05, 0x4f, 0x58, 0xb5, 0xed, 0xda, 0x4e, 0x73, 0xef, + 0x6d, 0x27, 0x25, 0x31, 0xa7, 0xe0, 0xb6, 0x8c, 0xc8, 0x9c, 0xaa, 0x77, 0x6f, 0xd4, 0xf6, 0xde, + 0xb4, 0x65, 0xd8, 0x7f, 0x30, 0xe0, 0xa6, 0x3a, 0xfe, 0x2e, 0xf1, 0xc8, 0x73, 0xc4, 0x83, 0x43, + 0x12, 0xb1, 0xbe, 0xf8, 0xd6, 0x71, 0xda, 0xb0, 0x18, 0x68, 0x24, 0x5f, 0x32, 0x1f, 0x05, 0x81, + 0x8e, 0x53, 0xeb, 0x28, 0xe1, 0x19, 0xdb, 0x0f, 0x02, 0x73, 0x07, 0x56, 0x4a, 0x1d, 0xae, 0xf2, + 0xa9, 0x8e, 0x59, 0xa9, 0x2d, 0xe5, 0x6a, 0x3a, 0xcb, 0xc4, 0xfe, 0xa7, 0x01, 0x2b, 0x1f, 0x86, + 0xac, 0x83, 0xc2, 0xd3, 0x10, 0x89, 0x9e, 0x2a, 0xbd, 0xa1, 0x4a, 0x0f, 0x27, 0x59, 0xcf, 0xeb, + 0xf0, 0x26, 0x4e, 0x8f, 0x32, 0xd3, 0x2c, 0xf4, 0x3e, 0xac, 0x16, 0x5d, 0x58, 0x54, 0x81, 0xde, + 0xcd, 0xc1, 0xda, 0x8b, 0xaf, 0xb7, 0x96, 0xf3, 0x62, 0x6b, 0xeb, 0x8a, 0x38, 0xf4, 0x96, 0xf1, + 0x88, 0x20, 0x30, 0x5b, 0xd0, 0xa4, 0x1d, 0xec, 0x0b, 0xf2, 0xcc, 0x8f, 0x06, 0x7d, 0x5d, 0x40, + 0x75, 0xaf, 0x41, 0x3b, 0xf8, 0x94, 0x3c, 0x7b, 0x34, 0xe8, 0x9b, 0xef, 0xc2, 0x9b, 0xf9, 0x00, + 0xf6, 0x13, 0x14, 0xfa, 0xca, 0x5e, 0x1d, 0x07, 0xd7, 0xf5, 0xb4, 0xe0, 0xad, 0xe5, 0xab, 0xe7, + 0x28, 0x54, 0xce, 0xf6, 0x83, 0x80, 0xdb, 0x2f, 0x67, 0x60, 0xf6, 0x04, 0x71, 0xd4, 0x17, 0xe6, + 0x19, 0x2c, 0x4b, 0xd2, 0x8f, 0x43, 0x24, 0x89, 0x9f, 0x32, 0x7c, 0xb6, 0xd3, 0xdb, 0x9a, 0xf9, + 0xab, 0xc3, 0xd2, 0xa9, 0x8c, 0xc7, 0x64, 0xd7, 0x69, 0x6b, 0xe9, 0xa9, 0x44, 0x92, 0x78, 0x4b, + 0x39, 0x46, 0x2a, 0x34, 0xef, 0x82, 0x25, 0xf9, 0x40, 0xc8, 0x92, 0x7b, 0x4b, 0xd2, 0x49, 0x73, + 0xf9, 0x66, 0xbe, 0x9e, 0xd2, 0x55, 0x41, 0x36, 0x57, 0xd3, 0x6c, 0xed, 0xdb, 0xd0, 0xec, 0x29, + 0xac, 0xa9, 0x19, 0x35, 0x8e, 0x59, 0x9f, 0x1c, 0x73, 0x55, 0xd9, 0x8f, 0x82, 0x7e, 0x02, 0x66, + 0x22, 0xf0, 0x38, 0xe6, 0xcc, 0x6b, 0xc4, 0x99, 0x08, 0x3c, 0x0a, 0x19, 0xc0, 0xa6, 0x50, 0xc5, + 0xe7, 0xf7, 0x89, 0xd4, 0xa4, 0x1d, 0x87, 0x24, 0xa2, 0xa2, 0x97, 0x83, 0xcf, 0x4e, 0x0e, 0xbe, + 0xa1, 0x81, 0x3e, 0x56, 0x38, 0x5e, 0x0e, 0x93, 0x79, 0x69, 0x43, 0xeb, 0x6a, 0x2f, 0x45, 0x82, + 0xe6, 0x74, 0x82, 0xfe, 0xef, 0x0a, 0x88, 0x22, 0x4b, 0x02, 0xde, 0xa9, 0x0c, 0x17, 0xd5, 0xd5, + 0xbe, 0x6e, 0x28, 0x9f, 0x93, 0xae, 0x62, 0x60, 0x94, 0xce, 0x19, 0x42, 0x8a, 0x01, 0x99, 0xb1, + 0x87, 0xba, 0x02, 0x15, 0xcc, 0xd1, 0x66, 0x34, 0xca, 0x6e, 0x11, 0x76, 0x39, 0x83, 0x0a, 0x8e, + 0xf0, 0x2a, 0x58, 0x1f, 0x10, 0xa2, 0xba, 0xb9, 0x32, 0x87, 0x48, 0xcc, 0x70, 0x4f, 0xcf, 0xc9, + 0x9a, 0xb7, 0x54, 0xcc, 0x9c, 0xfb, 0x4a, 0xfa, 0xb0, 0x3e, 0x3f, 0xbf, 0xd2, 0xb0, 0xbf, 0x07, + 0x0d, 0xdd, 0xcc, 0xfb, 0xf8, 0x42, 0x98, 0x9b, 0xd0, 0x50, 0x5d, 0x41, 0x84, 0x20, 0xc2, 0x32, + 0x34, 0x07, 0x94, 0x02, 0x5b, 0xc2, 0xc6, 0x75, 0xb7, 0x2d, 0x61, 0x3e, 0x81, 0xb9, 0x98, 0xe8, + 0xab, 0x80, 0x36, 0x6c, 0xee, 0xbd, 0xe7, 0x4c, 0x70, 0x17, 0x76, 0xae, 0x03, 0xf4, 0x72, 0x34, + 0x9b, 0x97, 0x77, 0xbc, 0xb1, 0x61, 0x23, 0xcc, 0xf3, 0x71, 0xa7, 0x3f, 0x79, 0x2d, 0xa7, 0x63, + 0x78, 0xa5, 0xcf, 0xdb, 0xd0, 0xdc, 0x4f, 0xb7, 0xfd, 0x11, 0x15, 0xf2, 0xf2, 0xb1, 0x2c, 0x54, + 0x8f, 0xe5, 0x21, 0x2c, 0x65, 0x83, 0xf3, 0x8c, 0x69, 0x42, 0x32, 0xff, 0x1f, 0x20, 0x9b, 0xb8, + 0x8a, 0xc8, 0x52, 0xca, 0x6e, 0x64, 0x92, 0xa3, 0x60, 0x64, 0xd6, 0x4d, 0x8f, 0xcc, 0x3a, 0xdb, + 0x83, 0xe5, 0x73, 0x81, 0x7f, 0x9a, 0xdf, 0xaa, 0x1e, 0xc7, 0xc2, 0x7c, 0x03, 0x66, 0x55, 0x0f, + 0x65, 0x40, 0x75, 0x6f, 0x26, 0x11, 0xf8, 0x48, 0xb3, 0x76, 0x79, 0x73, 0x63, 0xb1, 0x4f, 0x03, + 0x61, 0x4d, 0x6f, 0xd7, 0x76, 0xea, 0xde, 0xd2, 0xa0, 0x34, 0x3f, 0x0a, 0x84, 0xfd, 0x33, 0x68, + 0x56, 0x00, 0xcd, 0x25, 0x98, 0x2e, 0xb0, 0xa6, 0x69, 0x60, 0xde, 0x83, 0x8d, 0x12, 0x68, 0x94, + 0x86, 0x53, 0xc4, 0x86, 0x77, 0xa3, 0x50, 0x18, 0x61, 0x62, 0x61, 0x3f, 0x86, 0xf5, 0xa3, 0xb2, + 0xe9, 0x0b, 0x92, 0x1f, 0xd9, 0xa1, 0x31, 0x3a, 0xcd, 0x37, 0xa1, 0x51, 0xfc, 0x62, 0xd1, 0xbb, + 0xaf, 0x7b, 0xa5, 0xc0, 0xee, 0xc3, 0xca, 0xb9, 0xc0, 0xa7, 0x24, 0x0a, 0x4a, 0xb0, 0x6b, 0x0e, + 0xe0, 0x60, 0x1c, 0x68, 0xe2, 0xeb, 0x6f, 0xe9, 0x8e, 0xc1, 0xc6, 0x39, 0x0a, 0x69, 0x80, 0x24, + 0xe3, 0xa7, 0x44, 0xa6, 0x03, 0xf8, 0x04, 0xe1, 0x0b, 0x22, 0x85, 0xe9, 0x41, 0x3d, 0xa4, 0x42, + 0x66, 0x95, 0x75, 0xf7, 0xda, 0xca, 0x4a, 0x76, 0x9d, 0xeb, 0x40, 0x0e, 0x91, 0x44, 0x59, 0xef, + 0x6a, 0x2c, 0xfb, 0xbb, 0xb0, 0xf6, 0x31, 0x92, 0x03, 0x4e, 0x82, 0x91, 0x1c, 0xaf, 0x40, 0x4d, + 0xe5, 0xcf, 0xd0, 0xf9, 0x53, 0x8f, 0xea, 0x3e, 0x60, 0xdd, 0xff, 0x34, 0x66, 0x5c, 0x92, 0xe0, + 0xd2, 0x89, 0xbc, 0xe2, 0x78, 0x2f, 0x60, 0x4d, 0x1d, 0x96, 0x20, 0x51, 0xe0, 0x17, 0xfb, 0x4c, + 0xf3, 0xd8, 0xdc, 0xfb, 0xf1, 0x44, 0xdd, 0x31, 0xee, 0x2e, 0xdb, 0xc0, 0x6a, 0x32, 0x26, 0x17, + 0xf6, 0x6f, 0x0c, 0xb0, 0x8e, 0xc9, 0x70, 0x5f, 0x08, 0xda, 0x8d, 0xfa, 0x24, 0x92, 0x8a, 0x03, + 0x11, 0x26, 0xea, 0xd1, 0x7c, 0x0b, 0x16, 0x8b, 0x99, 0xab, 0x47, 0xad, 0xa1, 0x47, 0xed, 0x42, + 0x2e, 0x54, 0x0d, 0x66, 0xde, 0x03, 0x88, 0x39, 0x49, 0x7c, 0xec, 0x5f, 0x90, 0x61, 0x96, 0xc5, + 0xcd, 0xea, 0x08, 0x4d, 0x7f, 0x4f, 0x3a, 0x27, 0x83, 0x4e, 0x48, 0xf1, 0x31, 0x19, 0x7a, 0xf3, + 0x4a, 0xbf, 0x7d, 0x4c, 0x86, 0xea, 0x4e, 0x14, 0xb3, 0xe7, 0x84, 0xeb, 0xb9, 0x57, 0xf3, 0xd2, + 0x17, 0xfb, 0xb7, 0x06, 0xdc, 0x28, 0xd2, 0x91, 0x97, 0xeb, 0xc9, 0xa0, 0xa3, 0x2c, 0x5e, 0x71, + 0x6e, 0x97, 0xa2, 0x9d, 0xbe, 0x22, 0xda, 0xf7, 0x61, 0xa1, 0x68, 0x10, 0x15, 0x6f, 0x6d, 0x82, + 0x78, 0x9b, 0xb9, 0xc5, 0x31, 0x19, 0xda, 0xbf, 0xac, 0xc4, 0x76, 0x30, 0xac, 0x70, 0x1f, 0xff, + 0x0f, 0xb1, 0x15, 0x6e, 0xab, 0xb1, 0xe1, 0xaa, 0xfd, 0xa5, 0x0d, 0xd4, 0x2e, 0x6f, 0xc0, 0xfe, + 0xbd, 0x01, 0xeb, 0x55, 0xaf, 0xe2, 0x8c, 0x9d, 0xf0, 0x41, 0x44, 0x5e, 0xe5, 0xbd, 0x6c, 0xbf, + 0xe9, 0x6a, 0xfb, 0x3d, 0x81, 0xa5, 0x91, 0xa0, 0x44, 0x76, 0x1a, 0x3f, 0x9c, 0xa8, 0xc6, 0x2a, + 0xec, 0xea, 0x2d, 0x56, 0xf7, 0x21, 0xec, 0x3f, 0x1a, 0xb0, 0x9a, 0xc7, 0x58, 0x1c, 0x96, 0xf9, + 0x03, 0x30, 0x8b, 0xed, 0x95, 0xb7, 0xb7, 0xb4, 0xa4, 0x56, 0xf2, 0x95, 0xfc, 0xea, 0x56, 0x96, + 0xc6, 0x74, 0xa5, 0x34, 0xcc, 0x8f, 0x60, 0xad, 0x08, 0x39, 0xd6, 0x09, 0x9a, 0x38, 0x8b, 0xc5, + 0xfd, 0xb4, 0x10, 0xd9, 0xbf, 0x36, 0xca, 0x71, 0x98, 0xce, 0x63, 0xb1, 0x1f, 0x86, 0xd9, 0xa5, + 0xde, 0x8c, 0x61, 0x2e, 0x1d, 0xf9, 0x22, 0xe3, 0x8f, 0xcd, 0x2b, 0x87, 0xfb, 0x21, 0xc1, 0x7a, + 0xbe, 0xdf, 0x55, 0x2d, 0xf6, 0xe7, 0x6f, 0xb6, 0x6e, 0x77, 0xa9, 0xec, 0x0d, 0x3a, 0x0e, 0x66, + 0x7d, 0x37, 0xfb, 0x1e, 0x92, 0xfe, 0xbb, 0x23, 0x82, 0x0b, 0x57, 0x0e, 0x63, 0x22, 0x72, 0x1b, + 0xf1, 0xa7, 0x7f, 0xfc, 0xf5, 0xfb, 0x86, 0x97, 0xbb, 0x39, 0x78, 0xf2, 0xe5, 0x8b, 0x96, 0xf1, + 0xd5, 0x8b, 0x96, 0xf1, 0xf7, 0x17, 0x2d, 0xe3, 0xb3, 0x97, 0xad, 0xa9, 0xaf, 0x5e, 0xb6, 0xa6, + 0xfe, 0xf6, 0xb2, 0x35, 0xf5, 0xf3, 0xf7, 0x2e, 0x83, 0x96, 0x39, 0xba, 0x53, 0x7c, 0x81, 0x4a, + 0x7e, 0xe4, 0x7e, 0x3a, 0xfa, 0x7d, 0x4b, 0xfb, 0xeb, 0xcc, 0x6a, 0x36, 0x7d, 0xf7, 0xdf, 0x01, + 0x00, 0x00, 0xff, 0xff, 0x8f, 0xff, 0x87, 0xe4, 0x10, 0x13, 0x00, 0x00, } func (m *ConsumerAdditionProposal) Marshal() (dAtA []byte, err error) { @@ -2897,53 +2819,6 @@ func (m *ConsumerRewardsAllocation) MarshalToSizedBuffer(dAtA []byte) (int, erro return len(dAtA) - i, nil } -func (m *OptedInValidator) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *OptedInValidator) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *OptedInValidator) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.PublicKey) > 0 { - i -= len(m.PublicKey) - copy(dAtA[i:], m.PublicKey) - i = encodeVarintProvider(dAtA, i, uint64(len(m.PublicKey))) - i-- - dAtA[i] = 0x22 - } - if m.Power != 0 { - i = encodeVarintProvider(dAtA, i, uint64(m.Power)) - i-- - dAtA[i] = 0x18 - } - if m.BlockHeight != 0 { - i = encodeVarintProvider(dAtA, i, uint64(m.BlockHeight)) - i-- - dAtA[i] = 0x10 - } - if len(m.ProviderAddr) > 0 { - i -= len(m.ProviderAddr) - copy(dAtA[i:], m.ProviderAddr) - i = encodeVarintProvider(dAtA, i, uint64(len(m.ProviderAddr))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - func encodeVarintProvider(dAtA []byte, offset int, v uint64) int { offset -= sovProvider(v) base := offset @@ -3453,29 +3328,6 @@ func (m *ConsumerRewardsAllocation) Size() (n int) { return n } -func (m *OptedInValidator) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.ProviderAddr) - if l > 0 { - n += 1 + l + sovProvider(uint64(l)) - } - if m.BlockHeight != 0 { - n += 1 + sovProvider(uint64(m.BlockHeight)) - } - if m.Power != 0 { - n += 1 + sovProvider(uint64(m.Power)) - } - l = len(m.PublicKey) - if l > 0 { - n += 1 + l + sovProvider(uint64(l)) - } - return n -} - func sovProvider(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -7011,162 +6863,6 @@ func (m *ConsumerRewardsAllocation) Unmarshal(dAtA []byte) error { } return nil } -func (m *OptedInValidator) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProvider - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: OptedInValidator: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: OptedInValidator: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ProviderAddr", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProvider - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthProvider - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthProvider - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ProviderAddr = append(m.ProviderAddr[:0], dAtA[iNdEx:postIndex]...) - if m.ProviderAddr == nil { - m.ProviderAddr = []byte{} - } - iNdEx = postIndex - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field BlockHeight", wireType) - } - m.BlockHeight = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProvider - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.BlockHeight |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Power", wireType) - } - m.Power = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProvider - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Power |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PublicKey", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProvider - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthProvider - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthProvider - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.PublicKey = append(m.PublicKey[:0], dAtA[iNdEx:postIndex]...) - if m.PublicKey == nil { - m.PublicKey = []byte{} - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipProvider(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthProvider - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func skipProvider(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/ccv/types/expected_keepers.go b/x/ccv/types/expected_keepers.go index aaff34d878..73566926ec 100644 --- a/x/ccv/types/expected_keepers.go +++ b/x/ccv/types/expected_keepers.go @@ -156,6 +156,4 @@ type ScopedKeeper interface { type GovKeeper interface { GetProposal(ctx sdk.Context, proposalID uint64) (v1.Proposal, bool) - GetProposals(ctx sdk.Context) (proposals v1.Proposals) - GetVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress) (vote v1.Vote, found bool) } From 72f5f66b9acac46691daaf1640b2dbc7467191be Mon Sep 17 00:00:00 2001 From: Simon Noetzlin Date: Tue, 26 Mar 2024 10:14:48 +0100 Subject: [PATCH 036/110] feat!: update PSS cli (#1708) finalize PSS CLI cmds --- x/ccv/provider/client/cli/tx.go | 45 +++++++++++++++++++++++++++++++++ x/ccv/provider/handler.go | 10 ++++++-- x/ccv/provider/types/msg.go | 9 +++++++ 3 files changed, 62 insertions(+), 2 deletions(-) diff --git a/x/ccv/provider/client/cli/tx.go b/x/ccv/provider/client/cli/tx.go index be77ecf6d8..87fea113d1 100644 --- a/x/ccv/provider/client/cli/tx.go +++ b/x/ccv/provider/client/cli/tx.go @@ -288,3 +288,48 @@ func NewOptOutCmd() *cobra.Command { return cmd } + +func NewSetConsumerCommissionRate() *cobra.Command { + cmd := &cobra.Command{ + Use: "set-consumer-commission-rate [consumer-chain-id] [commission-rate]", + Short: "set a per-consumer chain commission", + Long: strings.TrimSpace( + fmt.Sprintf(`Note that the "commission-rate" argument is a fraction and should be in the range [0,1]. + Example: + %s set-consumer-commission-rate consumer-1 0.5 --from node0 --home ../node0`, + version.AppName), + ), + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + txf, err := tx.NewFactoryCLI(clientCtx, cmd.Flags()) + if err != nil { + return err + } + txf = txf.WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever) + + providerValAddr := clientCtx.GetFromAddress() + + commission, err := sdk.NewDecFromStr(args[1]) + if err != nil { + return err + } + msg := types.NewMsgSetConsumerCommissionRate(args[0], commission, sdk.ValAddress(providerValAddr)) + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + _ = cmd.MarkFlagRequired(flags.FlagFrom) + + return cmd +} diff --git a/x/ccv/provider/handler.go b/x/ccv/provider/handler.go index cf176a86c1..d361ec34f7 100644 --- a/x/ccv/provider/handler.go +++ b/x/ccv/provider/handler.go @@ -23,8 +23,14 @@ func NewHandler(k *keeper.Keeper) sdk.Handler { case *types.MsgSubmitConsumerMisbehaviour: res, err := msgServer.SubmitConsumerMisbehaviour(sdk.WrapSDKContext(ctx), msg) return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgSubmitConsumerDoubleVoting: - res, err := msgServer.SubmitConsumerDoubleVoting(sdk.WrapSDKContext(ctx), msg) + case *types.MsgOptIn: + res, err := msgServer.OptIn(sdk.WrapSDKContext(ctx), msg) + return sdk.WrapServiceResult(ctx, res, err) + case *types.MsgOptOut: + res, err := msgServer.OptOut(sdk.WrapSDKContext(ctx), msg) + return sdk.WrapServiceResult(ctx, res, err) + case *types.MsgSetConsumerCommissionRate: + res, err := msgServer.SetConsumerCommissionRate(sdk.WrapSDKContext(ctx), msg) return sdk.WrapServiceResult(ctx, res, err) default: return nil, errorsmod.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", types.ModuleName, msg) diff --git a/x/ccv/provider/types/msg.go b/x/ccv/provider/types/msg.go index 1a8d6fa145..70f090a971 100644 --- a/x/ccv/provider/types/msg.go +++ b/x/ccv/provider/types/msg.go @@ -314,6 +314,15 @@ func (msg MsgOptOut) ValidateBasic() error { return nil } +// NewMsgSetConsumerCommissionRate creates a new MsgSetConsumerCommissionRate msg instance. +func NewMsgSetConsumerCommissionRate(chainID string, commission sdk.Dec, providerValidatorAddress sdk.ValAddress) *MsgSetConsumerCommissionRate { + return &MsgSetConsumerCommissionRate{ + ChainId: chainID, + Rate: commission, + ProviderAddr: providerValidatorAddress.String(), + } +} + // Type implements the sdk.Msg interface. func (msg MsgOptOut) Type() string { return TypeMsgOptOut From 8ed60ee83defe646e4638787a9bd2c6dd98064d8 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Tue, 26 Mar 2024 10:53:36 +0100 Subject: [PATCH 037/110] Rename and add comission rate command to commands --- x/ccv/provider/client/cli/tx.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x/ccv/provider/client/cli/tx.go b/x/ccv/provider/client/cli/tx.go index 87fea113d1..876aaa9b8b 100644 --- a/x/ccv/provider/client/cli/tx.go +++ b/x/ccv/provider/client/cli/tx.go @@ -36,6 +36,7 @@ func GetTxCmd() *cobra.Command { cmd.AddCommand(NewSubmitConsumerDoubleVotingCmd()) cmd.AddCommand(NewOptInCmd()) cmd.AddCommand(NewOptOutCmd()) + cmd.AddCommand(NewSetConsumerCommissionRateCmd()) return cmd } @@ -289,7 +290,7 @@ func NewOptOutCmd() *cobra.Command { return cmd } -func NewSetConsumerCommissionRate() *cobra.Command { +func NewSetConsumerCommissionRateCmd() *cobra.Command { cmd := &cobra.Command{ Use: "set-consumer-commission-rate [consumer-chain-id] [commission-rate]", Short: "set a per-consumer chain commission", From a6989bf3bd43f84b474ddf99501f409fb017bb79 Mon Sep 17 00:00:00 2001 From: insumity Date: Wed, 27 Mar 2024 15:16:30 +0100 Subject: [PATCH 038/110] feat!: only perform consumer additions for non-empty chains (#1730) * init commit * Update x/ccv/provider/keeper/proposal.go Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> --------- Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> --- x/ccv/provider/keeper/proposal.go | 9 ++- x/ccv/provider/keeper/proposal_test.go | 87 ++++++++++++++++++++++---- 2 files changed, 83 insertions(+), 13 deletions(-) diff --git a/x/ccv/provider/keeper/proposal.go b/x/ccv/provider/keeper/proposal.go index 360ff8f9d2..c0aa684243 100644 --- a/x/ccv/provider/keeper/proposal.go +++ b/x/ccv/provider/keeper/proposal.go @@ -383,6 +383,13 @@ func (k Keeper) BeginBlockInit(ctx sdk.Context) { propsToExecute := k.GetConsumerAdditionPropsToExecute(ctx) for _, prop := range propsToExecute { + if prop.Top_N == 0 && len(k.GetAllOptedIn(ctx, prop.ChainId)) == 0 { + // drop the proposal + ctx.Logger().Info("consumer client could not be created because no validator has"+ + " opted in for the Opt-In chain: %s", prop.ChainId) + continue + } + // create consumer client in a cached context to handle errors cachedCtx, writeFn, err := k.CreateConsumerClientInCachedCtx(ctx, prop) if err != nil { @@ -393,7 +400,7 @@ func (k Keeper) BeginBlockInit(ctx sdk.Context) { // Only set Top N at the moment a chain starts. If we were to do this earlier (e.g., during the proposal), // then someone could create a bogus ConsumerAdditionProposal to override the Top N for a specific chain. - k.SetTopN(ctx, prop.ChainId, prop.Top_N) + k.SetTopN(cachedCtx, prop.ChainId, prop.Top_N) // The cached context is created with a new EventManager so we merge the event // into the original context diff --git a/x/ccv/provider/keeper/proposal_test.go b/x/ccv/provider/keeper/proposal_test.go index 99e8c74e49..60c7dd6ce0 100644 --- a/x/ccv/provider/keeper/proposal_test.go +++ b/x/ccv/provider/keeper/proposal_test.go @@ -926,7 +926,7 @@ func TestBeginBlockInit(t *testing.T) { 100000000000, 100000000000, 100000000000, - 67, + 50, ).(*providertypes.ConsumerAdditionProposal), providertypes.NewConsumerAdditionProposal( "title", "spawn time passed", "chain2", clienttypes.NewHeight(3, 4), []byte{}, []byte{}, @@ -938,7 +938,7 @@ func TestBeginBlockInit(t *testing.T) { 100000000000, 100000000000, 100000000000, - 0, + 50, ).(*providertypes.ConsumerAdditionProposal), providertypes.NewConsumerAdditionProposal( "title", "spawn time not passed", "chain3", clienttypes.NewHeight(3, 4), []byte{}, []byte{}, @@ -950,7 +950,7 @@ func TestBeginBlockInit(t *testing.T) { 100000000000, 100000000000, 100000000000, - 0, + 50, ).(*providertypes.ConsumerAdditionProposal), providertypes.NewConsumerAdditionProposal( "title", "invalid proposal: chain id already exists", "chain2", clienttypes.NewHeight(4, 5), []byte{}, []byte{}, @@ -962,46 +962,109 @@ func TestBeginBlockInit(t *testing.T) { 100000000000, 100000000000, 100000000000, + 50, + ).(*providertypes.ConsumerAdditionProposal), + providertypes.NewConsumerAdditionProposal( + "title", "opt-in chain with no validator opted in", "chain4", clienttypes.NewHeight(3, 4), []byte{}, []byte{}, + now.Add(-time.Hour*2).UTC(), + "0.75", + 10, + "", + 10000, + 100000000000, + 100000000000, + 100000000000, + 0, + ).(*providertypes.ConsumerAdditionProposal), + providertypes.NewConsumerAdditionProposal( + "title", "opt-in chain with at least one validator opted in", "chain5", clienttypes.NewHeight(3, 4), []byte{}, []byte{}, + now.Add(-time.Hour*1).UTC(), + "0.75", + 10, + "", + 10000, + 100000000000, + 100000000000, + 100000000000, 0, ).(*providertypes.ConsumerAdditionProposal), } - // Expect client creation for only for the 1st and second proposals (spawn time already passed and valid) - gomock.InOrder( - append(testkeeper.GetMocksForCreateConsumerClient(ctx, &mocks, "chain1", clienttypes.NewHeight(3, 4)), - testkeeper.GetMocksForCreateConsumerClient(ctx, &mocks, "chain2", clienttypes.NewHeight(3, 4))...)..., - ) + // Expect client creation for only the first, second, and sixth proposals (spawn time already passed and valid) + expectedCalls := testkeeper.GetMocksForCreateConsumerClient(ctx, &mocks, "chain1", clienttypes.NewHeight(3, 4)) + expectedCalls = append(expectedCalls, testkeeper.GetMocksForCreateConsumerClient(ctx, &mocks, "chain2", clienttypes.NewHeight(3, 4))...) + expectedCalls = append(expectedCalls, testkeeper.GetMocksForCreateConsumerClient(ctx, &mocks, "chain5", clienttypes.NewHeight(3, 4))...) + + gomock.InOrder(expectedCalls...) for _, prop := range pendingProps { providerKeeper.SetPendingConsumerAdditionProp(ctx, prop) } + // opt in a sample validator so the chain's proposal can successfully execute + providerKeeper.SetOptedIn(ctx, pendingProps[5].ChainId, providertypes.OptedInValidator{ + ProviderAddr: []byte{1}, + BlockHeight: int64(2), + Power: int64(3), + PublicKey: []byte{4}, + }) + providerKeeper.BeginBlockInit(ctx) - // Only the third proposal is still stored as pending + // first proposal is not pending anymore because its spawn time already passed and was executed _, found := providerKeeper.GetPendingConsumerAdditionProp( ctx, pendingProps[0].SpawnTime, pendingProps[0].ChainId) require.False(t, found) + // first proposal was successfully executed and hence consumer genesis was created + _, found = providerKeeper.GetConsumerGenesis(ctx, pendingProps[0].ChainId) + require.True(t, found) + // second proposal is not pending anymore because its spawn time already passed and was executed _, found = providerKeeper.GetPendingConsumerAdditionProp( ctx, pendingProps[1].SpawnTime, pendingProps[1].ChainId) require.False(t, found) + // second proposal was successfully executed and hence consumer genesis was created + _, found = providerKeeper.GetConsumerGenesis(ctx, pendingProps[1].ChainId) + require.True(t, found) + // third proposal is still stored as pending because its spawn time has not passed _, found = providerKeeper.GetPendingConsumerAdditionProp( ctx, pendingProps[2].SpawnTime, pendingProps[2].ChainId) require.True(t, found) + // because the proposal is still pending, no consumer genesis was created + _, found = providerKeeper.GetConsumerGenesis(ctx, pendingProps[2].ChainId) + require.False(t, found) - // check that the invalid proposal was dropped + // check that the invalid proposals were dropped _, found = providerKeeper.GetPendingConsumerAdditionProp( ctx, pendingProps[3].SpawnTime, pendingProps[3].ChainId) require.False(t, found) + // Note that we do not check that `GetConsumerGenesis(ctx, pendingProps[3].ChainId)` returns `false` here because + //`pendingProps[3]` is an invalid proposal due to the chain id already existing so the consumer genesis also exists + + // fifth proposal is dropped due to it being an Opt-In chain with no validators opted in + _, found = providerKeeper.GetPendingConsumerAdditionProp( + ctx, pendingProps[4].SpawnTime, pendingProps[4].ChainId) + require.False(t, found) + // because the proposal is dropped, no consumer genesis was created + _, found = providerKeeper.GetConsumerGenesis(ctx, pendingProps[4].ChainId) + require.False(t, found) + + // sixth proposal corresponds to an Opt-In chain with one opted-in validator and hence the proposal gets + // successfully executed + _, found = providerKeeper.GetPendingConsumerAdditionProp( + ctx, pendingProps[5].SpawnTime, pendingProps[5].ChainId) + require.False(t, found) + // sixth proposal was successfully executed and hence consumer genesis was created + _, found = providerKeeper.GetConsumerGenesis(ctx, pendingProps[5].ChainId) + require.True(t, found) // test that Top N is set correctly require.True(t, providerKeeper.IsTopN(ctx, "chain1")) topN, found := providerKeeper.GetTopN(ctx, "chain1") - require.Equal(t, uint32(67), topN) + require.Equal(t, uint32(50), topN) - require.True(t, providerKeeper.IsOptIn(ctx, "chain2")) + require.True(t, providerKeeper.IsOptIn(ctx, "chain4")) } // TestBeginBlockCCR tests BeginBlockCCR against the spec. From bfe10dfc83969f0db43db4f4a916b361d7cc1581 Mon Sep 17 00:00:00 2001 From: Simon Noetzlin Date: Thu, 28 Mar 2024 14:30:04 +0100 Subject: [PATCH 039/110] feat: Add queries for PSS and consumer commission rate (#1733) * init commit * nit change * cleaning up * clean up * fix distribution test * Update x/ccv/provider/keeper/hooks.go Co-authored-by: Simon Noetzlin * took into Simon's comments * took into rest of the comments * nit change * return an error if validator cannot opt out from a Top N chain * removed automatic opt-in for validators that vote Yes on proposals * tiny fix for E2E tests * nit change to remove unecessary else * update consumer chains query to return topN * update query consu chains proto * add consumer chains per validator query * Add PSS command to provider's cli * nits * add consumer commission rate query * nits * big renaming * fix doc * nits * nits * docs * Update proto/interchain_security/ccv/provider/v1/query.proto Co-authored-by: insumity * nit * add OptedIn in QueryConsumerChainsValidatorHasToValidate * remove OptIn field in consumer chains query response * include validators that opt-in during the next epochs * update has-to-validate condition * fix tinny bug in the tests after merging feat/partial-security * update doc * update cli description * Update x/ccv/provider/keeper/grpc_query.go Co-authored-by: insumity * changes --------- Co-authored-by: insumity --- go.mod | 2 +- .../ccv/provider/v1/query.proto | 64 + x/ccv/provider/client/cli/query.go | 123 ++ x/ccv/provider/keeper/grpc_query.go | 120 +- x/ccv/provider/keeper/keeper.go | 8 +- x/ccv/provider/keeper/keeper_test.go | 8 +- x/ccv/provider/keeper/partial_set_security.go | 5 +- x/ccv/provider/keeper/proposal_test.go | 7 +- x/ccv/provider/types/query.pb.go | 1485 +++++++++++++++-- x/ccv/provider/types/query.pb.gw.go | 249 +++ 10 files changed, 1954 insertions(+), 117 deletions(-) diff --git a/go.mod b/go.mod index 83656ba35a..e055de44f7 100644 --- a/go.mod +++ b/go.mod @@ -29,8 +29,8 @@ require ( golang.org/x/net v0.20.0 // indirect golang.org/x/sys v0.16.0 // indirect google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 // indirect - google.golang.org/protobuf v1.33.0 google.golang.org/grpc v1.62.1 + google.golang.org/protobuf v1.33.0 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/proto/interchain_security/ccv/provider/v1/query.proto b/proto/interchain_security/ccv/provider/v1/query.proto index 56b06a42c3..6315d38a6b 100644 --- a/proto/interchain_security/ccv/provider/v1/query.proto +++ b/proto/interchain_security/ccv/provider/v1/query.proto @@ -10,6 +10,7 @@ import "interchain_security/ccv/provider/v1/provider.proto"; import "interchain_security/ccv/v1/shared_consumer.proto"; import "interchain_security/ccv/v1/wire.proto"; import "tendermint/crypto/keys.proto"; +import "cosmos_proto/cosmos.proto"; service Query { // ConsumerGenesis queries the genesis state needed to start a consumer chain @@ -99,6 +100,33 @@ service Query { option (google.api.http).get = "/interchain_security/ccv/provider/params"; } + + // QueryConsumerChainOptedInValidators returns a list of validators consensus addresses + // that opted-in to the given consumer chain + rpc QueryConsumerChainOptedInValidators( + QueryConsumerChainOptedInValidatorsRequest) + returns (QueryConsumerChainOptedInValidatorsResponse) { + option (google.api.http).get = + "/interchain_security/ccv/provider/opted_in_validators"; + } + + // QueryConsumerChainsValidatorHasToValidate returns a list of consumer chains + // that a given validator must validate + rpc QueryConsumerChainsValidatorHasToValidate( + QueryConsumerChainsValidatorHasToValidateRequest) + returns (QueryConsumerChainsValidatorHasToValidateResponse) { + option (google.api.http).get = + "/interchain_security/ccv/provider/consumer_chains_per_validator"; + } + + // QueryValidatorConsumerCommissionRate returns the commission rate a given + // validator charges on a given consumer chain + rpc QueryValidatorConsumerCommissionRate( + QueryValidatorConsumerCommissionRateRequest) + returns (QueryValidatorConsumerCommissionRateResponse) { + option (google.api.http).get = + "/interchain_security/ccv/provider/consumer_commission_rate"; + } } message QueryConsumerGenesisRequest { string chain_id = 1; } @@ -127,6 +155,8 @@ message QueryConsumerChainStopProposalsResponse { message Chain { string chain_id = 1; string client_id = 2; + // If chain with `chainID` is a Top-N chain, i.e., enforces at least one validator to validate chain `chainID` + uint32 top_N = 3; } message QueryValidatorConsumerAddrRequest { @@ -212,3 +242,37 @@ message QueryParamsResponse { Params params = 1 [(gogoproto.nullable) = false]; } + +message QueryConsumerChainOptedInValidatorsRequest { + string chain_id = 1; +} + +message QueryConsumerChainOptedInValidatorsResponse { + // The consensus addresses of the validators on the provider chain + repeated string validators_provider_addresses = 1; +} + + +message QueryConsumerChainsValidatorHasToValidateRequest { + // The consensus address of the validator on the provider chain + string provider_address = 1 [ (gogoproto.moretags) = "yaml:\"address\"" ]; +} + +message QueryConsumerChainsValidatorHasToValidateResponse { + repeated string consumer_chain_ids = 1; +} + +message QueryValidatorConsumerCommissionRateRequest { + string chain_id = 1; + // The consensus address of the validator on the provider chain + string provider_address = 2 [ (gogoproto.moretags) = "yaml:\"address\"" ]; +} + +message QueryValidatorConsumerCommissionRateResponse { + // The rate to charge delegators on the consumer chain, as a fraction + string rate = 1 [ + (cosmos_proto.scalar) = "cosmos.Dec", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; +} diff --git a/x/ccv/provider/client/cli/query.go b/x/ccv/provider/client/cli/query.go index 10b33322c6..91cd48f94c 100644 --- a/x/ccv/provider/client/cli/query.go +++ b/x/ccv/provider/client/cli/query.go @@ -35,6 +35,9 @@ func NewQueryCmd() *cobra.Command { cmd.AddCommand(CmdProposedConsumerChains()) cmd.AddCommand(CmdAllPairsValConAddrByConsumerChainID()) cmd.AddCommand(CmdProviderParameters()) + cmd.AddCommand(CmdConsumerChainOptedInValidators()) + cmd.AddCommand(CmdConsumerChainsValidatorHasToValidate()) + cmd.AddCommand(CmdValidatorConsumerCommissionRate()) return cmd } @@ -409,3 +412,123 @@ $ %s query provider params return cmd } + +// Command to query opted-in validators by consumer chain ID +func CmdConsumerChainOptedInValidators() *cobra.Command { + cmd := &cobra.Command{ + Use: "consumer-opted-in-validators [chainid]", + Short: "Query opted-in validators for a given consumer chain", + Long: strings.TrimSpace( + fmt.Sprintf(`Query opted-in validators for a given consumer chain. +Example: +$ %s consumer-opted-in-validators foochain + `, version.AppName), + ), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.QueryConsumerChainOptedInValidators(cmd.Context(), + &types.QueryConsumerChainOptedInValidatorsRequest{ChainId: args[0]}) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +// Command to query the consumer chains list a given validator has to validate +func CmdConsumerChainsValidatorHasToValidate() *cobra.Command { + bech32PrefixConsAddr := sdk.GetConfig().GetBech32ConsensusAddrPrefix() + cmd := &cobra.Command{ + Use: "has-to-validate [provider-validator-address]", + Short: "Query the consumer chains list a given validator has to validate", + Long: strings.TrimSpace( + fmt.Sprintf(`the list of consumer chains that as a validator, you need to be running right now, is always a subset of this, so it seems like a very nice "safe bet". +Example: +$ %s has-to-validate %s1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj + `, version.AppName, bech32PrefixConsAddr), + ), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + addr, err := sdk.ConsAddressFromBech32(args[0]) + if err != nil { + return err + } + + res, err := queryClient.QueryConsumerChainsValidatorHasToValidate(cmd.Context(), + &types.QueryConsumerChainsValidatorHasToValidateRequest{ + ProviderAddress: addr.String(), + }) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +// Command to query the consumer commission rate a validator charges +// on a consumer chain +func CmdValidatorConsumerCommissionRate() *cobra.Command { + bech32PrefixConsAddr := sdk.GetConfig().GetBech32ConsensusAddrPrefix() + cmd := &cobra.Command{ + Use: "validator-consumer-commission-rate [chainid] [provider-validator-address]", + Short: "Query the consumer commission rate a validator charges on a consumer chain", + Long: strings.TrimSpace( + fmt.Sprintf(`Query the consumer commission rate a validator charges on a consumer chain. +Example: +$ %s validator-consumer-commission-rate foochain %s1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj + `, version.AppName, bech32PrefixConsAddr), + ), + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + addr, err := sdk.ConsAddressFromBech32(args[1]) + if err != nil { + return err + } + + res, err := queryClient.QueryValidatorConsumerCommissionRate(cmd.Context(), + &types.QueryValidatorConsumerCommissionRateRequest{ + ChainId: args[0], + ProviderAddress: addr.String(), + }) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/ccv/provider/keeper/grpc_query.go b/x/ccv/provider/keeper/grpc_query.go index d190a5f8b0..f18ec48bfb 100644 --- a/x/ccv/provider/keeper/grpc_query.go +++ b/x/ccv/provider/keeper/grpc_query.go @@ -2,6 +2,7 @@ package keeper import ( "context" + "fmt" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -42,7 +43,6 @@ func (k Keeper) QueryConsumerChains(goCtx context.Context, req *types.QueryConsu ctx := sdk.UnwrapSDKContext(goCtx) - // convert to array of pointers chains := []*types.Chain{} for _, chain := range k.GetAllConsumerChains(ctx) { // prevent implicit memory aliasing @@ -221,3 +221,121 @@ func (k Keeper) QueryParams(c context.Context, _ *types.QueryParamsRequest) (*ty return &types.QueryParamsResponse{Params: params}, nil } + +// QueryConsumerChainOptedInValidators returns all validators that opted-in to a given consumer chain +func (k Keeper) QueryConsumerChainOptedInValidators(goCtx context.Context, req *types.QueryConsumerChainOptedInValidatorsRequest) (*types.QueryConsumerChainOptedInValidatorsResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + consumerChainID := req.ChainId + if consumerChainID == "" { + return nil, status.Error(codes.InvalidArgument, "empty chainId") + } + + optedInVals := []string{} + ctx := sdk.UnwrapSDKContext(goCtx) + + if !k.IsConsumerProposedOrRegistered(ctx, consumerChainID) { + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("unknown consumer chain: %s", consumerChainID)) + } + + for _, v := range k.GetAllOptedIn(ctx, ctx.ChainID()) { + optedInVals = append(optedInVals, v.ToSdkConsAddr().String()) + } + + return &types.QueryConsumerChainOptedInValidatorsResponse{ + ValidatorsProviderAddresses: optedInVals, + }, nil +} + +// QueryConsumerChainsValidatorHasToValidate returns all consumer chains that the given validator has to validate now +// or in the next epoch if nothing changes. +func (k Keeper) QueryConsumerChainsValidatorHasToValidate(goCtx context.Context, req *types.QueryConsumerChainsValidatorHasToValidateRequest) (*types.QueryConsumerChainsValidatorHasToValidateResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + if req.ProviderAddress == "" { + return nil, status.Error(codes.InvalidArgument, "empty provider address") + } + + consAddr, err := sdk.ConsAddressFromBech32(req.ProviderAddress) + if err != nil { + return nil, status.Error(codes.InvalidArgument, "invalid provider address") + } + + ctx := sdk.UnwrapSDKContext(goCtx) + + // get all the consumer chains for which the validator is either already + // opted-in, currently a consumer validator or if its voting power is within the TopN validators + consumersToValidate := []string{} + for _, consumer := range k.GetAllConsumerChains(ctx) { + chainID := consumer.ChainId + provAddr := types.NewProviderConsAddress(consAddr) + if !k.IsOptedIn(ctx, chainID, provAddr) && !k.IsConsumerValidator(ctx, chainID, provAddr) { + // check that the validator voting power isn't in the TopN + if topN, found := k.GetTopN(ctx, chainID); found && topN > 0 { + val, found := k.stakingKeeper.GetValidatorByConsAddr(ctx, consAddr) + if !found { + return nil, status.Error(codes.InvalidArgument, "invalid provider address") + } + power := k.stakingKeeper.GetLastValidatorPower(ctx, val.GetOperator()) + minPowerToOptIn := k.ComputeMinPowerToOptIn(ctx, chainID, k.stakingKeeper.GetLastValidators(ctx), topN) + + // Check if the validator's voting power is smaller + // than the minimum and hence not automatically opted in + if power < minPowerToOptIn { + continue + } + } + } + + consumersToValidate = append(consumersToValidate, chainID) + } + + return &types.QueryConsumerChainsValidatorHasToValidateResponse{ + ConsumerChainIds: consumersToValidate, + }, nil +} + +// QueryValidatorConsumerCommissionRate returns the commission rate a given +// validator charges on a given consumer chain +func (k Keeper) QueryValidatorConsumerCommissionRate(goCtx context.Context, req *types.QueryValidatorConsumerCommissionRateRequest) (*types.QueryValidatorConsumerCommissionRateResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + consumerChainID := req.ChainId + if consumerChainID == "" { + return nil, status.Error(codes.InvalidArgument, "empty chainId") + } + + consAddr, err := sdk.ConsAddressFromBech32(req.ProviderAddress) + if err != nil { + return nil, status.Error(codes.InvalidArgument, "invalid provider address") + } + + ctx := sdk.UnwrapSDKContext(goCtx) + + if !k.IsConsumerProposedOrRegistered(ctx, consumerChainID) { + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("unknown consumer chain: %s", consumerChainID)) + } + + res := &types.QueryValidatorConsumerCommissionRateResponse{} + + // Check if the validator has a commission rate set for the consumer chain, + // otherwise use the commission rate from the validator staking module struct + consumerRate, found := k.GetConsumerCommissionRate(ctx, consumerChainID, types.NewProviderConsAddress(consAddr)) + if found { + res.Rate = consumerRate + } else { + v, ok := k.stakingKeeper.GetValidatorByConsAddr(ctx, consAddr) + if !ok { + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("unknown validator: %s", consAddr.String())) + } + res.Rate = v.Commission.Rate + } + + return res, nil +} diff --git a/x/ccv/provider/keeper/keeper.go b/x/ccv/provider/keeper/keeper.go index 7e79bf4f6c..080bf481c1 100644 --- a/x/ccv/provider/keeper/keeper.go +++ b/x/ccv/provider/keeper/keeper.go @@ -249,9 +249,15 @@ func (k Keeper) GetAllConsumerChains(ctx sdk.Context) (chains []types.Chain) { chainID := string(iterator.Key()[1:]) clientID := string(iterator.Value()) + // Get the consumer TopN value by checking + // if the chain is a TopN chain, + // otherwise it's a OptIn chain + topN, _ := k.GetTopN(ctx, chainID) + chains = append(chains, types.Chain{ ChainId: chainID, ClientId: clientID, + Top_N: topN, }) } @@ -1296,4 +1302,4 @@ func (k Keeper) DeleteConsumerCommissionRate( ) { store := ctx.KVStore(k.storeKey) store.Delete(types.ConsumerCommissionRateKey(chainID, providerAddr)) -} \ No newline at end of file +} diff --git a/x/ccv/provider/keeper/keeper_test.go b/x/ccv/provider/keeper/keeper_test.go index 640b2ac70d..c2cbc386de 100644 --- a/x/ccv/provider/keeper/keeper_test.go +++ b/x/ccv/provider/keeper/keeper_test.go @@ -7,10 +7,10 @@ import ( "testing" "time" - ibctesting "github.com/cosmos/ibc-go/v7/testing" - "github.com/stretchr/testify/require" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" sdk "github.com/cosmos/cosmos-sdk/types" + ibctesting "github.com/cosmos/ibc-go/v7/testing" + "github.com/stretchr/testify/require" abci "github.com/cometbft/cometbft/abci/types" tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" @@ -401,8 +401,10 @@ func TestGetAllConsumerChains(t *testing.T) { expectedGetAllOrder := []types.Chain{} for i, chainID := range chainIDs { clientID := fmt.Sprintf("client-%d", len(chainIDs)-i) + topN := uint32(i) pk.SetConsumerClientId(ctx, chainID, clientID) - expectedGetAllOrder = append(expectedGetAllOrder, types.Chain{ChainId: chainID, ClientId: clientID}) + pk.SetTopN(ctx, chainID, topN) + expectedGetAllOrder = append(expectedGetAllOrder, types.Chain{ChainId: chainID, ClientId: clientID, Top_N: topN}) } // sorting by chainID sort.Slice(expectedGetAllOrder, func(i, j int) bool { diff --git a/x/ccv/provider/keeper/partial_set_security.go b/x/ccv/provider/keeper/partial_set_security.go index c34885e117..7c2e6a9723 100644 --- a/x/ccv/provider/keeper/partial_set_security.go +++ b/x/ccv/provider/keeper/partial_set_security.go @@ -1,12 +1,13 @@ package keeper import ( + "math" + "sort" + errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - "math" - "sort" ) // HandleOptIn prepares validator `providerAddr` to opt in to `chainID` with an optional `consumerKey` consumer public key. diff --git a/x/ccv/provider/keeper/proposal_test.go b/x/ccv/provider/keeper/proposal_test.go index 60c7dd6ce0..b27ae443fd 100644 --- a/x/ccv/provider/keeper/proposal_test.go +++ b/x/ccv/provider/keeper/proposal_test.go @@ -1002,12 +1002,7 @@ func TestBeginBlockInit(t *testing.T) { } // opt in a sample validator so the chain's proposal can successfully execute - providerKeeper.SetOptedIn(ctx, pendingProps[5].ChainId, providertypes.OptedInValidator{ - ProviderAddr: []byte{1}, - BlockHeight: int64(2), - Power: int64(3), - PublicKey: []byte{4}, - }) + providerKeeper.SetOptedIn(ctx, pendingProps[5].ChainId, providertypes.ProviderConsAddress{[]byte{1}}) providerKeeper.BeginBlockInit(ctx) diff --git a/x/ccv/provider/types/query.pb.go b/x/ccv/provider/types/query.pb.go index 13f100c7ca..6ad8667003 100644 --- a/x/ccv/provider/types/query.pb.go +++ b/x/ccv/provider/types/query.pb.go @@ -7,6 +7,8 @@ import ( context "context" fmt "fmt" crypto "github.com/cometbft/cometbft/proto/tendermint/crypto" + _ "github.com/cosmos/cosmos-proto" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" _ "github.com/cosmos/gogoproto/gogoproto" grpc1 "github.com/cosmos/gogoproto/grpc" proto "github.com/cosmos/gogoproto/proto" @@ -374,6 +376,8 @@ func (m *QueryConsumerChainStopProposalsResponse) GetProposals() *ConsumerRemova type Chain struct { ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` ClientId string `protobuf:"bytes,2,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` + // If chain with `chainID` is a Top-N chain, i.e., enforces at least one validator to validate chain `chainID` + Top_N uint32 `protobuf:"varint,3,opt,name=top_N,json=topN,proto3" json:"top_N,omitempty"` } func (m *Chain) Reset() { *m = Chain{} } @@ -423,6 +427,13 @@ func (m *Chain) GetClientId() string { return "" } +func (m *Chain) GetTop_N() uint32 { + if m != nil { + return m.Top_N + } + return 0 +} + type QueryValidatorConsumerAddrRequest struct { // The id of the consumer chain ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` @@ -1153,6 +1164,299 @@ func (m *QueryParamsResponse) GetParams() Params { return Params{} } +type QueryConsumerChainOptedInValidatorsRequest struct { + ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` +} + +func (m *QueryConsumerChainOptedInValidatorsRequest) Reset() { + *m = QueryConsumerChainOptedInValidatorsRequest{} +} +func (m *QueryConsumerChainOptedInValidatorsRequest) String() string { + return proto.CompactTextString(m) +} +func (*QueryConsumerChainOptedInValidatorsRequest) ProtoMessage() {} +func (*QueryConsumerChainOptedInValidatorsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_422512d7b7586cd7, []int{25} +} +func (m *QueryConsumerChainOptedInValidatorsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryConsumerChainOptedInValidatorsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryConsumerChainOptedInValidatorsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryConsumerChainOptedInValidatorsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryConsumerChainOptedInValidatorsRequest.Merge(m, src) +} +func (m *QueryConsumerChainOptedInValidatorsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryConsumerChainOptedInValidatorsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryConsumerChainOptedInValidatorsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryConsumerChainOptedInValidatorsRequest proto.InternalMessageInfo + +func (m *QueryConsumerChainOptedInValidatorsRequest) GetChainId() string { + if m != nil { + return m.ChainId + } + return "" +} + +type QueryConsumerChainOptedInValidatorsResponse struct { + // The consensus addresses of the validators on the provider chain + ValidatorsProviderAddresses []string `protobuf:"bytes,1,rep,name=validators_provider_addresses,json=validatorsProviderAddresses,proto3" json:"validators_provider_addresses,omitempty"` +} + +func (m *QueryConsumerChainOptedInValidatorsResponse) Reset() { + *m = QueryConsumerChainOptedInValidatorsResponse{} +} +func (m *QueryConsumerChainOptedInValidatorsResponse) String() string { + return proto.CompactTextString(m) +} +func (*QueryConsumerChainOptedInValidatorsResponse) ProtoMessage() {} +func (*QueryConsumerChainOptedInValidatorsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_422512d7b7586cd7, []int{26} +} +func (m *QueryConsumerChainOptedInValidatorsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryConsumerChainOptedInValidatorsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryConsumerChainOptedInValidatorsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryConsumerChainOptedInValidatorsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryConsumerChainOptedInValidatorsResponse.Merge(m, src) +} +func (m *QueryConsumerChainOptedInValidatorsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryConsumerChainOptedInValidatorsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryConsumerChainOptedInValidatorsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryConsumerChainOptedInValidatorsResponse proto.InternalMessageInfo + +func (m *QueryConsumerChainOptedInValidatorsResponse) GetValidatorsProviderAddresses() []string { + if m != nil { + return m.ValidatorsProviderAddresses + } + return nil +} + +type QueryConsumerChainsValidatorHasToValidateRequest 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"` +} + +func (m *QueryConsumerChainsValidatorHasToValidateRequest) Reset() { + *m = QueryConsumerChainsValidatorHasToValidateRequest{} +} +func (m *QueryConsumerChainsValidatorHasToValidateRequest) String() string { + return proto.CompactTextString(m) +} +func (*QueryConsumerChainsValidatorHasToValidateRequest) ProtoMessage() {} +func (*QueryConsumerChainsValidatorHasToValidateRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_422512d7b7586cd7, []int{27} +} +func (m *QueryConsumerChainsValidatorHasToValidateRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryConsumerChainsValidatorHasToValidateRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryConsumerChainsValidatorHasToValidateRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryConsumerChainsValidatorHasToValidateRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryConsumerChainsValidatorHasToValidateRequest.Merge(m, src) +} +func (m *QueryConsumerChainsValidatorHasToValidateRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryConsumerChainsValidatorHasToValidateRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryConsumerChainsValidatorHasToValidateRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryConsumerChainsValidatorHasToValidateRequest proto.InternalMessageInfo + +func (m *QueryConsumerChainsValidatorHasToValidateRequest) GetProviderAddress() string { + if m != nil { + return m.ProviderAddress + } + return "" +} + +type QueryConsumerChainsValidatorHasToValidateResponse struct { + ConsumerChainIds []string `protobuf:"bytes,1,rep,name=consumer_chain_ids,json=consumerChainIds,proto3" json:"consumer_chain_ids,omitempty"` +} + +func (m *QueryConsumerChainsValidatorHasToValidateResponse) Reset() { + *m = QueryConsumerChainsValidatorHasToValidateResponse{} +} +func (m *QueryConsumerChainsValidatorHasToValidateResponse) String() string { + return proto.CompactTextString(m) +} +func (*QueryConsumerChainsValidatorHasToValidateResponse) ProtoMessage() {} +func (*QueryConsumerChainsValidatorHasToValidateResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_422512d7b7586cd7, []int{28} +} +func (m *QueryConsumerChainsValidatorHasToValidateResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryConsumerChainsValidatorHasToValidateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryConsumerChainsValidatorHasToValidateResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryConsumerChainsValidatorHasToValidateResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryConsumerChainsValidatorHasToValidateResponse.Merge(m, src) +} +func (m *QueryConsumerChainsValidatorHasToValidateResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryConsumerChainsValidatorHasToValidateResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryConsumerChainsValidatorHasToValidateResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryConsumerChainsValidatorHasToValidateResponse proto.InternalMessageInfo + +func (m *QueryConsumerChainsValidatorHasToValidateResponse) GetConsumerChainIds() []string { + if m != nil { + return m.ConsumerChainIds + } + return nil +} + +type QueryValidatorConsumerCommissionRateRequest struct { + ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + // The consensus address of the validator on the provider chain + ProviderAddress string `protobuf:"bytes,2,opt,name=provider_address,json=providerAddress,proto3" json:"provider_address,omitempty" yaml:"address"` +} + +func (m *QueryValidatorConsumerCommissionRateRequest) Reset() { + *m = QueryValidatorConsumerCommissionRateRequest{} +} +func (m *QueryValidatorConsumerCommissionRateRequest) String() string { + return proto.CompactTextString(m) +} +func (*QueryValidatorConsumerCommissionRateRequest) ProtoMessage() {} +func (*QueryValidatorConsumerCommissionRateRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_422512d7b7586cd7, []int{29} +} +func (m *QueryValidatorConsumerCommissionRateRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryValidatorConsumerCommissionRateRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryValidatorConsumerCommissionRateRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryValidatorConsumerCommissionRateRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryValidatorConsumerCommissionRateRequest.Merge(m, src) +} +func (m *QueryValidatorConsumerCommissionRateRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryValidatorConsumerCommissionRateRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryValidatorConsumerCommissionRateRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryValidatorConsumerCommissionRateRequest proto.InternalMessageInfo + +func (m *QueryValidatorConsumerCommissionRateRequest) GetChainId() string { + if m != nil { + return m.ChainId + } + return "" +} + +func (m *QueryValidatorConsumerCommissionRateRequest) GetProviderAddress() string { + if m != nil { + return m.ProviderAddress + } + return "" +} + +type QueryValidatorConsumerCommissionRateResponse struct { + // The rate to charge delegators on the consumer chain, as a fraction + Rate github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,1,opt,name=rate,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"rate"` +} + +func (m *QueryValidatorConsumerCommissionRateResponse) Reset() { + *m = QueryValidatorConsumerCommissionRateResponse{} +} +func (m *QueryValidatorConsumerCommissionRateResponse) String() string { + return proto.CompactTextString(m) +} +func (*QueryValidatorConsumerCommissionRateResponse) ProtoMessage() {} +func (*QueryValidatorConsumerCommissionRateResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_422512d7b7586cd7, []int{30} +} +func (m *QueryValidatorConsumerCommissionRateResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryValidatorConsumerCommissionRateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryValidatorConsumerCommissionRateResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryValidatorConsumerCommissionRateResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryValidatorConsumerCommissionRateResponse.Merge(m, src) +} +func (m *QueryValidatorConsumerCommissionRateResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryValidatorConsumerCommissionRateResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryValidatorConsumerCommissionRateResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryValidatorConsumerCommissionRateResponse proto.InternalMessageInfo + func init() { proto.RegisterType((*QueryConsumerGenesisRequest)(nil), "interchain_security.ccv.provider.v1.QueryConsumerGenesisRequest") proto.RegisterType((*QueryConsumerGenesisResponse)(nil), "interchain_security.ccv.provider.v1.QueryConsumerGenesisResponse") @@ -1179,6 +1483,12 @@ func init() { proto.RegisterType((*PairValConAddrProviderAndConsumer)(nil), "interchain_security.ccv.provider.v1.PairValConAddrProviderAndConsumer") proto.RegisterType((*QueryParamsRequest)(nil), "interchain_security.ccv.provider.v1.QueryParamsRequest") proto.RegisterType((*QueryParamsResponse)(nil), "interchain_security.ccv.provider.v1.QueryParamsResponse") + proto.RegisterType((*QueryConsumerChainOptedInValidatorsRequest)(nil), "interchain_security.ccv.provider.v1.QueryConsumerChainOptedInValidatorsRequest") + proto.RegisterType((*QueryConsumerChainOptedInValidatorsResponse)(nil), "interchain_security.ccv.provider.v1.QueryConsumerChainOptedInValidatorsResponse") + proto.RegisterType((*QueryConsumerChainsValidatorHasToValidateRequest)(nil), "interchain_security.ccv.provider.v1.QueryConsumerChainsValidatorHasToValidateRequest") + proto.RegisterType((*QueryConsumerChainsValidatorHasToValidateResponse)(nil), "interchain_security.ccv.provider.v1.QueryConsumerChainsValidatorHasToValidateResponse") + proto.RegisterType((*QueryValidatorConsumerCommissionRateRequest)(nil), "interchain_security.ccv.provider.v1.QueryValidatorConsumerCommissionRateRequest") + proto.RegisterType((*QueryValidatorConsumerCommissionRateResponse)(nil), "interchain_security.ccv.provider.v1.QueryValidatorConsumerCommissionRateResponse") } func init() { @@ -1186,95 +1496,113 @@ func init() { } var fileDescriptor_422512d7b7586cd7 = []byte{ - // 1403 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x58, 0x4f, 0x73, 0x14, 0xc5, - 0x1b, 0xce, 0x24, 0x90, 0x5f, 0xd2, 0xe1, 0xdf, 0xaf, 0x89, 0x18, 0x86, 0xb8, 0x0b, 0x43, 0xa9, - 0x01, 0x74, 0x26, 0x59, 0xb4, 0xe4, 0x8f, 0x21, 0xec, 0x26, 0x80, 0x5b, 0x81, 0x22, 0x0e, 0x88, - 0x55, 0x6a, 0xb9, 0x74, 0x66, 0xda, 0xcd, 0x14, 0xb3, 0xd3, 0x43, 0x77, 0xef, 0xc2, 0x16, 0xe5, - 0x01, 0x0f, 0xca, 0x91, 0x2a, 0xf5, 0xce, 0xc5, 0x2f, 0xe0, 0xa7, 0xe0, 0x06, 0x16, 0x17, 0x4f, - 0x68, 0x05, 0x0f, 0x96, 0x27, 0xcb, 0xbb, 0x55, 0xd6, 0xf4, 0xf4, 0xcc, 0xee, 0xec, 0x4e, 0x76, - 0x67, 0x37, 0xb9, 0x65, 0xbb, 0xfb, 0x7d, 0xde, 0xe7, 0x79, 0xbb, 0xfb, 0xed, 0x67, 0x02, 0x0c, - 0xc7, 0xe3, 0x98, 0x5a, 0x1b, 0xc8, 0xf1, 0x2a, 0x0c, 0x5b, 0x75, 0xea, 0xf0, 0xa6, 0x61, 0x59, - 0x0d, 0xc3, 0xa7, 0xa4, 0xe1, 0xd8, 0x98, 0x1a, 0x8d, 0x05, 0xe3, 0x6e, 0x1d, 0xd3, 0xa6, 0xee, - 0x53, 0xc2, 0x09, 0x3c, 0x9e, 0x12, 0xa0, 0x5b, 0x56, 0x43, 0x8f, 0x02, 0xf4, 0xc6, 0x82, 0x3a, - 0x5b, 0x25, 0xa4, 0xea, 0x62, 0x03, 0xf9, 0x8e, 0x81, 0x3c, 0x8f, 0x70, 0xc4, 0x1d, 0xe2, 0xb1, - 0x10, 0x42, 0x9d, 0xae, 0x92, 0x2a, 0x11, 0x7f, 0x1a, 0xc1, 0x5f, 0x72, 0x34, 0x2f, 0x63, 0xc4, - 0xaf, 0xf5, 0xfa, 0x57, 0x06, 0x77, 0x6a, 0x98, 0x71, 0x54, 0xf3, 0xe5, 0x82, 0x42, 0x16, 0xaa, - 0x31, 0x8b, 0x30, 0x66, 0x7e, 0xab, 0x98, 0xc6, 0x82, 0xc1, 0x36, 0x10, 0xc5, 0x76, 0xc5, 0x22, - 0x1e, 0xab, 0xd7, 0xe2, 0x88, 0x37, 0x7b, 0x44, 0xdc, 0x73, 0x28, 0x96, 0xcb, 0x66, 0x39, 0xf6, - 0x6c, 0x4c, 0x6b, 0x8e, 0xc7, 0x0d, 0x8b, 0x36, 0x7d, 0x4e, 0x8c, 0x3b, 0xb8, 0x29, 0x15, 0x6a, - 0x67, 0xc0, 0x91, 0x8f, 0x83, 0x9a, 0x2d, 0x4b, 0xec, 0x2b, 0xd8, 0xc3, 0xcc, 0x61, 0x26, 0xbe, - 0x5b, 0xc7, 0x8c, 0xc3, 0xc3, 0x60, 0x22, 0x4c, 0xe0, 0xd8, 0x33, 0xca, 0x51, 0x65, 0x6e, 0xd2, - 0xfc, 0x9f, 0xf8, 0x5d, 0xb6, 0xb5, 0x07, 0x60, 0x36, 0x3d, 0x92, 0xf9, 0xc4, 0x63, 0x18, 0x7e, - 0x0e, 0xf6, 0x56, 0xc3, 0xa1, 0x0a, 0xe3, 0x88, 0x63, 0x11, 0x3f, 0x55, 0x98, 0xd7, 0xb7, 0xda, - 0x96, 0xc6, 0x82, 0xde, 0x81, 0x75, 0x23, 0x88, 0x2b, 0xed, 0x7a, 0xfa, 0x32, 0x3f, 0x62, 0xee, - 0xa9, 0xb6, 0x8d, 0x69, 0xb3, 0x40, 0x4d, 0x24, 0x5f, 0x0e, 0xe0, 0x22, 0xd6, 0x1a, 0xea, 0x10, - 0x15, 0xcd, 0x4a, 0x66, 0x25, 0x30, 0x2e, 0xd2, 0xb3, 0x19, 0xe5, 0xe8, 0xd8, 0xdc, 0x54, 0xe1, - 0xa4, 0x9e, 0xe1, 0xa4, 0xe8, 0x02, 0xc4, 0x94, 0x91, 0xda, 0x09, 0xf0, 0x76, 0x77, 0x8a, 0x1b, - 0x1c, 0x51, 0xbe, 0x46, 0x89, 0x4f, 0x18, 0x72, 0x63, 0x36, 0x8f, 0x14, 0x30, 0xd7, 0x7f, 0xad, - 0xe4, 0xf6, 0x05, 0x98, 0xf4, 0xa3, 0x41, 0x59, 0xb1, 0x0b, 0xd9, 0xe8, 0x49, 0xf0, 0xa2, 0x6d, - 0x3b, 0xc1, 0x11, 0x6e, 0x41, 0xb7, 0x00, 0xb5, 0x39, 0xf0, 0x56, 0x1a, 0x13, 0xe2, 0x77, 0x91, - 0xfe, 0x56, 0x49, 0x17, 0x98, 0x58, 0x1a, 0xef, 0x74, 0x17, 0xe7, 0xc5, 0x81, 0x38, 0x9b, 0xb8, - 0x46, 0x1a, 0xc8, 0x4d, 0xa5, 0xbc, 0x04, 0x76, 0x8b, 0xd4, 0x3d, 0x8e, 0x22, 0x3c, 0x02, 0x26, - 0x2d, 0xd7, 0xc1, 0x1e, 0x0f, 0xe6, 0x46, 0xc5, 0xdc, 0x44, 0x38, 0x50, 0xb6, 0xb5, 0xef, 0x14, - 0x70, 0x4c, 0x28, 0xb9, 0x85, 0x5c, 0xc7, 0x46, 0x9c, 0xd0, 0xb6, 0x52, 0xd1, 0xfe, 0x07, 0x1d, - 0x2e, 0x82, 0x03, 0x11, 0xe9, 0x0a, 0xb2, 0x6d, 0x8a, 0x19, 0x0b, 0x93, 0x94, 0xe0, 0x3f, 0x2f, - 0xf3, 0xfb, 0x9a, 0xa8, 0xe6, 0x9e, 0xd3, 0xe4, 0x84, 0x66, 0xee, 0x8f, 0xd6, 0x16, 0xc3, 0x91, - 0x73, 0x13, 0x8f, 0x9e, 0xe4, 0x47, 0xfe, 0x7c, 0x92, 0x1f, 0xd1, 0xae, 0x03, 0xad, 0x17, 0x11, - 0x59, 0xcd, 0x13, 0xe0, 0x40, 0x74, 0xd1, 0xe3, 0x74, 0x21, 0xa3, 0xfd, 0x56, 0xdb, 0xfa, 0x20, - 0x59, 0xb7, 0xb4, 0xb5, 0xb6, 0xe4, 0xd9, 0xa4, 0x75, 0xe5, 0xea, 0x21, 0xad, 0x23, 0x7f, 0x2f, - 0x69, 0x49, 0x22, 0x2d, 0x69, 0x5d, 0x95, 0x94, 0xd2, 0x3a, 0xaa, 0xa6, 0x1d, 0x01, 0x87, 0x05, - 0xe0, 0xcd, 0x0d, 0x4a, 0x38, 0x77, 0xb1, 0xb8, 0xf6, 0xd1, 0xe1, 0xfc, 0x45, 0x91, 0xd7, 0xbf, - 0x63, 0x56, 0xa6, 0xc9, 0x83, 0x29, 0xe6, 0x22, 0xb6, 0x51, 0xa9, 0x61, 0x8e, 0xa9, 0xc8, 0x30, - 0x66, 0x02, 0x31, 0x74, 0x2d, 0x18, 0x81, 0x05, 0xf0, 0x5a, 0xdb, 0x82, 0x0a, 0x72, 0x5d, 0x72, - 0x0f, 0x79, 0x16, 0x16, 0xda, 0xc7, 0xcc, 0x83, 0xad, 0xa5, 0xc5, 0x68, 0x0a, 0x7e, 0x09, 0x66, - 0x3c, 0x7c, 0x9f, 0x57, 0x28, 0xf6, 0x5d, 0xec, 0x39, 0x6c, 0xa3, 0x62, 0x21, 0xcf, 0x0e, 0xc4, - 0xe2, 0x99, 0x31, 0x71, 0xe6, 0x55, 0x3d, 0x7c, 0x17, 0xf4, 0xe8, 0x5d, 0xd0, 0x6f, 0x46, 0xef, - 0x42, 0x69, 0x22, 0xe8, 0x61, 0x8f, 0x7f, 0xcb, 0x2b, 0xe6, 0xa1, 0x00, 0xc5, 0x8c, 0x40, 0x96, - 0x23, 0x0c, 0xed, 0x1d, 0x70, 0x52, 0x48, 0x32, 0x71, 0xd5, 0x61, 0x1c, 0x53, 0x6c, 0xb7, 0x6e, - 0xc7, 0x3d, 0x44, 0xed, 0x15, 0xec, 0x91, 0x5a, 0x7c, 0x3d, 0x2f, 0x81, 0x53, 0x99, 0x56, 0xcb, - 0x8a, 0x1c, 0x02, 0xe3, 0xb6, 0x18, 0x11, 0x1d, 0x6f, 0xd2, 0x94, 0xbf, 0xb4, 0x9c, 0xec, 0xe1, - 0xe1, 0xcd, 0xc3, 0xb6, 0xb8, 0x69, 0xe5, 0x95, 0x38, 0xcd, 0x43, 0x05, 0xbc, 0xb1, 0xc5, 0x02, - 0x89, 0x7c, 0x1b, 0xec, 0xf3, 0xdb, 0xe7, 0xa2, 0x9e, 0x5a, 0xc8, 0xd4, 0x00, 0x12, 0xb0, 0xb2, - 0xd1, 0x77, 0xe0, 0x69, 0x65, 0xb0, 0x37, 0xb1, 0x0c, 0xce, 0x00, 0x79, 0x7e, 0x57, 0x92, 0xc7, - 0x79, 0x05, 0xe6, 0x00, 0x88, 0x1a, 0x47, 0x79, 0x45, 0x6c, 0xe6, 0x2e, 0xb3, 0x6d, 0x44, 0xbb, - 0x0a, 0x0c, 0xa1, 0xa6, 0xe8, 0xba, 0x6b, 0xc8, 0xa1, 0xec, 0x16, 0x72, 0x97, 0x89, 0x17, 0x1c, - 0xb9, 0x52, 0xb2, 0xcf, 0x95, 0x57, 0x32, 0x3c, 0x80, 0x3f, 0x29, 0x60, 0x3e, 0x3b, 0x9c, 0xac, - 0xd7, 0x5d, 0xf0, 0x7f, 0x1f, 0x39, 0xb4, 0xd2, 0x40, 0x6e, 0xf0, 0x9e, 0x8b, 0x6b, 0x20, 0x4b, - 0x76, 0x39, 0x5b, 0xc9, 0x90, 0x43, 0x5b, 0x89, 0xe2, 0x6b, 0xe6, 0xb5, 0x0e, 0xc0, 0x3e, 0x3f, - 0xb1, 0x44, 0xdb, 0x54, 0xc0, 0xb1, 0xbe, 0x51, 0xa9, 0x5d, 0x4e, 0xc9, 0xdc, 0xe5, 0xb6, 0xd9, - 0x49, 0xe0, 0x12, 0xd8, 0x13, 0x87, 0xdf, 0xc1, 0x4d, 0x79, 0xa3, 0x66, 0xf5, 0x96, 0x77, 0xd1, - 0x43, 0xef, 0xa2, 0xaf, 0xd5, 0xd7, 0x5d, 0xc7, 0x5a, 0xc5, 0x4d, 0x73, 0x2a, 0x8a, 0x58, 0xc5, - 0x4d, 0x6d, 0x1a, 0xc0, 0xf0, 0xa0, 0x22, 0x8a, 0x5a, 0xd7, 0xe4, 0x36, 0x38, 0x98, 0x18, 0x95, - 0x9b, 0x50, 0x06, 0xe3, 0xbe, 0x18, 0x91, 0xaf, 0xd5, 0xa9, 0x8c, 0x95, 0x0f, 0x42, 0xe4, 0x29, - 0x95, 0x00, 0x85, 0x67, 0xd3, 0x60, 0xb7, 0x48, 0x01, 0x37, 0x15, 0x30, 0x9d, 0x66, 0x88, 0xe0, - 0xc5, 0x4c, 0xe8, 0x3d, 0x5c, 0x98, 0x5a, 0xdc, 0x06, 0x42, 0x28, 0x59, 0xbb, 0xf4, 0xcd, 0x8b, - 0x3f, 0xbe, 0x1f, 0x5d, 0x82, 0x8b, 0xfd, 0x6d, 0x74, 0xbc, 0x11, 0xd2, 0x71, 0x19, 0x0f, 0xa2, - 0x1b, 0xf0, 0x35, 0x7c, 0xa1, 0xc8, 0x8a, 0x26, 0xad, 0x15, 0x5c, 0x1a, 0x9c, 0x61, 0xc2, 0xb2, - 0xa9, 0x17, 0x87, 0x07, 0x90, 0x0a, 0xcf, 0x0a, 0x85, 0xa7, 0xe1, 0xc2, 0x00, 0x0a, 0x43, 0x33, - 0x07, 0x1f, 0x8e, 0x82, 0x99, 0x2d, 0x1c, 0x1a, 0x83, 0x57, 0x87, 0x64, 0x96, 0x6a, 0x06, 0xd5, - 0x6b, 0x3b, 0x84, 0x26, 0x45, 0x7f, 0x24, 0x44, 0x97, 0xe0, 0xc5, 0x41, 0x45, 0x07, 0x9e, 0x9c, - 0xf2, 0x4a, 0xec, 0xb3, 0xe0, 0xbf, 0x0a, 0x78, 0x3d, 0xdd, 0xf0, 0x31, 0xb8, 0x3a, 0x34, 0xe9, - 0x6e, 0x67, 0xa9, 0x5e, 0xdd, 0x19, 0x30, 0x59, 0x80, 0x2b, 0xa2, 0x00, 0x45, 0xb8, 0x34, 0x44, - 0x01, 0x88, 0xdf, 0xa6, 0xff, 0xef, 0xc8, 0x53, 0xa4, 0xba, 0x33, 0x78, 0x39, 0x3b, 0xeb, 0x5e, - 0x3e, 0x53, 0xbd, 0xb2, 0x6d, 0x1c, 0x29, 0xbc, 0x28, 0x84, 0x9f, 0x87, 0x67, 0x33, 0x7c, 0x17, - 0x47, 0x40, 0x95, 0x44, 0x8b, 0x4e, 0x91, 0xdc, 0xee, 0xda, 0x86, 0x92, 0x9c, 0xe2, 0x3f, 0x87, - 0x92, 0x9c, 0x66, 0x1f, 0x87, 0x93, 0x9c, 0x78, 0xd4, 0xe0, 0x33, 0x45, 0xbe, 0x13, 0x09, 0xe7, - 0x08, 0x2f, 0x64, 0xa7, 0x98, 0x66, 0x48, 0xd5, 0xa5, 0xa1, 0xe3, 0xa5, 0xb4, 0x33, 0x42, 0x5a, - 0x01, 0xce, 0xf7, 0x97, 0xc6, 0x25, 0x40, 0xf8, 0x55, 0x0d, 0x7f, 0x1c, 0x05, 0xc7, 0x33, 0x58, - 0x41, 0x78, 0x3d, 0x3b, 0xc5, 0x4c, 0x16, 0x54, 0x5d, 0xdb, 0x39, 0x40, 0x59, 0x84, 0x55, 0x51, - 0x84, 0x4b, 0x70, 0xb9, 0x7f, 0x11, 0x68, 0x8c, 0xd8, 0x3a, 0xd3, 0x54, 0x60, 0x56, 0x42, 0x6b, - 0x0b, 0xff, 0xea, 0xb2, 0xae, 0x49, 0x47, 0xc6, 0xe0, 0x00, 0xaf, 0xea, 0x16, 0xfe, 0x58, 0x2d, - 0x6d, 0x07, 0x42, 0xaa, 0x2e, 0x09, 0xd5, 0x1f, 0xc2, 0x73, 0xfd, 0x55, 0x47, 0xce, 0xb8, 0xd2, - 0xf9, 0x80, 0xfd, 0x30, 0x2a, 0xff, 0xc5, 0x90, 0xc1, 0x8a, 0xc2, 0x9b, 0xd9, 0x49, 0x67, 0x37, - 0xca, 0xea, 0x27, 0x3b, 0x8c, 0x2a, 0xab, 0x73, 0x5e, 0x54, 0xe7, 0x7d, 0x78, 0x7a, 0xe0, 0xfe, - 0xee, 0xd8, 0xf0, 0x67, 0x05, 0x4c, 0xb5, 0xf9, 0x3f, 0xf8, 0xc1, 0x00, 0xdb, 0xd5, 0xee, 0x23, - 0xd5, 0x33, 0x83, 0x07, 0x4a, 0xfe, 0xf3, 0x82, 0xff, 0x49, 0x38, 0x97, 0x61, 0x77, 0x43, 0x7f, - 0xf9, 0xe9, 0xd3, 0xcd, 0x9c, 0xf2, 0x7c, 0x33, 0xa7, 0xfc, 0xbe, 0x99, 0x53, 0x1e, 0xbf, 0xca, - 0x8d, 0x3c, 0x7f, 0x95, 0x1b, 0xf9, 0xf5, 0x55, 0x6e, 0xe4, 0xb3, 0xc5, 0xaa, 0xc3, 0x37, 0xea, - 0xeb, 0xba, 0x45, 0x6a, 0x86, 0x45, 0x58, 0x8d, 0xb0, 0x36, 0xd0, 0x77, 0x63, 0xd0, 0xc6, 0x7b, - 0xc6, 0xfd, 0x8e, 0x96, 0xd1, 0xf4, 0x31, 0x5b, 0x1f, 0x17, 0xdf, 0xa5, 0xa7, 0xff, 0x0b, 0x00, - 0x00, 0xff, 0xff, 0x67, 0x8a, 0xee, 0xb2, 0x49, 0x15, 0x00, 0x00, + // 1688 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0x5d, 0x6f, 0xd4, 0x46, + 0x17, 0x8e, 0x93, 0x90, 0x37, 0x99, 0xf0, 0xf5, 0x0e, 0xbc, 0xbc, 0xc1, 0x09, 0xbb, 0x60, 0x5a, + 0x1a, 0xbe, 0xec, 0x64, 0x29, 0xe2, 0x33, 0x84, 0x6c, 0x16, 0xc2, 0x2a, 0x7c, 0x2c, 0x26, 0x50, + 0xa9, 0xad, 0x6a, 0x1c, 0x7b, 0xba, 0xb1, 0xf0, 0x7a, 0x1c, 0x8f, 0xb3, 0xb0, 0x42, 0x95, 0x4a, + 0x2f, 0x0a, 0x77, 0xa5, 0x6a, 0x7b, 0x8f, 0x54, 0xf5, 0x0f, 0x54, 0xfd, 0x11, 0xdc, 0x95, 0x96, + 0x9b, 0xaa, 0x17, 0xb4, 0x0a, 0xbd, 0xa8, 0x7a, 0x55, 0xf5, 0xbe, 0x52, 0xe5, 0xf1, 0xd8, 0x5e, + 0xef, 0x3a, 0xbb, 0xde, 0xdd, 0xf4, 0x2a, 0xf1, 0xcc, 0x9c, 0xe7, 0x9c, 0xe7, 0xcc, 0x99, 0x33, + 0xf3, 0x2c, 0x90, 0x0c, 0xcb, 0x45, 0x8e, 0xb6, 0xa2, 0x1a, 0x96, 0x42, 0x90, 0xb6, 0xe6, 0x18, + 0x6e, 0x4d, 0xd2, 0xb4, 0xaa, 0x64, 0x3b, 0xb8, 0x6a, 0xe8, 0xc8, 0x91, 0xaa, 0xd3, 0xd2, 0xea, + 0x1a, 0x72, 0x6a, 0xa2, 0xed, 0x60, 0x17, 0xc3, 0x83, 0x09, 0x06, 0xa2, 0xa6, 0x55, 0xc5, 0xc0, + 0x40, 0xac, 0x4e, 0xf3, 0x13, 0x65, 0x8c, 0xcb, 0x26, 0x92, 0x54, 0xdb, 0x90, 0x54, 0xcb, 0xc2, + 0xae, 0xea, 0x1a, 0xd8, 0x22, 0x3e, 0x04, 0xbf, 0xbb, 0x8c, 0xcb, 0x98, 0xfe, 0x2b, 0x79, 0xff, + 0xb1, 0xd1, 0x2c, 0xb3, 0xa1, 0x5f, 0xcb, 0x6b, 0x1f, 0x4a, 0xae, 0x51, 0x41, 0xc4, 0x55, 0x2b, + 0x36, 0x5b, 0x90, 0x4b, 0x13, 0x6a, 0x18, 0x85, 0x6f, 0x33, 0xb5, 0x91, 0x4d, 0x75, 0x5a, 0x22, + 0x2b, 0xaa, 0x83, 0x74, 0x45, 0xc3, 0x16, 0x59, 0xab, 0x84, 0x16, 0x6f, 0xb6, 0xb0, 0xb8, 0x6f, + 0x38, 0x88, 0x2d, 0x9b, 0x70, 0x91, 0xa5, 0x23, 0xa7, 0x62, 0x58, 0xae, 0xa4, 0x39, 0x35, 0xdb, + 0xc5, 0xd2, 0x3d, 0x54, 0x0b, 0x18, 0xee, 0xd5, 0x30, 0xa9, 0x60, 0xa2, 0xf8, 0x24, 0xfd, 0x0f, + 0x7f, 0x4a, 0x38, 0x0d, 0xc6, 0x6f, 0x7a, 0xe9, 0x9c, 0x67, 0x6e, 0x17, 0x90, 0x85, 0x88, 0x41, + 0x64, 0xb4, 0xba, 0x86, 0x88, 0x0b, 0xf7, 0x82, 0x61, 0xdf, 0xb7, 0xa1, 0x8f, 0x71, 0xfb, 0xb9, + 0xc9, 0x11, 0xf9, 0x3f, 0xf4, 0xbb, 0xa8, 0x0b, 0x0f, 0xc1, 0x44, 0xb2, 0x25, 0xb1, 0xb1, 0x45, + 0x10, 0x7c, 0x0f, 0x6c, 0x2b, 0xfb, 0x43, 0x0a, 0x71, 0x55, 0x17, 0x51, 0xfb, 0xd1, 0xdc, 0x94, + 0xb8, 0xd1, 0x8e, 0x55, 0xa7, 0xc5, 0x06, 0xac, 0x5b, 0x9e, 0x5d, 0x7e, 0xf0, 0xf9, 0xab, 0x6c, + 0x9f, 0xbc, 0xb5, 0x5c, 0x37, 0x26, 0x4c, 0x00, 0x3e, 0xe6, 0x7c, 0xde, 0x83, 0x0b, 0xa2, 0x16, + 0xd4, 0x06, 0x52, 0xc1, 0x2c, 0x8b, 0x2c, 0x0f, 0x86, 0xa8, 0x7b, 0x32, 0xc6, 0xed, 0x1f, 0x98, + 0x1c, 0xcd, 0x1d, 0x11, 0x53, 0x14, 0x91, 0x48, 0x41, 0x64, 0x66, 0x29, 0x1c, 0x06, 0x6f, 0x35, + 0xbb, 0xb8, 0xe5, 0xaa, 0x8e, 0x5b, 0x72, 0xb0, 0x8d, 0x89, 0x6a, 0x86, 0xd1, 0x3c, 0xe1, 0xc0, + 0x64, 0xfb, 0xb5, 0x2c, 0xb6, 0xf7, 0xc1, 0x88, 0x1d, 0x0c, 0xb2, 0x8c, 0x5d, 0x48, 0x17, 0x1e, + 0x03, 0x9f, 0xd3, 0x75, 0xc3, 0xab, 0xee, 0x08, 0x3a, 0x02, 0x14, 0x26, 0xc1, 0xa1, 0xa4, 0x48, + 0xb0, 0xdd, 0x14, 0xf4, 0xa7, 0x5c, 0x32, 0xc1, 0xd8, 0xd2, 0x70, 0xa7, 0x9b, 0x62, 0x9e, 0xe9, + 0x28, 0x66, 0x19, 0x55, 0x70, 0x55, 0x35, 0x13, 0x43, 0x5e, 0x02, 0x5b, 0xa8, 0xeb, 0x16, 0xa5, + 0x08, 0xc7, 0xc1, 0x88, 0x66, 0x1a, 0xc8, 0x72, 0xbd, 0xb9, 0x7e, 0x3a, 0x37, 0xec, 0x0f, 0x14, + 0x75, 0xb8, 0x0b, 0x6c, 0x71, 0xb1, 0xad, 0x5c, 0x1f, 0x1b, 0xd8, 0xcf, 0x4d, 0x6e, 0x93, 0x07, + 0x5d, 0x6c, 0x5f, 0x17, 0x1e, 0x73, 0xe0, 0x00, 0xa5, 0x77, 0x47, 0x35, 0x0d, 0x5d, 0x75, 0xb1, + 0x53, 0x97, 0x3f, 0xa7, 0x7d, 0xf5, 0xc3, 0x19, 0xb0, 0x33, 0x60, 0xa2, 0xa8, 0xba, 0xee, 0x20, + 0x42, 0x7c, 0xcf, 0x79, 0xf8, 0xd7, 0xab, 0xec, 0xf6, 0x9a, 0x5a, 0x31, 0xcf, 0x0a, 0x6c, 0x42, + 0x90, 0x77, 0x04, 0x6b, 0xe7, 0xfc, 0x91, 0xb3, 0xc3, 0x4f, 0x9e, 0x65, 0xfb, 0x7e, 0x7f, 0x96, + 0xed, 0x13, 0x6e, 0x00, 0xa1, 0x55, 0x20, 0x2c, 0xc5, 0x87, 0xc1, 0xce, 0xa0, 0x31, 0x84, 0xee, + 0xfc, 0x88, 0x76, 0x68, 0x75, 0xeb, 0x3d, 0x67, 0xcd, 0xd4, 0x4a, 0x75, 0xce, 0xd3, 0x51, 0x6b, + 0xf2, 0xd5, 0x82, 0x5a, 0x83, 0xff, 0x56, 0xd4, 0xe2, 0x81, 0x44, 0xd4, 0x9a, 0x32, 0xc9, 0xa8, + 0x35, 0x64, 0x4d, 0x18, 0x07, 0x7b, 0x29, 0xe0, 0xd2, 0x8a, 0x83, 0x5d, 0xd7, 0x44, 0xb4, 0x17, + 0x04, 0x15, 0xfb, 0x03, 0xc7, 0x7a, 0x42, 0xc3, 0x2c, 0x73, 0x93, 0x05, 0xa3, 0xc4, 0x54, 0xc9, + 0x8a, 0x52, 0x41, 0x2e, 0x72, 0xa8, 0x87, 0x01, 0x19, 0xd0, 0xa1, 0x6b, 0xde, 0x08, 0xcc, 0x81, + 0xff, 0xd5, 0x2d, 0x50, 0x54, 0xd3, 0xc4, 0xf7, 0x55, 0x4b, 0x43, 0x94, 0xfb, 0x80, 0xbc, 0x2b, + 0x5a, 0x3a, 0x17, 0x4c, 0xc1, 0x0f, 0xc0, 0x98, 0x85, 0x1e, 0xb8, 0x8a, 0x83, 0x6c, 0x13, 0x59, + 0x06, 0x59, 0x51, 0x34, 0xd5, 0xd2, 0x3d, 0xb2, 0x88, 0x96, 0xdb, 0x68, 0x8e, 0x17, 0xfd, 0x7b, + 0x44, 0x0c, 0xee, 0x11, 0x71, 0x29, 0xb8, 0x47, 0xf2, 0xc3, 0x5e, 0x63, 0x7b, 0xfa, 0x4b, 0x96, + 0x93, 0xf7, 0x78, 0x28, 0x72, 0x00, 0x32, 0x1f, 0x60, 0x08, 0xc7, 0xc0, 0x11, 0x4a, 0x49, 0x46, + 0x65, 0x83, 0xb8, 0xc8, 0x41, 0x7a, 0x74, 0x64, 0xee, 0xab, 0x8e, 0x5e, 0x40, 0x16, 0xae, 0x84, + 0x67, 0xf6, 0x12, 0x38, 0x9a, 0x6a, 0x35, 0xcb, 0xc8, 0x1e, 0x30, 0xa4, 0xd3, 0x11, 0xda, 0x06, + 0x47, 0x64, 0xf6, 0x25, 0x64, 0x58, 0x63, 0xf7, 0x8f, 0x23, 0xd2, 0xe9, 0xf1, 0x2b, 0x16, 0x42, + 0x37, 0x8f, 0x38, 0xb0, 0x6f, 0x83, 0x05, 0x0c, 0xf9, 0x2e, 0xd8, 0x6e, 0xd7, 0xcf, 0x05, 0x8d, + 0x36, 0x97, 0xaa, 0x2b, 0xc4, 0x60, 0x59, 0xf7, 0x6f, 0xc0, 0x13, 0x8a, 0x60, 0x5b, 0x6c, 0x19, + 0x1c, 0x03, 0xac, 0x7e, 0x0b, 0xf1, 0x72, 0x2e, 0xc0, 0x0c, 0x00, 0x41, 0x37, 0x29, 0x16, 0xe8, + 0x66, 0x0e, 0xca, 0x75, 0x23, 0xc2, 0x55, 0x20, 0x51, 0x36, 0x73, 0xa6, 0x59, 0x52, 0x0d, 0x87, + 0xdc, 0x51, 0xcd, 0x79, 0x6c, 0x79, 0x25, 0x97, 0x8f, 0x37, 0xbf, 0x62, 0x21, 0xc5, 0xad, 0xf8, + 0x0d, 0x07, 0xa6, 0xd2, 0xc3, 0xb1, 0x7c, 0xad, 0x82, 0xff, 0xda, 0xaa, 0xe1, 0x28, 0x55, 0xd5, + 0xf4, 0xee, 0x7f, 0x7a, 0x0c, 0x58, 0xca, 0x2e, 0xa7, 0x4b, 0x99, 0x6a, 0x38, 0x91, 0xa3, 0xf0, + 0x98, 0x59, 0x51, 0x01, 0x6c, 0xb7, 0x63, 0x4b, 0x84, 0x75, 0x0e, 0x1c, 0x68, 0x6b, 0x95, 0xd8, + 0xe5, 0xb8, 0xd4, 0x5d, 0xae, 0xc7, 0x4e, 0x02, 0x67, 0xc1, 0xd6, 0xd0, 0xfc, 0x1e, 0xaa, 0xb1, + 0x13, 0x35, 0x21, 0x46, 0x6f, 0x1d, 0xd1, 0x7f, 0xeb, 0x88, 0xa5, 0xb5, 0x65, 0xd3, 0xd0, 0x16, + 0x51, 0x4d, 0x1e, 0x0d, 0x2c, 0x16, 0x51, 0x4d, 0xd8, 0x0d, 0xa0, 0x5f, 0xa8, 0xaa, 0xa3, 0x46, + 0xc7, 0xe4, 0x2e, 0xd8, 0x15, 0x1b, 0x65, 0x9b, 0x50, 0x04, 0x43, 0x36, 0x1d, 0x61, 0x57, 0xd8, + 0xd1, 0x94, 0x99, 0xf7, 0x4c, 0x58, 0x95, 0x32, 0x00, 0x61, 0x81, 0x1d, 0xdb, 0xd8, 0x7e, 0xdf, + 0xb0, 0x5d, 0xa4, 0x17, 0xad, 0xb0, 0x19, 0xa6, 0x79, 0x63, 0xad, 0xb2, 0x13, 0xdd, 0x0e, 0x28, + 0x7c, 0xd8, 0xec, 0xab, 0x86, 0xa3, 0x4a, 0xe3, 0xce, 0xa1, 0xe0, 0xa0, 0x8f, 0x47, 0x8b, 0x4a, + 0xf1, 0x1d, 0x43, 0x44, 0x58, 0x65, 0xf5, 0x1b, 0x7f, 0x3b, 0x85, 0xce, 0xae, 0xa8, 0x64, 0x09, + 0xb3, 0xaf, 0xa0, 0xf5, 0xf6, 0x58, 0x26, 0x82, 0x0a, 0xa6, 0x3b, 0x70, 0xc9, 0xb8, 0x1e, 0x03, + 0x30, 0x2c, 0x8e, 0x20, 0x7d, 0x01, 0xc1, 0xb0, 0xea, 0xfc, 0x83, 0xa6, 0xd3, 0x4b, 0xf1, 0x68, + 0xf2, 0x35, 0x3b, 0x8f, 0x2b, 0x15, 0x83, 0x10, 0x03, 0x5b, 0x72, 0x1d, 0xa3, 0x7f, 0xed, 0xe6, + 0x17, 0x3e, 0xe6, 0xc0, 0xb1, 0x74, 0x91, 0x30, 0xa2, 0x25, 0x30, 0xe8, 0x04, 0xcf, 0xe7, 0x91, + 0xfc, 0x79, 0xaf, 0xd0, 0x7e, 0x7e, 0x95, 0x3d, 0x54, 0x36, 0xdc, 0x95, 0xb5, 0x65, 0x51, 0xc3, + 0x15, 0xf6, 0xa0, 0x67, 0x7f, 0x8e, 0x13, 0xfd, 0x9e, 0xe4, 0xd6, 0x6c, 0x44, 0xc4, 0x02, 0xd2, + 0x7e, 0xfc, 0xee, 0x38, 0x60, 0xef, 0xfd, 0x02, 0xd2, 0x64, 0x8a, 0x94, 0xfb, 0x7c, 0x1c, 0x6c, + 0xa1, 0x21, 0xc0, 0x75, 0x0e, 0xec, 0x4e, 0x7a, 0xc4, 0xc3, 0x8b, 0xa9, 0x8a, 0xbf, 0x85, 0x72, + 0xe0, 0xe7, 0x7a, 0x40, 0xf0, 0x99, 0x0b, 0x97, 0x3e, 0x79, 0xf9, 0xdb, 0x17, 0xfd, 0xb3, 0x70, + 0xa6, 0xbd, 0x2a, 0x0c, 0x4b, 0x81, 0xa9, 0x04, 0xe9, 0x61, 0xb0, 0x7d, 0x1f, 0xc1, 0x97, 0x1c, + 0x3b, 0xf0, 0xf1, 0xfa, 0x82, 0xb3, 0x9d, 0x47, 0x18, 0x93, 0x19, 0xfc, 0xc5, 0xee, 0x01, 0x18, + 0xc3, 0x33, 0x94, 0xe1, 0x09, 0x38, 0xdd, 0x01, 0x43, 0x5f, 0x80, 0xc0, 0x47, 0xfd, 0x60, 0x6c, + 0x03, 0x55, 0x41, 0xe0, 0xd5, 0x2e, 0x23, 0x4b, 0x14, 0x30, 0xfc, 0xb5, 0x4d, 0x42, 0x63, 0xa4, + 0xaf, 0x50, 0xd2, 0x79, 0x78, 0xb1, 0x53, 0xd2, 0x9e, 0x8e, 0x74, 0x5c, 0x25, 0xd4, 0x06, 0xf0, + 0x6f, 0x0e, 0xfc, 0x3f, 0x59, 0xa4, 0x10, 0xb8, 0xd8, 0x75, 0xd0, 0xcd, 0x6a, 0x88, 0xbf, 0xba, + 0x39, 0x60, 0x2c, 0x01, 0x0b, 0x34, 0x01, 0x73, 0x70, 0xb6, 0x8b, 0x04, 0x60, 0xbb, 0x8e, 0xff, + 0x9f, 0xc1, 0x93, 0x37, 0x51, 0x3c, 0xc0, 0xcb, 0xe9, 0xa3, 0x6e, 0x25, 0x83, 0xf8, 0x85, 0x9e, + 0x71, 0x18, 0xf1, 0x39, 0x4a, 0xfc, 0x1c, 0x3c, 0x93, 0xe2, 0x67, 0x9e, 0x00, 0x48, 0x89, 0xbd, + 0x20, 0x12, 0x28, 0xd7, 0x5f, 0x61, 0x5d, 0x51, 0x4e, 0x90, 0x47, 0x5d, 0x51, 0x4e, 0x52, 0x37, + 0xdd, 0x51, 0x8e, 0xdd, 0x2f, 0xf0, 0x7b, 0x8e, 0x3d, 0x63, 0x62, 0xc2, 0x06, 0x5e, 0x48, 0x1f, + 0x62, 0x92, 0x5e, 0xe2, 0x67, 0xbb, 0xb6, 0x67, 0xd4, 0x4e, 0x53, 0x6a, 0x39, 0x38, 0xd5, 0x9e, + 0x9a, 0xcb, 0x00, 0xfc, 0x5f, 0x82, 0xe0, 0x57, 0xfd, 0xe0, 0x60, 0x0a, 0xa5, 0x02, 0x6f, 0xa4, + 0x0f, 0x31, 0x95, 0x42, 0xe2, 0x4b, 0x9b, 0x07, 0xc8, 0x92, 0xb0, 0x48, 0x93, 0x70, 0x09, 0xce, + 0xb7, 0x4f, 0x82, 0x13, 0x22, 0x46, 0x35, 0xed, 0x50, 0x4c, 0xc5, 0x57, 0x5e, 0xf0, 0x8f, 0x26, + 0x65, 0x15, 0x17, 0x0c, 0x04, 0x76, 0x70, 0xab, 0x6e, 0x20, 0xdf, 0xf8, 0x7c, 0x2f, 0x10, 0x8c, + 0x75, 0x9e, 0xb2, 0x3e, 0x0f, 0xcf, 0xb6, 0x67, 0x1d, 0x08, 0x37, 0xa5, 0xf1, 0x02, 0xfb, 0xb2, + 0x9f, 0xfd, 0x2c, 0x96, 0x42, 0x29, 0xc1, 0xa5, 0xf4, 0x41, 0xa7, 0xd7, 0x71, 0xfc, 0xed, 0x4d, + 0x46, 0x65, 0xd9, 0x39, 0x47, 0xb3, 0x73, 0x12, 0x9e, 0xe8, 0xb8, 0xbf, 0x1b, 0x3a, 0xfc, 0x96, + 0x03, 0xa3, 0x75, 0xf2, 0x04, 0x9e, 0xea, 0x60, 0xbb, 0xea, 0x65, 0x0e, 0x7f, 0xba, 0x73, 0x43, + 0x16, 0xff, 0x14, 0x8d, 0xff, 0x08, 0x9c, 0x4c, 0xb1, 0xbb, 0x7e, 0x90, 0x8f, 0x83, 0x03, 0xdd, + 0x5a, 0xa8, 0x74, 0x72, 0xa0, 0x53, 0x69, 0xa7, 0x4e, 0x0e, 0x74, 0x3a, 0x0d, 0x25, 0xcc, 0x50, + 0xf2, 0xa7, 0xe0, 0xc9, 0xf6, 0xe4, 0xb1, 0x07, 0xa2, 0x18, 0x96, 0x12, 0xe9, 0x29, 0xf8, 0x75, + 0x3f, 0x38, 0x9c, 0x5a, 0xcc, 0xc0, 0xdb, 0xdd, 0xbe, 0x20, 0x5b, 0xea, 0x31, 0xfe, 0xce, 0x66, + 0xc3, 0xf6, 0xfa, 0x70, 0x21, 0x8a, 0x8d, 0x9c, 0x28, 0x4d, 0xf0, 0xb3, 0x7e, 0xf0, 0x46, 0x1a, + 0x11, 0x04, 0x4b, 0x3d, 0x3c, 0x3d, 0x12, 0x95, 0x1d, 0x7f, 0x73, 0x13, 0x11, 0x3b, 0xef, 0x86, + 0x51, 0x5a, 0x42, 0x28, 0xc5, 0xd3, 0x64, 0xf9, 0x77, 0x9e, 0xaf, 0x67, 0xb8, 0x17, 0xeb, 0x19, + 0xee, 0xd7, 0xf5, 0x0c, 0xf7, 0xf4, 0x75, 0xa6, 0xef, 0xc5, 0xeb, 0x4c, 0xdf, 0x4f, 0xaf, 0x33, + 0x7d, 0xef, 0xce, 0x34, 0x2b, 0xbd, 0xc8, 0xcd, 0xf1, 0xd0, 0x4d, 0xf5, 0x6d, 0xe9, 0x41, 0xc3, + 0xa5, 0xeb, 0x89, 0xc0, 0xe5, 0x21, 0xfa, 0xc3, 0xe3, 0x89, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, + 0xc8, 0x14, 0xa5, 0x41, 0x5a, 0x1b, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1319,6 +1647,15 @@ type QueryClient interface { QueryAllPairsValConAddrByConsumerChainID(ctx context.Context, in *QueryAllPairsValConAddrByConsumerChainIDRequest, opts ...grpc.CallOption) (*QueryAllPairsValConAddrByConsumerChainIDResponse, error) // QueryParams returns all current values of provider parameters QueryParams(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) + // QueryConsumerChainOptedInValidators returns a list of validators consensus address + // that opted-in to the given consumer chain + QueryConsumerChainOptedInValidators(ctx context.Context, in *QueryConsumerChainOptedInValidatorsRequest, opts ...grpc.CallOption) (*QueryConsumerChainOptedInValidatorsResponse, error) + // QueryConsumerChainsValidatorHasToValidate returns a list of consumer chains + // that a given validator must validate + QueryConsumerChainsValidatorHasToValidate(ctx context.Context, in *QueryConsumerChainsValidatorHasToValidateRequest, opts ...grpc.CallOption) (*QueryConsumerChainsValidatorHasToValidateResponse, error) + // QueryValidatorConsumerCommissionRate returns the commission rate a given + // validator charges on a given consumer chain + QueryValidatorConsumerCommissionRate(ctx context.Context, in *QueryValidatorConsumerCommissionRateRequest, opts ...grpc.CallOption) (*QueryValidatorConsumerCommissionRateResponse, error) } type queryClient struct { @@ -1428,6 +1765,33 @@ func (c *queryClient) QueryParams(ctx context.Context, in *QueryParamsRequest, o return out, nil } +func (c *queryClient) QueryConsumerChainOptedInValidators(ctx context.Context, in *QueryConsumerChainOptedInValidatorsRequest, opts ...grpc.CallOption) (*QueryConsumerChainOptedInValidatorsResponse, error) { + out := new(QueryConsumerChainOptedInValidatorsResponse) + err := c.cc.Invoke(ctx, "/interchain_security.ccv.provider.v1.Query/QueryConsumerChainOptedInValidators", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) QueryConsumerChainsValidatorHasToValidate(ctx context.Context, in *QueryConsumerChainsValidatorHasToValidateRequest, opts ...grpc.CallOption) (*QueryConsumerChainsValidatorHasToValidateResponse, error) { + out := new(QueryConsumerChainsValidatorHasToValidateResponse) + err := c.cc.Invoke(ctx, "/interchain_security.ccv.provider.v1.Query/QueryConsumerChainsValidatorHasToValidate", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) QueryValidatorConsumerCommissionRate(ctx context.Context, in *QueryValidatorConsumerCommissionRateRequest, opts ...grpc.CallOption) (*QueryValidatorConsumerCommissionRateResponse, error) { + out := new(QueryValidatorConsumerCommissionRateResponse) + err := c.cc.Invoke(ctx, "/interchain_security.ccv.provider.v1.Query/QueryValidatorConsumerCommissionRate", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // QueryServer is the server API for Query service. type QueryServer interface { // ConsumerGenesis queries the genesis state needed to start a consumer chain @@ -1460,6 +1824,15 @@ type QueryServer interface { QueryAllPairsValConAddrByConsumerChainID(context.Context, *QueryAllPairsValConAddrByConsumerChainIDRequest) (*QueryAllPairsValConAddrByConsumerChainIDResponse, error) // QueryParams returns all current values of provider parameters QueryParams(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) + // QueryConsumerChainOptedInValidators returns a list of validators consensus address + // that opted-in to the given consumer chain + QueryConsumerChainOptedInValidators(context.Context, *QueryConsumerChainOptedInValidatorsRequest) (*QueryConsumerChainOptedInValidatorsResponse, error) + // QueryConsumerChainsValidatorHasToValidate returns a list of consumer chains + // that a given validator must validate + QueryConsumerChainsValidatorHasToValidate(context.Context, *QueryConsumerChainsValidatorHasToValidateRequest) (*QueryConsumerChainsValidatorHasToValidateResponse, error) + // QueryValidatorConsumerCommissionRate returns the commission rate a given + // validator charges on a given consumer chain + QueryValidatorConsumerCommissionRate(context.Context, *QueryValidatorConsumerCommissionRateRequest) (*QueryValidatorConsumerCommissionRateResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -1499,6 +1872,15 @@ func (*UnimplementedQueryServer) QueryAllPairsValConAddrByConsumerChainID(ctx co func (*UnimplementedQueryServer) QueryParams(ctx context.Context, req *QueryParamsRequest) (*QueryParamsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method QueryParams not implemented") } +func (*UnimplementedQueryServer) QueryConsumerChainOptedInValidators(ctx context.Context, req *QueryConsumerChainOptedInValidatorsRequest) (*QueryConsumerChainOptedInValidatorsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method QueryConsumerChainOptedInValidators not implemented") +} +func (*UnimplementedQueryServer) QueryConsumerChainsValidatorHasToValidate(ctx context.Context, req *QueryConsumerChainsValidatorHasToValidateRequest) (*QueryConsumerChainsValidatorHasToValidateResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method QueryConsumerChainsValidatorHasToValidate not implemented") +} +func (*UnimplementedQueryServer) QueryValidatorConsumerCommissionRate(ctx context.Context, req *QueryValidatorConsumerCommissionRateRequest) (*QueryValidatorConsumerCommissionRateResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method QueryValidatorConsumerCommissionRate not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -1702,6 +2084,60 @@ func _Query_QueryParams_Handler(srv interface{}, ctx context.Context, dec func(i return interceptor(ctx, in, info, handler) } +func _Query_QueryConsumerChainOptedInValidators_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryConsumerChainOptedInValidatorsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).QueryConsumerChainOptedInValidators(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/interchain_security.ccv.provider.v1.Query/QueryConsumerChainOptedInValidators", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).QueryConsumerChainOptedInValidators(ctx, req.(*QueryConsumerChainOptedInValidatorsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_QueryConsumerChainsValidatorHasToValidate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryConsumerChainsValidatorHasToValidateRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).QueryConsumerChainsValidatorHasToValidate(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/interchain_security.ccv.provider.v1.Query/QueryConsumerChainsValidatorHasToValidate", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).QueryConsumerChainsValidatorHasToValidate(ctx, req.(*QueryConsumerChainsValidatorHasToValidateRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_QueryValidatorConsumerCommissionRate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryValidatorConsumerCommissionRateRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).QueryValidatorConsumerCommissionRate(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/interchain_security.ccv.provider.v1.Query/QueryValidatorConsumerCommissionRate", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).QueryValidatorConsumerCommissionRate(ctx, req.(*QueryValidatorConsumerCommissionRateRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "interchain_security.ccv.provider.v1.Query", HandlerType: (*QueryServer)(nil), @@ -1750,6 +2186,18 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "QueryParams", Handler: _Query_QueryParams_Handler, }, + { + MethodName: "QueryConsumerChainOptedInValidators", + Handler: _Query_QueryConsumerChainOptedInValidators_Handler, + }, + { + MethodName: "QueryConsumerChainsValidatorHasToValidate", + Handler: _Query_QueryConsumerChainsValidatorHasToValidate_Handler, + }, + { + MethodName: "QueryValidatorConsumerCommissionRate", + Handler: _Query_QueryValidatorConsumerCommissionRate_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "interchain_security/ccv/provider/v1/query.proto", @@ -2014,7 +2462,12 @@ func (m *Chain) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if len(m.ClientId) > 0 { + if m.Top_N != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.Top_N)) + i-- + dAtA[i] = 0x18 + } + if len(m.ClientId) > 0 { i -= len(m.ClientId) copy(dAtA[i:], m.ClientId) i = encodeVarintQuery(dAtA, i, uint64(len(m.ClientId))) @@ -2551,6 +3004,200 @@ func (m *QueryParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *QueryConsumerChainOptedInValidatorsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryConsumerChainOptedInValidatorsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryConsumerChainOptedInValidatorsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ChainId) > 0 { + i -= len(m.ChainId) + copy(dAtA[i:], m.ChainId) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ChainId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryConsumerChainOptedInValidatorsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryConsumerChainOptedInValidatorsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryConsumerChainOptedInValidatorsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ValidatorsProviderAddresses) > 0 { + for iNdEx := len(m.ValidatorsProviderAddresses) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.ValidatorsProviderAddresses[iNdEx]) + copy(dAtA[i:], m.ValidatorsProviderAddresses[iNdEx]) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ValidatorsProviderAddresses[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryConsumerChainsValidatorHasToValidateRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryConsumerChainsValidatorHasToValidateRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryConsumerChainsValidatorHasToValidateRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ProviderAddress) > 0 { + i -= len(m.ProviderAddress) + copy(dAtA[i:], m.ProviderAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ProviderAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryConsumerChainsValidatorHasToValidateResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryConsumerChainsValidatorHasToValidateResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryConsumerChainsValidatorHasToValidateResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ConsumerChainIds) > 0 { + for iNdEx := len(m.ConsumerChainIds) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.ConsumerChainIds[iNdEx]) + copy(dAtA[i:], m.ConsumerChainIds[iNdEx]) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ConsumerChainIds[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryValidatorConsumerCommissionRateRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryValidatorConsumerCommissionRateRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryValidatorConsumerCommissionRateRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ProviderAddress) > 0 { + i -= len(m.ProviderAddress) + copy(dAtA[i:], m.ProviderAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ProviderAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.ChainId) > 0 { + i -= len(m.ChainId) + copy(dAtA[i:], m.ChainId) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ChainId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryValidatorConsumerCommissionRateResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryValidatorConsumerCommissionRateResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryValidatorConsumerCommissionRateResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.Rate.Size() + i -= size + if _, err := m.Rate.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { offset -= sovQuery(v) base := offset @@ -2668,6 +3315,9 @@ func (m *Chain) Size() (n int) { if l > 0 { n += 1 + l + sovQuery(uint64(l)) } + if m.Top_N != 0 { + n += 1 + sovQuery(uint64(m.Top_N)) + } return n } @@ -2890,6 +3540,90 @@ func (m *QueryParamsResponse) Size() (n int) { return n } +func (m *QueryConsumerChainOptedInValidatorsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ChainId) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryConsumerChainOptedInValidatorsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.ValidatorsProviderAddresses) > 0 { + for _, s := range m.ValidatorsProviderAddresses { + l = len(s) + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func (m *QueryConsumerChainsValidatorHasToValidateRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ProviderAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryConsumerChainsValidatorHasToValidateResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.ConsumerChainIds) > 0 { + for _, s := range m.ConsumerChainIds { + l = len(s) + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func (m *QueryValidatorConsumerCommissionRateRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ChainId) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.ProviderAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryValidatorConsumerCommissionRateResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Rate.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + func sovQuery(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -3560,20 +4294,39 @@ func (m *Chain) Unmarshal(dAtA []byte) error { } m.ClientId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Top_N", wireType) } - iNdEx += skippy - } + m.Top_N = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Top_N |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } } if iNdEx > l { @@ -4960,6 +5713,532 @@ func (m *QueryParamsResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryConsumerChainOptedInValidatorsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryConsumerChainOptedInValidatorsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryConsumerChainOptedInValidatorsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", 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.ChainId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryConsumerChainOptedInValidatorsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryConsumerChainOptedInValidatorsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryConsumerChainOptedInValidatorsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorsProviderAddresses", 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.ValidatorsProviderAddresses = append(m.ValidatorsProviderAddresses, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryConsumerChainsValidatorHasToValidateRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryConsumerChainsValidatorHasToValidateRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryConsumerChainsValidatorHasToValidateRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProviderAddress", 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.ProviderAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryConsumerChainsValidatorHasToValidateResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryConsumerChainsValidatorHasToValidateResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryConsumerChainsValidatorHasToValidateResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConsumerChainIds", 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.ConsumerChainIds = append(m.ConsumerChainIds, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryValidatorConsumerCommissionRateRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryValidatorConsumerCommissionRateRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryValidatorConsumerCommissionRateRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", 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.ChainId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProviderAddress", 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.ProviderAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryValidatorConsumerCommissionRateResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryValidatorConsumerCommissionRateResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryValidatorConsumerCommissionRateResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Rate", 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 + } + if err := m.Rate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipQuery(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/ccv/provider/types/query.pb.gw.go b/x/ccv/provider/types/query.pb.gw.go index bc37627c52..9b13ca9999 100644 --- a/x/ccv/provider/types/query.pb.gw.go +++ b/x/ccv/provider/types/query.pb.gw.go @@ -321,6 +321,114 @@ func local_request_Query_QueryParams_0(ctx context.Context, marshaler runtime.Ma } +var ( + filter_Query_QueryConsumerChainOptedInValidators_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_QueryConsumerChainOptedInValidators_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryConsumerChainOptedInValidatorsRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_QueryConsumerChainOptedInValidators_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.QueryConsumerChainOptedInValidators(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_QueryConsumerChainOptedInValidators_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryConsumerChainOptedInValidatorsRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_QueryConsumerChainOptedInValidators_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.QueryConsumerChainOptedInValidators(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_QueryConsumerChainsValidatorHasToValidate_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_QueryConsumerChainsValidatorHasToValidate_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryConsumerChainsValidatorHasToValidateRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_QueryConsumerChainsValidatorHasToValidate_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.QueryConsumerChainsValidatorHasToValidate(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_QueryConsumerChainsValidatorHasToValidate_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryConsumerChainsValidatorHasToValidateRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_QueryConsumerChainsValidatorHasToValidate_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.QueryConsumerChainsValidatorHasToValidate(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_QueryValidatorConsumerCommissionRate_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_QueryValidatorConsumerCommissionRate_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryValidatorConsumerCommissionRateRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_QueryValidatorConsumerCommissionRate_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.QueryValidatorConsumerCommissionRate(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_QueryValidatorConsumerCommissionRate_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryValidatorConsumerCommissionRateRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_QueryValidatorConsumerCommissionRate_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.QueryValidatorConsumerCommissionRate(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterQueryHandlerServer registers the http handlers for service Query to "mux". // UnaryRPC :call QueryServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -580,6 +688,75 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_QueryConsumerChainOptedInValidators_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_QueryConsumerChainOptedInValidators_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_QueryConsumerChainOptedInValidators_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_QueryConsumerChainsValidatorHasToValidate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_QueryConsumerChainsValidatorHasToValidate_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_QueryConsumerChainsValidatorHasToValidate_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_QueryValidatorConsumerCommissionRate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_QueryValidatorConsumerCommissionRate_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_QueryValidatorConsumerCommissionRate_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -841,6 +1018,66 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_QueryConsumerChainOptedInValidators_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_QueryConsumerChainOptedInValidators_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_QueryConsumerChainOptedInValidators_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_QueryConsumerChainsValidatorHasToValidate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_QueryConsumerChainsValidatorHasToValidate_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_QueryConsumerChainsValidatorHasToValidate_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_QueryValidatorConsumerCommissionRate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_QueryValidatorConsumerCommissionRate_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_QueryValidatorConsumerCommissionRate_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -866,6 +1103,12 @@ var ( pattern_Query_QueryAllPairsValConAddrByConsumerChainID_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"interchain_security", "ccv", "provider", "consumer_chain_id"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_QueryParams_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"interchain_security", "ccv", "provider", "params"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_QueryConsumerChainOptedInValidators_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"interchain_security", "ccv", "provider", "opted_in_validators"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_QueryConsumerChainsValidatorHasToValidate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"interchain_security", "ccv", "provider", "consumer_chains_per_validator"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_QueryValidatorConsumerCommissionRate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"interchain_security", "ccv", "provider", "consumer_commission_rate"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( @@ -890,4 +1133,10 @@ var ( forward_Query_QueryAllPairsValConAddrByConsumerChainID_0 = runtime.ForwardResponseMessage forward_Query_QueryParams_0 = runtime.ForwardResponseMessage + + forward_Query_QueryConsumerChainOptedInValidators_0 = runtime.ForwardResponseMessage + + forward_Query_QueryConsumerChainsValidatorHasToValidate_0 = runtime.ForwardResponseMessage + + forward_Query_QueryValidatorConsumerCommissionRate_0 = runtime.ForwardResponseMessage ) From 26f3c82106cb55318cc31c81e6365c9d7fb18a29 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Date: Tue, 2 Apr 2024 09:16:34 +0200 Subject: [PATCH 040/110] fix!: Fix opt-in assignment (#1732) * Make the same validator assigning the same key a noop instead of an error * Adjust test * Update tests * Fix newline warning * Regenerate traces * Add key assignment change to changelog * Add info log for same key same validator assignments * Add changelog entry to api-breaking * Update x/ccv/provider/handler_test.go Co-authored-by: insumity * Add more comments to test and return right validator --------- Co-authored-by: insumity --- ...1732-assigning-already-assigned-key-fix.md | 2 + ...1732-assigning-already-assigned-key-fix.md | 2 + tests/e2e/main.go | 4 +- tests/e2e/steps_compatibility.go | 12 ---- tests/e2e/steps_start_chains.go | 16 ++++-- .../consumer-double-sign.json | 26 ++++++++- .../e2e/tracehandler_testdata/democracy.json | 26 ++++++++- .../democracyRewardsSteps.json | 26 ++++++++- .../e2e/tracehandler_testdata/happyPath.json | 26 ++++++++- .../multipleConsumers.json | 52 +++++++++++++++-- .../e2e/tracehandler_testdata/shorthappy.json | 26 ++++++++- .../tracehandler_testdata/slashThrottle.json | 26 ++++++++- tests/integration/key_assignment.go | 57 +++++++++++++++++-- x/ccv/provider/handler_test.go | 33 ++++++++++- x/ccv/provider/keeper/key_assignment.go | 22 +++++-- 15 files changed, 302 insertions(+), 54 deletions(-) create mode 100644 .changelog/unreleased/api-breaking/provider/1732-assigning-already-assigned-key-fix.md create mode 100644 .changelog/unreleased/state-breaking/provider/1732-assigning-already-assigned-key-fix.md diff --git a/.changelog/unreleased/api-breaking/provider/1732-assigning-already-assigned-key-fix.md b/.changelog/unreleased/api-breaking/provider/1732-assigning-already-assigned-key-fix.md new file mode 100644 index 0000000000..667a481d3f --- /dev/null +++ b/.changelog/unreleased/api-breaking/provider/1732-assigning-already-assigned-key-fix.md @@ -0,0 +1,2 @@ +- Assigning a key that is already assigned by the same validator will now be a no-op instead of throwing an error. + ([\#1732](https://github.com/cosmos/interchain-security/pull/1732)) \ No newline at end of file diff --git a/.changelog/unreleased/state-breaking/provider/1732-assigning-already-assigned-key-fix.md b/.changelog/unreleased/state-breaking/provider/1732-assigning-already-assigned-key-fix.md new file mode 100644 index 0000000000..667a481d3f --- /dev/null +++ b/.changelog/unreleased/state-breaking/provider/1732-assigning-already-assigned-key-fix.md @@ -0,0 +1,2 @@ +- Assigning a key that is already assigned by the same validator will now be a no-op instead of throwing an error. + ([\#1732](https://github.com/cosmos/interchain-security/pull/1732)) \ No newline at end of file diff --git a/tests/e2e/main.go b/tests/e2e/main.go index 7b2ba26278..00a9d0ea15 100644 --- a/tests/e2e/main.go +++ b/tests/e2e/main.go @@ -430,13 +430,13 @@ TEST RESULTS } } if len(passedTests) > 0 { - report += fmt.Sprintln("\n\nPASSED TESTS:\n") + report += fmt.Sprintln("\n\nPASSED TESTS:") for _, t := range passedTests { report += t.Report() } } if len(remainingTests) > 0 { - report += fmt.Sprintln("\n\nREMAINING TESTS:\n") + report += fmt.Sprintln("\n\nREMAINING TESTS:") for _, t := range remainingTests { report += t.Report() } diff --git a/tests/e2e/steps_compatibility.go b/tests/e2e/steps_compatibility.go index ef3cab4e73..000287d640 100644 --- a/tests/e2e/steps_compatibility.go +++ b/tests/e2e/steps_compatibility.go @@ -85,18 +85,6 @@ func compstepsStartConsumerChain(consumerName string, proposalIndex, chainIndex }, }, }, - { - // op should fail - key already assigned by the same validator - Action: AssignConsumerPubKeyAction{ - Chain: ChainID(consumerName), - Validator: ValidatorID("carol"), - ConsumerPubkey: getDefaultValidators()[ValidatorID("carol")].ConsumerValPubKey, - ReconfigureNode: false, - ExpectError: true, - ExpectedError: "a validator has assigned the consumer key already: consumer key is already in use by a validator", - }, - State: State{}, - }, { // op should fail - key already assigned by another validator Action: AssignConsumerPubKeyAction{ diff --git a/tests/e2e/steps_start_chains.go b/tests/e2e/steps_start_chains.go index 08732e3f37..8dcbd7d06f 100644 --- a/tests/e2e/steps_start_chains.go +++ b/tests/e2e/steps_start_chains.go @@ -82,16 +82,24 @@ func stepsStartConsumerChain(consumerName string, proposalIndex, chainIndex uint }, }, { - // op should fail - key already assigned by the same validator + // op should be a noop - key already assigned, but by the same validator Action: AssignConsumerPubKeyAction{ Chain: ChainID(consumerName), Validator: ValidatorID("carol"), ConsumerPubkey: getDefaultValidators()[ValidatorID("carol")].ConsumerValPubKey, ReconfigureNode: false, - ExpectError: true, - ExpectedError: "a validator has assigned the consumer key already: consumer key is already in use by a validator", + ExpectError: false, + }, + State: State{ + ChainID(consumerName): ChainState{ + AssignedKeys: &map[ValidatorID]string{ + ValidatorID("carol"): getDefaultValidators()[ValidatorID("carol")].ConsumerValconsAddressOnProvider, + }, + ProviderKeys: &map[ValidatorID]string{ + ValidatorID("carol"): getDefaultValidators()[ValidatorID("carol")].ValconsAddress, + }, + }, }, - State: State{}, }, { // op should fail - key already assigned by another validator diff --git a/tests/e2e/tracehandler_testdata/consumer-double-sign.json b/tests/e2e/tracehandler_testdata/consumer-double-sign.json index e93049cf8b..8a5203757b 100644 --- a/tests/e2e/tracehandler_testdata/consumer-double-sign.json +++ b/tests/e2e/tracehandler_testdata/consumer-double-sign.json @@ -134,10 +134,30 @@ "Validator": "carol", "ConsumerPubkey": "{\"@type\":\"/cosmos.crypto.ed25519.PubKey\",\"key\":\"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is=\"}", "ReconfigureNode": false, - "ExpectError": true, - "ExpectedError": "a validator has assigned the consumer key already: consumer key is already in use by a validator" + "ExpectError": false, + "ExpectedError": "" }, - "State": {} + "State": { + "consu": { + "ValBalances": null, + "ProposedConsumerChains": null, + "ValPowers": null, + "StakedTokens": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": { + "carol": "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk" + }, + "ProviderKeys": { + "carol": "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6" + }, + "ConsumerPendingPacketQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "ClientsFrozenHeights": null, + "Proposals": null + } + } }, { "ActionType": "main.AssignConsumerPubKeyAction", diff --git a/tests/e2e/tracehandler_testdata/democracy.json b/tests/e2e/tracehandler_testdata/democracy.json index 10c9838122..3f425a2a92 100644 --- a/tests/e2e/tracehandler_testdata/democracy.json +++ b/tests/e2e/tracehandler_testdata/democracy.json @@ -134,10 +134,30 @@ "Validator": "carol", "ConsumerPubkey": "{\"@type\":\"/cosmos.crypto.ed25519.PubKey\",\"key\":\"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is=\"}", "ReconfigureNode": false, - "ExpectError": true, - "ExpectedError": "a validator has assigned the consumer key already: consumer key is already in use by a validator" + "ExpectError": false, + "ExpectedError": "" }, - "State": {} + "State": { + "democ": { + "ValBalances": null, + "ProposedConsumerChains": null, + "ValPowers": null, + "StakedTokens": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": { + "carol": "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk" + }, + "ProviderKeys": { + "carol": "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6" + }, + "ConsumerPendingPacketQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "ClientsFrozenHeights": null, + "Proposals": null + } + } }, { "ActionType": "main.AssignConsumerPubKeyAction", diff --git a/tests/e2e/tracehandler_testdata/democracyRewardsSteps.json b/tests/e2e/tracehandler_testdata/democracyRewardsSteps.json index 7e6d90cace..1235c47a22 100644 --- a/tests/e2e/tracehandler_testdata/democracyRewardsSteps.json +++ b/tests/e2e/tracehandler_testdata/democracyRewardsSteps.json @@ -134,10 +134,30 @@ "Validator": "carol", "ConsumerPubkey": "{\"@type\":\"/cosmos.crypto.ed25519.PubKey\",\"key\":\"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is=\"}", "ReconfigureNode": false, - "ExpectError": true, - "ExpectedError": "a validator has assigned the consumer key already: consumer key is already in use by a validator" + "ExpectError": false, + "ExpectedError": "" }, - "State": {} + "State": { + "democ": { + "ValBalances": null, + "ProposedConsumerChains": null, + "ValPowers": null, + "StakedTokens": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": { + "carol": "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk" + }, + "ProviderKeys": { + "carol": "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6" + }, + "ConsumerPendingPacketQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "ClientsFrozenHeights": null, + "Proposals": null + } + } }, { "ActionType": "main.AssignConsumerPubKeyAction", diff --git a/tests/e2e/tracehandler_testdata/happyPath.json b/tests/e2e/tracehandler_testdata/happyPath.json index 5b9505e848..04afc707a6 100644 --- a/tests/e2e/tracehandler_testdata/happyPath.json +++ b/tests/e2e/tracehandler_testdata/happyPath.json @@ -134,10 +134,30 @@ "Validator": "carol", "ConsumerPubkey": "{\"@type\":\"/cosmos.crypto.ed25519.PubKey\",\"key\":\"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is=\"}", "ReconfigureNode": false, - "ExpectError": true, - "ExpectedError": "a validator has assigned the consumer key already: consumer key is already in use by a validator" + "ExpectError": false, + "ExpectedError": "" }, - "State": {} + "State": { + "consu": { + "ValBalances": null, + "ProposedConsumerChains": null, + "ValPowers": null, + "StakedTokens": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": { + "carol": "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk" + }, + "ProviderKeys": { + "carol": "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6" + }, + "ConsumerPendingPacketQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "ClientsFrozenHeights": null, + "Proposals": null + } + } }, { "ActionType": "main.AssignConsumerPubKeyAction", diff --git a/tests/e2e/tracehandler_testdata/multipleConsumers.json b/tests/e2e/tracehandler_testdata/multipleConsumers.json index fdb69d1e47..610e8a786f 100644 --- a/tests/e2e/tracehandler_testdata/multipleConsumers.json +++ b/tests/e2e/tracehandler_testdata/multipleConsumers.json @@ -134,10 +134,30 @@ "Validator": "carol", "ConsumerPubkey": "{\"@type\":\"/cosmos.crypto.ed25519.PubKey\",\"key\":\"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is=\"}", "ReconfigureNode": false, - "ExpectError": true, - "ExpectedError": "a validator has assigned the consumer key already: consumer key is already in use by a validator" + "ExpectError": false, + "ExpectedError": "" }, - "State": {} + "State": { + "consu": { + "ValBalances": null, + "ProposedConsumerChains": null, + "ValPowers": null, + "StakedTokens": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": { + "carol": "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk" + }, + "ProviderKeys": { + "carol": "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6" + }, + "ConsumerPendingPacketQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "ClientsFrozenHeights": null, + "Proposals": null + } + } }, { "ActionType": "main.AssignConsumerPubKeyAction", @@ -399,10 +419,30 @@ "Validator": "carol", "ConsumerPubkey": "{\"@type\":\"/cosmos.crypto.ed25519.PubKey\",\"key\":\"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is=\"}", "ReconfigureNode": false, - "ExpectError": true, - "ExpectedError": "a validator has assigned the consumer key already: consumer key is already in use by a validator" + "ExpectError": false, + "ExpectedError": "" }, - "State": {} + "State": { + "densu": { + "ValBalances": null, + "ProposedConsumerChains": null, + "ValPowers": null, + "StakedTokens": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": { + "carol": "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk" + }, + "ProviderKeys": { + "carol": "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6" + }, + "ConsumerPendingPacketQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "ClientsFrozenHeights": null, + "Proposals": null + } + } }, { "ActionType": "main.AssignConsumerPubKeyAction", diff --git a/tests/e2e/tracehandler_testdata/shorthappy.json b/tests/e2e/tracehandler_testdata/shorthappy.json index 607c1d6d7c..1be75865aa 100644 --- a/tests/e2e/tracehandler_testdata/shorthappy.json +++ b/tests/e2e/tracehandler_testdata/shorthappy.json @@ -134,10 +134,30 @@ "Validator": "carol", "ConsumerPubkey": "{\"@type\":\"/cosmos.crypto.ed25519.PubKey\",\"key\":\"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is=\"}", "ReconfigureNode": false, - "ExpectError": true, - "ExpectedError": "a validator has assigned the consumer key already: consumer key is already in use by a validator" + "ExpectError": false, + "ExpectedError": "" }, - "State": {} + "State": { + "consu": { + "ValBalances": null, + "ProposedConsumerChains": null, + "ValPowers": null, + "StakedTokens": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": { + "carol": "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk" + }, + "ProviderKeys": { + "carol": "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6" + }, + "ConsumerPendingPacketQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "ClientsFrozenHeights": null, + "Proposals": null + } + } }, { "ActionType": "main.AssignConsumerPubKeyAction", diff --git a/tests/e2e/tracehandler_testdata/slashThrottle.json b/tests/e2e/tracehandler_testdata/slashThrottle.json index e99e7e2973..352f7cc06d 100644 --- a/tests/e2e/tracehandler_testdata/slashThrottle.json +++ b/tests/e2e/tracehandler_testdata/slashThrottle.json @@ -134,10 +134,30 @@ "Validator": "carol", "ConsumerPubkey": "{\"@type\":\"/cosmos.crypto.ed25519.PubKey\",\"key\":\"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is=\"}", "ReconfigureNode": false, - "ExpectError": true, - "ExpectedError": "a validator has assigned the consumer key already: consumer key is already in use by a validator" + "ExpectError": false, + "ExpectedError": "" }, - "State": {} + "State": { + "consu": { + "ValBalances": null, + "ProposedConsumerChains": null, + "ValPowers": null, + "StakedTokens": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": { + "carol": "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk" + }, + "ProviderKeys": { + "carol": "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6" + }, + "ConsumerPendingPacketQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "ClientsFrozenHeights": null, + "Proposals": null + } + } }, { "ActionType": "main.AssignConsumerPubKeyAction", diff --git a/tests/integration/key_assignment.go b/tests/integration/key_assignment.go index ab6cb63146..799109c0d4 100644 --- a/tests/integration/key_assignment.go +++ b/tests/integration/key_assignment.go @@ -79,7 +79,7 @@ func (s *CCVTestSuite) TestKeyAssignment() { }, false, 2, }, { - "double same-key assignment in same block", func(pk *providerkeeper.Keeper) error { + "double same-key assignment in same block by different vals", func(pk *providerkeeper.Keeper) error { // establish CCV channel s.SetupCCVChannel(s.path) @@ -90,8 +90,9 @@ func (s *CCVTestSuite) TestKeyAssignment() { return err } - // same key assignment - err = pk.AssignConsumerKey(s.providerCtx(), s.consumerChain.ChainID, validator, consumerKey) + // same key assignment, but different validator + validator2, _ := generateNewConsumerKey(s, 1) + err = pk.AssignConsumerKey(s.providerCtx(), s.consumerChain.ChainID, validator2, consumerKey) if err != nil { return err } @@ -100,6 +101,28 @@ func (s *CCVTestSuite) TestKeyAssignment() { return nil }, true, 2, }, + { + "double same-key assignment in same block by same val", func(pk *providerkeeper.Keeper) error { + // establish CCV channel + s.SetupCCVChannel(s.path) + + // key assignment + validator, consumerKey := generateNewConsumerKey(s, 0) + err := pk.AssignConsumerKey(s.providerCtx(), s.consumerChain.ChainID, validator, consumerKey) + if err != nil { + return err + } + + // same key assignment, but different validator + err = pk.AssignConsumerKey(s.providerCtx(), s.consumerChain.ChainID, validator, consumerKey) + if err != nil { + return err + } + s.nextEpoch() + + return nil + }, false, 2, + }, { "double key assignment in same block", func(pk *providerkeeper.Keeper) error { // establish CCV channel @@ -124,7 +147,7 @@ func (s *CCVTestSuite) TestKeyAssignment() { }, false, 2, }, { - "double same-key assignment in different blocks", func(pk *providerkeeper.Keeper) error { + "double same-key assignment in different blocks by different vals", func(pk *providerkeeper.Keeper) error { // establish CCV channel s.SetupCCVChannel(s.path) @@ -137,7 +160,8 @@ func (s *CCVTestSuite) TestKeyAssignment() { s.nextEpoch() // same key assignment - err = pk.AssignConsumerKey(s.providerCtx(), s.consumerChain.ChainID, validator, consumerKey) + validator2, _ := generateNewConsumerKey(s, 1) + err = pk.AssignConsumerKey(s.providerCtx(), s.consumerChain.ChainID, validator2, consumerKey) if err != nil { return err } @@ -146,6 +170,29 @@ func (s *CCVTestSuite) TestKeyAssignment() { return nil }, true, 2, }, + { + "double same-key assignment in different blocks by same val", func(pk *providerkeeper.Keeper) error { + // establish CCV channel + s.SetupCCVChannel(s.path) + + // key assignment + validator, consumerKey := generateNewConsumerKey(s, 0) + err := pk.AssignConsumerKey(s.providerCtx(), s.consumerChain.ChainID, validator, consumerKey) + if err != nil { + return err + } + s.nextEpoch() + + // same key assignment + err = pk.AssignConsumerKey(s.providerCtx(), s.consumerChain.ChainID, validator, consumerKey) + if err != nil { + return err + } + s.nextEpoch() + + return nil + }, false, 2, + }, { "double key assignment in different blocks", func(pk *providerkeeper.Keeper) error { // establish CCV channel diff --git a/x/ccv/provider/handler_test.go b/x/ccv/provider/handler_test.go index 8cefa3f949..6e13511e3b 100644 --- a/x/ccv/provider/handler_test.go +++ b/x/ccv/provider/handler_test.go @@ -34,6 +34,10 @@ func TestAssignConsensusKeyForConsumerChain(t *testing.T) { providerCryptoId := testcrypto.NewCryptoIdentityFromIntSeed(0) providerConsAddr := providerCryptoId.ProviderConsAddress() + // a different providerConsAddr, to simulate different validators having assigned keys + providerCryptoId2 := testcrypto.NewCryptoIdentityFromIntSeed(10) + providerConsAddr2 := providerCryptoId2.ProviderConsAddress() + consumerCryptoId := testcrypto.NewCryptoIdentityFromIntSeed(1) consumerConsAddr := consumerCryptoId.ConsumerConsAddress() consumerKeyBz := base64.StdEncoding.EncodeToString(consumerCryptoId.ConsensusSDKPubKey().Bytes()) @@ -101,7 +105,32 @@ func TestAssignConsensusKeyForConsumerChain(t *testing.T) { chainID: "chainid", }, { - name: "fail: consumer key in use", + name: "fail: consumer key in use by other validator", + setup: func(ctx sdk.Context, + k keeper.Keeper, mocks testkeeper.MockedKeepers, + ) { + k.SetPendingConsumerAdditionProp(ctx, &providertypes.ConsumerAdditionProposal{ + ChainId: "chainid", + }) + // Use the consumer key already used by some other validator + k.SetValidatorByConsumerAddr(ctx, "chainid", consumerConsAddr, providerConsAddr2) + + gomock.InOrder( + mocks.MockStakingKeeper.EXPECT().GetValidator( + ctx, providerCryptoId.SDKValOpAddress(), + // validator should not be missing + ).Return(providerCryptoId.SDKStakingValidator(), true).Times(1), + mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, + consumerConsAddr.ToSdkConsAddr(), + // return false - no other validator uses the consumer key to validate *on the provider* + ).Return(stakingtypes.Validator{}, false), + ) + }, + expError: true, + chainID: "chainid", + }, + { + name: "success: consumer key in use, but by the same validator", setup: func(ctx sdk.Context, k keeper.Keeper, mocks testkeeper.MockedKeepers, ) { @@ -121,7 +150,7 @@ func TestAssignConsensusKeyForConsumerChain(t *testing.T) { ).Return(stakingtypes.Validator{}, false), ) }, - expError: true, + expError: false, chainID: "chainid", }, } diff --git a/x/ccv/provider/keeper/key_assignment.go b/x/ccv/provider/keeper/key_assignment.go index 983b92cb26..67f4d89fdd 100644 --- a/x/ccv/provider/keeper/key_assignment.go +++ b/x/ccv/provider/keeper/key_assignment.go @@ -371,12 +371,24 @@ func (k Keeper) AssignConsumerKey( } } - if _, found := k.GetValidatorByConsumerAddr(ctx, chainID, consumerAddr); found { + if existingProviderAddr, found := k.GetValidatorByConsumerAddr(ctx, chainID, consumerAddr); found { // consumer key is already in use - // prevent multiple validators from assigning the same key - return errorsmod.Wrapf( - types.ErrConsumerKeyInUse, "a validator has assigned the consumer key already", - ) + if providerAddr.Address.Equals(existingProviderAddr.Address) { + // the validator itself is the one already using the consumer key, + // just do a noop + k.Logger(ctx).Info("tried to assign a consumer key that is already assigned to the validator", + "consumer chainID", chainID, + "validator", providerAddr.String(), + "consumer consensus addr", consumerAddr.String(), + ) + return nil + } else { + // the validators are different -> throw an error to + // prevent multiple validators from assigning the same key + return errorsmod.Wrapf( + types.ErrConsumerKeyInUse, "a validator has assigned the consumer key already", + ) + } } // get the previous key assigned for this validator on this consumer chain From 67ca8e81fbfb7500b39f4feb75166359a83fc655 Mon Sep 17 00:00:00 2001 From: Simon Noetzlin Date: Tue, 2 Apr 2024 16:50:42 +0200 Subject: [PATCH 041/110] fix silly bug in PSS opted-in val query --- x/ccv/provider/keeper/grpc_query.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/ccv/provider/keeper/grpc_query.go b/x/ccv/provider/keeper/grpc_query.go index f18ec48bfb..23bb97010d 100644 --- a/x/ccv/provider/keeper/grpc_query.go +++ b/x/ccv/provider/keeper/grpc_query.go @@ -240,7 +240,7 @@ func (k Keeper) QueryConsumerChainOptedInValidators(goCtx context.Context, req * return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("unknown consumer chain: %s", consumerChainID)) } - for _, v := range k.GetAllOptedIn(ctx, ctx.ChainID()) { + for _, v := range k.GetAllOptedIn(ctx, consumerChainID) { optedInVals = append(optedInVals, v.ToSdkConsAddr().String()) } From e4690f24ef5c0494b5b61340d2c4ce61c1ca9270 Mon Sep 17 00:00:00 2001 From: mpoke Date: Thu, 28 Mar 2024 19:27:41 +0100 Subject: [PATCH 042/110] fix logging in ibc_module.go --- x/ccv/consumer/ibc_module.go | 2 +- x/ccv/provider/ibc_module.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/x/ccv/consumer/ibc_module.go b/x/ccv/consumer/ibc_module.go index f0e2a3e6c6..71caa4a082 100644 --- a/x/ccv/consumer/ibc_module.go +++ b/x/ccv/consumer/ibc_module.go @@ -246,7 +246,7 @@ func (am AppModule) OnRecvPacket( ackErr = err logger.Error(fmt.Sprintf("%s sequence %d", ackErr.Error(), packet.Sequence)) } else { - logger.Info("successfully handled VSCPacket sequence: %d", packet.Sequence) + logger.Info("successfully handled VSCPacket", "sequence", packet.Sequence) } } diff --git a/x/ccv/provider/ibc_module.go b/x/ccv/provider/ibc_module.go index 3b4f0fa050..f6ad43d60b 100644 --- a/x/ccv/provider/ibc_module.go +++ b/x/ccv/provider/ibc_module.go @@ -201,7 +201,7 @@ func (am AppModule) OnRecvPacket( data := *consumerPacket.GetVscMaturedPacketData() err = am.keeper.OnRecvVSCMaturedPacket(ctx, packet, data) if err == nil { - logger.Info("successfully handled VSCMaturedPacket sequence: %d", packet.Sequence) + logger.Info("successfully handled VSCMaturedPacket", "sequence", packet.Sequence) eventAttributes = append(eventAttributes, sdk.NewAttribute(ccv.AttributeValSetUpdateID, strconv.Itoa(int(data.ValsetUpdateId)))) } case ccv.SlashPacket: @@ -211,7 +211,7 @@ func (am AppModule) OnRecvPacket( ackResult, err = am.keeper.OnRecvSlashPacket(ctx, packet, data) if err == nil { ack = channeltypes.NewResultAcknowledgement(ackResult) - logger.Info("successfully handled SlashPacket sequence: %d", packet.Sequence) + logger.Info("successfully handled SlashPacket", "sequence", packet.Sequence) eventAttributes = append(eventAttributes, sdk.NewAttribute(ccv.AttributeValSetUpdateID, strconv.Itoa(int(data.ValsetUpdateId)))) } default: From bff07fe8d4f0f30fd271eac9b6d30bebb3ca8adb Mon Sep 17 00:00:00 2001 From: insumity Date: Wed, 3 Apr 2024 09:50:09 +0200 Subject: [PATCH 043/110] test: add partial-set-security E2E tests (#1737) * init commit * fix traces * Add PSS to default tests * Update tests/e2e/steps_partial_set_security.go Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * Update tests/e2e/steps_partial_set_security.go Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> --------- Co-authored-by: Philip Offtermatt Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> --- tests/e2e/actions.go | 104 +++- tests/e2e/main.go | 14 +- tests/e2e/steps_compatibility.go | 1 + tests/e2e/steps_consumer_misbehaviour.go | 1 + tests/e2e/steps_partial_set_security.go | 482 ++++++++++++++++++ tests/e2e/steps_sovereign_changeover.go | 1 + tests/e2e/steps_start_chains.go | 1 + tests/e2e/test_driver.go | 4 + .../e2e/tracehandler_testdata/changeover.json | 3 +- .../consumer-double-sign.json | 3 +- .../consumer-misbehaviour.json | 3 +- .../e2e/tracehandler_testdata/democracy.json | 3 +- .../democracyRewardsSteps.json | 3 +- .../e2e/tracehandler_testdata/happyPath.json | 3 +- .../multipleConsumers.json | 6 +- .../e2e/tracehandler_testdata/shorthappy.json | 3 +- .../tracehandler_testdata/slashThrottle.json | 3 +- x/ccv/provider/keeper/proposal_test.go | 3 +- 18 files changed, 625 insertions(+), 16 deletions(-) create mode 100644 tests/e2e/steps_partial_set_security.go diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index e49c37ae71..2ca395ab93 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -253,6 +253,7 @@ type SubmitConsumerAdditionProposalAction struct { SpawnTime uint InitialHeight clienttypes.Height DistributionChannel string + TopN uint32 } func (tr TestConfig) submitConsumerAdditionProposal( @@ -278,7 +279,7 @@ func (tr TestConfig) submitConsumerAdditionProposal( UnbondingPeriod: params.UnbondingPeriod, Deposit: fmt.Sprint(action.Deposit) + `stake`, DistributionTransmissionChannel: action.DistributionChannel, - TopN: 100, + TopN: action.TopN, } bz, err := json.Marshal(prop) @@ -292,9 +293,14 @@ func (tr TestConfig) submitConsumerAdditionProposal( } //#nosec G204 -- bypass unsafe quoting warning (no production code) - bz, err = target.ExecCommand( + cmd := target.ExecCommand( "/bin/bash", "-c", fmt.Sprintf(`echo '%s' > %s`, jsonStr, "/temp-proposal.json"), - ).CombinedOutput() + ) + bz, err = cmd.CombinedOutput() + + if verbose { + log.Println("submitConsumerAdditionProposal cmd: ", cmd.String()) + } if err != nil { log.Fatal(err, "\n", string(bz)) @@ -2292,6 +2298,98 @@ func (tc TestConfig) startConsumerEvidenceDetector( tc.waitBlocks("provi", 10, 2*time.Minute) } +type OptInAction struct { + Chain ChainID + Validator ValidatorID +} + +func (tr TestConfig) optIn(action OptInAction, target ExecutionTarget, verbose bool) { + // Note: to get error response reported back from this command '--gas auto' needs to be set. + gas := "auto" + // Unfortunately, --gas auto does not work with CometMock. so when using CometMock, just use --gas 9000000 then + if tr.useCometmock { + gas = "9000000" + } + + // Use: "opt-in [consumer-chain-id] [consumer-pubkey]", + optIn := fmt.Sprintf( + `%s tx provider opt-in %s --from validator%s --chain-id %s --home %s --node %s --gas %s --keyring-backend test -y -o json`, + tr.chainConfigs[ChainID("provi")].BinaryName, + string(tr.chainConfigs[action.Chain].ChainId), + action.Validator, + tr.chainConfigs[ChainID("provi")].ChainId, + tr.getValidatorHome(ChainID("provi"), action.Validator), + tr.getValidatorNode(ChainID("provi"), action.Validator), + gas, + ) + + cmd := target.ExecCommand( + "/bin/bash", "-c", + optIn, + ) + + if verbose { + fmt.Println("optIn cmd:", cmd.String()) + } + + bz, err := cmd.CombinedOutput() + _, _ = bz, err + if !tr.useCometmock { // error report only works with --gas auto, which does not work with CometMock, so ignore + if verbose { + fmt.Printf("got expected error during opt in | err: %s | output: %s \n", err, string(bz)) + } + } + + // wait for inclusion in a block -> '--broadcast-mode block' is deprecated + tr.waitBlocks(ChainID("provi"), 2, 30*time.Second) +} + +type OptOutAction struct { + Chain ChainID + Validator ValidatorID +} + +func (tr TestConfig) optOut(action OptOutAction, target ExecutionTarget, verbose bool) { + // Note: to get error response reported back from this command '--gas auto' needs to be set. + gas := "auto" + // Unfortunately, --gas auto does not work with CometMock. so when using CometMock, just use --gas 9000000 then + if tr.useCometmock { + gas = "9000000" + } + + // Use: "opt-out [consumer-chain-id]", + optIn := fmt.Sprintf( + `%s tx provider opt-out %s --from validator%s --chain-id %s --home %s --node %s --gas %s --keyring-backend test -y -o json`, + tr.chainConfigs[ChainID("provi")].BinaryName, + string(tr.chainConfigs[action.Chain].ChainId), + action.Validator, + tr.chainConfigs[ChainID("provi")].ChainId, + tr.getValidatorHome(ChainID("provi"), action.Validator), + tr.getValidatorNode(ChainID("provi"), action.Validator), + gas, + ) + + cmd := target.ExecCommand( + "/bin/bash", "-c", + optIn, + ) + + if verbose { + fmt.Println("optOut cmd:", cmd.String()) + } + + bz, err := cmd.CombinedOutput() + _, _ = bz, err + if !tr.useCometmock { // error report only works with --gas auto, which does not work with CometMock, so ignore + if verbose { + fmt.Printf("got expected error during opt out | err: %s | output: %s \n", err, string(bz)) + } + } + + // wait for inclusion in a block -> '--broadcast-mode block' is deprecated + tr.waitBlocks(ChainID("provi"), 2, 30*time.Second) +} + // WaitTime waits for the given duration. // To make sure that the new timestamp is visible on-chain, it also waits until at least one block has been // produced on each chain after waiting. diff --git a/tests/e2e/main.go b/tests/e2e/main.go index 00a9d0ea15..4f432fd5ed 100644 --- a/tests/e2e/main.go +++ b/tests/e2e/main.go @@ -156,6 +156,18 @@ var stepChoices = map[string]StepChoice{ description: `Minimal set of test steps to perform compatibility tests`, testConfig: CompatibilityTestCfg, }, + "partial-set-security-opt-in": { + name: "partial-set-security-opt-in", + steps: stepsOptInChain(), + description: "test partial set security for an Opt-In chain", + testConfig: DefaultTestCfg, + }, + "partial-set-security-top-n": { + name: "partial-set-security-top-n", + steps: stepsTopNChain(), + description: "test partial set security for a Top-N chain", + testConfig: DefaultTestCfg, + }, } func getTestCaseUsageString() string { @@ -241,7 +253,7 @@ func getTestCases(selectedPredefinedTests, selectedTestFiles TestSet, providerVe "changeover", "happy-path", "democracy-reward", "democracy", "slash-throttle", "consumer-double-sign", "consumer-misbehaviour", - "consumer-double-downtime", + "consumer-double-downtime", "partial-set-security-opt-in", "partial-set-security-top-n", } if includeMultiConsumer != nil && *includeMultiConsumer { selectedPredefinedTests = append(selectedPredefinedTests, "multiconsumer") diff --git a/tests/e2e/steps_compatibility.go b/tests/e2e/steps_compatibility.go index 000287d640..0007f746e0 100644 --- a/tests/e2e/steps_compatibility.go +++ b/tests/e2e/steps_compatibility.go @@ -41,6 +41,7 @@ func compstepsStartConsumerChain(consumerName string, proposalIndex, chainIndex ConsumerChain: ChainID(consumerName), SpawnTime: 0, InitialHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: 1}, + TopN: 100, }, State: State{ ChainID("provi"): ChainState{ diff --git a/tests/e2e/steps_consumer_misbehaviour.go b/tests/e2e/steps_consumer_misbehaviour.go index 3cb4ce0f1b..bd6e3f1d3c 100644 --- a/tests/e2e/steps_consumer_misbehaviour.go +++ b/tests/e2e/steps_consumer_misbehaviour.go @@ -36,6 +36,7 @@ func stepsStartChainsWithSoftOptOut(consumerName string) []Step { ConsumerChain: ChainID(consumerName), SpawnTime: 0, InitialHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: 1}, + TopN: 100, }, State: State{ ChainID("provi"): ChainState{ diff --git a/tests/e2e/steps_partial_set_security.go b/tests/e2e/steps_partial_set_security.go new file mode 100644 index 0000000000..b9536caa0c --- /dev/null +++ b/tests/e2e/steps_partial_set_security.go @@ -0,0 +1,482 @@ +package main + +import clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + +// stepsOptInChain starts a provider chain and an Opt-In chain and opts in and out validators +func stepsOptInChain() []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: SubmitConsumerAdditionProposalAction{ + Chain: ChainID("provi"), + From: ValidatorID("alice"), + Deposit: 10000001, + ConsumerChain: ChainID("consu"), + SpawnTime: 0, + InitialHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: 1}, + TopN: 0, + }, + State: State{ + ChainID("provi"): ChainState{ + Proposals: &map[uint]Proposal{ + 1: ConsumerAdditionProposal{ + Deposit: 10000001, + Chain: ChainID("consu"), + SpawnTime: 0, + InitialHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: 1}, + Status: "PROPOSAL_STATUS_VOTING_PERIOD", + }, + }, + }, + }, + }, + // Οpt in "alice" and "bob" so the chain is not empty when it is about to start. Note, that "alice" and "bob" use + // the provider's public key (see `UseConsumerKey` is set to `false` in `getDefaultValidators`) and hence do not + // need a consumer-key assigment. + { + Action: OptInAction{ + Chain: ChainID("consu"), + Validator: ValidatorID("alice"), + }, + State: State{}, + }, + { + Action: OptInAction{ + Chain: ChainID("consu"), + Validator: ValidatorID("bob"), + }, + State: State{}, + }, + { + Action: VoteGovProposalAction{ + Chain: ChainID("provi"), + From: []ValidatorID{ValidatorID("alice"), ValidatorID("bob")}, + Vote: []string{"yes", "yes"}, + PropNumber: 1, + }, + State: State{ + ChainID("provi"): ChainState{ + Proposals: &map[uint]Proposal{ + 1: ConsumerAdditionProposal{ + Deposit: 10000001, + Chain: ChainID("consu"), + SpawnTime: 0, + InitialHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: 1}, + Status: "PROPOSAL_STATUS_PASSED", + }, + }, + }, + }, + }, + { + // we start all the validators but only "alice" and "bob" have opted in and hence + // only "alice" and "bob" are validating blocks + 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}, + }, + // For consumers that're launching with the provider being on an earlier version + // of ICS before the soft opt-out threshold was introduced, we need to set the + // soft opt-out threshold to 0.05 in the consumer genesis to ensure that the + // consumer binary doesn't panic. Sdk requires that all params are set to valid + // values from the genesis file. + GenesisChanges: ".app_state.ccvconsumer.params.soft_opt_out_threshold = \"0.05\"", + }, + State: State{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 100, + ValidatorID("bob"): 200, + // carol has not yet opted in + ValidatorID("carol"): 0, + }, + }, + }, + }, + { + 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: OptInAction{ + Chain: ChainID("consu"), + Validator: ValidatorID("carol"), + }, + State: State{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 100, + ValidatorID("bob"): 200, + // "carol" has opted in, but the VSCPacket capturing the opt-in was not relayed yet + ValidatorID("carol"): 0, + }, + }, + }, + }, + { + // assign the consumer key "carol" is using on the consumer chain to be the one "carol" uses when opting in + Action: AssignConsumerPubKeyAction{ + Chain: ChainID("consu"), + Validator: ValidatorID("carol"), + // reconfigure the node -> validator was using provider key + // until this point -> key matches config.consumerValPubKey for "carol" + ConsumerPubkey: getDefaultValidators()[ValidatorID("carol")].ConsumerValPubKey, + ReconfigureNode: true, + }, + 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"): 200, + // carol has now opted in + ValidatorID("carol"): 300, + }, + }, + }, + }, + { + Action: OptOutAction{ + Chain: ChainID("consu"), + Validator: ValidatorID("bob"), + }, + State: State{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 100, + // "bob" has not yet opted out from the consumer chain because the VSCPacket has not yet been relayed + ValidatorID("bob"): 200, + ValidatorID("carol"): 300, + }, + }, + }, + }, + { + Action: RelayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID("consu"), + Port: "provider", + Channel: 0, + }, + State: State{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 100, + // bob has now opted out + ValidatorID("bob"): 0, + ValidatorID("carol"): 300, + }, + }, + }, + }, + { + // re opt-in "bob" + Action: OptInAction{ + Chain: ChainID("consu"), + Validator: ValidatorID("bob"), + }, + State: State{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 100, + // "bob" has not yet been opted in from the consumer chain because the VSCPacket has not yet been relayed + ValidatorID("bob"): 0, + ValidatorID("carol"): 300, + }, + }, + }, + }, + { + Action: RelayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID("consu"), + Port: "provider", + Channel: 0, + }, + State: State{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 100, + // bob has now opted in + ValidatorID("bob"): 200, + ValidatorID("carol"): 300, + }, + }, + }, + }, + } + + return s +} + +// stepsTopNChain starts a provider chain and a Top-N chain and opts in and out validators +func stepsTopNChain() []Step { + s := []Step{ + { + // start a new chain where "alice", "bob", and "carol" have 20%, 30%, and 50% of + // the total voting power respectively + Action: StartChainAction{ + Chain: ChainID("provi"), + Validators: []StartChainValidator{ + {Id: ValidatorID("alice"), Stake: 200000000, Allocation: 10000000000}, + {Id: ValidatorID("bob"), Stake: 300000000, Allocation: 10000000000}, + {Id: ValidatorID("carol"), Stake: 500000000, Allocation: 10000000000}, + }, + }, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 200, + ValidatorID("bob"): 300, + ValidatorID("carol"): 500, + }, + }, + }, + }, + { + // propose a Top-N chain with N = 51% and hence both "carol" and "bob" have to validate + Action: SubmitConsumerAdditionProposalAction{ + Chain: ChainID("provi"), + From: ValidatorID("alice"), + Deposit: 10000001, + ConsumerChain: ChainID("consu"), + SpawnTime: 0, + InitialHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: 1}, + TopN: 51, + }, + State: State{ + ChainID("provi"): ChainState{ + Proposals: &map[uint]Proposal{ + 1: ConsumerAdditionProposal{ + Deposit: 10000001, + Chain: ChainID("consu"), + SpawnTime: 0, + InitialHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: 1}, + Status: "PROPOSAL_STATUS_VOTING_PERIOD", + }, + }, + }, + }, + }, + { + // change the consumer key "carol" is using on the consumer chain to be the one "carol" uses when opting in + Action: AssignConsumerPubKeyAction{ + Chain: ChainID("consu"), + Validator: ValidatorID("carol"), + // reconfigure the node -> validator was using provider key + // until this point -> key matches config.consumerValPubKey for "bob" + ConsumerPubkey: getDefaultValidators()[ValidatorID("carol")].ConsumerValPubKey, + ReconfigureNode: true, + }, + State: State{}, + }, + { + Action: VoteGovProposalAction{ + Chain: ChainID("provi"), + From: []ValidatorID{ValidatorID("alice"), ValidatorID("bob")}, + Vote: []string{"yes", "yes"}, + PropNumber: 1, + }, + State: State{ + ChainID("provi"): ChainState{ + Proposals: &map[uint]Proposal{ + 1: ConsumerAdditionProposal{ + Deposit: 10000001, + Chain: ChainID("consu"), + SpawnTime: 0, + InitialHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: 1}, + Status: "PROPOSAL_STATUS_PASSED", + }, + }, + }, + }, + }, + { + // we start all the validators but only "alice" and "bob" have opted in and hence + // only "alice" and "bob" are validating blocks + Action: StartConsumerChainAction{ + ConsumerChain: ChainID("consu"), + ProviderChain: ChainID("provi"), + Validators: []StartChainValidator{ + {Id: ValidatorID("alice"), Stake: 200000000, Allocation: 10000000000}, + {Id: ValidatorID("bob"), Stake: 300000000, Allocation: 10000000000}, + {Id: ValidatorID("carol"), Stake: 500000000, Allocation: 10000000000}, + }, + // For consumers that're launching with the provider being on an earlier version + // of ICS before the soft opt-out threshold was introduced, we need to set the + // soft opt-out threshold to 0.05 in the consumer genesis to ensure that the + // consumer binary doesn't panic. Sdk requires that all params are set to valid + // values from the genesis file. + GenesisChanges: ".app_state.ccvconsumer.params.soft_opt_out_threshold = \"0.05\"", + }, + State: State{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 0, + ValidatorID("bob"): 300, + ValidatorID("carol"): 500, + }, + }, + }, + }, + { + 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: OptInAction{ + Chain: ChainID("consu"), + Validator: ValidatorID("alice"), + }, + State: State{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + // "alice" is not yet opted in because the VSCPacket has not yet been relayed + ValidatorID("alice"): 0, + ValidatorID("bob"): 300, + ValidatorID("carol"): 500, + }, + }, + }, + }, + { + Action: RelayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID("consu"), + Port: "provider", + Channel: 0, + }, + State: State{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + // "alice" is now opted in + ValidatorID("alice"): 200, + ValidatorID("bob"): 300, + ValidatorID("carol"): 500, + }, + }, + }, + }, + { + Action: OptOutAction{ + Chain: ChainID("consu"), + Validator: ValidatorID("carol"), + }, + State: State{}, + }, + { + Action: OptOutAction{ + Chain: ChainID("consu"), + Validator: ValidatorID("bob"), + }, + State: State{}, + }, + { + // opting out "bob" or "carol" does not work because they belong to the Top N validators + Action: RelayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID("consu"), + Port: "provider", + Channel: 0, + }, + State: State{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 200, + ValidatorID("bob"): 300, + ValidatorID("carol"): 500, + }, + }, + }, + }, + { + Action: OptOutAction{ + Chain: ChainID("consu"), + Validator: ValidatorID("alice"), + }, + State: State{}, + }, + { + Action: RelayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID("consu"), + Port: "provider", + Channel: 0, + }, + State: State{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + // "alice" has now opted out + ValidatorID("alice"): 0, + ValidatorID("bob"): 300, + ValidatorID("carol"): 500, + }, + }, + }, + }, + } + + return s +} diff --git a/tests/e2e/steps_sovereign_changeover.go b/tests/e2e/steps_sovereign_changeover.go index 69e6680677..1ddd5a2143 100644 --- a/tests/e2e/steps_sovereign_changeover.go +++ b/tests/e2e/steps_sovereign_changeover.go @@ -48,6 +48,7 @@ func stepsChangeoverToConsumer(consumerName string) []Step { DistributionChannel: "channel-0", SpawnTime: 0, InitialHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: 111}, // 1 block after upgrade !important + TopN: 100, }, State: State{ ChainID("provi"): ChainState{ diff --git a/tests/e2e/steps_start_chains.go b/tests/e2e/steps_start_chains.go index 8dcbd7d06f..2ff3226dec 100644 --- a/tests/e2e/steps_start_chains.go +++ b/tests/e2e/steps_start_chains.go @@ -38,6 +38,7 @@ func stepsStartConsumerChain(consumerName string, proposalIndex, chainIndex uint ConsumerChain: ChainID(consumerName), SpawnTime: 0, InitialHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: 1}, + TopN: 100, }, State: State{ ChainID("provi"): ChainState{ diff --git a/tests/e2e/test_driver.go b/tests/e2e/test_driver.go index 052559b3ba..a12dc7862e 100644 --- a/tests/e2e/test_driver.go +++ b/tests/e2e/test_driver.go @@ -138,6 +138,10 @@ func (td *DefaultDriver) runAction(action interface{}) error { td.testCfg.startConsumerEvidenceDetector(action, td.target, td.verbose) case SubmitChangeRewardDenomsProposalAction: td.testCfg.submitChangeRewardDenomsProposal(action, td.target, td.verbose) + case OptInAction: + td.testCfg.optIn(action, td.target, td.verbose) + case OptOutAction: + td.testCfg.optOut(action, td.target, td.verbose) default: log.Fatalf("unknown action in testRun %s: %#v", td.testCfg.name, action) } diff --git a/tests/e2e/tracehandler_testdata/changeover.json b/tests/e2e/tracehandler_testdata/changeover.json index 47d6fc621d..ca6552e059 100644 --- a/tests/e2e/tracehandler_testdata/changeover.json +++ b/tests/e2e/tracehandler_testdata/changeover.json @@ -229,7 +229,8 @@ "InitialHeight": { "revision_height": 111 }, - "DistributionChannel": "channel-0" + "DistributionChannel": "channel-0", + "TopN": 100 }, "State": { "provi": { diff --git a/tests/e2e/tracehandler_testdata/consumer-double-sign.json b/tests/e2e/tracehandler_testdata/consumer-double-sign.json index 8a5203757b..b72d020990 100644 --- a/tests/e2e/tracehandler_testdata/consumer-double-sign.json +++ b/tests/e2e/tracehandler_testdata/consumer-double-sign.json @@ -57,7 +57,8 @@ "InitialHeight": { "revision_height": 1 }, - "DistributionChannel": "" + "DistributionChannel": "", + "TopN": 100 }, "State": { "provi": { diff --git a/tests/e2e/tracehandler_testdata/consumer-misbehaviour.json b/tests/e2e/tracehandler_testdata/consumer-misbehaviour.json index 43e242e7dc..5c839c35a6 100644 --- a/tests/e2e/tracehandler_testdata/consumer-misbehaviour.json +++ b/tests/e2e/tracehandler_testdata/consumer-misbehaviour.json @@ -51,7 +51,8 @@ "InitialHeight": { "revision_height": 1 }, - "DistributionChannel": "" + "DistributionChannel": "", + "TopN": 100 }, "State": { "provi": { diff --git a/tests/e2e/tracehandler_testdata/democracy.json b/tests/e2e/tracehandler_testdata/democracy.json index 3f425a2a92..427066d0c2 100644 --- a/tests/e2e/tracehandler_testdata/democracy.json +++ b/tests/e2e/tracehandler_testdata/democracy.json @@ -57,7 +57,8 @@ "InitialHeight": { "revision_height": 1 }, - "DistributionChannel": "" + "DistributionChannel": "", + "TopN": 100 }, "State": { "provi": { diff --git a/tests/e2e/tracehandler_testdata/democracyRewardsSteps.json b/tests/e2e/tracehandler_testdata/democracyRewardsSteps.json index 1235c47a22..e9210fe0cd 100644 --- a/tests/e2e/tracehandler_testdata/democracyRewardsSteps.json +++ b/tests/e2e/tracehandler_testdata/democracyRewardsSteps.json @@ -57,7 +57,8 @@ "InitialHeight": { "revision_height": 1 }, - "DistributionChannel": "" + "DistributionChannel": "", + "TopN": 100 }, "State": { "provi": { diff --git a/tests/e2e/tracehandler_testdata/happyPath.json b/tests/e2e/tracehandler_testdata/happyPath.json index 04afc707a6..6a99e3c97d 100644 --- a/tests/e2e/tracehandler_testdata/happyPath.json +++ b/tests/e2e/tracehandler_testdata/happyPath.json @@ -57,7 +57,8 @@ "InitialHeight": { "revision_height": 1 }, - "DistributionChannel": "" + "DistributionChannel": "", + "TopN": 100 }, "State": { "provi": { diff --git a/tests/e2e/tracehandler_testdata/multipleConsumers.json b/tests/e2e/tracehandler_testdata/multipleConsumers.json index 610e8a786f..5d51282c0d 100644 --- a/tests/e2e/tracehandler_testdata/multipleConsumers.json +++ b/tests/e2e/tracehandler_testdata/multipleConsumers.json @@ -57,7 +57,8 @@ "InitialHeight": { "revision_height": 1 }, - "DistributionChannel": "" + "DistributionChannel": "", + "TopN": 100 }, "State": { "provi": { @@ -342,7 +343,8 @@ "InitialHeight": { "revision_height": 1 }, - "DistributionChannel": "" + "DistributionChannel": "", + "TopN": 100 }, "State": { "provi": { diff --git a/tests/e2e/tracehandler_testdata/shorthappy.json b/tests/e2e/tracehandler_testdata/shorthappy.json index 1be75865aa..4b228b7e29 100644 --- a/tests/e2e/tracehandler_testdata/shorthappy.json +++ b/tests/e2e/tracehandler_testdata/shorthappy.json @@ -57,7 +57,8 @@ "InitialHeight": { "revision_height": 1 }, - "DistributionChannel": "" + "DistributionChannel": "", + "TopN": 100 }, "State": { "provi": { diff --git a/tests/e2e/tracehandler_testdata/slashThrottle.json b/tests/e2e/tracehandler_testdata/slashThrottle.json index 352f7cc06d..d347c551a2 100644 --- a/tests/e2e/tracehandler_testdata/slashThrottle.json +++ b/tests/e2e/tracehandler_testdata/slashThrottle.json @@ -57,7 +57,8 @@ "InitialHeight": { "revision_height": 1 }, - "DistributionChannel": "" + "DistributionChannel": "", + "TopN": 100 }, "State": { "provi": { diff --git a/x/ccv/provider/keeper/proposal_test.go b/x/ccv/provider/keeper/proposal_test.go index b27ae443fd..69534326e0 100644 --- a/x/ccv/provider/keeper/proposal_test.go +++ b/x/ccv/provider/keeper/proposal_test.go @@ -1002,8 +1002,7 @@ func TestBeginBlockInit(t *testing.T) { } // opt in a sample validator so the chain's proposal can successfully execute - providerKeeper.SetOptedIn(ctx, pendingProps[5].ChainId, providertypes.ProviderConsAddress{[]byte{1}}) - + providerKeeper.SetOptedIn(ctx, pendingProps[5].ChainId, providertypes.NewProviderConsAddress([]byte("providerAddr"))) providerKeeper.BeginBlockInit(ctx) // first proposal is not pending anymore because its spawn time already passed and was executed From d0f7a42be9d4da14a05b6a3ebddf0320964ab387 Mon Sep 17 00:00:00 2001 From: insumity Date: Wed, 3 Apr 2024 11:51:57 +0200 Subject: [PATCH 044/110] Nit changes based on Simons comments. To be pushed directly because E2E PR 1737 were the comments were written was accidentally merged. --- tests/e2e/actions.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index 2ca395ab93..27e9b3cd36 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -2333,7 +2333,10 @@ func (tr TestConfig) optIn(action OptInAction, target ExecutionTarget, verbose b } bz, err := cmd.CombinedOutput() - _, _ = bz, err + if err != nil { + log.Fatal(err, "\n", string(bz)) + } + if !tr.useCometmock { // error report only works with --gas auto, which does not work with CometMock, so ignore if verbose { fmt.Printf("got expected error during opt in | err: %s | output: %s \n", err, string(bz)) @@ -2379,7 +2382,10 @@ func (tr TestConfig) optOut(action OptOutAction, target ExecutionTarget, verbose } bz, err := cmd.CombinedOutput() - _, _ = bz, err + if err != nil { + log.Fatal(err, "\n", string(bz)) + } + if !tr.useCometmock { // error report only works with --gas auto, which does not work with CometMock, so ignore if verbose { fmt.Printf("got expected error during opt out | err: %s | output: %s \n", err, string(bz)) From 67091f82e1007f7773f1be19424d863bbad6c036 Mon Sep 17 00:00:00 2001 From: insumity Date: Mon, 8 Apr 2024 09:40:50 +0200 Subject: [PATCH 045/110] fix!: return a SlashAck even if the validator is not a consumer validator (#1763) * init commit * fix test --- x/ccv/provider/keeper/relay.go | 3 ++- x/ccv/provider/keeper/relay_test.go | 15 +++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/x/ccv/provider/keeper/relay.go b/x/ccv/provider/keeper/relay.go index 1ef8547243..35c98aa088 100644 --- a/x/ccv/provider/keeper/relay.go +++ b/x/ccv/provider/keeper/relay.go @@ -405,7 +405,8 @@ func (k Keeper) HandleSlashPacket(ctx sdk.Context, chainID string, data ccv.Slas if !k.IsConsumerValidator(ctx, chainID, providerConsAddr) { k.Logger(ctx).Error("cannot jail validator %s that does not belong to consumer %s valset", providerConsAddr.String(), chainID) - // drop packet + // drop packet but return a slash ack so that the consumer can send another slash packet + k.AppendSlashAck(ctx, chainID, consumerConsAddr.String()) return } diff --git a/x/ccv/provider/keeper/relay_test.go b/x/ccv/provider/keeper/relay_test.go index 594783a9a1..a0c0b20e48 100644 --- a/x/ccv/provider/keeper/relay_test.go +++ b/x/ccv/provider/keeper/relay_test.go @@ -303,8 +303,9 @@ func TestHandleSlashPacket(t *testing.T) { name string packetData ccv.SlashPacketData // The mocks that we expect to be called for the specified packet data. - expectedCalls func(sdk.Context, testkeeper.MockedKeepers, ccv.SlashPacketData) []*gomock.Call - expectedSlashAcksLen int + expectedCalls func(sdk.Context, testkeeper.MockedKeepers, ccv.SlashPacketData) []*gomock.Call + expectedSlashAcksLen int + expectedSlashAckConsumerConsAddress types.ConsumerConsAddress }{ { "validator isn't a consumer validator", @@ -318,7 +319,8 @@ func TestHandleSlashPacket(t *testing.T) { ) []*gomock.Call { return []*gomock.Call{} }, - 0, + 1, + dummyConsAddr, }, { "unfound validator", @@ -340,6 +342,7 @@ func TestHandleSlashPacket(t *testing.T) { } }, 0, + consumerConsAddr, }, { "found, but tombstoned validator", @@ -362,6 +365,7 @@ func TestHandleSlashPacket(t *testing.T) { } }, 0, + consumerConsAddr, }, { "drop packet when infraction height not found", @@ -385,6 +389,7 @@ func TestHandleSlashPacket(t *testing.T) { } }, 0, + consumerConsAddr, }, { "full downtime packet handling, uses init chain height and non-jailed validator", @@ -402,6 +407,7 @@ func TestHandleSlashPacket(t *testing.T) { true) // expectJailing = true }, 1, + consumerConsAddr, }, { "full downtime packet handling, uses valid vscID and jailed validator", @@ -419,6 +425,7 @@ func TestHandleSlashPacket(t *testing.T) { false) // expectJailing = false, validator is already jailed. }, 1, + consumerConsAddr, }, // Note: double-sign slash packet handling should not occur, see OnRecvSlashPacket. } @@ -447,7 +454,7 @@ func TestHandleSlashPacket(t *testing.T) { if tc.expectedSlashAcksLen == 1 { // must match the consumer address - require.Equal(t, consumerConsAddr.String(), providerKeeper.GetSlashAcks(ctx, chainId)[0]) + require.Equal(t, tc.expectedSlashAckConsumerConsAddress.String(), providerKeeper.GetSlashAcks(ctx, chainId)[0]) require.NotEqual(t, providerConsAddr.String(), providerKeeper.GetSlashAcks(ctx, chainId)[0]) require.NotEqual(t, providerConsAddr.String(), consumerConsAddr.String()) } From f9344e22d1737a86cc300092d46606af87a68ded Mon Sep 17 00:00:00 2001 From: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Date: Mon, 8 Apr 2024 16:28:31 +0200 Subject: [PATCH 046/110] test: Expand PSS e2e test to include slashing (#1752) * Expand test to include slashing * Add back existing steps * Add downtime to top N test * Fix nits --- tests/e2e/steps_partial_set_security.go | 396 +++++++++++++++++++++++- 1 file changed, 394 insertions(+), 2 deletions(-) diff --git a/tests/e2e/steps_partial_set_security.go b/tests/e2e/steps_partial_set_security.go index b9536caa0c..751a710499 100644 --- a/tests/e2e/steps_partial_set_security.go +++ b/tests/e2e/steps_partial_set_security.go @@ -225,7 +225,7 @@ func stepsOptInChain() []Step { ChainID("consu"): ChainState{ ValPowers: &map[ValidatorID]uint{ ValidatorID("alice"): 100, - // "bob" has not yet been opted in from the consumer chain because the VSCPacket has not yet been relayed + // "bob" has not yet been opted in to the consumer chain because the VSCPacket has not yet been relayed ValidatorID("bob"): 0, ValidatorID("carol"): 300, }, @@ -243,7 +243,190 @@ func stepsOptInChain() []Step { ChainID("consu"): ChainState{ ValPowers: &map[ValidatorID]uint{ ValidatorID("alice"): 100, - // bob has now opted in + // bob is in power on the consumer + ValidatorID("bob"): 200, + ValidatorID("carol"): 300, + }, + }, + }, + }, + { + // DowntimeSlash for alice on consumer + Action: DowntimeSlashAction{ + Chain: ChainID("consu"), + Validator: ValidatorID("alice"), + }, + // powers are not affected yet on either chain + State: State{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 100, + ValidatorID("bob"): 200, + ValidatorID("carol"): 300, + }, + }, + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 100, + ValidatorID("bob"): 200, + ValidatorID("carol"): 300, + }, + }, + }, + }, + { + // relay the slash packet + Action: RelayPacketsAction{ + ChainA: ChainID("consu"), + ChainB: ChainID("provi"), + Port: "consumer", + Channel: 0, + }, + // alice's power is reduced on the provider + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 0, + ValidatorID("bob"): 200, + ValidatorID("carol"): 300, + }, + }, + }, + }, + { + // relay the VSCPacket that contains the slashed power for alice + Action: RelayPacketsAction{ + ChainA: ChainID("consu"), + ChainB: ChainID("provi"), + Port: "consumer", + Channel: 0, + }, + // alice's power is reduced on the provider + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 0, + ValidatorID("bob"): 200, + ValidatorID("carol"): 300, + }, + }, + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + // alice should definitely not be in power on the consumer + ValidatorID("alice"): 0, + ValidatorID("bob"): 200, + ValidatorID("carol"): 300, + }, + }, + }, + }, + { + // unjail alice + Action: UnjailValidatorAction{ + Provider: ChainID("provi"), + Validator: ValidatorID("alice"), + }, + // alices power is restored on the provider + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 100, + ValidatorID("bob"): 200, + ValidatorID("carol"): 300, + }, + }, + // still 0 power on the consumer + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 0, + ValidatorID("bob"): 200, + ValidatorID("carol"): 300, + }, + }, + }, + }, + { + // relay the VSCPacket that puts alice back into power on the consumer + Action: RelayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID("consu"), + Port: "provider", + Channel: 0, + }, + // alice's power is restored on the consumer + State: State{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 100, + ValidatorID("bob"): 200, + ValidatorID("carol"): 300, + }, + }, + }, + }, + { + // slash alice for downtime again + Action: DowntimeSlashAction{ + Chain: ChainID("consu"), + Validator: ValidatorID("alice"), + }, + // alice's power is not yet reduced, the packet needs to be relayed + State: State{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 100, + ValidatorID("bob"): 200, + ValidatorID("carol"): 300, + }, + }, + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 100, + ValidatorID("bob"): 200, + ValidatorID("carol"): 300, + }, + }, + }, + }, + { + // relay the slash packet + Action: RelayPacketsAction{ + ChainA: ChainID("consu"), + ChainB: ChainID("provi"), + Port: "consumer", + Channel: 0, + }, + // alice's power is reduced on the provider + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 0, + ValidatorID("bob"): 200, + ValidatorID("carol"): 300, + }, + }, + }, + }, + { + // relay the VSCPacket that contains the slashed power for alice + Action: RelayPacketsAction{ + ChainA: ChainID("consu"), + ChainB: ChainID("provi"), + Port: "consumer", + Channel: 0, + }, + // alice's power is reduced on the consumer + State: State{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 0, + ValidatorID("bob"): 200, + ValidatorID("carol"): 300, + }, + }, + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 0, ValidatorID("bob"): 200, ValidatorID("carol"): 300, }, @@ -476,6 +659,215 @@ func stepsTopNChain() []Step { }, }, }, + // opt alice back in + { + Action: OptInAction{ + Chain: ChainID("consu"), + Validator: ValidatorID("alice"), + }, + State: State{}, + }, + { + Action: RelayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID("consu"), + Port: "provider", + Channel: 0, + }, + State: State{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + // "alice" has now opted in + ValidatorID("alice"): 200, + ValidatorID("bob"): 300, + ValidatorID("carol"): 500, + }, + }, + }, + }, + { + // DowntimeSlash for alice on consumer + Action: DowntimeSlashAction{ + Chain: ChainID("consu"), + Validator: ValidatorID("alice"), + }, + // powers are not affected yet on either chain + State: State{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 200, + ValidatorID("bob"): 300, + ValidatorID("carol"): 500, + }, + }, + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 200, + ValidatorID("bob"): 300, + ValidatorID("carol"): 500, + }, + }, + }, + }, + { + // relay the slash packet + Action: RelayPacketsAction{ + ChainA: ChainID("consu"), + ChainB: ChainID("provi"), + Port: "consumer", + Channel: 0, + }, + // alice's power is reduced on the provider + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 0, + ValidatorID("bob"): 300, + ValidatorID("carol"): 500, + }, + }, + }, + }, + { + // relay the VSCPacket that contains the slashed power for alice + Action: RelayPacketsAction{ + ChainA: ChainID("consu"), + ChainB: ChainID("provi"), + Port: "consumer", + Channel: 0, + }, + // alice's power is reduced on the provider + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 0, + ValidatorID("bob"): 300, + ValidatorID("carol"): 500, + }, + }, + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + // alice should definitely not be in power on the consumer + ValidatorID("alice"): 0, + ValidatorID("bob"): 300, + ValidatorID("carol"): 500, + }, + }, + }, + }, + { + // unjail alice + Action: UnjailValidatorAction{ + Provider: ChainID("provi"), + Validator: ValidatorID("alice"), + }, + // alices power is restored on the provider + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 200, + ValidatorID("bob"): 300, + ValidatorID("carol"): 500, + }, + }, + // still 0 power on the consumer + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 0, + ValidatorID("bob"): 300, + ValidatorID("carol"): 500, + }, + }, + }, + }, + { + // relay the VSCPacket that puts alice back into power on the consumer + Action: RelayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID("consu"), + Port: "provider", + Channel: 0, + }, + // alice's power is restored on the consumer + State: State{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 200, + ValidatorID("bob"): 300, + ValidatorID("carol"): 500, + }, + }, + }, + }, + { + // slash alice for downtime again + Action: DowntimeSlashAction{ + Chain: ChainID("consu"), + Validator: ValidatorID("alice"), + }, + // alice's power is not yet reduced, the packet needs to be relayed + State: State{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 200, + ValidatorID("bob"): 300, + ValidatorID("carol"): 500, + }, + }, + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 200, + ValidatorID("bob"): 300, + ValidatorID("carol"): 500, + }, + }, + }, + }, + { + // relay the slash packet + Action: RelayPacketsAction{ + ChainA: ChainID("consu"), + ChainB: ChainID("provi"), + Port: "consumer", + Channel: 0, + }, + // alice's power is reduced on the provider + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 0, + ValidatorID("bob"): 300, + ValidatorID("carol"): 500, + }, + }, + }, + }, + { + // relay the VSCPacket that contains the slashed power for alice + Action: RelayPacketsAction{ + ChainA: ChainID("consu"), + ChainB: ChainID("provi"), + Port: "consumer", + Channel: 0, + }, + // alice's power is reduced on the consumer + State: State{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 0, + ValidatorID("bob"): 300, + ValidatorID("carol"): 500, + }, + }, + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 0, + ValidatorID("bob"): 300, + ValidatorID("carol"): 500, + }, + }, + }, + }, } return s From 795c9fdc6424ecdc14c75caef1aad3bc8fdc2a65 Mon Sep 17 00:00:00 2001 From: Simon Noetzlin Date: Thu, 11 Apr 2024 08:20:24 +0200 Subject: [PATCH 047/110] fix!: update unbonding pausing for PSS (#1728) * draft PSS unbonding fix * fix hook logic to retrieve validator address from ubd op * add unbonding pausing unit-test * remove panic in hook --- testutil/keeper/mocks.go | 59 +++++++++++++++++++++++++ x/ccv/provider/keeper/hooks.go | 59 ++++++++++++++++++++++++- x/ccv/provider/keeper/relay_test.go | 68 ++++++++++++++++++++++++++++- x/ccv/types/expected_keepers.go | 4 ++ 4 files changed, 188 insertions(+), 2 deletions(-) diff --git a/testutil/keeper/mocks.go b/testutil/keeper/mocks.go index e588f51e30..7abadd63d5 100644 --- a/testutil/keeper/mocks.go +++ b/testutil/keeper/mocks.go @@ -49,6 +49,20 @@ func (m *MockStakingKeeper) EXPECT() *MockStakingKeeperMockRecorder { return m.recorder } +// BlockValidatorUpdates mocks base method. +func (m *MockStakingKeeper) BlockValidatorUpdates(ctx types0.Context) []types.ValidatorUpdate { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BlockValidatorUpdates", ctx) + ret0, _ := ret[0].([]types.ValidatorUpdate) + return ret0 +} + +// BlockValidatorUpdates indicates an expected call of BlockValidatorUpdates. +func (mr *MockStakingKeeperMockRecorder) BlockValidatorUpdates(ctx interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockValidatorUpdates", reflect.TypeOf((*MockStakingKeeper)(nil).BlockValidatorUpdates), ctx) +} + // BondDenom mocks base method. func (m *MockStakingKeeper) BondDenom(ctx types0.Context) string { m.ctrl.T.Helper() @@ -119,6 +133,21 @@ func (mr *MockStakingKeeperMockRecorder) GetLastValidators(ctx interface{}) *gom return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLastValidators", reflect.TypeOf((*MockStakingKeeper)(nil).GetLastValidators), ctx) } +// GetRedelegationByUnbondingID mocks base method. +func (m *MockStakingKeeper) GetRedelegationByUnbondingID(ctx types0.Context, id uint64) (types5.Redelegation, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetRedelegationByUnbondingID", ctx, id) + ret0, _ := ret[0].(types5.Redelegation) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// GetRedelegationByUnbondingID indicates an expected call of GetRedelegationByUnbondingID. +func (mr *MockStakingKeeperMockRecorder) GetRedelegationByUnbondingID(ctx, id interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRedelegationByUnbondingID", reflect.TypeOf((*MockStakingKeeper)(nil).GetRedelegationByUnbondingID), ctx, id) +} + // GetRedelegationsFromSrcValidator mocks base method. func (m *MockStakingKeeper) GetRedelegationsFromSrcValidator(ctx types0.Context, valAddr types0.ValAddress) []types5.Redelegation { m.ctrl.T.Helper() @@ -133,6 +162,21 @@ func (mr *MockStakingKeeperMockRecorder) GetRedelegationsFromSrcValidator(ctx, v return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRedelegationsFromSrcValidator", reflect.TypeOf((*MockStakingKeeper)(nil).GetRedelegationsFromSrcValidator), ctx, valAddr) } +// GetUnbondingDelegationByUnbondingID mocks base method. +func (m *MockStakingKeeper) GetUnbondingDelegationByUnbondingID(ctx types0.Context, id uint64) (types5.UnbondingDelegation, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUnbondingDelegationByUnbondingID", ctx, id) + ret0, _ := ret[0].(types5.UnbondingDelegation) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// GetUnbondingDelegationByUnbondingID indicates an expected call of GetUnbondingDelegationByUnbondingID. +func (mr *MockStakingKeeperMockRecorder) GetUnbondingDelegationByUnbondingID(ctx, id interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUnbondingDelegationByUnbondingID", reflect.TypeOf((*MockStakingKeeper)(nil).GetUnbondingDelegationByUnbondingID), ctx, id) +} + // GetUnbondingDelegationsFromValidator mocks base method. func (m *MockStakingKeeper) GetUnbondingDelegationsFromValidator(ctx types0.Context, valAddr types0.ValAddress) []types5.UnbondingDelegation { m.ctrl.T.Helper() @@ -192,6 +236,21 @@ func (mr *MockStakingKeeperMockRecorder) GetValidatorByConsAddr(ctx, consAddr in return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetValidatorByConsAddr", reflect.TypeOf((*MockStakingKeeper)(nil).GetValidatorByConsAddr), ctx, consAddr) } +// GetValidatorByUnbondingID mocks base method. +func (m *MockStakingKeeper) GetValidatorByUnbondingID(ctx types0.Context, id uint64) (types5.Validator, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetValidatorByUnbondingID", ctx, id) + ret0, _ := ret[0].(types5.Validator) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// GetValidatorByUnbondingID indicates an expected call of GetValidatorByUnbondingID. +func (mr *MockStakingKeeperMockRecorder) GetValidatorByUnbondingID(ctx, id interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetValidatorByUnbondingID", reflect.TypeOf((*MockStakingKeeper)(nil).GetValidatorByUnbondingID), ctx, id) +} + // GetValidatorUpdates mocks base method. func (m *MockStakingKeeper) GetValidatorUpdates(ctx types0.Context) []types.ValidatorUpdate { m.ctrl.T.Helper() diff --git a/x/ccv/provider/keeper/hooks.go b/x/ccv/provider/keeper/hooks.go index 88590a9875..ed926f16c7 100644 --- a/x/ccv/provider/keeper/hooks.go +++ b/x/ccv/provider/keeper/hooks.go @@ -8,6 +8,7 @@ import ( v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" ) @@ -35,8 +36,64 @@ func (k *Keeper) Hooks() Hooks { func (h Hooks) AfterUnbondingInitiated(ctx sdk.Context, id uint64) error { var consumerChainIDS []string + // get validator address from unbonding operation + unbondingType, found := h.k.stakingKeeper.GetUnbondingType(ctx, id) + vadAddrBech32 := "" + if !found { + ctx.Logger().Error("undefined type for unbonding operation id: %d", id) + return nil + } + + switch unbondingType { + case stakingtypes.UnbondingType_UnbondingDelegation: + ubd, found := h.k.stakingKeeper.GetUnbondingDelegationByUnbondingID(ctx, id) + if !found { + ctx.Logger().Error("unfound ubonding delegation for unbonding id: %d", id) + return nil + } + vadAddrBech32 = ubd.ValidatorAddress + case stakingtypes.UnbondingType_Redelegation: + red, found := h.k.stakingKeeper.GetRedelegationByUnbondingID(ctx, id) + if !found { + ctx.Logger().Error("unfound relegation for unbonding operation id: %d", id) + return nil + } + vadAddrBech32 = red.ValidatorSrcAddress + case stakingtypes.UnbondingType_ValidatorUnbonding: + val, found := h.k.stakingKeeper.GetValidatorByUnbondingID(ctx, id) + if !found { + ctx.Logger().Error("unfound validator for unbonding operation id: %d", id) + return nil + } + vadAddrBech32 = val.OperatorAddress + default: + ctx.Logger().Error("invalid unbonding operation type: %s", unbondingType) + return nil + } + + valAddr, err := sdk.ValAddressFromBech32(vadAddrBech32) + if err != nil { + ctx.Logger().Error(err.Error()) + return nil + } + + validator, found := h.k.stakingKeeper.GetValidator(ctx, valAddr) + if !found { + ctx.Logger().Error("unfound validator for validator address %s", vadAddrBech32) + return nil + } + + consAddr, err := validator.GetConsAddr() + if err != nil { + ctx.Logger().Error(err.Error()) + return nil + } + + // get all consumers where the validator is in the validator set for _, chain := range h.k.GetAllConsumerChains(ctx) { - consumerChainIDS = append(consumerChainIDS, chain.ChainId) + if h.k.IsConsumerValidator(ctx, chain.ChainId, types.NewProviderConsAddress(consAddr)) { + consumerChainIDS = append(consumerChainIDS, chain.ChainId) + } } if len(consumerChainIDS) == 0 { diff --git a/x/ccv/provider/keeper/relay_test.go b/x/ccv/provider/keeper/relay_test.go index a0c0b20e48..5afbf70248 100644 --- a/x/ccv/provider/keeper/relay_test.go +++ b/x/ccv/provider/keeper/relay_test.go @@ -12,7 +12,9 @@ import ( "cosmossdk.io/math" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" @@ -475,6 +477,10 @@ func TestHandleVSCMaturedPacket(t *testing.T) { // Start first unbonding without any consumers registered var unbondingOpId uint64 = 1 + gomock.InOrder( + mocks.MockStakingKeeper.EXPECT().GetUnbondingType(ctx, unbondingOpId).Return(stakingtypes.UnbondingType_Undefined, false), + ) + err := pk.Hooks().AfterUnbondingInitiated(ctx, unbondingOpId) require.NoError(t, err) // Check that no unbonding op was stored @@ -485,12 +491,34 @@ func TestHandleVSCMaturedPacket(t *testing.T) { pk.IncrementValidatorSetUpdateId(ctx) require.Equal(t, uint64(2), pk.GetValidatorSetUpdateId(ctx)) - // Registered first consumer + // Register first consumer pk.SetConsumerClientId(ctx, "chain-1", "client-1") + // Create 2 validators + vals := []stakingtypes.Validator{} + valsPk := []cryptotypes.PubKey{} + for i := 0; i < 2; i++ { + pubkey, err := cryptocodec.FromTmPubKeyInterface(cryptotestutil.NewCryptoIdentityFromIntSeed(54321 + i).TMCryptoPubKey()) + require.NoError(t, err) + valsPk = append(valsPk, pubkey) + pkAny, err := codectypes.NewAnyWithValue(pubkey) + require.NoError(t, err) + vals = append(vals, stakingtypes.Validator{ConsensusPubkey: pkAny}) + } + + // Opt-in one validator to consumer + pk.SetConsumerValidator(ctx, "chain-1", types.ConsumerValidator{ProviderConsAddr: valsPk[0].Address()}) + // Start second unbonding unbondingOpId = 2 gomock.InOrder( + mocks.MockStakingKeeper.EXPECT().GetUnbondingType(ctx, unbondingOpId).Return(stakingtypes.UnbondingType_UnbondingDelegation, true), + mocks.MockStakingKeeper.EXPECT().GetUnbondingDelegationByUnbondingID(ctx, unbondingOpId).Return( + stakingtypes.UnbondingDelegation{ + ValidatorAddress: sdk.ValAddress([]byte{1}).String(), + }, true), + mocks.MockStakingKeeper.EXPECT().GetValidator(ctx, sdk.ValAddress([]byte{1})). + Return(vals[0], true), mocks.MockStakingKeeper.EXPECT().PutUnbondingOnHold(ctx, unbondingOpId).Return(nil), ) err = pk.Hooks().AfterUnbondingInitiated(ctx, unbondingOpId) @@ -514,10 +542,21 @@ func TestHandleVSCMaturedPacket(t *testing.T) { // Registered second consumer pk.SetConsumerClientId(ctx, "chain-2", "client-2") + // Opt-in both validators to second consumer + pk.SetConsumerValidator(ctx, "chain-2", types.ConsumerValidator{ProviderConsAddr: valsPk[0].Address()}) + pk.SetConsumerValidator(ctx, "chain-2", types.ConsumerValidator{ProviderConsAddr: valsPk[1].Address()}) + // Start third and fourth unbonding unbondingOpIds := []uint64{3, 4} for _, id := range unbondingOpIds { gomock.InOrder( + mocks.MockStakingKeeper.EXPECT().GetUnbondingType(ctx, id).Return(stakingtypes.UnbondingType_Redelegation, true), + mocks.MockStakingKeeper.EXPECT().GetRedelegationByUnbondingID(ctx, id).Return( + stakingtypes.Redelegation{ + ValidatorSrcAddress: sdk.ValAddress([]byte{1}).String(), + }, true), + mocks.MockStakingKeeper.EXPECT().GetValidator(ctx, sdk.ValAddress([]byte{1})). + Return(vals[0], true), mocks.MockStakingKeeper.EXPECT().PutUnbondingOnHold(ctx, id).Return(nil), ) err = pk.Hooks().AfterUnbondingInitiated(ctx, id) @@ -538,6 +577,33 @@ func TestHandleVSCMaturedPacket(t *testing.T) { require.Equal(t, unbondingOpIds, ids) } + // Increment vscID + pk.IncrementValidatorSetUpdateId(ctx) + require.Equal(t, uint64(4), pk.GetValidatorSetUpdateId(ctx)) + + // Start fith unbonding + unbondingOpId = 5 + gomock.InOrder( + mocks.MockStakingKeeper.EXPECT().GetUnbondingType(ctx, unbondingOpId).Return(stakingtypes.UnbondingType_ValidatorUnbonding, true), + mocks.MockStakingKeeper.EXPECT().GetValidatorByUnbondingID(ctx, unbondingOpId).Return( + stakingtypes.Validator{ + OperatorAddress: sdk.ValAddress([]byte{1}).String(), + }, true), + mocks.MockStakingKeeper.EXPECT().GetValidator(ctx, sdk.ValAddress([]byte{1})). + Return(vals[1], true), + mocks.MockStakingKeeper.EXPECT().PutUnbondingOnHold(ctx, unbondingOpId).Return(nil), + ) + err = pk.Hooks().AfterUnbondingInitiated(ctx, unbondingOpId) + require.NoError(t, err) + + // Check that an unbonding op was stored for chain-2 only + // since it's the only consumer the unbonding validator has opted-in to + expectedChains = []string{"chain-2"} + unbondingOp, found = pk.GetUnbondingOp(ctx, unbondingOpId) + require.True(t, found) + require.Equal(t, unbondingOpId, unbondingOp.Id) + require.Equal(t, expectedChains, unbondingOp.UnbondingConsumerChains) + // Handle VSCMatured packet from chain-1 for vscID 1. // Note that no VSCPacket was sent as the chain was not yet registered, // but the code should still work diff --git a/x/ccv/types/expected_keepers.go b/x/ccv/types/expected_keepers.go index 73566926ec..7b77ebd095 100644 --- a/x/ccv/types/expected_keepers.go +++ b/x/ccv/types/expected_keepers.go @@ -42,6 +42,9 @@ type StakingKeeper interface { IterateLastValidatorPowers(ctx sdk.Context, cb func(addr sdk.ValAddress, power int64) (stop bool)) PowerReduction(ctx sdk.Context) math.Int PutUnbondingOnHold(ctx sdk.Context, id uint64) error + GetUnbondingDelegationByUnbondingID(ctx sdk.Context, id uint64) (ubd stakingtypes.UnbondingDelegation, found bool) + GetRedelegationByUnbondingID(ctx sdk.Context, id uint64) (red stakingtypes.Redelegation, found bool) + GetValidatorByUnbondingID(ctx sdk.Context, id uint64) (val stakingtypes.Validator, found bool) IterateValidators(ctx sdk.Context, f func(index int64, validator stakingtypes.ValidatorI) (stop bool)) Validator(ctx sdk.Context, addr sdk.ValAddress) stakingtypes.ValidatorI IsValidatorJailed(ctx sdk.Context, addr sdk.ConsAddress) bool @@ -54,6 +57,7 @@ type StakingKeeper interface { GetUnbondingDelegationsFromValidator(ctx sdk.Context, valAddr sdk.ValAddress) (ubds []stakingtypes.UnbondingDelegation) GetRedelegationsFromSrcValidator(ctx sdk.Context, valAddr sdk.ValAddress) (reds []stakingtypes.Redelegation) GetUnbondingType(ctx sdk.Context, id uint64) (unbondingType stakingtypes.UnbondingType, found bool) + BlockValidatorUpdates(ctx sdk.Context) []abci.ValidatorUpdate } // SlashingKeeper defines the contract expected to perform ccv slashing From d4419ca46a966857c67dc9a7822349330479c235 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Tue, 23 Apr 2024 10:57:01 +0200 Subject: [PATCH 048/110] Get back 3.2.0 and 3.3.0 changelog from main --- .../bug-fixes/consumer/1146-pending-packets.md | 2 ++ .../consumer/1150-revert-wire-breaking.md | 2 ++ .../bug-fixes/consumer/1244-validate-transfer.md | 2 ++ .../bug-fixes/consumer/1262-fee-pool-addr.md | 2 ++ .../v3.2.0/bug-fixes/consumer/1295-migration.md | 2 ++ .changelog/v3.2.0/dependencies/1196-bump-ibc.md | 3 +++ .changelog/v3.2.0/dependencies/1258-bump-ibc.md | 3 +++ .changelog/v3.2.0/dependencies/1258-bump-sdk.md | 3 +++ .changelog/v3.2.0/dependencies/1259-bump-sdk.md | 3 +++ .../features/consumer/1024-jail-throttling-v2.md | 2 ++ .../features/provider/1076-export-timestamps.md | 2 ++ .../features/provider/1280-reward-denoms.md | 3 +++ .../improvements/1244-consumer-unbonding.md | 2 ++ .../consumer/1037-optimize-storage.md | 2 ++ .../v3.2.0/state-breaking/1196-bump-ibc.md | 3 +++ .../state-breaking/1244-consumer-unbonding.md | 2 ++ .../v3.2.0/state-breaking/1258-bump-ibc.md | 3 +++ .../v3.2.0/state-breaking/1258-bump-sdk.md | 3 +++ .../v3.2.0/state-breaking/1259-bump-sdk.md | 3 +++ .../consumer/1024-jail-throttling-v2.md | 2 ++ .../consumer/1037-optimize-storage.md | 2 ++ .../consumer/1146-pending-packets.md | 2 ++ .../consumer/1150-revert-wire-breaking.md | 2 ++ .../consumer/1244-validate-transfer.md | 2 ++ .../consumer/1262-fee-pool-addr.md | 2 ++ .../state-breaking/consumer/1295-migration.md | 2 ++ .../provider/1280-reward-denoms.md | 3 +++ .changelog/v3.2.0/summary.md | 1 + ...aphic-verification-of-equivocation-feature.md | 2 ++ .changelog/v3.3.0/dependencies/1373-bump-ibc.md | 3 +++ .changelog/v3.3.0/features/1336-quint-model.md | 2 ++ .../provider/1339-check-key-assignment-in-use.md | 3 +++ .../1340-cryptographic-equivocation-feature.md | 4 ++++ .../v3.3.0/improvements/1324-consumer-genesis.md | 16 ++++++++++++++++ .../v3.3.0/improvements/1350-cleanup-types.md | 3 +++ .../provider/1503-query-key-assignment.md | 1 + .../state-breaking/1324-consumer-genesis.md | 2 ++ .../v3.3.0/state-breaking/1460-msg-validation.md | 3 +++ .../provider/1339-check-key-assignment-in-use.md | 3 +++ .../1340-cryptographic-equivocation-feature.md | 4 ++++ .changelog/v3.3.0/summary.md | 1 + 41 files changed, 112 insertions(+) create mode 100644 .changelog/v3.2.0/bug-fixes/consumer/1146-pending-packets.md create mode 100644 .changelog/v3.2.0/bug-fixes/consumer/1150-revert-wire-breaking.md create mode 100644 .changelog/v3.2.0/bug-fixes/consumer/1244-validate-transfer.md create mode 100644 .changelog/v3.2.0/bug-fixes/consumer/1262-fee-pool-addr.md create mode 100644 .changelog/v3.2.0/bug-fixes/consumer/1295-migration.md create mode 100644 .changelog/v3.2.0/dependencies/1196-bump-ibc.md create mode 100644 .changelog/v3.2.0/dependencies/1258-bump-ibc.md create mode 100644 .changelog/v3.2.0/dependencies/1258-bump-sdk.md create mode 100644 .changelog/v3.2.0/dependencies/1259-bump-sdk.md create mode 100644 .changelog/v3.2.0/features/consumer/1024-jail-throttling-v2.md create mode 100644 .changelog/v3.2.0/features/provider/1076-export-timestamps.md create mode 100644 .changelog/v3.2.0/features/provider/1280-reward-denoms.md create mode 100644 .changelog/v3.2.0/improvements/1244-consumer-unbonding.md create mode 100644 .changelog/v3.2.0/improvements/consumer/1037-optimize-storage.md create mode 100644 .changelog/v3.2.0/state-breaking/1196-bump-ibc.md create mode 100644 .changelog/v3.2.0/state-breaking/1244-consumer-unbonding.md create mode 100644 .changelog/v3.2.0/state-breaking/1258-bump-ibc.md create mode 100644 .changelog/v3.2.0/state-breaking/1258-bump-sdk.md create mode 100644 .changelog/v3.2.0/state-breaking/1259-bump-sdk.md create mode 100644 .changelog/v3.2.0/state-breaking/consumer/1024-jail-throttling-v2.md create mode 100644 .changelog/v3.2.0/state-breaking/consumer/1037-optimize-storage.md create mode 100644 .changelog/v3.2.0/state-breaking/consumer/1146-pending-packets.md create mode 100644 .changelog/v3.2.0/state-breaking/consumer/1150-revert-wire-breaking.md create mode 100644 .changelog/v3.2.0/state-breaking/consumer/1244-validate-transfer.md create mode 100644 .changelog/v3.2.0/state-breaking/consumer/1262-fee-pool-addr.md create mode 100644 .changelog/v3.2.0/state-breaking/consumer/1295-migration.md create mode 100644 .changelog/v3.2.0/state-breaking/provider/1280-reward-denoms.md create mode 100644 .changelog/v3.2.0/summary.md create mode 100644 .changelog/v3.3.0/api-breaking/provider/1340-add-cryptographic-verification-of-equivocation-feature.md create mode 100644 .changelog/v3.3.0/dependencies/1373-bump-ibc.md create mode 100644 .changelog/v3.3.0/features/1336-quint-model.md create mode 100644 .changelog/v3.3.0/features/provider/1339-check-key-assignment-in-use.md create mode 100644 .changelog/v3.3.0/features/provider/1340-cryptographic-equivocation-feature.md create mode 100644 .changelog/v3.3.0/improvements/1324-consumer-genesis.md create mode 100644 .changelog/v3.3.0/improvements/1350-cleanup-types.md create mode 100644 .changelog/v3.3.0/improvements/provider/1503-query-key-assignment.md create mode 100644 .changelog/v3.3.0/state-breaking/1324-consumer-genesis.md create mode 100644 .changelog/v3.3.0/state-breaking/1460-msg-validation.md create mode 100644 .changelog/v3.3.0/state-breaking/provider/1339-check-key-assignment-in-use.md create mode 100644 .changelog/v3.3.0/state-breaking/provider/1340-cryptographic-equivocation-feature.md create mode 100644 .changelog/v3.3.0/summary.md diff --git a/.changelog/v3.2.0/bug-fixes/consumer/1146-pending-packets.md b/.changelog/v3.2.0/bug-fixes/consumer/1146-pending-packets.md new file mode 100644 index 0000000000..0bab707fec --- /dev/null +++ b/.changelog/v3.2.0/bug-fixes/consumer/1146-pending-packets.md @@ -0,0 +1,2 @@ +- Fix deletion of pending packets that may cause duplicate sends + ([\#1146](https://github.com/cosmos/interchain-security/pull/1146)) \ No newline at end of file diff --git a/.changelog/v3.2.0/bug-fixes/consumer/1150-revert-wire-breaking.md b/.changelog/v3.2.0/bug-fixes/consumer/1150-revert-wire-breaking.md new file mode 100644 index 0000000000..067448e770 --- /dev/null +++ b/.changelog/v3.2.0/bug-fixes/consumer/1150-revert-wire-breaking.md @@ -0,0 +1,2 @@ +- Remove `idx` field from the `ccv.ConsumerPacketData` type as this would break the + wire ([\#1150](https://github.com/cosmos/interchain-security/pull/1150)) \ No newline at end of file diff --git a/.changelog/v3.2.0/bug-fixes/consumer/1244-validate-transfer.md b/.changelog/v3.2.0/bug-fixes/consumer/1244-validate-transfer.md new file mode 100644 index 0000000000..2d94c79c75 --- /dev/null +++ b/.changelog/v3.2.0/bug-fixes/consumer/1244-validate-transfer.md @@ -0,0 +1,2 @@ +- Validate token transfer messages before calling `Transfer()`. + ([\#1244](https://github.com/cosmos/interchain-security/pull/1244)) \ No newline at end of file diff --git a/.changelog/v3.2.0/bug-fixes/consumer/1262-fee-pool-addr.md b/.changelog/v3.2.0/bug-fixes/consumer/1262-fee-pool-addr.md new file mode 100644 index 0000000000..bbb54db2e3 --- /dev/null +++ b/.changelog/v3.2.0/bug-fixes/consumer/1262-fee-pool-addr.md @@ -0,0 +1,2 @@ +- Remove incorrect address validation on `ProviderFeePoolAddrStr` param. + ([\#1262](https://github.com/cosmos/interchain-security/pull/1262)) \ No newline at end of file diff --git a/.changelog/v3.2.0/bug-fixes/consumer/1295-migration.md b/.changelog/v3.2.0/bug-fixes/consumer/1295-migration.md new file mode 100644 index 0000000000..739b08dc39 --- /dev/null +++ b/.changelog/v3.2.0/bug-fixes/consumer/1295-migration.md @@ -0,0 +1,2 @@ +- Increment consumer consensus version and register consumer migration. + ([\#1295](https://github.com/cosmos/interchain-security/pull/1295)) \ No newline at end of file diff --git a/.changelog/v3.2.0/dependencies/1196-bump-ibc.md b/.changelog/v3.2.0/dependencies/1196-bump-ibc.md new file mode 100644 index 0000000000..fcf4450150 --- /dev/null +++ b/.changelog/v3.2.0/dependencies/1196-bump-ibc.md @@ -0,0 +1,3 @@ +- Bump [ibc-go](https://github.com/cosmos/ibc-go) to + [v7.2.0](https://github.com/cosmos/ibc-go/releases/tag/v7.2.0). + ([\#1196](https://github.com/cosmos/interchain-security/pull/1196)) \ No newline at end of file diff --git a/.changelog/v3.2.0/dependencies/1258-bump-ibc.md b/.changelog/v3.2.0/dependencies/1258-bump-ibc.md new file mode 100644 index 0000000000..68c6e2b104 --- /dev/null +++ b/.changelog/v3.2.0/dependencies/1258-bump-ibc.md @@ -0,0 +1,3 @@ +- Bump [ibc-go](https://github.com/cosmos/ibc-go) to + [v7.3.0](https://github.com/cosmos/ibc-go/releases/tag/v7.3.0). + ([\#1258](https://github.com/cosmos/interchain-security/pull/1258)) \ No newline at end of file diff --git a/.changelog/v3.2.0/dependencies/1258-bump-sdk.md b/.changelog/v3.2.0/dependencies/1258-bump-sdk.md new file mode 100644 index 0000000000..7344fac97e --- /dev/null +++ b/.changelog/v3.2.0/dependencies/1258-bump-sdk.md @@ -0,0 +1,3 @@ +- Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to + [v0.47.4](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.4). + ([\#1258](https://github.com/cosmos/interchain-security/pull/1258)) \ No newline at end of file diff --git a/.changelog/v3.2.0/dependencies/1259-bump-sdk.md b/.changelog/v3.2.0/dependencies/1259-bump-sdk.md new file mode 100644 index 0000000000..247c623b7d --- /dev/null +++ b/.changelog/v3.2.0/dependencies/1259-bump-sdk.md @@ -0,0 +1,3 @@ +- Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to + [v0.47.5](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.5). + ([\#1259](https://github.com/cosmos/interchain-security/pull/1259)) \ No newline at end of file diff --git a/.changelog/v3.2.0/features/consumer/1024-jail-throttling-v2.md b/.changelog/v3.2.0/features/consumer/1024-jail-throttling-v2.md new file mode 100644 index 0000000000..7570facb34 --- /dev/null +++ b/.changelog/v3.2.0/features/consumer/1024-jail-throttling-v2.md @@ -0,0 +1,2 @@ +- Add the consumer-side changes for jail throttling with retries (cf. ADR 008). + ([\#1024](https://github.com/cosmos/interchain-security/pull/1024)) \ No newline at end of file diff --git a/.changelog/v3.2.0/features/provider/1076-export-timestamps.md b/.changelog/v3.2.0/features/provider/1076-export-timestamps.md new file mode 100644 index 0000000000..f2a8608f8b --- /dev/null +++ b/.changelog/v3.2.0/features/provider/1076-export-timestamps.md @@ -0,0 +1,2 @@ +- Add `InitTimeoutTimestamps` and `ExportedVscSendTimestamps` to exported + genesis. ([\#1076](https://github.com/cosmos/interchain-security/pull/1076)) \ No newline at end of file diff --git a/.changelog/v3.2.0/features/provider/1280-reward-denoms.md b/.changelog/v3.2.0/features/provider/1280-reward-denoms.md new file mode 100644 index 0000000000..c1f3659a44 --- /dev/null +++ b/.changelog/v3.2.0/features/provider/1280-reward-denoms.md @@ -0,0 +1,3 @@ +- Add a governance proposal for setting on the provider the denominations for + rewards from consumer chains. + ([\#1280](https://github.com/cosmos/interchain-security/pull/1280)) \ No newline at end of file diff --git a/.changelog/v3.2.0/improvements/1244-consumer-unbonding.md b/.changelog/v3.2.0/improvements/1244-consumer-unbonding.md new file mode 100644 index 0000000000..4a8504e4ce --- /dev/null +++ b/.changelog/v3.2.0/improvements/1244-consumer-unbonding.md @@ -0,0 +1,2 @@ +- Update the default consumer unbonding period to 2 weeks. + ([\#1244](https://github.com/cosmos/interchain-security/pull/1244)) \ No newline at end of file diff --git a/.changelog/v3.2.0/improvements/consumer/1037-optimize-storage.md b/.changelog/v3.2.0/improvements/consumer/1037-optimize-storage.md new file mode 100644 index 0000000000..726906420b --- /dev/null +++ b/.changelog/v3.2.0/improvements/consumer/1037-optimize-storage.md @@ -0,0 +1,2 @@ +- Optimize pending packets storage on consumer, with migration. + ([\#1037](https://github.com/cosmos/interchain-security/pull/1037)) \ No newline at end of file diff --git a/.changelog/v3.2.0/state-breaking/1196-bump-ibc.md b/.changelog/v3.2.0/state-breaking/1196-bump-ibc.md new file mode 100644 index 0000000000..fcf4450150 --- /dev/null +++ b/.changelog/v3.2.0/state-breaking/1196-bump-ibc.md @@ -0,0 +1,3 @@ +- Bump [ibc-go](https://github.com/cosmos/ibc-go) to + [v7.2.0](https://github.com/cosmos/ibc-go/releases/tag/v7.2.0). + ([\#1196](https://github.com/cosmos/interchain-security/pull/1196)) \ No newline at end of file diff --git a/.changelog/v3.2.0/state-breaking/1244-consumer-unbonding.md b/.changelog/v3.2.0/state-breaking/1244-consumer-unbonding.md new file mode 100644 index 0000000000..4a8504e4ce --- /dev/null +++ b/.changelog/v3.2.0/state-breaking/1244-consumer-unbonding.md @@ -0,0 +1,2 @@ +- Update the default consumer unbonding period to 2 weeks. + ([\#1244](https://github.com/cosmos/interchain-security/pull/1244)) \ No newline at end of file diff --git a/.changelog/v3.2.0/state-breaking/1258-bump-ibc.md b/.changelog/v3.2.0/state-breaking/1258-bump-ibc.md new file mode 100644 index 0000000000..68c6e2b104 --- /dev/null +++ b/.changelog/v3.2.0/state-breaking/1258-bump-ibc.md @@ -0,0 +1,3 @@ +- Bump [ibc-go](https://github.com/cosmos/ibc-go) to + [v7.3.0](https://github.com/cosmos/ibc-go/releases/tag/v7.3.0). + ([\#1258](https://github.com/cosmos/interchain-security/pull/1258)) \ No newline at end of file diff --git a/.changelog/v3.2.0/state-breaking/1258-bump-sdk.md b/.changelog/v3.2.0/state-breaking/1258-bump-sdk.md new file mode 100644 index 0000000000..7344fac97e --- /dev/null +++ b/.changelog/v3.2.0/state-breaking/1258-bump-sdk.md @@ -0,0 +1,3 @@ +- Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to + [v0.47.4](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.4). + ([\#1258](https://github.com/cosmos/interchain-security/pull/1258)) \ No newline at end of file diff --git a/.changelog/v3.2.0/state-breaking/1259-bump-sdk.md b/.changelog/v3.2.0/state-breaking/1259-bump-sdk.md new file mode 100644 index 0000000000..247c623b7d --- /dev/null +++ b/.changelog/v3.2.0/state-breaking/1259-bump-sdk.md @@ -0,0 +1,3 @@ +- Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to + [v0.47.5](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.5). + ([\#1259](https://github.com/cosmos/interchain-security/pull/1259)) \ No newline at end of file diff --git a/.changelog/v3.2.0/state-breaking/consumer/1024-jail-throttling-v2.md b/.changelog/v3.2.0/state-breaking/consumer/1024-jail-throttling-v2.md new file mode 100644 index 0000000000..7570facb34 --- /dev/null +++ b/.changelog/v3.2.0/state-breaking/consumer/1024-jail-throttling-v2.md @@ -0,0 +1,2 @@ +- Add the consumer-side changes for jail throttling with retries (cf. ADR 008). + ([\#1024](https://github.com/cosmos/interchain-security/pull/1024)) \ No newline at end of file diff --git a/.changelog/v3.2.0/state-breaking/consumer/1037-optimize-storage.md b/.changelog/v3.2.0/state-breaking/consumer/1037-optimize-storage.md new file mode 100644 index 0000000000..726906420b --- /dev/null +++ b/.changelog/v3.2.0/state-breaking/consumer/1037-optimize-storage.md @@ -0,0 +1,2 @@ +- Optimize pending packets storage on consumer, with migration. + ([\#1037](https://github.com/cosmos/interchain-security/pull/1037)) \ No newline at end of file diff --git a/.changelog/v3.2.0/state-breaking/consumer/1146-pending-packets.md b/.changelog/v3.2.0/state-breaking/consumer/1146-pending-packets.md new file mode 100644 index 0000000000..a10d75a505 --- /dev/null +++ b/.changelog/v3.2.0/state-breaking/consumer/1146-pending-packets.md @@ -0,0 +1,2 @@ +- Fix deletion of pending packets that may cause duplicate sends + ([\#1146](https://github.com/cosmos/interchain-security/pull/1146)) \ No newline at end of file diff --git a/.changelog/v3.2.0/state-breaking/consumer/1150-revert-wire-breaking.md b/.changelog/v3.2.0/state-breaking/consumer/1150-revert-wire-breaking.md new file mode 100644 index 0000000000..067448e770 --- /dev/null +++ b/.changelog/v3.2.0/state-breaking/consumer/1150-revert-wire-breaking.md @@ -0,0 +1,2 @@ +- Remove `idx` field from the `ccv.ConsumerPacketData` type as this would break the + wire ([\#1150](https://github.com/cosmos/interchain-security/pull/1150)) \ No newline at end of file diff --git a/.changelog/v3.2.0/state-breaking/consumer/1244-validate-transfer.md b/.changelog/v3.2.0/state-breaking/consumer/1244-validate-transfer.md new file mode 100644 index 0000000000..2d94c79c75 --- /dev/null +++ b/.changelog/v3.2.0/state-breaking/consumer/1244-validate-transfer.md @@ -0,0 +1,2 @@ +- Validate token transfer messages before calling `Transfer()`. + ([\#1244](https://github.com/cosmos/interchain-security/pull/1244)) \ No newline at end of file diff --git a/.changelog/v3.2.0/state-breaking/consumer/1262-fee-pool-addr.md b/.changelog/v3.2.0/state-breaking/consumer/1262-fee-pool-addr.md new file mode 100644 index 0000000000..bbb54db2e3 --- /dev/null +++ b/.changelog/v3.2.0/state-breaking/consumer/1262-fee-pool-addr.md @@ -0,0 +1,2 @@ +- Remove incorrect address validation on `ProviderFeePoolAddrStr` param. + ([\#1262](https://github.com/cosmos/interchain-security/pull/1262)) \ No newline at end of file diff --git a/.changelog/v3.2.0/state-breaking/consumer/1295-migration.md b/.changelog/v3.2.0/state-breaking/consumer/1295-migration.md new file mode 100644 index 0000000000..739b08dc39 --- /dev/null +++ b/.changelog/v3.2.0/state-breaking/consumer/1295-migration.md @@ -0,0 +1,2 @@ +- Increment consumer consensus version and register consumer migration. + ([\#1295](https://github.com/cosmos/interchain-security/pull/1295)) \ No newline at end of file diff --git a/.changelog/v3.2.0/state-breaking/provider/1280-reward-denoms.md b/.changelog/v3.2.0/state-breaking/provider/1280-reward-denoms.md new file mode 100644 index 0000000000..c1f3659a44 --- /dev/null +++ b/.changelog/v3.2.0/state-breaking/provider/1280-reward-denoms.md @@ -0,0 +1,3 @@ +- Add a governance proposal for setting on the provider the denominations for + rewards from consumer chains. + ([\#1280](https://github.com/cosmos/interchain-security/pull/1280)) \ No newline at end of file diff --git a/.changelog/v3.2.0/summary.md b/.changelog/v3.2.0/summary.md new file mode 100644 index 0000000000..e7b2c7d6d4 --- /dev/null +++ b/.changelog/v3.2.0/summary.md @@ -0,0 +1 @@ +*November 24, 2023* diff --git a/.changelog/v3.3.0/api-breaking/provider/1340-add-cryptographic-verification-of-equivocation-feature.md b/.changelog/v3.3.0/api-breaking/provider/1340-add-cryptographic-verification-of-equivocation-feature.md new file mode 100644 index 0000000000..c50662be72 --- /dev/null +++ b/.changelog/v3.3.0/api-breaking/provider/1340-add-cryptographic-verification-of-equivocation-feature.md @@ -0,0 +1,2 @@ +- Deprecate equivocation proposals. +([\#1340](https://github.com/cosmos/interchain-security/pull/1340)) \ No newline at end of file diff --git a/.changelog/v3.3.0/dependencies/1373-bump-ibc.md b/.changelog/v3.3.0/dependencies/1373-bump-ibc.md new file mode 100644 index 0000000000..efe4e0c286 --- /dev/null +++ b/.changelog/v3.3.0/dependencies/1373-bump-ibc.md @@ -0,0 +1,3 @@ +- Bump [ibc-go](https://github.com/cosmos/ibc-go) to + [v7.3.1](https://github.com/cosmos/ibc-go/releases/tag/v7.3.1). + ([\#1373](https://github.com/cosmos/interchain-security/pull/1373)) \ No newline at end of file diff --git a/.changelog/v3.3.0/features/1336-quint-model.md b/.changelog/v3.3.0/features/1336-quint-model.md new file mode 100644 index 0000000000..96c4562b32 --- /dev/null +++ b/.changelog/v3.3.0/features/1336-quint-model.md @@ -0,0 +1,2 @@ +- Add Quint model of Replicated Security. + ([\#1336](https://github.com/cosmos/interchain-security/pull/1336)) \ No newline at end of file diff --git a/.changelog/v3.3.0/features/provider/1339-check-key-assignment-in-use.md b/.changelog/v3.3.0/features/provider/1339-check-key-assignment-in-use.md new file mode 100644 index 0000000000..9f274f7bb4 --- /dev/null +++ b/.changelog/v3.3.0/features/provider/1339-check-key-assignment-in-use.md @@ -0,0 +1,3 @@ +- Update how consumer-assigned keys are checked when a validator is + created on the provider. + ([\#1339](https://github.com/cosmos/interchain-security/pull/1339)) \ No newline at end of file diff --git a/.changelog/v3.3.0/features/provider/1340-cryptographic-equivocation-feature.md b/.changelog/v3.3.0/features/provider/1340-cryptographic-equivocation-feature.md new file mode 100644 index 0000000000..5437fba186 --- /dev/null +++ b/.changelog/v3.3.0/features/provider/1340-cryptographic-equivocation-feature.md @@ -0,0 +1,4 @@ +- Introduce the cryptographic verification of equivocation feature to the provider + (cf. [ADR-005](docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md) + & [ADR-013](docs/docs/adrs/adr-013-equivocation-slashing.md)). + ([\#1340](https://github.com/cosmos/interchain-security/pull/1340)) \ No newline at end of file diff --git a/.changelog/v3.3.0/improvements/1324-consumer-genesis.md b/.changelog/v3.3.0/improvements/1324-consumer-genesis.md new file mode 100644 index 0000000000..a727be8341 --- /dev/null +++ b/.changelog/v3.3.0/improvements/1324-consumer-genesis.md @@ -0,0 +1,16 @@ +- Split out consumer genesis state to reduce shared data between provider and + consumer. ([\#1324](https://github.com/cosmos/interchain-security/pull/1324)) + - Note: This breaks json format used by augmenting Genesis files of consumer + chains with consumer genesis content exported from provider chain. Consumer + Genesis content exported from a provider chain using major version 1, 2 or 3 + of the provider module needs to be transformed with the transformation command + introduced by this PR: + ``` + Transform the consumer genesis file from a provider version v1, v2 or v3 to a version supported by this consumer. Result is printed to STDOUT. + + Example: + $ transform /path/to/ccv_consumer_genesis.json + + Usage: + interchain-security-cd genesis transform [genesis-file] [flags] + ``` \ No newline at end of file diff --git a/.changelog/v3.3.0/improvements/1350-cleanup-types.md b/.changelog/v3.3.0/improvements/1350-cleanup-types.md new file mode 100644 index 0000000000..6e26fc3992 --- /dev/null +++ b/.changelog/v3.3.0/improvements/1350-cleanup-types.md @@ -0,0 +1,3 @@ +- Refactor shared events, codecs and errors assign to + consumer and provider dedicated types where possible. + ([\#1350](https://github.com/cosmos/interchain-security/pull/1350)) \ No newline at end of file diff --git a/.changelog/v3.3.0/improvements/provider/1503-query-key-assignment.md b/.changelog/v3.3.0/improvements/provider/1503-query-key-assignment.md new file mode 100644 index 0000000000..62b505ec01 --- /dev/null +++ b/.changelog/v3.3.0/improvements/provider/1503-query-key-assignment.md @@ -0,0 +1 @@ +- Add `QueryAllPairsValConAddrByConsumerChainID` method to get list of all pairs `valConsensus` address by `Consummer chainID`. ([\#1503](https://github.com/cosmos/interchain-security/pull/1503)) \ No newline at end of file diff --git a/.changelog/v3.3.0/state-breaking/1324-consumer-genesis.md b/.changelog/v3.3.0/state-breaking/1324-consumer-genesis.md new file mode 100644 index 0000000000..b47f7199fd --- /dev/null +++ b/.changelog/v3.3.0/state-breaking/1324-consumer-genesis.md @@ -0,0 +1,2 @@ +- Split out consumer genesis state to reduce shared data between provider and + consumer. ([\#1324](https://github.com/cosmos/interchain-security/pull/1324)) \ No newline at end of file diff --git a/.changelog/v3.3.0/state-breaking/1460-msg-validation.md b/.changelog/v3.3.0/state-breaking/1460-msg-validation.md new file mode 100644 index 0000000000..46d18bd4c9 --- /dev/null +++ b/.changelog/v3.3.0/state-breaking/1460-msg-validation.md @@ -0,0 +1,3 @@ +- Improve validation of IBC packet data and provider messages. Also, + enable the provider to validate consumer packets before handling them. + ([\#1460](https://github.com/cosmos/interchain-security/pull/1460)) \ No newline at end of file diff --git a/.changelog/v3.3.0/state-breaking/provider/1339-check-key-assignment-in-use.md b/.changelog/v3.3.0/state-breaking/provider/1339-check-key-assignment-in-use.md new file mode 100644 index 0000000000..2890582ba8 --- /dev/null +++ b/.changelog/v3.3.0/state-breaking/provider/1339-check-key-assignment-in-use.md @@ -0,0 +1,3 @@ +- Change the states by adding a consumer key for each chain that is + not yet registered meaning for which the gov proposal has not passed. + ([\#1339](https://github.com/cosmos/interchain-security/pull/1339)) \ No newline at end of file diff --git a/.changelog/v3.3.0/state-breaking/provider/1340-cryptographic-equivocation-feature.md b/.changelog/v3.3.0/state-breaking/provider/1340-cryptographic-equivocation-feature.md new file mode 100644 index 0000000000..5437fba186 --- /dev/null +++ b/.changelog/v3.3.0/state-breaking/provider/1340-cryptographic-equivocation-feature.md @@ -0,0 +1,4 @@ +- Introduce the cryptographic verification of equivocation feature to the provider + (cf. [ADR-005](docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md) + & [ADR-013](docs/docs/adrs/adr-013-equivocation-slashing.md)). + ([\#1340](https://github.com/cosmos/interchain-security/pull/1340)) \ No newline at end of file diff --git a/.changelog/v3.3.0/summary.md b/.changelog/v3.3.0/summary.md new file mode 100644 index 0000000000..e556c0f0ca --- /dev/null +++ b/.changelog/v3.3.0/summary.md @@ -0,0 +1 @@ +*January 5, 2024* From 45b77bc2dfaa4181db99992a89f07ad31ec04b22 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Tue, 23 Apr 2024 10:57:44 +0200 Subject: [PATCH 049/110] Port epilogue from main --- .changelog/epilogue.md | 198 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 196 insertions(+), 2 deletions(-) diff --git a/.changelog/epilogue.md b/.changelog/epilogue.md index 15e2568e25..88987ef0a0 100644 --- a/.changelog/epilogue.md +++ b/.changelog/epilogue.md @@ -1,3 +1,197 @@ -## Previous Versions +## v3.1.0 -[CHANGELOG of previous versions](https://github.com/cosmos/interchain-security/blob/main/CHANGELOG.md) \ No newline at end of file +Date July 11th, 2023 + +A minor upgrade to v3.0.0, which removes the panic in the consumer ccv module which would occur in an emergency scenario where the ccv channel is closed. This release also fixes how a distribution related event is emitted, and bumps cometbft. + +* (feat) [#1127](https://github.com/cosmos/interchain-security/pull/1127) Remove consumer panic when ccv channel is closed +* (fix) [#720](https://github.com/cosmos/interchain-security/issues/720) Fix the attribute `AttributeDistributionTotal` value in `FeeDistribution` event emit. +* (deps) [#1119](https://github.com/cosmos/interchain-security/pull/1119) bump cometbft from `v0.37.1` to `0.37.2`. + +## v3.0.0 + +Date: June 21st, 2023 + +Interchain Security v3 uses SDK 0.47 and IBC 7. + +* (fix) [#1093](https://github.com/cosmos/interchain-security/pull/1093) Make SlashPacketData backward compatible when sending data over the wire +* (deps) [#1019](https://github.com/cosmos/interchain-security/pull/1019) Bump multiple dependencies. + * Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to [v0.47.3](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.3). + * Bump [ibc-go](https://github.com/cosmos/ibc-go) to [v7.1.0](https://github.com/cosmos/ibc-go/releases/tag/v7.1.0). + * Bump [CometBFT](https://github.com/cometbft/cometbft) to [v0.37.1](https://github.com/cometbft/cometbft/releases/tag/v0.37.1). +* `[x/ccv/provider]` (fix) [#945](https://github.com/cosmos/interchain-security/issues/945) Refactor `AfterUnbondingInitiated` to not panic when `PutUnbondingOnHold` returns error. +* `[x/ccv/provider]` (fix) [#977](https://github.com/cosmos/interchain-security/pull/977) Avoids panicking the provider when an unbonding delegation was removed through a `CancelUnbondingDelegation` message. +* `[x/ccv/democracy]` (feat) [#1019](https://github.com/cosmos/interchain-security/pull/1019) Whitelisting non-legacy params in the "democracy module" require the entire module to be whitelisted. + +## v2.4.0-lsm + +*November 20, 2023* + +* (fix) [#1439](https://github.com/cosmos/interchain-security/pull/1439) Fix unmarshaling for the CLI consumer double vote cmd. +* (feat!) [#1435](https://github.com/cosmos/interchain-security/pull/1435) Add height-base filter for consumer equivocation evidence. + +## v2.3.0-provider-lsm + +*November 15, 2023* + +❗ *This release is deprecated and should not be used in production.* + +* (fix!) [#1422](https://github.com/cosmos/interchain-security/pull/1422) Fix the misbehaviour handling by verifying the signatures of byzantine validators. + +## v2.2.0-provider-lsm + +❗ *This release is deprecated and should not be used in production.* + +### Cryptographic verification of equivocation +* New feature enabling the provider chain to verify equivocation evidence on its own instead of trusting consumer chains, see [EPIC](https://github.com/cosmos/interchain-security/issues/732). + +## v2.1.0-provider-lsm + +Date: September 15th, 2023 + +* (feature!) [#1280](https://github.com/cosmos/interchain-security/pull/1280) provider proposal for changing reward denoms + +## v2.0.0-lsm + +Date: August 18th, 2023 + +* (deps!) [#1120](https://github.com/cosmos/interchain-security/pull/1120) Bump [Cosmos SDK](https://github.com/cosmos/cosmos-sdk) to [v0.45.16-ics-lsm](https://github.com/cosmos/cosmos-sdk/tree/v0.45.16-ics-lsm). This requires adapting ICS to support this SDK release. Changes are state breaking. +* (fix) [#720](https://github.com/cosmos/interchain-security/issues/720) Fix the attribute `AttributeDistributionTotal` value in `FeeDistribution` event emit. + +## v2.0.0 + +Date: June 1st, 2023 + +Unlike prior releases, the ICS `v2.0.0` release will be based on the main branch. `v2.0.0` will contain all the accumulated PRs from the various releases below, along with other PRs that were merged, but not released to production. After `v2.0.0`, we plan to revamp release practices, and how we modularize the repo for consumer/provider. + +Upgrading a provider from `v1.1.0-multiden` to `v2.0.0` will require state migrations. See [migration.go](https://github.com/cosmos/interchain-security/blob/v2.0.0/x/ccv/provider/keeper/migration.go). + +Upgrading a consumer from `v1.2.0-multiden` to `v2.0.0` will NOT require state migrations. + +Some PRs from v2.0.0 may reappear from other releases below. This is due to the fact that ICS v1.1.0 deviates from the commit ordering of the main branch, and other releases thereafter are based on v1.1.0. + +### High level changes included in v2.0.0 + +* MVP for standalone to consumer changeover, see [EPIC](https://github.com/cosmos/interchain-security/issues/756) +* MVP for soft opt out, see [EPIC](https://github.com/cosmos/interchain-security/issues/851) +* Various fixes, critical and non-critical +* Docs updates which should not affect production code + +## Notable PRs included in v2.0.0 + +* (feat!) Add DistributionTransmissionChannel to ConsumerAdditionProposal [#965](https://github.com/cosmos/interchain-security/pull/965) +* (feat/fix) limit vsc matured packets handled per endblocker [#1004](https://github.com/cosmos/interchain-security/pull/1004) +* (fix) consumer key prefix order to avoid complex migrations [#963](https://github.com/cosmos/interchain-security/pull/963) and [#991](https://github.com/cosmos/interchain-security/pull/991). The latter PR is the proper fix. +* (feat) v1->v2 migrations to accommodate a bugfix having to do with store keys, introduce new params, and deal with consumer genesis state schema changes [#975](https://github.com/cosmos/interchain-security/pull/975) and [#997](https://github.com/cosmos/interchain-security/pull/997) +* (deps) Bump github.com/cosmos/ibc-go/v4 from 4.4.0 to 4.4.2 [#982](https://github.com/cosmos/interchain-security/pull/982) +* (fix) partially revert key assignment type safety PR [#980](https://github.com/cosmos/interchain-security/pull/980) +* (fix) Remove panics on failure to send IBC packets [#876](https://github.com/cosmos/interchain-security/pull/876) +* (fix) Prevent denom DOS [#931](https://github.com/cosmos/interchain-security/pull/931) +* (fix) multisig for assigning consumer key, use json [#916](https://github.com/cosmos/interchain-security/pull/916) +* (deps) Bump github.com/cosmos/ibc-go/v4 from 4.3.0 to 4.4.0 [#902](https://github.com/cosmos/interchain-security/pull/902) +* (feat) Add warnings when provider unbonding is shorter than consumer unbonding [#858](https://github.com/cosmos/interchain-security/pull/858) +* (chore) use go 1.19 [#899](https://github.com/cosmos/interchain-security/pull/899), [#840](https://github.com/cosmos/interchain-security/pull/840) +* (feat) Standalone to consumer changeover - recycle existing transfer channel [#832](https://github.com/cosmos/interchain-security/pull/832) +* (deps) Bump IBC [862](https://github.com/cosmos/interchain-security/pull/862) +* (testing) Add tests for soft opt out [#857](https://github.com/cosmos/interchain-security/pull/857) +* (feat) Standalone to consumer changeover - staking functionalities [#794](https://github.com/cosmos/interchain-security/pull/794) +* (fix) prevent provider from sending VSCPackets with multiple updates for the same validator [#850](https://github.com/cosmos/interchain-security/pull/850) +* (feat) Soft opt out [#833](https://github.com/cosmos/interchain-security/issues/833) +* (fix) Correctly handle VSC packet with duplicate val updates on consumer [#846](https://github.com/cosmos/interchain-security/pull/846) +* (deps) bump sdk to v0.45.15.ics [#805](https://github.com/cosmos/interchain-security/pull/805) +* (refactor) Remove spm module [#812](https://github.com/cosmos/interchain-security/pull/812) +* (feat) Standalone to consumer changeover part 1 [#757](https://github.com/cosmos/interchain-security/pull/757) +* (chore) Swap names of e2e and integration tests [#681](https://github.com/cosmos/interchain-security/pull/681) +* (fix) fix StopConsumerChain not running in cachedContext [#802](https://github.com/cosmos/interchain-security/pull/802). Also in earlier releases with different commit order! +* (docs) Introduce docs website [#759](https://github.com/cosmos/interchain-security/pull/759) +* (fix) Serialize correct byte prefix for SlashLogKey [#786](https://github.com/cosmos/interchain-security/pull/786) +* (feature) Improve keeper field validation [#766](https://github.com/cosmos/interchain-security/pull/766) +* (docs) Contributing guidelines [#744](https://github.com/cosmos/interchain-security/pull/744) +* (refactor) Key assignment type safety [#725](https://github.com/cosmos/interchain-security/pull/725) +* (fix) Update protos and fix deps [#752](https://github.com/cosmos/interchain-security/pull/752) +* (api) Add consumer QueryParams [#746](https://github.com/cosmos/interchain-security/pull/746) +* (feature) New validation for keeper fields [#740](https://github.com/cosmos/interchain-security/pull/740) + +## v1.2.0-multiden + +The first release candidate for a fix built on top of v1.2.0, intended for consumers. This release adds a list of denoms on the consumer that are allowed to be sent to the provider as rewards. This prevents a potential DOS attack that was discovered during the audit of Replicated Security performed by Oak Security and funded by the Cosmos Hub community through Proposal 687. In an effort to move quickly, this release also includes a multisig fix that is effective only for provider. It shouldn't affect the consumer module. + +Note PRs were made in a private security repo. + +[full diff](https://github.com/cosmos/interchain-security/compare/v1.2.0...v1.2.0-multiden-rc0) + +## v1.1.0-multiden + +This release combines two fixes on top of v1.1.0, that we judged were urgent to get onto the Cosmos Hub before the launch of the first ICS consumer chain. This is an emergency release intended for providers. + +The first fix is to enable the use of multisigs and Ledger devices when assigning keys for consumer chains. The second is to prevent a possible DOS vector involving the reward distribution system. + +Note PRs were made in a private security repo. + +[full diff](https://github.com/cosmos/interchain-security/compare/v1.1.0...release/v1.1.0-multiden) + +### Multisig fix + +On April 25th (a week and a half ago), we began receiving reports that validators using multisigs and Ledger devices were getting errors reading Error: unable to resolve type URL /interchain_security.ccv.provider.v1.MsgAssignConsumerKey: tx parse error when attempting to assign consensus keys for consumer chains. + +We quickly narrowed the problem down to issues having to do with using the PubKey type directly in the MsgAssignConsumerKey transaction, and Amino (a deprecated serialization library still used in Ledger devices and multisigs) not being able to handle this. We attempted to fix this with the assistance of the Cosmos-SDK team, but after making no headway for a few days, we decided to simply use a JSON representation of the PubKey in the transaction. This is how it is usually represented anyway. We have verified that this fixes the problem. + +### Distribution fix + +The ICS distribution system works by allowing consumer chains to send rewards to a module address on the provider called the FeePoolAddress. From here they are automatically distributed to all validators and delegators through the distribution system that already exists to distribute staking rewards. The FeePoolAddress is usually blocked so that no tokens can be sent to it, but to enable ICS distribution we had to unblock it. + +We recently realized that unblocking the FeePoolAddress could enable an attacker to send a huge number of different denoms into the distribution system. The distribution system would then attempt to distribute them all, leading to out of memory errors. Fixing a similar attack vector that existed in the distribution system before ICS led us to this realization. + +To fix this problem, we have re-blocked the FeePoolAddress and created a new address called the ConsumerRewardsPool. Consumer chains now send rewards to this new address. There is also a new transaction type called RegisterConsumerRewardDenom. This transaction allows people to register denoms to be used as rewards from consumer chains. It costs 10 Atoms to run this transaction.The Atoms are transferred to the community pool. Only denoms registered with this command are then transferred to the FeePoolAddress and distributed out to delegators and validators. + +## v1.2.1 + +* (fix) Remove SPM [#812](https://github.com/cosmos/interchain-security/pull/812) +* (refactor) Key assignment type safety [#725](https://github.com/cosmos/interchain-security/pull/725) + +## v1.2.0 + +Date: April 13th, 2023 + +* (feat) Soft opt-out [#833](https://github.com/cosmos/interchain-security/pull/833) +* (fix) Correctly handle VSC packet with duplicate val updates on consumer [#846](https://github.com/cosmos/interchain-security/pull/846) +* (chore) bump: sdk v0.45.15-ics [#805](https://github.com/cosmos/interchain-security/pull/805) +* (api) add interchain security consumer QueryParams [#746](https://github.com/cosmos/interchain-security/pull/746) + +## v1.1.1 + +* (fix) Remove SPM [#812](https://github.com/cosmos/interchain-security/pull/812) +* (refactor) Key assignment type safety [#725](https://github.com/cosmos/interchain-security/pull/725) + +## v1.1.0 + +Date: March 24th, 2023 + +* (fix) StopConsumerChain not running in cachedContext [#802](https://github.com/cosmos/interchain-security/pull/802) + +## v1.0.0 + +Date: February 6th, 2023 + +This is the first version of Interchain Security (ICS), also known as _Replicated Security_ (RS). +Replicated Security is a feature which will allow a chain -- referred to as the _provider_ -- to share security with other chains -- referred to as _consumers_. +This means that the provider's validator set will be granted the right to validate consumer chains. +The communication between the provider and the consumer chains is done through the IBC protocol over a unique, ordered channel (one for each consumer chain). Thus, RS is an IBC application. + +### Features / sub-protocols + +RS consist of the following core features: + +- **Channel Initialization**: Enables the provider to add new consumer chains. This process is governance-gated, i.e., to add a new consumer chain, a `ConsumerAdditionProposal` governance proposal must be sent to the provider and it must receive the necessary votes. +- **Validator Set Update**: Enables the provider to + (1) update the consumers on the voting power granted to validators (based on the changes in the active validator set on the provider chain), + and (2) ensure the timely completion of unbonding operations (e.g., undelegations). +- **Consumer Initiated Slashing**: Enables the provider to jail validators for downtime infractions on the consumer chains. +- **Reward Distribution**: Enables the consumers to transfer to the provider (over IBC) a portion of their block rewards as payment for the security provided. Once transferred, these rewards are distributed on the provider using the protocol in the [distribution module of Cosmos SDK](https://docs.cosmos.network/v0.45/modules/distribution/). +- **Consumer Chain Removal**: Enables the provider to remove a consumer either after a `ConsumerRemovalProposal` passes governance or after one of the timeout periods elapses -- `InitTimeoutPeriod`, `VscTimeoutPeriod`, `IBCTimeoutPeriod`. +- **Social Slashing**: Equivocation offenses (double signing etc.) on consumer chains are logged, and then can be used in a governance proposal to slash the validators responsible. + +In addition, RS has the following features: + +- **Key Assignment**: Enables validator operators to use different consensus keys for each consumer chain validator node that they operate. +- **Jail Throttling**: Enables the provider to slow down a "worst case scenario" attack where a malicious consumer binary attempts to jail a significant amount (> 2/3) of the voting power, effectively taking control of the provider. \ No newline at end of file From 6b86836ffdd14d6930050ffe4c1cf7fb6da493b1 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Tue, 23 Apr 2024 11:00:59 +0200 Subject: [PATCH 050/110] Fix proto conflict --- proto/interchain_security/ccv/provider/v1/query.proto | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/proto/interchain_security/ccv/provider/v1/query.proto b/proto/interchain_security/ccv/provider/v1/query.proto index 97dedd58e5..9b00989f6d 100644 --- a/proto/interchain_security/ccv/provider/v1/query.proto +++ b/proto/interchain_security/ccv/provider/v1/query.proto @@ -249,7 +249,6 @@ message QueryParamsResponse { Params params = 1 [(gogoproto.nullable) = false]; } -<<<<<<< HEAD message QueryConsumerChainOptedInValidatorsRequest { string chain_id = 1; @@ -284,11 +283,10 @@ message QueryValidatorConsumerCommissionRateResponse { (gogoproto.nullable) = false ]; } -======= + message QueryOldestUnconfirmedVscRequest { string chain_id = 1; } message QueryOldestUnconfirmedVscResponse { interchain_security.ccv.provider.v1.VscSendTimestamp vsc_send_timestamp = 1 [ (gogoproto.nullable) = false ]; } ->>>>>>> main From 6ccb8ed0cdc09d6cbd164f147bb99582a6b920ec Mon Sep 17 00:00:00 2001 From: Simon Noetzlin Date: Tue, 23 Apr 2024 11:06:51 +0200 Subject: [PATCH 051/110] generate proto files --- x/ccv/provider/types/query.pb.go | 824 +++++++++++++++------------- x/ccv/provider/types/query.pb.gw.go | 131 +++-- 2 files changed, 526 insertions(+), 429 deletions(-) diff --git a/x/ccv/provider/types/query.pb.go b/x/ccv/provider/types/query.pb.go index 4aa87e44f4..49c580244a 100644 --- a/x/ccv/provider/types/query.pb.go +++ b/x/ccv/provider/types/query.pb.go @@ -1024,9 +1024,9 @@ func (m *QueryAllPairsValConAddrByConsumerChainIDResponse) GetPairValConAddr() [ type PairValConAddrProviderAndConsumer 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"` + ProviderAddress string `protobuf:"bytes,1,opt,name=provider_address,json=providerAddress,proto3" json:"provider_address,omitempty" yaml:"provider_address"` // The consensus address of the validator on the consumer chain - ConsumerAddress string `protobuf:"bytes,2,opt,name=consumer_address,json=consumerAddress,proto3" json:"consumer_address,omitempty" yaml:"address"` + ConsumerAddress string `protobuf:"bytes,2,opt,name=consumer_address,json=consumerAddress,proto3" json:"consumer_address,omitempty" yaml:"consumer_address"` ConsumerKey *crypto.PublicKey `protobuf:"bytes,3,opt,name=consumer_key,json=consumerKey,proto3" json:"consumer_key,omitempty"` } @@ -1164,7 +1164,6 @@ func (m *QueryParamsResponse) GetParams() Params { return Params{} } -<<<<<<< HEAD type QueryConsumerChainOptedInValidatorsRequest struct { ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` } @@ -1185,24 +1184,6 @@ func (m *QueryConsumerChainOptedInValidatorsRequest) XXX_Unmarshal(b []byte) err func (m *QueryConsumerChainOptedInValidatorsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { return xxx_messageInfo_QueryConsumerChainOptedInValidatorsRequest.Marshal(b, m, deterministic) -======= -type QueryOldestUnconfirmedVscRequest struct { - ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` -} - -func (m *QueryOldestUnconfirmedVscRequest) Reset() { *m = QueryOldestUnconfirmedVscRequest{} } -func (m *QueryOldestUnconfirmedVscRequest) String() string { return proto.CompactTextString(m) } -func (*QueryOldestUnconfirmedVscRequest) ProtoMessage() {} -func (*QueryOldestUnconfirmedVscRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_422512d7b7586cd7, []int{25} -} -func (m *QueryOldestUnconfirmedVscRequest) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryOldestUnconfirmedVscRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryOldestUnconfirmedVscRequest.Marshal(b, m, deterministic) ->>>>>>> main } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -1212,7 +1193,6 @@ func (m *QueryOldestUnconfirmedVscRequest) XXX_Marshal(b []byte, deterministic b return b[:n], nil } } -<<<<<<< HEAD func (m *QueryConsumerChainOptedInValidatorsRequest) XXX_Merge(src proto.Message) { xxx_messageInfo_QueryConsumerChainOptedInValidatorsRequest.Merge(m, src) } @@ -1226,28 +1206,12 @@ func (m *QueryConsumerChainOptedInValidatorsRequest) XXX_DiscardUnknown() { var xxx_messageInfo_QueryConsumerChainOptedInValidatorsRequest proto.InternalMessageInfo func (m *QueryConsumerChainOptedInValidatorsRequest) GetChainId() string { -======= -func (m *QueryOldestUnconfirmedVscRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryOldestUnconfirmedVscRequest.Merge(m, src) -} -func (m *QueryOldestUnconfirmedVscRequest) XXX_Size() int { - return m.Size() -} -func (m *QueryOldestUnconfirmedVscRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryOldestUnconfirmedVscRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryOldestUnconfirmedVscRequest proto.InternalMessageInfo - -func (m *QueryOldestUnconfirmedVscRequest) GetChainId() string { ->>>>>>> main if m != nil { return m.ChainId } return "" } -<<<<<<< HEAD type QueryConsumerChainOptedInValidatorsResponse struct { // The consensus addresses of the validators on the provider chain ValidatorsProviderAddresses []string `protobuf:"bytes,1,rep,name=validators_provider_addresses,json=validatorsProviderAddresses,proto3" json:"validators_provider_addresses,omitempty"` @@ -1269,24 +1233,6 @@ func (m *QueryConsumerChainOptedInValidatorsResponse) XXX_Unmarshal(b []byte) er func (m *QueryConsumerChainOptedInValidatorsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { return xxx_messageInfo_QueryConsumerChainOptedInValidatorsResponse.Marshal(b, m, deterministic) -======= -type QueryOldestUnconfirmedVscResponse struct { - VscSendTimestamp VscSendTimestamp `protobuf:"bytes,1,opt,name=vsc_send_timestamp,json=vscSendTimestamp,proto3" json:"vsc_send_timestamp"` -} - -func (m *QueryOldestUnconfirmedVscResponse) Reset() { *m = QueryOldestUnconfirmedVscResponse{} } -func (m *QueryOldestUnconfirmedVscResponse) String() string { return proto.CompactTextString(m) } -func (*QueryOldestUnconfirmedVscResponse) ProtoMessage() {} -func (*QueryOldestUnconfirmedVscResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_422512d7b7586cd7, []int{26} -} -func (m *QueryOldestUnconfirmedVscResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryOldestUnconfirmedVscResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryOldestUnconfirmedVscResponse.Marshal(b, m, deterministic) ->>>>>>> main } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -1296,7 +1242,6 @@ func (m *QueryOldestUnconfirmedVscResponse) XXX_Marshal(b []byte, deterministic return b[:n], nil } } -<<<<<<< HEAD func (m *QueryConsumerChainOptedInValidatorsResponse) XXX_Merge(src proto.Message) { xxx_messageInfo_QueryConsumerChainOptedInValidatorsResponse.Merge(m, src) } @@ -1512,7 +1457,75 @@ func (m *QueryValidatorConsumerCommissionRateResponse) XXX_DiscardUnknown() { var xxx_messageInfo_QueryValidatorConsumerCommissionRateResponse proto.InternalMessageInfo -======= +type QueryOldestUnconfirmedVscRequest struct { + ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` +} + +func (m *QueryOldestUnconfirmedVscRequest) Reset() { *m = QueryOldestUnconfirmedVscRequest{} } +func (m *QueryOldestUnconfirmedVscRequest) String() string { return proto.CompactTextString(m) } +func (*QueryOldestUnconfirmedVscRequest) ProtoMessage() {} +func (*QueryOldestUnconfirmedVscRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_422512d7b7586cd7, []int{31} +} +func (m *QueryOldestUnconfirmedVscRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryOldestUnconfirmedVscRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryOldestUnconfirmedVscRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryOldestUnconfirmedVscRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryOldestUnconfirmedVscRequest.Merge(m, src) +} +func (m *QueryOldestUnconfirmedVscRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryOldestUnconfirmedVscRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryOldestUnconfirmedVscRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryOldestUnconfirmedVscRequest proto.InternalMessageInfo + +func (m *QueryOldestUnconfirmedVscRequest) GetChainId() string { + if m != nil { + return m.ChainId + } + return "" +} + +type QueryOldestUnconfirmedVscResponse struct { + VscSendTimestamp VscSendTimestamp `protobuf:"bytes,1,opt,name=vsc_send_timestamp,json=vscSendTimestamp,proto3" json:"vsc_send_timestamp"` +} + +func (m *QueryOldestUnconfirmedVscResponse) Reset() { *m = QueryOldestUnconfirmedVscResponse{} } +func (m *QueryOldestUnconfirmedVscResponse) String() string { return proto.CompactTextString(m) } +func (*QueryOldestUnconfirmedVscResponse) ProtoMessage() {} +func (*QueryOldestUnconfirmedVscResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_422512d7b7586cd7, []int{32} +} +func (m *QueryOldestUnconfirmedVscResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryOldestUnconfirmedVscResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryOldestUnconfirmedVscResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} func (m *QueryOldestUnconfirmedVscResponse) XXX_Merge(src proto.Message) { xxx_messageInfo_QueryOldestUnconfirmedVscResponse.Merge(m, src) } @@ -1532,7 +1545,6 @@ func (m *QueryOldestUnconfirmedVscResponse) GetVscSendTimestamp() VscSendTimesta return VscSendTimestamp{} } ->>>>>>> main func init() { proto.RegisterType((*QueryConsumerGenesisRequest)(nil), "interchain_security.ccv.provider.v1.QueryConsumerGenesisRequest") proto.RegisterType((*QueryConsumerGenesisResponse)(nil), "interchain_security.ccv.provider.v1.QueryConsumerGenesisResponse") @@ -1559,17 +1571,14 @@ func init() { proto.RegisterType((*PairValConAddrProviderAndConsumer)(nil), "interchain_security.ccv.provider.v1.PairValConAddrProviderAndConsumer") proto.RegisterType((*QueryParamsRequest)(nil), "interchain_security.ccv.provider.v1.QueryParamsRequest") proto.RegisterType((*QueryParamsResponse)(nil), "interchain_security.ccv.provider.v1.QueryParamsResponse") -<<<<<<< HEAD proto.RegisterType((*QueryConsumerChainOptedInValidatorsRequest)(nil), "interchain_security.ccv.provider.v1.QueryConsumerChainOptedInValidatorsRequest") proto.RegisterType((*QueryConsumerChainOptedInValidatorsResponse)(nil), "interchain_security.ccv.provider.v1.QueryConsumerChainOptedInValidatorsResponse") proto.RegisterType((*QueryConsumerChainsValidatorHasToValidateRequest)(nil), "interchain_security.ccv.provider.v1.QueryConsumerChainsValidatorHasToValidateRequest") proto.RegisterType((*QueryConsumerChainsValidatorHasToValidateResponse)(nil), "interchain_security.ccv.provider.v1.QueryConsumerChainsValidatorHasToValidateResponse") proto.RegisterType((*QueryValidatorConsumerCommissionRateRequest)(nil), "interchain_security.ccv.provider.v1.QueryValidatorConsumerCommissionRateRequest") proto.RegisterType((*QueryValidatorConsumerCommissionRateResponse)(nil), "interchain_security.ccv.provider.v1.QueryValidatorConsumerCommissionRateResponse") -======= proto.RegisterType((*QueryOldestUnconfirmedVscRequest)(nil), "interchain_security.ccv.provider.v1.QueryOldestUnconfirmedVscRequest") proto.RegisterType((*QueryOldestUnconfirmedVscResponse)(nil), "interchain_security.ccv.provider.v1.QueryOldestUnconfirmedVscResponse") ->>>>>>> main } func init() { @@ -1577,211 +1586,121 @@ func init() { } var fileDescriptor_422512d7b7586cd7 = []byte{ -<<<<<<< HEAD - // 1688 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0x5d, 0x6f, 0xd4, 0x46, - 0x17, 0x8e, 0x93, 0x90, 0x37, 0x99, 0xf0, 0xf5, 0x0e, 0xbc, 0xbc, 0xc1, 0x09, 0xbb, 0x60, 0x5a, - 0x1a, 0xbe, 0xec, 0x64, 0x29, 0xe2, 0x33, 0x84, 0x6c, 0x16, 0xc2, 0x2a, 0x7c, 0x2c, 0x26, 0x50, - 0xa9, 0xad, 0x6a, 0x1c, 0x7b, 0xba, 0xb1, 0xf0, 0x7a, 0x1c, 0x8f, 0xb3, 0xb0, 0x42, 0x95, 0x4a, - 0x2f, 0x0a, 0x77, 0xa5, 0x6a, 0x7b, 0x8f, 0x54, 0xf5, 0x0f, 0x54, 0xfd, 0x11, 0xdc, 0x95, 0x96, - 0x9b, 0xaa, 0x17, 0xb4, 0x0a, 0xbd, 0xa8, 0x7a, 0x55, 0xf5, 0xbe, 0x52, 0xe5, 0xf1, 0xd8, 0x5e, - 0xef, 0x3a, 0xbb, 0xde, 0xdd, 0xf4, 0x2a, 0xf1, 0xcc, 0x9c, 0xe7, 0x9c, 0xe7, 0xcc, 0x99, 0x33, - 0xf3, 0x2c, 0x90, 0x0c, 0xcb, 0x45, 0x8e, 0xb6, 0xa2, 0x1a, 0x96, 0x42, 0x90, 0xb6, 0xe6, 0x18, - 0x6e, 0x4d, 0xd2, 0xb4, 0xaa, 0x64, 0x3b, 0xb8, 0x6a, 0xe8, 0xc8, 0x91, 0xaa, 0xd3, 0xd2, 0xea, - 0x1a, 0x72, 0x6a, 0xa2, 0xed, 0x60, 0x17, 0xc3, 0x83, 0x09, 0x06, 0xa2, 0xa6, 0x55, 0xc5, 0xc0, - 0x40, 0xac, 0x4e, 0xf3, 0x13, 0x65, 0x8c, 0xcb, 0x26, 0x92, 0x54, 0xdb, 0x90, 0x54, 0xcb, 0xc2, - 0xae, 0xea, 0x1a, 0xd8, 0x22, 0x3e, 0x04, 0xbf, 0xbb, 0x8c, 0xcb, 0x98, 0xfe, 0x2b, 0x79, 0xff, - 0xb1, 0xd1, 0x2c, 0xb3, 0xa1, 0x5f, 0xcb, 0x6b, 0x1f, 0x4a, 0xae, 0x51, 0x41, 0xc4, 0x55, 0x2b, - 0x36, 0x5b, 0x90, 0x4b, 0x13, 0x6a, 0x18, 0x85, 0x6f, 0x33, 0xb5, 0x91, 0x4d, 0x75, 0x5a, 0x22, - 0x2b, 0xaa, 0x83, 0x74, 0x45, 0xc3, 0x16, 0x59, 0xab, 0x84, 0x16, 0x6f, 0xb6, 0xb0, 0xb8, 0x6f, - 0x38, 0x88, 0x2d, 0x9b, 0x70, 0x91, 0xa5, 0x23, 0xa7, 0x62, 0x58, 0xae, 0xa4, 0x39, 0x35, 0xdb, - 0xc5, 0xd2, 0x3d, 0x54, 0x0b, 0x18, 0xee, 0xd5, 0x30, 0xa9, 0x60, 0xa2, 0xf8, 0x24, 0xfd, 0x0f, - 0x7f, 0x4a, 0x38, 0x0d, 0xc6, 0x6f, 0x7a, 0xe9, 0x9c, 0x67, 0x6e, 0x17, 0x90, 0x85, 0x88, 0x41, - 0x64, 0xb4, 0xba, 0x86, 0x88, 0x0b, 0xf7, 0x82, 0x61, 0xdf, 0xb7, 0xa1, 0x8f, 0x71, 0xfb, 0xb9, - 0xc9, 0x11, 0xf9, 0x3f, 0xf4, 0xbb, 0xa8, 0x0b, 0x0f, 0xc1, 0x44, 0xb2, 0x25, 0xb1, 0xb1, 0x45, - 0x10, 0x7c, 0x0f, 0x6c, 0x2b, 0xfb, 0x43, 0x0a, 0x71, 0x55, 0x17, 0x51, 0xfb, 0xd1, 0xdc, 0x94, - 0xb8, 0xd1, 0x8e, 0x55, 0xa7, 0xc5, 0x06, 0xac, 0x5b, 0x9e, 0x5d, 0x7e, 0xf0, 0xf9, 0xab, 0x6c, - 0x9f, 0xbc, 0xb5, 0x5c, 0x37, 0x26, 0x4c, 0x00, 0x3e, 0xe6, 0x7c, 0xde, 0x83, 0x0b, 0xa2, 0x16, - 0xd4, 0x06, 0x52, 0xc1, 0x2c, 0x8b, 0x2c, 0x0f, 0x86, 0xa8, 0x7b, 0x32, 0xc6, 0xed, 0x1f, 0x98, - 0x1c, 0xcd, 0x1d, 0x11, 0x53, 0x14, 0x91, 0x48, 0x41, 0x64, 0x66, 0x29, 0x1c, 0x06, 0x6f, 0x35, - 0xbb, 0xb8, 0xe5, 0xaa, 0x8e, 0x5b, 0x72, 0xb0, 0x8d, 0x89, 0x6a, 0x86, 0xd1, 0x3c, 0xe1, 0xc0, - 0x64, 0xfb, 0xb5, 0x2c, 0xb6, 0xf7, 0xc1, 0x88, 0x1d, 0x0c, 0xb2, 0x8c, 0x5d, 0x48, 0x17, 0x1e, - 0x03, 0x9f, 0xd3, 0x75, 0xc3, 0xab, 0xee, 0x08, 0x3a, 0x02, 0x14, 0x26, 0xc1, 0xa1, 0xa4, 0x48, - 0xb0, 0xdd, 0x14, 0xf4, 0xa7, 0x5c, 0x32, 0xc1, 0xd8, 0xd2, 0x70, 0xa7, 0x9b, 0x62, 0x9e, 0xe9, - 0x28, 0x66, 0x19, 0x55, 0x70, 0x55, 0x35, 0x13, 0x43, 0x5e, 0x02, 0x5b, 0xa8, 0xeb, 0x16, 0xa5, - 0x08, 0xc7, 0xc1, 0x88, 0x66, 0x1a, 0xc8, 0x72, 0xbd, 0xb9, 0x7e, 0x3a, 0x37, 0xec, 0x0f, 0x14, - 0x75, 0xb8, 0x0b, 0x6c, 0x71, 0xb1, 0xad, 0x5c, 0x1f, 0x1b, 0xd8, 0xcf, 0x4d, 0x6e, 0x93, 0x07, - 0x5d, 0x6c, 0x5f, 0x17, 0x1e, 0x73, 0xe0, 0x00, 0xa5, 0x77, 0x47, 0x35, 0x0d, 0x5d, 0x75, 0xb1, - 0x53, 0x97, 0x3f, 0xa7, 0x7d, 0xf5, 0xc3, 0x19, 0xb0, 0x33, 0x60, 0xa2, 0xa8, 0xba, 0xee, 0x20, - 0x42, 0x7c, 0xcf, 0x79, 0xf8, 0xd7, 0xab, 0xec, 0xf6, 0x9a, 0x5a, 0x31, 0xcf, 0x0a, 0x6c, 0x42, - 0x90, 0x77, 0x04, 0x6b, 0xe7, 0xfc, 0x91, 0xb3, 0xc3, 0x4f, 0x9e, 0x65, 0xfb, 0x7e, 0x7f, 0x96, - 0xed, 0x13, 0x6e, 0x00, 0xa1, 0x55, 0x20, 0x2c, 0xc5, 0x87, 0xc1, 0xce, 0xa0, 0x31, 0x84, 0xee, - 0xfc, 0x88, 0x76, 0x68, 0x75, 0xeb, 0x3d, 0x67, 0xcd, 0xd4, 0x4a, 0x75, 0xce, 0xd3, 0x51, 0x6b, - 0xf2, 0xd5, 0x82, 0x5a, 0x83, 0xff, 0x56, 0xd4, 0xe2, 0x81, 0x44, 0xd4, 0x9a, 0x32, 0xc9, 0xa8, - 0x35, 0x64, 0x4d, 0x18, 0x07, 0x7b, 0x29, 0xe0, 0xd2, 0x8a, 0x83, 0x5d, 0xd7, 0x44, 0xb4, 0x17, - 0x04, 0x15, 0xfb, 0x03, 0xc7, 0x7a, 0x42, 0xc3, 0x2c, 0x73, 0x93, 0x05, 0xa3, 0xc4, 0x54, 0xc9, - 0x8a, 0x52, 0x41, 0x2e, 0x72, 0xa8, 0x87, 0x01, 0x19, 0xd0, 0xa1, 0x6b, 0xde, 0x08, 0xcc, 0x81, - 0xff, 0xd5, 0x2d, 0x50, 0x54, 0xd3, 0xc4, 0xf7, 0x55, 0x4b, 0x43, 0x94, 0xfb, 0x80, 0xbc, 0x2b, - 0x5a, 0x3a, 0x17, 0x4c, 0xc1, 0x0f, 0xc0, 0x98, 0x85, 0x1e, 0xb8, 0x8a, 0x83, 0x6c, 0x13, 0x59, - 0x06, 0x59, 0x51, 0x34, 0xd5, 0xd2, 0x3d, 0xb2, 0x88, 0x96, 0xdb, 0x68, 0x8e, 0x17, 0xfd, 0x7b, - 0x44, 0x0c, 0xee, 0x11, 0x71, 0x29, 0xb8, 0x47, 0xf2, 0xc3, 0x5e, 0x63, 0x7b, 0xfa, 0x4b, 0x96, - 0x93, 0xf7, 0x78, 0x28, 0x72, 0x00, 0x32, 0x1f, 0x60, 0x08, 0xc7, 0xc0, 0x11, 0x4a, 0x49, 0x46, - 0x65, 0x83, 0xb8, 0xc8, 0x41, 0x7a, 0x74, 0x64, 0xee, 0xab, 0x8e, 0x5e, 0x40, 0x16, 0xae, 0x84, - 0x67, 0xf6, 0x12, 0x38, 0x9a, 0x6a, 0x35, 0xcb, 0xc8, 0x1e, 0x30, 0xa4, 0xd3, 0x11, 0xda, 0x06, - 0x47, 0x64, 0xf6, 0x25, 0x64, 0x58, 0x63, 0xf7, 0x8f, 0x23, 0xd2, 0xe9, 0xf1, 0x2b, 0x16, 0x42, - 0x37, 0x8f, 0x38, 0xb0, 0x6f, 0x83, 0x05, 0x0c, 0xf9, 0x2e, 0xd8, 0x6e, 0xd7, 0xcf, 0x05, 0x8d, - 0x36, 0x97, 0xaa, 0x2b, 0xc4, 0x60, 0x59, 0xf7, 0x6f, 0xc0, 0x13, 0x8a, 0x60, 0x5b, 0x6c, 0x19, - 0x1c, 0x03, 0xac, 0x7e, 0x0b, 0xf1, 0x72, 0x2e, 0xc0, 0x0c, 0x00, 0x41, 0x37, 0x29, 0x16, 0xe8, - 0x66, 0x0e, 0xca, 0x75, 0x23, 0xc2, 0x55, 0x20, 0x51, 0x36, 0x73, 0xa6, 0x59, 0x52, 0x0d, 0x87, - 0xdc, 0x51, 0xcd, 0x79, 0x6c, 0x79, 0x25, 0x97, 0x8f, 0x37, 0xbf, 0x62, 0x21, 0xc5, 0xad, 0xf8, - 0x0d, 0x07, 0xa6, 0xd2, 0xc3, 0xb1, 0x7c, 0xad, 0x82, 0xff, 0xda, 0xaa, 0xe1, 0x28, 0x55, 0xd5, - 0xf4, 0xee, 0x7f, 0x7a, 0x0c, 0x58, 0xca, 0x2e, 0xa7, 0x4b, 0x99, 0x6a, 0x38, 0x91, 0xa3, 0xf0, - 0x98, 0x59, 0x51, 0x01, 0x6c, 0xb7, 0x63, 0x4b, 0x84, 0x75, 0x0e, 0x1c, 0x68, 0x6b, 0x95, 0xd8, - 0xe5, 0xb8, 0xd4, 0x5d, 0xae, 0xc7, 0x4e, 0x02, 0x67, 0xc1, 0xd6, 0xd0, 0xfc, 0x1e, 0xaa, 0xb1, - 0x13, 0x35, 0x21, 0x46, 0x6f, 0x1d, 0xd1, 0x7f, 0xeb, 0x88, 0xa5, 0xb5, 0x65, 0xd3, 0xd0, 0x16, - 0x51, 0x4d, 0x1e, 0x0d, 0x2c, 0x16, 0x51, 0x4d, 0xd8, 0x0d, 0xa0, 0x5f, 0xa8, 0xaa, 0xa3, 0x46, - 0xc7, 0xe4, 0x2e, 0xd8, 0x15, 0x1b, 0x65, 0x9b, 0x50, 0x04, 0x43, 0x36, 0x1d, 0x61, 0x57, 0xd8, - 0xd1, 0x94, 0x99, 0xf7, 0x4c, 0x58, 0x95, 0x32, 0x00, 0x61, 0x81, 0x1d, 0xdb, 0xd8, 0x7e, 0xdf, - 0xb0, 0x5d, 0xa4, 0x17, 0xad, 0xb0, 0x19, 0xa6, 0x79, 0x63, 0xad, 0xb2, 0x13, 0xdd, 0x0e, 0x28, - 0x7c, 0xd8, 0xec, 0xab, 0x86, 0xa3, 0x4a, 0xe3, 0xce, 0xa1, 0xe0, 0xa0, 0x8f, 0x47, 0x8b, 0x4a, - 0xf1, 0x1d, 0x43, 0x44, 0x58, 0x65, 0xf5, 0x1b, 0x7f, 0x3b, 0x85, 0xce, 0xae, 0xa8, 0x64, 0x09, - 0xb3, 0xaf, 0xa0, 0xf5, 0xf6, 0x58, 0x26, 0x82, 0x0a, 0xa6, 0x3b, 0x70, 0xc9, 0xb8, 0x1e, 0x03, - 0x30, 0x2c, 0x8e, 0x20, 0x7d, 0x01, 0xc1, 0xb0, 0xea, 0xfc, 0x83, 0xa6, 0xd3, 0x4b, 0xf1, 0x68, - 0xf2, 0x35, 0x3b, 0x8f, 0x2b, 0x15, 0x83, 0x10, 0x03, 0x5b, 0x72, 0x1d, 0xa3, 0x7f, 0xed, 0xe6, - 0x17, 0x3e, 0xe6, 0xc0, 0xb1, 0x74, 0x91, 0x30, 0xa2, 0x25, 0x30, 0xe8, 0x04, 0xcf, 0xe7, 0x91, - 0xfc, 0x79, 0xaf, 0xd0, 0x7e, 0x7e, 0x95, 0x3d, 0x54, 0x36, 0xdc, 0x95, 0xb5, 0x65, 0x51, 0xc3, - 0x15, 0xf6, 0xa0, 0x67, 0x7f, 0x8e, 0x13, 0xfd, 0x9e, 0xe4, 0xd6, 0x6c, 0x44, 0xc4, 0x02, 0xd2, - 0x7e, 0xfc, 0xee, 0x38, 0x60, 0xef, 0xfd, 0x02, 0xd2, 0x64, 0x8a, 0x94, 0xfb, 0x7c, 0x1c, 0x6c, - 0xa1, 0x21, 0xc0, 0x75, 0x0e, 0xec, 0x4e, 0x7a, 0xc4, 0xc3, 0x8b, 0xa9, 0x8a, 0xbf, 0x85, 0x72, - 0xe0, 0xe7, 0x7a, 0x40, 0xf0, 0x99, 0x0b, 0x97, 0x3e, 0x79, 0xf9, 0xdb, 0x17, 0xfd, 0xb3, 0x70, - 0xa6, 0xbd, 0x2a, 0x0c, 0x4b, 0x81, 0xa9, 0x04, 0xe9, 0x61, 0xb0, 0x7d, 0x1f, 0xc1, 0x97, 0x1c, - 0x3b, 0xf0, 0xf1, 0xfa, 0x82, 0xb3, 0x9d, 0x47, 0x18, 0x93, 0x19, 0xfc, 0xc5, 0xee, 0x01, 0x18, - 0xc3, 0x33, 0x94, 0xe1, 0x09, 0x38, 0xdd, 0x01, 0x43, 0x5f, 0x80, 0xc0, 0x47, 0xfd, 0x60, 0x6c, - 0x03, 0x55, 0x41, 0xe0, 0xd5, 0x2e, 0x23, 0x4b, 0x14, 0x30, 0xfc, 0xb5, 0x4d, 0x42, 0x63, 0xa4, - 0xaf, 0x50, 0xd2, 0x79, 0x78, 0xb1, 0x53, 0xd2, 0x9e, 0x8e, 0x74, 0x5c, 0x25, 0xd4, 0x06, 0xf0, - 0x6f, 0x0e, 0xfc, 0x3f, 0x59, 0xa4, 0x10, 0xb8, 0xd8, 0x75, 0xd0, 0xcd, 0x6a, 0x88, 0xbf, 0xba, - 0x39, 0x60, 0x2c, 0x01, 0x0b, 0x34, 0x01, 0x73, 0x70, 0xb6, 0x8b, 0x04, 0x60, 0xbb, 0x8e, 0xff, - 0x9f, 0xc1, 0x93, 0x37, 0x51, 0x3c, 0xc0, 0xcb, 0xe9, 0xa3, 0x6e, 0x25, 0x83, 0xf8, 0x85, 0x9e, - 0x71, 0x18, 0xf1, 0x39, 0x4a, 0xfc, 0x1c, 0x3c, 0x93, 0xe2, 0x67, 0x9e, 0x00, 0x48, 0x89, 0xbd, - 0x20, 0x12, 0x28, 0xd7, 0x5f, 0x61, 0x5d, 0x51, 0x4e, 0x90, 0x47, 0x5d, 0x51, 0x4e, 0x52, 0x37, - 0xdd, 0x51, 0x8e, 0xdd, 0x2f, 0xf0, 0x7b, 0x8e, 0x3d, 0x63, 0x62, 0xc2, 0x06, 0x5e, 0x48, 0x1f, - 0x62, 0x92, 0x5e, 0xe2, 0x67, 0xbb, 0xb6, 0x67, 0xd4, 0x4e, 0x53, 0x6a, 0x39, 0x38, 0xd5, 0x9e, - 0x9a, 0xcb, 0x00, 0xfc, 0x5f, 0x82, 0xe0, 0x57, 0xfd, 0xe0, 0x60, 0x0a, 0xa5, 0x02, 0x6f, 0xa4, - 0x0f, 0x31, 0x95, 0x42, 0xe2, 0x4b, 0x9b, 0x07, 0xc8, 0x92, 0xb0, 0x48, 0x93, 0x70, 0x09, 0xce, - 0xb7, 0x4f, 0x82, 0x13, 0x22, 0x46, 0x35, 0xed, 0x50, 0x4c, 0xc5, 0x57, 0x5e, 0xf0, 0x8f, 0x26, - 0x65, 0x15, 0x17, 0x0c, 0x04, 0x76, 0x70, 0xab, 0x6e, 0x20, 0xdf, 0xf8, 0x7c, 0x2f, 0x10, 0x8c, - 0x75, 0x9e, 0xb2, 0x3e, 0x0f, 0xcf, 0xb6, 0x67, 0x1d, 0x08, 0x37, 0xa5, 0xf1, 0x02, 0xfb, 0xb2, - 0x9f, 0xfd, 0x2c, 0x96, 0x42, 0x29, 0xc1, 0xa5, 0xf4, 0x41, 0xa7, 0xd7, 0x71, 0xfc, 0xed, 0x4d, - 0x46, 0x65, 0xd9, 0x39, 0x47, 0xb3, 0x73, 0x12, 0x9e, 0xe8, 0xb8, 0xbf, 0x1b, 0x3a, 0xfc, 0x96, - 0x03, 0xa3, 0x75, 0xf2, 0x04, 0x9e, 0xea, 0x60, 0xbb, 0xea, 0x65, 0x0e, 0x7f, 0xba, 0x73, 0x43, - 0x16, 0xff, 0x14, 0x8d, 0xff, 0x08, 0x9c, 0x4c, 0xb1, 0xbb, 0x7e, 0x90, 0x8f, 0x83, 0x03, 0xdd, - 0x5a, 0xa8, 0x74, 0x72, 0xa0, 0x53, 0x69, 0xa7, 0x4e, 0x0e, 0x74, 0x3a, 0x0d, 0x25, 0xcc, 0x50, - 0xf2, 0xa7, 0xe0, 0xc9, 0xf6, 0xe4, 0xb1, 0x07, 0xa2, 0x18, 0x96, 0x12, 0xe9, 0x29, 0xf8, 0x75, - 0x3f, 0x38, 0x9c, 0x5a, 0xcc, 0xc0, 0xdb, 0xdd, 0xbe, 0x20, 0x5b, 0xea, 0x31, 0xfe, 0xce, 0x66, - 0xc3, 0xf6, 0xfa, 0x70, 0x21, 0x8a, 0x8d, 0x9c, 0x28, 0x4d, 0xf0, 0xb3, 0x7e, 0xf0, 0x46, 0x1a, - 0x11, 0x04, 0x4b, 0x3d, 0x3c, 0x3d, 0x12, 0x95, 0x1d, 0x7f, 0x73, 0x13, 0x11, 0x3b, 0xef, 0x86, - 0x51, 0x5a, 0x42, 0x28, 0xc5, 0xd3, 0x64, 0xf9, 0x77, 0x9e, 0xaf, 0x67, 0xb8, 0x17, 0xeb, 0x19, - 0xee, 0xd7, 0xf5, 0x0c, 0xf7, 0xf4, 0x75, 0xa6, 0xef, 0xc5, 0xeb, 0x4c, 0xdf, 0x4f, 0xaf, 0x33, - 0x7d, 0xef, 0xce, 0x34, 0x2b, 0xbd, 0xc8, 0xcd, 0xf1, 0xd0, 0x4d, 0xf5, 0x6d, 0xe9, 0x41, 0xc3, - 0xa5, 0xeb, 0x89, 0xc0, 0xe5, 0x21, 0xfa, 0xc3, 0xe3, 0x89, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, - 0xc8, 0x14, 0xa5, 0x41, 0x5a, 0x1b, 0x00, 0x00, -======= - // 1501 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x58, 0xcf, 0x73, 0xdb, 0x44, - 0x14, 0x8e, 0x92, 0x36, 0x24, 0x9b, 0xfe, 0x62, 0x5b, 0x4a, 0xaa, 0x06, 0xbb, 0x55, 0x07, 0x48, - 0x5b, 0x90, 0x12, 0x97, 0x0e, 0xfd, 0x41, 0x9a, 0xda, 0x49, 0x5a, 0x3c, 0x69, 0xa7, 0x41, 0x6d, - 0xc3, 0x0c, 0x30, 0xa8, 0x1b, 0x69, 0xeb, 0x68, 0x2a, 0x6b, 0xd5, 0x5d, 0xd9, 0xad, 0xa7, 0xc3, - 0xa1, 0x1c, 0xa0, 0x27, 0xa6, 0x33, 0xc0, 0xbd, 0x17, 0xfe, 0x01, 0xfe, 0x8a, 0x72, 0xa2, 0x4c, - 0x2f, 0x9c, 0x0a, 0x93, 0x72, 0x60, 0x38, 0x31, 0x5c, 0x38, 0x31, 0xc3, 0x68, 0xb5, 0x92, 0x2d, - 0x5b, 0xb1, 0x65, 0x27, 0x37, 0x7b, 0xb5, 0xef, 0x7b, 0xdf, 0xf7, 0xf4, 0xf6, 0xed, 0x67, 0x03, - 0xcd, 0x76, 0x7d, 0x4c, 0xcd, 0x75, 0x64, 0xbb, 0x06, 0xc3, 0x66, 0x8d, 0xda, 0x7e, 0x43, 0x33, - 0xcd, 0xba, 0xe6, 0x51, 0x52, 0xb7, 0x2d, 0x4c, 0xb5, 0xfa, 0xac, 0x76, 0xb7, 0x86, 0x69, 0x43, - 0xf5, 0x28, 0xf1, 0x09, 0x3c, 0x96, 0x12, 0xa0, 0x9a, 0x66, 0x5d, 0x8d, 0x02, 0xd4, 0xfa, 0xac, - 0x3c, 0x55, 0x21, 0xa4, 0xe2, 0x60, 0x0d, 0x79, 0xb6, 0x86, 0x5c, 0x97, 0xf8, 0xc8, 0xb7, 0x89, - 0xcb, 0x42, 0x08, 0xf9, 0x40, 0x85, 0x54, 0x08, 0xff, 0xa8, 0x05, 0x9f, 0xc4, 0x6a, 0x5e, 0xc4, - 0xf0, 0x6f, 0x6b, 0xb5, 0xdb, 0x9a, 0x6f, 0x57, 0x31, 0xf3, 0x51, 0xd5, 0x13, 0x1b, 0x0a, 0x59, - 0xa8, 0xc6, 0x2c, 0xc2, 0x98, 0x99, 0xcd, 0x62, 0xea, 0xb3, 0x1a, 0x5b, 0x47, 0x14, 0x5b, 0x86, - 0x49, 0x5c, 0x56, 0xab, 0xc6, 0x11, 0x6f, 0x76, 0x89, 0xb8, 0x67, 0x53, 0x2c, 0xb6, 0x4d, 0xf9, - 0xd8, 0xb5, 0x30, 0xad, 0xda, 0xae, 0xaf, 0x99, 0xb4, 0xe1, 0xf9, 0x44, 0xbb, 0x83, 0x1b, 0x42, - 0xa1, 0x72, 0x06, 0x1c, 0xfe, 0x28, 0xa8, 0xd9, 0x82, 0xc0, 0xbe, 0x8c, 0x5d, 0xcc, 0x6c, 0xa6, - 0xe3, 0xbb, 0x35, 0xcc, 0x7c, 0x78, 0x08, 0x8c, 0x85, 0x09, 0x6c, 0x6b, 0x52, 0x3a, 0x22, 0x4d, - 0x8f, 0xeb, 0xaf, 0xf0, 0xef, 0x65, 0x4b, 0x79, 0x00, 0xa6, 0xd2, 0x23, 0x99, 0x47, 0x5c, 0x86, - 0xe1, 0xa7, 0x60, 0x77, 0x25, 0x5c, 0x32, 0x98, 0x8f, 0x7c, 0xcc, 0xe3, 0x27, 0x0a, 0x33, 0xea, - 0x66, 0xaf, 0xa5, 0x3e, 0xab, 0xb6, 0x61, 0x5d, 0x0f, 0xe2, 0x4a, 0x3b, 0x9e, 0xbe, 0xc8, 0x0f, - 0xe9, 0xbb, 0x2a, 0x2d, 0x6b, 0xca, 0x14, 0x90, 0x13, 0xc9, 0x17, 0x02, 0xb8, 0x88, 0xb5, 0x82, - 0xda, 0x44, 0x45, 0x4f, 0x05, 0xb3, 0x12, 0x18, 0xe5, 0xe9, 0xd9, 0xa4, 0x74, 0x64, 0x64, 0x7a, - 0xa2, 0x70, 0x42, 0xcd, 0xd0, 0x29, 0x2a, 0x07, 0xd1, 0x45, 0xa4, 0x72, 0x1c, 0xbc, 0xdd, 0x99, - 0xe2, 0xba, 0x8f, 0xa8, 0xbf, 0x42, 0x89, 0x47, 0x18, 0x72, 0x62, 0x36, 0x8f, 0x24, 0x30, 0xdd, - 0x7b, 0xaf, 0xe0, 0xf6, 0x19, 0x18, 0xf7, 0xa2, 0x45, 0x51, 0xb1, 0x0b, 0xd9, 0xe8, 0x09, 0xf0, - 0xa2, 0x65, 0xd9, 0x41, 0x0b, 0x37, 0xa1, 0x9b, 0x80, 0xca, 0x34, 0x78, 0x2b, 0x8d, 0x09, 0xf1, - 0x3a, 0x48, 0x7f, 0x25, 0xa5, 0x0b, 0x4c, 0x6c, 0x8d, 0xdf, 0x74, 0x07, 0xe7, 0xb9, 0xbe, 0x38, - 0xeb, 0xb8, 0x4a, 0xea, 0xc8, 0x49, 0xa5, 0x3c, 0x0f, 0x76, 0xf2, 0xd4, 0x5d, 0x5a, 0x11, 0x1e, - 0x06, 0xe3, 0xa6, 0x63, 0x63, 0xd7, 0x0f, 0x9e, 0x0d, 0xf3, 0x67, 0x63, 0xe1, 0x42, 0xd9, 0x52, - 0xbe, 0x96, 0xc0, 0x51, 0xae, 0x64, 0x15, 0x39, 0xb6, 0x85, 0x7c, 0x42, 0x5b, 0x4a, 0x45, 0x7b, - 0x37, 0x3a, 0x9c, 0x03, 0xfb, 0x22, 0xd2, 0x06, 0xb2, 0x2c, 0x8a, 0x19, 0x0b, 0x93, 0x94, 0xe0, - 0x3f, 0x2f, 0xf2, 0x7b, 0x1a, 0xa8, 0xea, 0x9c, 0x53, 0xc4, 0x03, 0x45, 0xdf, 0x1b, 0xed, 0x2d, - 0x86, 0x2b, 0xe7, 0xc6, 0x1e, 0x3d, 0xc9, 0x0f, 0xfd, 0xf9, 0x24, 0x3f, 0xa4, 0x5c, 0x03, 0x4a, - 0x37, 0x22, 0xa2, 0x9a, 0xc7, 0xc1, 0xbe, 0xe8, 0xa0, 0xc7, 0xe9, 0x42, 0x46, 0x7b, 0xcd, 0x96, - 0xfd, 0x41, 0xb2, 0x4e, 0x69, 0x2b, 0x2d, 0xc9, 0xb3, 0x49, 0xeb, 0xc8, 0xd5, 0x45, 0x5a, 0x5b, - 0xfe, 0x6e, 0xd2, 0x92, 0x44, 0x9a, 0xd2, 0x3a, 0x2a, 0x29, 0xa4, 0xb5, 0x55, 0x4d, 0x39, 0x0c, - 0x0e, 0x71, 0xc0, 0x1b, 0xeb, 0x94, 0xf8, 0xbe, 0x83, 0xf9, 0xb1, 0x8f, 0x9a, 0xf3, 0x17, 0x49, - 0x1c, 0xff, 0xb6, 0xa7, 0x22, 0x4d, 0x1e, 0x4c, 0x30, 0x07, 0xb1, 0x75, 0xa3, 0x8a, 0x7d, 0x4c, - 0x79, 0x86, 0x11, 0x1d, 0xf0, 0xa5, 0xab, 0xc1, 0x0a, 0x2c, 0x80, 0xd7, 0x5a, 0x36, 0x18, 0xc8, - 0x71, 0xc8, 0x3d, 0xe4, 0x9a, 0x98, 0x6b, 0x1f, 0xd1, 0xf7, 0x37, 0xb7, 0x16, 0xa3, 0x47, 0xf0, - 0x73, 0x30, 0xe9, 0xe2, 0xfb, 0xbe, 0x41, 0xb1, 0xe7, 0x60, 0xd7, 0x66, 0xeb, 0x86, 0x89, 0x5c, - 0x2b, 0x10, 0x8b, 0x27, 0x47, 0x78, 0xcf, 0xcb, 0x6a, 0x78, 0x2f, 0xa8, 0xd1, 0xbd, 0xa0, 0xde, - 0x88, 0xee, 0x85, 0xd2, 0x58, 0x30, 0xc3, 0x1e, 0xff, 0x96, 0x97, 0xf4, 0x83, 0x01, 0x8a, 0x1e, - 0x81, 0x2c, 0x44, 0x18, 0xca, 0x3b, 0xe0, 0x04, 0x97, 0xa4, 0xe3, 0x8a, 0xcd, 0x7c, 0x4c, 0xb1, - 0xd5, 0x3c, 0x1d, 0xf7, 0x10, 0xb5, 0x16, 0xb1, 0x4b, 0xaa, 0xf1, 0xf1, 0x5c, 0x02, 0x27, 0x33, - 0xed, 0x16, 0x15, 0x39, 0x08, 0x46, 0x2d, 0xbe, 0xc2, 0x27, 0xde, 0xb8, 0x2e, 0xbe, 0x29, 0x39, - 0x31, 0xc3, 0xc3, 0x93, 0x87, 0x2d, 0x7e, 0xd2, 0xca, 0x8b, 0x71, 0x9a, 0x87, 0x12, 0x78, 0x63, - 0x93, 0x0d, 0x02, 0xf9, 0x16, 0xd8, 0xe3, 0xb5, 0x3e, 0x8b, 0x66, 0x6a, 0x21, 0xd3, 0x00, 0x48, - 0xc0, 0x8a, 0x41, 0xdf, 0x86, 0xa7, 0x94, 0xc1, 0xee, 0xc4, 0x36, 0x38, 0x09, 0x44, 0xff, 0x2e, - 0x26, 0xdb, 0x79, 0x11, 0xe6, 0x00, 0x88, 0x06, 0x47, 0x79, 0x91, 0xbf, 0xcc, 0x1d, 0x7a, 0xcb, - 0x8a, 0x72, 0x05, 0x68, 0x5c, 0x4d, 0xd1, 0x71, 0x56, 0x90, 0x4d, 0xd9, 0x2a, 0x72, 0x16, 0x88, - 0x1b, 0xb4, 0x5c, 0x29, 0x39, 0xe7, 0xca, 0x8b, 0x19, 0x2e, 0xc0, 0x1f, 0x24, 0x30, 0x93, 0x1d, - 0x4e, 0xd4, 0xeb, 0x2e, 0x78, 0xd5, 0x43, 0x36, 0x35, 0xea, 0xc8, 0x09, 0xee, 0x73, 0x7e, 0x0c, - 0x44, 0xc9, 0x2e, 0x65, 0x2b, 0x19, 0xb2, 0x69, 0x33, 0x51, 0x7c, 0xcc, 0xdc, 0x66, 0x03, 0xec, - 0xf1, 0x12, 0x5b, 0x94, 0x0d, 0x09, 0x1c, 0xed, 0x19, 0x95, 0x3a, 0xe5, 0xa4, 0xcc, 0x53, 0x6e, - 0x8b, 0x93, 0x04, 0xce, 0x83, 0x5d, 0x71, 0xf8, 0x1d, 0xdc, 0x10, 0x27, 0x6a, 0x4a, 0x6d, 0x7a, - 0x17, 0x35, 0xf4, 0x2e, 0xea, 0x4a, 0x6d, 0xcd, 0xb1, 0xcd, 0x65, 0xdc, 0xd0, 0x27, 0xa2, 0x88, - 0x65, 0xdc, 0x50, 0x0e, 0x00, 0x18, 0x36, 0x2a, 0xa2, 0xa8, 0x79, 0x4c, 0x6e, 0x81, 0xfd, 0x89, - 0x55, 0xf1, 0x12, 0xca, 0x60, 0xd4, 0xe3, 0x2b, 0xe2, 0xb6, 0x3a, 0x99, 0xb1, 0xf2, 0x41, 0x88, - 0xe8, 0x52, 0x01, 0xa0, 0xcc, 0x81, 0x23, 0x3c, 0xc3, 0x35, 0xc7, 0xc2, 0xcc, 0xbf, 0xe9, 0x9a, - 0xc4, 0xbd, 0x6d, 0xd3, 0x2a, 0xb6, 0x56, 0x99, 0x99, 0xa1, 0x87, 0xbe, 0x89, 0x26, 0x78, 0x7a, - 0xbc, 0xe0, 0x6b, 0x03, 0x58, 0x67, 0xa6, 0xc1, 0xb0, 0x6b, 0x19, 0xb1, 0xd7, 0x14, 0xdc, 0x4f, - 0x67, 0xe2, 0xbe, 0xca, 0xcc, 0xeb, 0xd8, 0xb5, 0x9a, 0x03, 0x29, 0x54, 0xb1, 0xaf, 0xde, 0xb6, - 0x5e, 0xf8, 0xe9, 0x20, 0xd8, 0xc9, 0x09, 0xc1, 0x0d, 0x09, 0x1c, 0x48, 0x33, 0x78, 0xf0, 0x62, - 0xa6, 0x8c, 0x5d, 0x5c, 0xa5, 0x5c, 0xdc, 0x02, 0x42, 0x58, 0x12, 0x65, 0xe9, 0xcb, 0xe7, 0x7f, - 0x7c, 0x3b, 0x3c, 0x0f, 0xe7, 0x7a, 0xff, 0x2c, 0x88, 0x1b, 0x4b, 0x38, 0x48, 0xed, 0x41, 0xf4, - 0x36, 0xbe, 0x80, 0xcf, 0x25, 0xd1, 0x21, 0x49, 0xab, 0x08, 0xe7, 0xfb, 0x67, 0x98, 0xb0, 0xa0, - 0xf2, 0xc5, 0xc1, 0x01, 0x84, 0xc2, 0xb3, 0x5c, 0xe1, 0x29, 0x38, 0xdb, 0x87, 0xc2, 0xd0, 0x9c, - 0xc2, 0x87, 0xc3, 0x60, 0x72, 0x13, 0xc7, 0xc9, 0xe0, 0x95, 0x01, 0x99, 0xa5, 0x9a, 0x5b, 0xf9, - 0xea, 0x36, 0xa1, 0x09, 0xd1, 0x1f, 0x72, 0xd1, 0x25, 0x78, 0xb1, 0x5f, 0xd1, 0xc1, 0x6f, 0x0c, - 0xea, 0x1b, 0xb1, 0x6f, 0x84, 0xff, 0x49, 0xe0, 0xf5, 0x74, 0x03, 0xcb, 0xe0, 0xf2, 0xc0, 0xa4, - 0x3b, 0x9d, 0xb2, 0x7c, 0x65, 0x7b, 0xc0, 0x44, 0x01, 0x2e, 0xf3, 0x02, 0x14, 0xe1, 0xfc, 0x00, - 0x05, 0x20, 0x5e, 0x8b, 0xfe, 0xbf, 0x23, 0x8f, 0x94, 0xea, 0x36, 0xe1, 0xa5, 0xec, 0xac, 0xbb, - 0xf9, 0x66, 0xf9, 0xf2, 0x96, 0x71, 0x84, 0xf0, 0x22, 0x17, 0x7e, 0x1e, 0x9e, 0xcd, 0xf0, 0x3b, - 0x3f, 0x02, 0x32, 0x12, 0x57, 0x4e, 0x8a, 0xe4, 0x56, 0x17, 0x3a, 0x90, 0xe4, 0x14, 0x3f, 0x3d, - 0x90, 0xe4, 0x34, 0x3b, 0x3c, 0x98, 0xe4, 0xc4, 0x25, 0x0d, 0x7f, 0x96, 0xc4, 0xbd, 0x97, 0x70, - 0xc2, 0xf0, 0x42, 0x76, 0x8a, 0x69, 0x06, 0x5b, 0x9e, 0x1f, 0x38, 0x5e, 0x48, 0x3b, 0xc3, 0xa5, - 0x15, 0xe0, 0x4c, 0x6f, 0x69, 0xbe, 0x00, 0x08, 0xff, 0x25, 0x80, 0xdf, 0x0f, 0x83, 0x63, 0x19, - 0xac, 0x2d, 0xbc, 0x96, 0x9d, 0x62, 0x26, 0x4b, 0x2d, 0xaf, 0x6c, 0x1f, 0xa0, 0x28, 0xc2, 0x32, - 0x2f, 0xc2, 0x12, 0x5c, 0xe8, 0x5d, 0x04, 0x1a, 0x23, 0x36, 0x7b, 0x9a, 0x72, 0x4c, 0x23, 0xb4, - 0xea, 0xf0, 0xaf, 0x0e, 0x2b, 0x9e, 0x74, 0x98, 0x0c, 0xf6, 0x71, 0xab, 0x6e, 0xe2, 0xf7, 0xe5, - 0xd2, 0x56, 0x20, 0x84, 0xea, 0x12, 0x57, 0xfd, 0x01, 0x3c, 0xd7, 0x5b, 0x75, 0xe4, 0xf4, 0x8d, - 0xf6, 0x0b, 0xec, 0xbb, 0x61, 0xf1, 0x97, 0x49, 0x06, 0x6b, 0x0d, 0x6f, 0x64, 0x27, 0x9d, 0xdd, - 0xf8, 0xcb, 0x37, 0xb7, 0x19, 0x55, 0x54, 0xe7, 0x3c, 0xaf, 0xce, 0x69, 0x78, 0xaa, 0xef, 0xf9, - 0x6e, 0x5b, 0xf0, 0x47, 0x09, 0x4c, 0xb4, 0xf8, 0x59, 0xf8, 0x7e, 0x1f, 0xaf, 0xab, 0xd5, 0x17, - 0xcb, 0x67, 0xfa, 0x0f, 0x14, 0xfc, 0x67, 0x38, 0xff, 0x13, 0x70, 0x3a, 0xc3, 0xdb, 0x0d, 0x49, - 0xfe, 0x2b, 0x89, 0x9f, 0xf2, 0x69, 0x16, 0x17, 0x2e, 0x65, 0x67, 0xd2, 0xc5, 0x62, 0xcb, 0x97, - 0xb6, 0x0a, 0xd3, 0xff, 0x91, 0x25, 0x1c, 0xc7, 0xa8, 0x35, 0x81, 0x8c, 0x3a, 0x33, 0x5b, 0xcc, - 0x65, 0xe9, 0xe3, 0xa7, 0x1b, 0x39, 0xe9, 0xd9, 0x46, 0x4e, 0xfa, 0x7d, 0x23, 0x27, 0x3d, 0x7e, - 0x99, 0x1b, 0x7a, 0xf6, 0x32, 0x37, 0xf4, 0xeb, 0xcb, 0xdc, 0xd0, 0x27, 0x73, 0x15, 0xdb, 0x5f, - 0xaf, 0xad, 0xa9, 0x26, 0xa9, 0x6a, 0x26, 0x61, 0x55, 0xc2, 0x5a, 0xf2, 0xbd, 0x1b, 0xe7, 0xab, - 0xbf, 0xa7, 0xdd, 0x6f, 0x1b, 0x96, 0x0d, 0x0f, 0xb3, 0xb5, 0x51, 0xfe, 0x0f, 0xc3, 0xa9, 0xff, - 0x03, 0x00, 0x00, 0xff, 0xff, 0xe2, 0x62, 0xc2, 0x43, 0x13, 0x17, 0x00, 0x00, ->>>>>>> main + // 1811 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0xdb, 0x6f, 0xdc, 0x4e, + 0x15, 0x8e, 0x93, 0x34, 0x24, 0x93, 0xde, 0x98, 0x96, 0x36, 0x75, 0xd2, 0xdd, 0xd4, 0x85, 0x92, + 0xde, 0xec, 0x64, 0x4b, 0xd5, 0x6b, 0x9a, 0x66, 0xb3, 0x49, 0xba, 0x4a, 0xdb, 0x6c, 0xdd, 0x34, + 0x48, 0x80, 0x70, 0x1d, 0x7b, 0xba, 0xb1, 0xea, 0xf5, 0x38, 0x1e, 0xef, 0xb6, 0xab, 0x0a, 0x89, + 0xf2, 0x40, 0x2b, 0x21, 0x41, 0x25, 0xe0, 0xbd, 0x12, 0xe2, 0x1f, 0x40, 0xfc, 0x11, 0x7d, 0xa3, + 0xd0, 0x17, 0xc4, 0x43, 0x40, 0x29, 0x0f, 0x88, 0x27, 0x54, 0x21, 0xf1, 0x84, 0xf4, 0x93, 0xc7, + 0x63, 0x7b, 0xbd, 0xeb, 0xec, 0x7a, 0x37, 0xf9, 0x3d, 0x25, 0x3b, 0x97, 0xef, 0x9c, 0xef, 0xcc, + 0x39, 0x67, 0xe6, 0x33, 0x90, 0x0c, 0xcb, 0x45, 0x8e, 0xb6, 0xa9, 0x1a, 0x96, 0x42, 0x90, 0x56, + 0x75, 0x0c, 0xb7, 0x2e, 0x69, 0x5a, 0x4d, 0xb2, 0x1d, 0x5c, 0x33, 0x74, 0xe4, 0x48, 0xb5, 0x19, + 0x69, 0xab, 0x8a, 0x9c, 0xba, 0x68, 0x3b, 0xd8, 0xc5, 0xf0, 0x6c, 0xc2, 0x06, 0x51, 0xd3, 0x6a, + 0x62, 0xb0, 0x41, 0xac, 0xcd, 0xf0, 0x13, 0x65, 0x8c, 0xcb, 0x26, 0x92, 0x54, 0xdb, 0x90, 0x54, + 0xcb, 0xc2, 0xae, 0xea, 0x1a, 0xd8, 0x22, 0x3e, 0x04, 0x7f, 0xbc, 0x8c, 0xcb, 0x98, 0xfe, 0x2b, + 0x79, 0xff, 0xb1, 0xd1, 0x2c, 0xdb, 0x43, 0x7f, 0x6d, 0x54, 0x9f, 0x49, 0xae, 0x51, 0x41, 0xc4, + 0x55, 0x2b, 0x36, 0x5b, 0x90, 0x4b, 0xe3, 0x6a, 0xe8, 0x85, 0xbf, 0x67, 0x7a, 0xb7, 0x3d, 0xb5, + 0x19, 0x89, 0x6c, 0xaa, 0x0e, 0xd2, 0x15, 0x0d, 0x5b, 0xa4, 0x5a, 0x09, 0x77, 0x7c, 0xa7, 0xcd, + 0x8e, 0x17, 0x86, 0x83, 0xd8, 0xb2, 0x09, 0x17, 0x59, 0x3a, 0x72, 0x2a, 0x86, 0xe5, 0x4a, 0x9a, + 0x53, 0xb7, 0x5d, 0x2c, 0x3d, 0x47, 0xf5, 0x80, 0xe1, 0x29, 0x0d, 0x93, 0x0a, 0x26, 0x8a, 0x4f, + 0xd2, 0xff, 0xe1, 0x4f, 0x09, 0xd7, 0xc1, 0xf8, 0x23, 0x2f, 0x9c, 0x0b, 0xcc, 0xec, 0x32, 0xb2, + 0x10, 0x31, 0x88, 0x8c, 0xb6, 0xaa, 0x88, 0xb8, 0xf0, 0x14, 0x18, 0xf6, 0x6d, 0x1b, 0xfa, 0x18, + 0x37, 0xc9, 0x4d, 0x8d, 0xc8, 0xdf, 0xa0, 0xbf, 0x8b, 0xba, 0xf0, 0x0a, 0x4c, 0x24, 0xef, 0x24, + 0x36, 0xb6, 0x08, 0x82, 0x3f, 0x04, 0x87, 0xca, 0xfe, 0x90, 0x42, 0x5c, 0xd5, 0x45, 0x74, 0xff, + 0x68, 0x6e, 0x5a, 0xdc, 0xed, 0xc4, 0x6a, 0x33, 0x62, 0x13, 0xd6, 0x63, 0x6f, 0x5f, 0x7e, 0xf0, + 0xc3, 0x76, 0xb6, 0x4f, 0x3e, 0x58, 0x6e, 0x18, 0x13, 0x26, 0x00, 0x1f, 0x33, 0xbe, 0xe0, 0xc1, + 0x05, 0x5e, 0x0b, 0x6a, 0x13, 0xa9, 0x60, 0x96, 0x79, 0x96, 0x07, 0x43, 0xd4, 0x3c, 0x19, 0xe3, + 0x26, 0x07, 0xa6, 0x46, 0x73, 0x17, 0xc4, 0x14, 0x49, 0x24, 0x52, 0x10, 0x99, 0xed, 0x14, 0xce, + 0x83, 0xef, 0xb6, 0x9a, 0x78, 0xec, 0xaa, 0x8e, 0x5b, 0x72, 0xb0, 0x8d, 0x89, 0x6a, 0x86, 0xde, + 0xbc, 0xe5, 0xc0, 0x54, 0xe7, 0xb5, 0xcc, 0xb7, 0x1f, 0x81, 0x11, 0x3b, 0x18, 0x64, 0x11, 0xbb, + 0x93, 0xce, 0x3d, 0x06, 0x3e, 0xaf, 0xeb, 0x86, 0x97, 0xdd, 0x11, 0x74, 0x04, 0x28, 0x4c, 0x81, + 0x73, 0x49, 0x9e, 0x60, 0xbb, 0xc5, 0xe9, 0x9f, 0x73, 0xc9, 0x04, 0x63, 0x4b, 0xc3, 0x93, 0x6e, + 0xf1, 0x79, 0xb6, 0x2b, 0x9f, 0x65, 0x54, 0xc1, 0x35, 0xd5, 0x4c, 0x74, 0x79, 0x0d, 0x1c, 0xa0, + 0xa6, 0xdb, 0xa4, 0x22, 0x1c, 0x07, 0x23, 0x9a, 0x69, 0x20, 0xcb, 0xf5, 0xe6, 0xfa, 0xe9, 0xdc, + 0xb0, 0x3f, 0x50, 0xd4, 0xe1, 0x31, 0x70, 0xc0, 0xc5, 0xb6, 0xf2, 0x70, 0x6c, 0x60, 0x92, 0x9b, + 0x3a, 0x24, 0x0f, 0xba, 0xd8, 0x7e, 0x28, 0xbc, 0xe1, 0xc0, 0x19, 0x4a, 0x6f, 0x5d, 0x35, 0x0d, + 0x5d, 0x75, 0xb1, 0xd3, 0x10, 0x3f, 0xa7, 0x73, 0xf6, 0xc3, 0x59, 0x70, 0x34, 0x60, 0xa2, 0xa8, + 0xba, 0xee, 0x20, 0x42, 0x7c, 0xcb, 0x79, 0xf8, 0x65, 0x3b, 0x7b, 0xb8, 0xae, 0x56, 0xcc, 0x9b, + 0x02, 0x9b, 0x10, 0xe4, 0x23, 0xc1, 0xda, 0x79, 0x7f, 0xe4, 0xe6, 0xf0, 0xdb, 0xf7, 0xd9, 0xbe, + 0x7f, 0xbd, 0xcf, 0xf6, 0x09, 0xab, 0x40, 0x68, 0xe7, 0x08, 0x0b, 0xf1, 0x79, 0x70, 0x34, 0x68, + 0x0c, 0xa1, 0x39, 0xdf, 0xa3, 0x23, 0x5a, 0xc3, 0x7a, 0xcf, 0x58, 0x2b, 0xb5, 0x52, 0x83, 0xf1, + 0x74, 0xd4, 0x5a, 0x6c, 0xb5, 0xa1, 0xd6, 0x64, 0xbf, 0x1d, 0xb5, 0xb8, 0x23, 0x11, 0xb5, 0x96, + 0x48, 0x32, 0x6a, 0x4d, 0x51, 0x13, 0xc6, 0xc1, 0x29, 0x0a, 0xb8, 0xb6, 0xe9, 0x60, 0xd7, 0x35, + 0x11, 0xed, 0x05, 0x41, 0xc6, 0xfe, 0x99, 0x63, 0x3d, 0xa1, 0x69, 0x96, 0x99, 0xc9, 0x82, 0x51, + 0x62, 0xaa, 0x64, 0x53, 0xa9, 0x20, 0x17, 0x39, 0xd4, 0xc2, 0x80, 0x0c, 0xe8, 0xd0, 0x03, 0x6f, + 0x04, 0xe6, 0xc0, 0xb7, 0x1a, 0x16, 0x28, 0xaa, 0x69, 0xe2, 0x17, 0xaa, 0xa5, 0x21, 0xca, 0x7d, + 0x40, 0x3e, 0x16, 0x2d, 0x9d, 0x0f, 0xa6, 0xe0, 0x8f, 0xc1, 0x98, 0x85, 0x5e, 0xba, 0x8a, 0x83, + 0x6c, 0x13, 0x59, 0x06, 0xd9, 0x54, 0x34, 0xd5, 0xd2, 0x3d, 0xb2, 0x88, 0xa6, 0xdb, 0x68, 0x8e, + 0x17, 0xfd, 0x7b, 0x44, 0x0c, 0xee, 0x11, 0x71, 0x2d, 0xb8, 0x47, 0xf2, 0xc3, 0x5e, 0x63, 0x7b, + 0xf7, 0xf7, 0x2c, 0x27, 0x9f, 0xf0, 0x50, 0xe4, 0x00, 0x64, 0x21, 0xc0, 0x10, 0x2e, 0x81, 0x0b, + 0x94, 0x92, 0x8c, 0xca, 0x06, 0x71, 0x91, 0x83, 0xf4, 0xa8, 0x64, 0x5e, 0xa8, 0x8e, 0x5e, 0x40, + 0x16, 0xae, 0x84, 0x35, 0xbb, 0x08, 0x2e, 0xa6, 0x5a, 0xcd, 0x22, 0x72, 0x02, 0x0c, 0xe9, 0x74, + 0x84, 0xb6, 0xc1, 0x11, 0x99, 0xfd, 0x12, 0x32, 0xac, 0xb1, 0xfb, 0xe5, 0x88, 0x74, 0x5a, 0x7e, + 0xc5, 0x42, 0x68, 0xe6, 0x35, 0x07, 0x4e, 0xef, 0xb2, 0x80, 0x21, 0x3f, 0x05, 0x87, 0xed, 0xc6, + 0xb9, 0xa0, 0xd1, 0xe6, 0x52, 0x75, 0x85, 0x18, 0x2c, 0xeb, 0xfe, 0x4d, 0x78, 0x42, 0x11, 0x1c, + 0x8a, 0x2d, 0x83, 0x63, 0x80, 0xe5, 0x6f, 0x21, 0x9e, 0xce, 0x05, 0x98, 0x01, 0x20, 0xe8, 0x26, + 0xc5, 0x02, 0x3d, 0xcc, 0x41, 0xb9, 0x61, 0x44, 0xb8, 0x0f, 0x24, 0xca, 0x66, 0xde, 0x34, 0x4b, + 0xaa, 0xe1, 0x90, 0x75, 0xd5, 0x5c, 0xc0, 0x96, 0x97, 0x72, 0xf9, 0x78, 0xf3, 0x2b, 0x16, 0x52, + 0xdc, 0x8a, 0xbf, 0xe7, 0xc0, 0x74, 0x7a, 0x38, 0x16, 0xaf, 0x2d, 0xf0, 0x4d, 0x5b, 0x35, 0x1c, + 0xa5, 0xa6, 0x9a, 0xde, 0xfd, 0x4f, 0xcb, 0x80, 0x85, 0x6c, 0x29, 0x5d, 0xc8, 0x54, 0xc3, 0x89, + 0x0c, 0x85, 0x65, 0x66, 0x45, 0x09, 0x70, 0xd8, 0x8e, 0x2d, 0x11, 0xfe, 0xcb, 0x81, 0x33, 0x1d, + 0x77, 0xc1, 0xa5, 0xdd, 0x6a, 0x33, 0x3f, 0xfe, 0x65, 0x3b, 0x7b, 0xd2, 0x6f, 0x05, 0xcd, 0x2b, + 0x5a, 0xdb, 0x9d, 0x87, 0xb3, 0x4b, 0x4b, 0x69, 0xc0, 0x69, 0x5e, 0xd1, 0xda, 0x5b, 0xe0, 0x1c, + 0x38, 0x18, 0xae, 0x7a, 0x8e, 0xea, 0xac, 0xc6, 0x26, 0xc4, 0xe8, 0xf5, 0x23, 0xfa, 0xaf, 0x1f, + 0xb1, 0x54, 0xdd, 0x30, 0x0d, 0x6d, 0x05, 0xd5, 0xe5, 0xd1, 0x60, 0xc7, 0x0a, 0xaa, 0x0b, 0xc7, + 0x01, 0xf4, 0x53, 0x57, 0x75, 0xd4, 0xa8, 0x70, 0x9e, 0x82, 0x63, 0xb1, 0x51, 0x76, 0x2c, 0x45, + 0x30, 0x64, 0xd3, 0x11, 0x76, 0xa9, 0x5d, 0x4c, 0x79, 0x16, 0xde, 0x16, 0x96, 0xb7, 0x0c, 0x40, + 0x58, 0x66, 0x85, 0x1c, 0xcb, 0x80, 0x55, 0xdb, 0x45, 0x7a, 0xd1, 0x0a, 0xdb, 0x63, 0x9a, 0x57, + 0xd7, 0x16, 0xab, 0xf1, 0x4e, 0x40, 0xe1, 0x53, 0xe7, 0x74, 0x2d, 0x1c, 0x55, 0x9a, 0x4f, 0x0a, + 0x05, 0xa5, 0x3f, 0x1e, 0x2d, 0x2a, 0xc5, 0x8f, 0x0e, 0x11, 0x61, 0x8b, 0x65, 0x74, 0xfc, 0x35, + 0x15, 0x1a, 0xbb, 0xa7, 0x92, 0x35, 0xcc, 0x7e, 0x05, 0xcd, 0x38, 0xf1, 0x7a, 0xe4, 0x52, 0x5f, + 0x8f, 0x82, 0x0a, 0x66, 0xba, 0x30, 0xc9, 0xb8, 0x5e, 0x02, 0x30, 0x4c, 0x8e, 0x20, 0x7c, 0x01, + 0xc1, 0x30, 0xfd, 0xfc, 0xd2, 0xd3, 0xe9, 0x35, 0x79, 0x31, 0xf9, 0xe2, 0x5d, 0xc0, 0x95, 0x8a, + 0x41, 0x88, 0x81, 0x2d, 0xb9, 0x81, 0xd1, 0xd7, 0xf6, 0x16, 0x10, 0x7e, 0xca, 0x81, 0x4b, 0xe9, + 0x3c, 0x61, 0x44, 0x4b, 0x60, 0xd0, 0x09, 0x1e, 0xd4, 0x23, 0xf9, 0xdb, 0x5e, 0xa2, 0xfd, 0x6d, + 0x3b, 0x7b, 0xae, 0x6c, 0xb8, 0x9b, 0xd5, 0x0d, 0x51, 0xc3, 0x15, 0xf6, 0xc4, 0x67, 0x7f, 0x2e, + 0x13, 0xfd, 0xb9, 0xe4, 0xd6, 0x6d, 0x44, 0xc4, 0x02, 0xd2, 0xfe, 0xf2, 0xc7, 0xcb, 0x80, 0x29, + 0x80, 0x02, 0xd2, 0x64, 0x8a, 0x24, 0xcc, 0x82, 0x49, 0xea, 0xc1, 0xaa, 0xa9, 0x23, 0xe2, 0x3e, + 0xb1, 0x34, 0x6c, 0x3d, 0x33, 0x9c, 0x0a, 0xd2, 0xd7, 0x89, 0x96, 0x22, 0x29, 0x7f, 0x19, 0x3c, + 0x39, 0x92, 0xf7, 0x33, 0xb7, 0x0d, 0x00, 0x6b, 0x44, 0x53, 0x08, 0xb2, 0x74, 0x25, 0x14, 0x53, + 0xac, 0xb4, 0xae, 0xa6, 0x2a, 0xad, 0x75, 0xa2, 0x3d, 0x46, 0x96, 0x1e, 0xdd, 0xa0, 0x7e, 0x91, + 0x1d, 0xad, 0x35, 0x8d, 0xe7, 0x7e, 0x71, 0x1a, 0x1c, 0xa0, 0x0e, 0xc1, 0x1d, 0x0e, 0x1c, 0x4f, + 0x92, 0x29, 0xf0, 0x6e, 0x2a, 0x8b, 0x6d, 0xb4, 0x11, 0x3f, 0xbf, 0x07, 0x04, 0x3f, 0x24, 0xc2, + 0xe2, 0xcf, 0x3e, 0xfd, 0xf3, 0xd7, 0xfd, 0x73, 0x70, 0xb6, 0xb3, 0xee, 0x0d, 0x53, 0x9b, 0xe9, + 0x20, 0xe9, 0x55, 0x70, 0x1a, 0x3f, 0x81, 0x9f, 0x38, 0xd6, 0xc0, 0xe2, 0xf5, 0x02, 0xe7, 0xba, + 0xf7, 0x30, 0x26, 0xa4, 0xf8, 0xbb, 0xbd, 0x03, 0x30, 0x86, 0x37, 0x28, 0xc3, 0x2b, 0x70, 0xa6, + 0x0b, 0x86, 0xbe, 0xc4, 0x82, 0xaf, 0xfb, 0xc1, 0xd8, 0x2e, 0xba, 0x89, 0xc0, 0xfb, 0x3d, 0x7a, + 0x96, 0x28, 0xd1, 0xf8, 0x07, 0xfb, 0x84, 0xc6, 0x48, 0xdf, 0xa3, 0xa4, 0xf3, 0xf0, 0x6e, 0xb7, + 0xa4, 0x3d, 0xa5, 0xec, 0xb8, 0x4a, 0xa8, 0x7e, 0xe0, 0xff, 0x39, 0x70, 0x32, 0x59, 0x86, 0x11, + 0xb8, 0xd2, 0xb3, 0xd3, 0xad, 0x7a, 0x8f, 0xbf, 0xbf, 0x3f, 0x60, 0x2c, 0x00, 0xcb, 0x34, 0x00, + 0xf3, 0x70, 0xae, 0x87, 0x00, 0x60, 0xbb, 0x81, 0xff, 0x7f, 0x82, 0x47, 0x7d, 0xa2, 0x3c, 0x82, + 0x4b, 0xe9, 0xbd, 0x6e, 0x27, 0xf4, 0xf8, 0xe5, 0x3d, 0xe3, 0x30, 0xe2, 0xf3, 0x94, 0xf8, 0x2d, + 0x78, 0x23, 0xc5, 0x87, 0xac, 0x00, 0x48, 0x89, 0x3d, 0x7c, 0x12, 0x28, 0x37, 0x5e, 0xc9, 0x3d, + 0x51, 0x4e, 0x10, 0x80, 0x3d, 0x51, 0x4e, 0xd2, 0x6f, 0xbd, 0x51, 0x8e, 0xdd, 0x97, 0xf0, 0x4f, + 0x1c, 0x7b, 0x96, 0xc5, 0xa4, 0x1b, 0xbc, 0x93, 0xde, 0xc5, 0x24, 0x45, 0xc8, 0xcf, 0xf5, 0xbc, + 0x9f, 0x51, 0xbb, 0x4e, 0xa9, 0xe5, 0xe0, 0x74, 0x67, 0x6a, 0x2e, 0x03, 0xf0, 0xbf, 0x75, 0xc1, + 0xdf, 0xf6, 0x83, 0xb3, 0x29, 0xb4, 0x18, 0x5c, 0x4d, 0xef, 0x62, 0x2a, 0x0d, 0xc8, 0x97, 0xf6, + 0x0f, 0x90, 0x05, 0x61, 0x85, 0x06, 0x61, 0x11, 0x2e, 0x74, 0x0e, 0x82, 0x13, 0x22, 0x46, 0x39, + 0xed, 0x50, 0x4c, 0xc5, 0xd7, 0x96, 0xf0, 0xdf, 0x2d, 0xda, 0x31, 0x2e, 0x89, 0x08, 0xec, 0xe2, + 0x56, 0xdd, 0x45, 0xa0, 0xf2, 0xf9, 0xbd, 0x40, 0x30, 0xd6, 0x79, 0xca, 0xfa, 0x36, 0xbc, 0xd9, + 0x99, 0x75, 0x20, 0x4d, 0x95, 0xe6, 0x0b, 0xec, 0x37, 0xfd, 0xec, 0xc3, 0x5f, 0x0a, 0x2d, 0x08, + 0xd7, 0xd2, 0x3b, 0x9d, 0x5e, 0xa9, 0xf2, 0x4f, 0xf6, 0x19, 0x95, 0x45, 0xe7, 0x16, 0x8d, 0xce, + 0x55, 0x78, 0xa5, 0xeb, 0xfe, 0x6e, 0xe8, 0xf0, 0x0f, 0x1c, 0x18, 0x6d, 0x90, 0x5b, 0xf0, 0x5a, + 0x17, 0xc7, 0xd5, 0x28, 0xdb, 0xf8, 0xeb, 0xdd, 0x6f, 0x64, 0xfe, 0x4f, 0x53, 0xff, 0x2f, 0xc0, + 0xa9, 0x14, 0xa7, 0xeb, 0x3b, 0xf9, 0x26, 0x28, 0xe8, 0xf6, 0xc2, 0xab, 0x9b, 0x82, 0x4e, 0xa5, + 0x05, 0xbb, 0x29, 0xe8, 0x74, 0x9a, 0x50, 0x98, 0xa5, 0xe4, 0xaf, 0xc1, 0xab, 0x9d, 0xc9, 0x63, + 0x0f, 0x44, 0x31, 0x2c, 0x25, 0xd2, 0x87, 0xf0, 0x77, 0xfd, 0xe0, 0x7c, 0x6a, 0x71, 0x06, 0x9f, + 0xf4, 0xfa, 0x82, 0x6c, 0xab, 0x2f, 0xf9, 0xf5, 0xfd, 0x86, 0xdd, 0xeb, 0xc3, 0x85, 0x28, 0x36, + 0x72, 0xa2, 0x30, 0xc1, 0x5f, 0xf5, 0x83, 0x6f, 0xa7, 0x11, 0x75, 0xb0, 0xb4, 0x87, 0xa7, 0x47, + 0xa2, 0x52, 0xe5, 0x1f, 0xed, 0x23, 0x62, 0xf7, 0xdd, 0x30, 0x0a, 0x4b, 0x08, 0xa5, 0x78, 0x1a, + 0x13, 0xfe, 0x8f, 0x63, 0x5f, 0x6f, 0x93, 0x44, 0x22, 0x5c, 0x4c, 0xef, 0x74, 0x1b, 0x91, 0xca, + 0x2f, 0xed, 0x15, 0xa6, 0xfb, 0x4b, 0x0f, 0x53, 0x1c, 0xa5, 0x1a, 0x01, 0x29, 0x35, 0xa2, 0x35, + 0xc8, 0xb3, 0xfc, 0xf7, 0x3f, 0xec, 0x64, 0xb8, 0x8f, 0x3b, 0x19, 0xee, 0x1f, 0x3b, 0x19, 0xee, + 0xdd, 0xe7, 0x4c, 0xdf, 0xc7, 0xcf, 0x99, 0xbe, 0xbf, 0x7e, 0xce, 0xf4, 0xfd, 0x60, 0xb6, 0x55, + 0xb3, 0x47, 0xf6, 0x2e, 0x87, 0xf6, 0x6a, 0xdf, 0x93, 0x5e, 0x36, 0x3d, 0x37, 0x3c, 0x39, 0xbf, + 0x31, 0x44, 0x3f, 0x2a, 0x5f, 0xf9, 0x2a, 0x00, 0x00, 0xff, 0xff, 0x2d, 0xeb, 0x2b, 0x80, 0x36, + 0x1d, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1826,8 +1745,7 @@ type QueryClient interface { QueryAllPairsValConAddrByConsumerChainID(ctx context.Context, in *QueryAllPairsValConAddrByConsumerChainIDRequest, opts ...grpc.CallOption) (*QueryAllPairsValConAddrByConsumerChainIDResponse, error) // QueryParams returns all current values of provider parameters QueryParams(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) -<<<<<<< HEAD - // QueryConsumerChainOptedInValidators returns a list of validators consensus address + // QueryConsumerChainOptedInValidators returns a list of validators consensus addresses // that opted-in to the given consumer chain QueryConsumerChainOptedInValidators(ctx context.Context, in *QueryConsumerChainOptedInValidatorsRequest, opts ...grpc.CallOption) (*QueryConsumerChainOptedInValidatorsResponse, error) // QueryConsumerChainsValidatorHasToValidate returns a list of consumer chains @@ -1836,10 +1754,8 @@ type QueryClient interface { // QueryValidatorConsumerCommissionRate returns the commission rate a given // validator charges on a given consumer chain QueryValidatorConsumerCommissionRate(ctx context.Context, in *QueryValidatorConsumerCommissionRateRequest, opts ...grpc.CallOption) (*QueryValidatorConsumerCommissionRateResponse, error) -======= // QueryOldestUnconfirmedVsc returns the send timestamp of the oldest unconfirmed VSCPacket for a given chainID QueryOldestUnconfirmedVsc(ctx context.Context, in *QueryOldestUnconfirmedVscRequest, opts ...grpc.CallOption) (*QueryOldestUnconfirmedVscResponse, error) ->>>>>>> main } type queryClient struct { @@ -1949,7 +1865,6 @@ func (c *queryClient) QueryParams(ctx context.Context, in *QueryParamsRequest, o return out, nil } -<<<<<<< HEAD func (c *queryClient) QueryConsumerChainOptedInValidators(ctx context.Context, in *QueryConsumerChainOptedInValidatorsRequest, opts ...grpc.CallOption) (*QueryConsumerChainOptedInValidatorsResponse, error) { out := new(QueryConsumerChainOptedInValidatorsResponse) err := c.cc.Invoke(ctx, "/interchain_security.ccv.provider.v1.Query/QueryConsumerChainOptedInValidators", in, out, opts...) @@ -1971,11 +1886,15 @@ func (c *queryClient) QueryConsumerChainsValidatorHasToValidate(ctx context.Cont func (c *queryClient) QueryValidatorConsumerCommissionRate(ctx context.Context, in *QueryValidatorConsumerCommissionRateRequest, opts ...grpc.CallOption) (*QueryValidatorConsumerCommissionRateResponse, error) { out := new(QueryValidatorConsumerCommissionRateResponse) err := c.cc.Invoke(ctx, "/interchain_security.ccv.provider.v1.Query/QueryValidatorConsumerCommissionRate", in, out, opts...) -======= + if err != nil { + return nil, err + } + return out, nil +} + func (c *queryClient) QueryOldestUnconfirmedVsc(ctx context.Context, in *QueryOldestUnconfirmedVscRequest, opts ...grpc.CallOption) (*QueryOldestUnconfirmedVscResponse, error) { out := new(QueryOldestUnconfirmedVscResponse) err := c.cc.Invoke(ctx, "/interchain_security.ccv.provider.v1.Query/QueryOldestUnconfirmedVsc", in, out, opts...) ->>>>>>> main if err != nil { return nil, err } @@ -2014,8 +1933,7 @@ type QueryServer interface { QueryAllPairsValConAddrByConsumerChainID(context.Context, *QueryAllPairsValConAddrByConsumerChainIDRequest) (*QueryAllPairsValConAddrByConsumerChainIDResponse, error) // QueryParams returns all current values of provider parameters QueryParams(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) -<<<<<<< HEAD - // QueryConsumerChainOptedInValidators returns a list of validators consensus address + // QueryConsumerChainOptedInValidators returns a list of validators consensus addresses // that opted-in to the given consumer chain QueryConsumerChainOptedInValidators(context.Context, *QueryConsumerChainOptedInValidatorsRequest) (*QueryConsumerChainOptedInValidatorsResponse, error) // QueryConsumerChainsValidatorHasToValidate returns a list of consumer chains @@ -2024,10 +1942,8 @@ type QueryServer interface { // QueryValidatorConsumerCommissionRate returns the commission rate a given // validator charges on a given consumer chain QueryValidatorConsumerCommissionRate(context.Context, *QueryValidatorConsumerCommissionRateRequest) (*QueryValidatorConsumerCommissionRateResponse, error) -======= // QueryOldestUnconfirmedVsc returns the send timestamp of the oldest unconfirmed VSCPacket for a given chainID QueryOldestUnconfirmedVsc(context.Context, *QueryOldestUnconfirmedVscRequest) (*QueryOldestUnconfirmedVscResponse, error) ->>>>>>> main } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -2067,7 +1983,6 @@ func (*UnimplementedQueryServer) QueryAllPairsValConAddrByConsumerChainID(ctx co func (*UnimplementedQueryServer) QueryParams(ctx context.Context, req *QueryParamsRequest) (*QueryParamsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method QueryParams not implemented") } -<<<<<<< HEAD func (*UnimplementedQueryServer) QueryConsumerChainOptedInValidators(ctx context.Context, req *QueryConsumerChainOptedInValidatorsRequest) (*QueryConsumerChainOptedInValidatorsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method QueryConsumerChainOptedInValidators not implemented") } @@ -2076,10 +1991,9 @@ func (*UnimplementedQueryServer) QueryConsumerChainsValidatorHasToValidate(ctx c } func (*UnimplementedQueryServer) QueryValidatorConsumerCommissionRate(ctx context.Context, req *QueryValidatorConsumerCommissionRateRequest) (*QueryValidatorConsumerCommissionRateResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method QueryValidatorConsumerCommissionRate not implemented") -======= +} func (*UnimplementedQueryServer) QueryOldestUnconfirmedVsc(ctx context.Context, req *QueryOldestUnconfirmedVscRequest) (*QueryOldestUnconfirmedVscResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method QueryOldestUnconfirmedVsc not implemented") ->>>>>>> main } func RegisterQueryServer(s grpc1.Server, srv QueryServer) { @@ -2284,18 +2198,12 @@ func _Query_QueryParams_Handler(srv interface{}, ctx context.Context, dec func(i return interceptor(ctx, in, info, handler) } -<<<<<<< HEAD func _Query_QueryConsumerChainOptedInValidators_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(QueryConsumerChainOptedInValidatorsRequest) -======= -func _Query_QueryOldestUnconfirmedVsc_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryOldestUnconfirmedVscRequest) ->>>>>>> main if err := dec(in); err != nil { return nil, err } if interceptor == nil { -<<<<<<< HEAD return srv.(QueryServer).QueryConsumerChainOptedInValidators(ctx, in) } info := &grpc.UnaryServerInfo{ @@ -2340,7 +2248,16 @@ func _Query_QueryValidatorConsumerCommissionRate_Handler(srv interface{}, ctx co } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(QueryServer).QueryValidatorConsumerCommissionRate(ctx, req.(*QueryValidatorConsumerCommissionRateRequest)) -======= + } + return interceptor(ctx, in, info, handler) +} + +func _Query_QueryOldestUnconfirmedVsc_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryOldestUnconfirmedVscRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { return srv.(QueryServer).QueryOldestUnconfirmedVsc(ctx, in) } info := &grpc.UnaryServerInfo{ @@ -2349,7 +2266,6 @@ func _Query_QueryValidatorConsumerCommissionRate_Handler(srv interface{}, ctx co } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(QueryServer).QueryOldestUnconfirmedVsc(ctx, req.(*QueryOldestUnconfirmedVscRequest)) ->>>>>>> main } return interceptor(ctx, in, info, handler) } @@ -2403,7 +2319,6 @@ var _Query_serviceDesc = grpc.ServiceDesc{ Handler: _Query_QueryParams_Handler, }, { -<<<<<<< HEAD MethodName: "QueryConsumerChainOptedInValidators", Handler: _Query_QueryConsumerChainOptedInValidators_Handler, }, @@ -2414,10 +2329,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{ { MethodName: "QueryValidatorConsumerCommissionRate", Handler: _Query_QueryValidatorConsumerCommissionRate_Handler, -======= + }, + { MethodName: "QueryOldestUnconfirmedVsc", Handler: _Query_QueryOldestUnconfirmedVsc_Handler, ->>>>>>> main }, }, Streams: []grpc.StreamDesc{}, @@ -3225,11 +3140,7 @@ func (m *QueryParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -<<<<<<< HEAD func (m *QueryConsumerChainOptedInValidatorsRequest) Marshal() (dAtA []byte, err error) { -======= -func (m *QueryOldestUnconfirmedVscRequest) Marshal() (dAtA []byte, err error) { ->>>>>>> main size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -3239,20 +3150,12 @@ func (m *QueryOldestUnconfirmedVscRequest) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -<<<<<<< HEAD func (m *QueryConsumerChainOptedInValidatorsRequest) MarshalTo(dAtA []byte) (int, error) { -======= -func (m *QueryOldestUnconfirmedVscRequest) MarshalTo(dAtA []byte) (int, error) { ->>>>>>> main size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -<<<<<<< HEAD func (m *QueryConsumerChainOptedInValidatorsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { -======= -func (m *QueryOldestUnconfirmedVscRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { ->>>>>>> main i := len(dAtA) _ = i var l int @@ -3267,11 +3170,7 @@ func (m *QueryOldestUnconfirmedVscRequest) MarshalToSizedBuffer(dAtA []byte) (in return len(dAtA) - i, nil } -<<<<<<< HEAD func (m *QueryConsumerChainOptedInValidatorsResponse) Marshal() (dAtA []byte, err error) { -======= -func (m *QueryOldestUnconfirmedVscResponse) Marshal() (dAtA []byte, err error) { ->>>>>>> main size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -3281,16 +3180,11 @@ func (m *QueryOldestUnconfirmedVscResponse) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -<<<<<<< HEAD func (m *QueryConsumerChainOptedInValidatorsResponse) MarshalTo(dAtA []byte) (int, error) { -======= -func (m *QueryOldestUnconfirmedVscResponse) MarshalTo(dAtA []byte) (int, error) { ->>>>>>> main size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -<<<<<<< HEAD func (m *QueryConsumerChainOptedInValidatorsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i @@ -3423,27 +3317,79 @@ func (m *QueryValidatorConsumerCommissionRateResponse) MarshalTo(dAtA []byte) (i } func (m *QueryValidatorConsumerCommissionRateResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { -======= -func (m *QueryOldestUnconfirmedVscResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { ->>>>>>> main i := len(dAtA) _ = i var l int _ = l { -<<<<<<< HEAD size := m.Rate.Size() i -= size if _, err := m.Rate.MarshalTo(dAtA[i:]); err != nil { return 0, err } -======= + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *QueryOldestUnconfirmedVscRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryOldestUnconfirmedVscRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryOldestUnconfirmedVscRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ChainId) > 0 { + i -= len(m.ChainId) + copy(dAtA[i:], m.ChainId) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ChainId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryOldestUnconfirmedVscResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryOldestUnconfirmedVscResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryOldestUnconfirmedVscResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { size, err := m.VscSendTimestamp.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } i -= size ->>>>>>> main i = encodeVarintQuery(dAtA, i, uint64(size)) } i-- @@ -3793,11 +3739,7 @@ func (m *QueryParamsResponse) Size() (n int) { return n } -<<<<<<< HEAD func (m *QueryConsumerChainOptedInValidatorsRequest) Size() (n int) { -======= -func (m *QueryOldestUnconfirmedVscRequest) Size() (n int) { ->>>>>>> main if m == nil { return 0 } @@ -3810,17 +3752,12 @@ func (m *QueryOldestUnconfirmedVscRequest) Size() (n int) { return n } -<<<<<<< HEAD func (m *QueryConsumerChainOptedInValidatorsResponse) Size() (n int) { -======= -func (m *QueryOldestUnconfirmedVscResponse) Size() (n int) { ->>>>>>> main if m == nil { return 0 } var l int _ = l -<<<<<<< HEAD if len(m.ValidatorsProviderAddresses) > 0 { for _, s := range m.ValidatorsProviderAddresses { l = len(s) @@ -3882,9 +3819,30 @@ func (m *QueryValidatorConsumerCommissionRateResponse) Size() (n int) { var l int _ = l l = m.Rate.Size() -======= + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryOldestUnconfirmedVscRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ChainId) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryOldestUnconfirmedVscResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l l = m.VscSendTimestamp.Size() ->>>>>>> main n += 1 + l + sovQuery(uint64(l)) return n } @@ -5978,11 +5936,7 @@ func (m *QueryParamsResponse) Unmarshal(dAtA []byte) error { } return nil } -<<<<<<< HEAD func (m *QueryConsumerChainOptedInValidatorsRequest) Unmarshal(dAtA []byte) error { -======= -func (m *QueryOldestUnconfirmedVscRequest) Unmarshal(dAtA []byte) error { ->>>>>>> main l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -6005,17 +5959,10 @@ func (m *QueryOldestUnconfirmedVscRequest) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { -<<<<<<< HEAD return fmt.Errorf("proto: QueryConsumerChainOptedInValidatorsRequest: wiretype end group for non-group") } if fieldNum <= 0 { return fmt.Errorf("proto: QueryConsumerChainOptedInValidatorsRequest: illegal tag %d (wire type %d)", fieldNum, wire) -======= - return fmt.Errorf("proto: QueryOldestUnconfirmedVscRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryOldestUnconfirmedVscRequest: illegal tag %d (wire type %d)", fieldNum, wire) ->>>>>>> main } switch fieldNum { case 1: @@ -6071,11 +6018,7 @@ func (m *QueryOldestUnconfirmedVscRequest) Unmarshal(dAtA []byte) error { } return nil } -<<<<<<< HEAD func (m *QueryConsumerChainOptedInValidatorsResponse) Unmarshal(dAtA []byte) error { -======= -func (m *QueryOldestUnconfirmedVscResponse) Unmarshal(dAtA []byte) error { ->>>>>>> main l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -6098,30 +6041,17 @@ func (m *QueryOldestUnconfirmedVscResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { -<<<<<<< HEAD return fmt.Errorf("proto: QueryConsumerChainOptedInValidatorsResponse: wiretype end group for non-group") } if fieldNum <= 0 { return fmt.Errorf("proto: QueryConsumerChainOptedInValidatorsResponse: illegal tag %d (wire type %d)", fieldNum, wire) -======= - return fmt.Errorf("proto: QueryOldestUnconfirmedVscResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryOldestUnconfirmedVscResponse: illegal tag %d (wire type %d)", fieldNum, wire) ->>>>>>> main } switch fieldNum { case 1: if wireType != 2 { -<<<<<<< HEAD return fmt.Errorf("proto: wrong wireType = %d for field ValidatorsProviderAddresses", wireType) } var stringLen uint64 -======= - return fmt.Errorf("proto: wrong wireType = %d for field VscSendTimestamp", wireType) - } - var msglen int ->>>>>>> main for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowQuery @@ -6131,34 +6061,22 @@ func (m *QueryOldestUnconfirmedVscResponse) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ -<<<<<<< HEAD stringLen |= uint64(b&0x7F) << shift -======= - msglen |= int(b&0x7F) << shift ->>>>>>> main if b < 0x80 { break } } -<<<<<<< HEAD intStringLen := int(stringLen) if intStringLen < 0 { return ErrInvalidLengthQuery } postIndex := iNdEx + intStringLen -======= - if msglen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + msglen ->>>>>>> main if postIndex < 0 { return ErrInvalidLengthQuery } if postIndex > l { return io.ErrUnexpectedEOF } -<<<<<<< HEAD m.ValidatorsProviderAddresses = append(m.ValidatorsProviderAddresses, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex default: @@ -6520,9 +6438,171 @@ func (m *QueryValidatorConsumerCommissionRateResponse) Unmarshal(dAtA []byte) er return io.ErrUnexpectedEOF } if err := m.Rate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { -======= + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryOldestUnconfirmedVscRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryOldestUnconfirmedVscRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryOldestUnconfirmedVscRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", 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.ChainId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryOldestUnconfirmedVscResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryOldestUnconfirmedVscResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryOldestUnconfirmedVscResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field VscSendTimestamp", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } if err := m.VscSendTimestamp.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { ->>>>>>> main return err } iNdEx = postIndex diff --git a/x/ccv/provider/types/query.pb.gw.go b/x/ccv/provider/types/query.pb.gw.go index 874c92c1bf..e44ddd00f5 100644 --- a/x/ccv/provider/types/query.pb.gw.go +++ b/x/ccv/provider/types/query.pb.gw.go @@ -321,7 +321,6 @@ func local_request_Query_QueryParams_0(ctx context.Context, marshaler runtime.Ma } -<<<<<<< HEAD var ( filter_Query_QueryConsumerChainOptedInValidators_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} ) @@ -338,36 +337,10 @@ func request_Query_QueryConsumerChainOptedInValidators_0(ctx context.Context, ma } msg, err := client.QueryConsumerChainOptedInValidators(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) -======= -func request_Query_QueryOldestUnconfirmedVsc_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryOldestUnconfirmedVscRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["chain_id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "chain_id") - } - - protoReq.ChainId, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "chain_id", err) - } - - msg, err := client.QueryOldestUnconfirmedVsc(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) ->>>>>>> main return msg, metadata, err } -<<<<<<< HEAD func local_request_Query_QueryConsumerChainOptedInValidators_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq QueryConsumerChainOptedInValidatorsRequest var metadata runtime.ServerMetadata @@ -452,7 +425,37 @@ func local_request_Query_QueryValidatorConsumerCommissionRate_0(ctx context.Cont } msg, err := server.QueryValidatorConsumerCommissionRate(ctx, &protoReq) -======= + return msg, metadata, err + +} + +func request_Query_QueryOldestUnconfirmedVsc_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryOldestUnconfirmedVscRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["chain_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "chain_id") + } + + protoReq.ChainId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "chain_id", err) + } + + msg, err := client.QueryOldestUnconfirmedVsc(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + func local_request_Query_QueryOldestUnconfirmedVsc_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq QueryOldestUnconfirmedVscRequest var metadata runtime.ServerMetadata @@ -476,7 +479,6 @@ func local_request_Query_QueryOldestUnconfirmedVsc_0(ctx context.Context, marsha } msg, err := server.QueryOldestUnconfirmedVsc(ctx, &protoReq) ->>>>>>> main return msg, metadata, err } @@ -740,11 +742,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) -<<<<<<< HEAD mux.Handle("GET", pattern_Query_QueryConsumerChainOptedInValidators_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { -======= - mux.Handle("GET", pattern_Query_QueryOldestUnconfirmedVsc_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ->>>>>>> main ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream @@ -755,11 +753,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } -<<<<<<< HEAD resp, md, err := local_request_Query_QueryConsumerChainOptedInValidators_0(rctx, inboundMarshaler, server, req, pathParams) -======= - resp, md, err := local_request_Query_QueryOldestUnconfirmedVsc_0(rctx, inboundMarshaler, server, req, pathParams) ->>>>>>> main md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { @@ -767,7 +761,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv return } -<<<<<<< HEAD forward_Query_QueryConsumerChainOptedInValidators_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) @@ -815,9 +808,29 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv } forward_Query_QueryValidatorConsumerCommissionRate_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) -======= + + }) + + mux.Handle("GET", pattern_Query_QueryOldestUnconfirmedVsc_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_QueryOldestUnconfirmedVsc_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + forward_Query_QueryOldestUnconfirmedVsc_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) ->>>>>>> main }) @@ -1082,11 +1095,7 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) -<<<<<<< HEAD mux.Handle("GET", pattern_Query_QueryConsumerChainOptedInValidators_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { -======= - mux.Handle("GET", pattern_Query_QueryOldestUnconfirmedVsc_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ->>>>>>> main ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) @@ -1095,18 +1104,13 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } -<<<<<<< HEAD resp, md, err := request_Query_QueryConsumerChainOptedInValidators_0(rctx, inboundMarshaler, client, req, pathParams) -======= - resp, md, err := request_Query_QueryOldestUnconfirmedVsc_0(rctx, inboundMarshaler, client, req, pathParams) ->>>>>>> main ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } -<<<<<<< HEAD forward_Query_QueryConsumerChainOptedInValidators_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) @@ -1148,9 +1152,26 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie } forward_Query_QueryValidatorConsumerCommissionRate_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) -======= + + }) + + mux.Handle("GET", pattern_Query_QueryOldestUnconfirmedVsc_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_QueryOldestUnconfirmedVsc_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + forward_Query_QueryOldestUnconfirmedVsc_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) ->>>>>>> main }) @@ -1180,15 +1201,13 @@ var ( pattern_Query_QueryParams_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"interchain_security", "ccv", "provider", "params"}, "", runtime.AssumeColonVerbOpt(false))) -<<<<<<< HEAD pattern_Query_QueryConsumerChainOptedInValidators_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"interchain_security", "ccv", "provider", "opted_in_validators"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_QueryConsumerChainsValidatorHasToValidate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"interchain_security", "ccv", "provider", "consumer_chains_per_validator"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_QueryValidatorConsumerCommissionRate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"interchain_security", "ccv", "provider", "consumer_commission_rate"}, "", runtime.AssumeColonVerbOpt(false))) -======= + pattern_Query_QueryOldestUnconfirmedVsc_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"interchain_security", "ccv", "provider", "oldest_unconfirmed_vsc", "chain_id"}, "", runtime.AssumeColonVerbOpt(false))) ->>>>>>> main ) var ( @@ -1214,13 +1233,11 @@ var ( forward_Query_QueryParams_0 = runtime.ForwardResponseMessage -<<<<<<< HEAD forward_Query_QueryConsumerChainOptedInValidators_0 = runtime.ForwardResponseMessage forward_Query_QueryConsumerChainsValidatorHasToValidate_0 = runtime.ForwardResponseMessage forward_Query_QueryValidatorConsumerCommissionRate_0 = runtime.ForwardResponseMessage -======= + forward_Query_QueryOldestUnconfirmedVsc_0 = runtime.ForwardResponseMessage ->>>>>>> main ) From 42787803086cd5581e32476a72f1207da1024c36 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Tue, 23 Apr 2024 11:07:02 +0200 Subject: [PATCH 052/110] Port RELEASE_NOTES --- RELEASE_NOTES.md | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 414c6e3437..3a172a79c4 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,17 +1,37 @@ -# Replicated Security v4.0.0 Release Notes + + +# Replicated Security Release Notes + + +❗ ***Note this release is ONLY relevant to *** ## 📝 Changelog -Check out the [changelog](https://github.com/cosmos/interchain-security/blob/v4.0.0/CHANGELOG.md) for a list of relevant changes or [compare all changes](https://github.com/cosmos/interchain-security/compare/v3.3.0...v4.0.0) from last release. +** REMOVE THE LINE BELOW TO ENABLE THE MARKDOWN LINK CHECKER FOR RELEASE ** + + +Check out the [changelog](https://github.com/cosmos/interchain-security/blob//CHANGELOG.md) for a list of relevant changes or [compare all changes](https://github.com/cosmos/interchain-security/compare/release/...) from last release. Refer to the [upgrading guide](https://github.com/cosmos/interchain-security/blob/release//UPGRADING.md) when migrating from `` to ``. +** REMOVE THE LINE BELOW TO ENABLE THE MARKDOWN LINK CHECKER FOR RELEASE ** + ## 🚀 Highlights -This release introduces the following noteworthy changes: + -- It sets the minimum required version of Go to `1.21`. -- It adds the provider-side changes for jail throttling with retries and, as a result, it fully enables the jail throttling with retries feature (cf. [ADR 008](https://github.com/cosmos/interchain-security/blob/release/v3.2.x/docs/docs/adrs/adr-008-throttle-retries.md)). -- Fixes a bug in the soft opt-out protocol -- it avoids jailing validators immediately once they can no longer opt-out from validating consumer chains. -- Fixes a bug the validation of VSCPackets caused by marshaling to string using Bech32. +## ❤️ Contributors + +* Informal Systems ([@informalinc](https://twitter.com/informalinc)) + +This list is non-exhaustive and ordered alphabetically. +Thank you to everyone who contributed to this release! From 7c351837f1c35fb866ac72fc0fc85a0aa1aca9bb Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Tue, 23 Apr 2024 11:11:39 +0200 Subject: [PATCH 053/110] Fix merge for tests --- x/ccv/provider/keeper/relay_test.go | 9 +-------- .../provider/keeper/validator_set_update_test.go | 16 +++------------- 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/x/ccv/provider/keeper/relay_test.go b/x/ccv/provider/keeper/relay_test.go index ebb99c9bf5..5afbf70248 100644 --- a/x/ccv/provider/keeper/relay_test.go +++ b/x/ccv/provider/keeper/relay_test.go @@ -12,18 +12,15 @@ import ( "cosmossdk.io/math" -<<<<<<< HEAD codectypes "github.com/cosmos/cosmos-sdk/codec/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" -======= - cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" ->>>>>>> main sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" abci "github.com/cometbft/cometbft/abci/types" + "github.com/cosmos/interchain-security/v4/testutil/crypto" cryptotestutil "github.com/cosmos/interchain-security/v4/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" @@ -771,14 +768,10 @@ func TestEndBlockVSU(t *testing.T) { var lastValidators []stakingtypes.Validator var valAddresses []sdk.ValAddress for i := 0; i < 4; i++ { -<<<<<<< HEAD validator := crypto.NewCryptoIdentityFromIntSeed(i).SDKStakingValidator() lastValidators = append(lastValidators, validator) valAddresses = append(valAddresses, validator.GetOperator()) mocks.MockStakingKeeper.EXPECT().GetLastValidatorPower(gomock.Any(), validator.GetOperator()).Return(int64(i + 1)).AnyTimes() -======= - lastValidators = append(lastValidators, cryptotestutil.NewCryptoIdentityFromIntSeed(i).SDKStakingValidator()) ->>>>>>> main } mocks.MockStakingKeeper.EXPECT().GetLastValidators(gomock.Any()).Return(lastValidators).AnyTimes() diff --git a/x/ccv/provider/keeper/validator_set_update_test.go b/x/ccv/provider/keeper/validator_set_update_test.go index 3e4e2cbb99..22fad61288 100644 --- a/x/ccv/provider/keeper/validator_set_update_test.go +++ b/x/ccv/provider/keeper/validator_set_update_test.go @@ -124,23 +124,12 @@ func createStakingValidator(ctx sdk.Context, mocks testkeeper.MockedKeepers, ind mocks.MockStakingKeeper.EXPECT(). GetLastValidatorPower(ctx, providerValidatorAddr).Return(power).AnyTimes() -<<<<<<< HEAD return stakingtypes.Validator{ OperatorAddress: providerValidatorAddr.String(), ConsensusPubkey: pkAny, -======= - var providerValidatorAddr sdk.ValAddress = providerAddr.Address.Bytes() - - mocks.MockStakingKeeper.EXPECT(). - GetLastValidatorPower(ctx, providerValidatorAddr).Return(power).AnyTimes() - - return stakingtypes.Validator{ - OperatorAddress: providerValidatorAddr.String(), - ConsensusPubkey: pkAny, - } ->>>>>>> main } } + func TestDiff(t *testing.T) { // In what follows we create 6 validators: A, B, C, D, E, and F where currentValidators = {A, B, C, D, E} // and nextValidators = {B, C, D, E, F}. For the validators {B, C, D, E} in the intersection we have: @@ -402,7 +391,8 @@ func TestComputeNextEpochConsumerValSetConsiderOnlyOptIn(t *testing.T) { expectedValAConsumerValidator := types.ConsumerValidator{ ProviderConsAddr: types.NewProviderConsAddress(valAConsAddr).Address.Bytes(), Power: 1, - ConsumerPublicKey: &valAPublicKey} + ConsumerPublicKey: &valAPublicKey, + } expectedValidators = append(expectedValidators, expectedValAConsumerValidator) // create a staking validator B that has set a consumer public key From 411ca4d5c778f617b7df00a62975e1f1914e20f0 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Tue, 23 Apr 2024 11:12:44 +0200 Subject: [PATCH 054/110] Merge declaration and assignment --- x/ccv/provider/keeper/validator_set_update_test.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/x/ccv/provider/keeper/validator_set_update_test.go b/x/ccv/provider/keeper/validator_set_update_test.go index 22fad61288..6883fc3b50 100644 --- a/x/ccv/provider/keeper/validator_set_update_test.go +++ b/x/ccv/provider/keeper/validator_set_update_test.go @@ -117,9 +117,7 @@ func createStakingValidator(ctx sdk.Context, mocks testkeeper.MockedKeepers, ind providerAddr := types.NewProviderConsAddress(consAddr) pk, _ := cryptocodec.FromTmPubKeyInterface(providerConsPubKey) pkAny, _ := codectypes.NewAnyWithValue(pk) - - var providerValidatorAddr sdk.ValAddress - providerValidatorAddr = providerAddr.Address.Bytes() + providerValidatorAddr := sdk.ValAddress(providerAddr.Address.Bytes()) mocks.MockStakingKeeper.EXPECT(). GetLastValidatorPower(ctx, providerValidatorAddr).Return(power).AnyTimes() From 62edffe00f59573709166d38d22ee1bcab5aa973 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Tue, 23 Apr 2024 11:17:44 +0200 Subject: [PATCH 055/110] Clean up model files --- tests/mbt/model/identify_violation.sh | 77 --------------------------- tests/mbt/model/run_invariants.sh | 6 --- 2 files changed, 83 deletions(-) delete mode 100755 tests/mbt/model/identify_violation.sh delete mode 100755 tests/mbt/model/run_invariants.sh diff --git a/tests/mbt/model/identify_violation.sh b/tests/mbt/model/identify_violation.sh deleted file mode 100755 index efa65c7822..0000000000 --- a/tests/mbt/model/identify_violation.sh +++ /dev/null @@ -1,77 +0,0 @@ -#!/bin/bash - -# Check if a seed is provided -if [ $# -eq 0 ]; then - echo "Usage: $0 " - exit 1 -fi - -# The seed provided as the first argument -seed="$1" - -# The command from which to extract invariants and the model file (paste your command inside the single quotes) -command='quint run --invariant "all{ValidatorUpdatesArePropagatedInv,ValidatorSetHasExistedInv,SameVscPacketsInv,MatureOnTimeInv,EventuallyMatureOnProviderInv}" ccv_model.qnt --max-steps 200 --max-samples 200' - -# Extract the invariants part of the command -invariants_string=$(echo $command | awk -F'--invariant "' '{print $2}' | awk -F'" ' '{print $1}') -# Extract the model file from the command -model_file=$(echo $command | awk '{for(i=1;i<=NF;i++) if ($i ~ /\.qnt$/) print $(i)}') - -# Extract max-steps, max-samples, and --step values if they exist -max_steps=$(echo $command | grep -oP '(?<=--max-steps )[^ ]*' || echo "") -max_samples=$(echo $command | grep -oP '(?<=--max-samples )[^ ]*' || echo "") -step_value=$(echo $command | grep -oP '(?<=--step )[^ ]*' || echo "") - -# Construct optional arguments -optional_args="" -if [ -n "$max_steps" ]; then - optional_args+="--max-steps $max_steps " -fi -if [ -n "$max_samples" ]; then - optional_args+="--max-samples $max_samples " -fi -if [ -n "$step_value" ]; then - optional_args+="--step $step_value " -fi - -# Remove "all{" and "}" from the string, then split by "," -invariants=$(echo $invariants_string | sed 's/all{//g' | sed 's/}//g' | tr ',' '\n') - -# Store the results -violated_invariants=() -nonviolated_invariants=() - -# Loop over each invariant -while read -r invariant; do - if [ -z "$invariant" ]; then - continue - fi - - echo "Checking invariant: $invariant with model file: $model_file" - - # Run the Quint command with the current invariant, model file, and optional arguments - quint_cmd="quint run --invariant \"$invariant\" $model_file $optional_args--seed=$seed" - echo "Executing $quint_cmd" - result=$(eval $quint_cmd) - - # Check if the invariant was violated - if [[ $result == *"[violation]"* ]]; then - echo "Invariant violated: $invariant" - violated_invariants+=("$invariant") - else - echo "Invariant not violated: $invariant" - nonviolated_invariants+=("$invariant") - fi -done <<< "$invariants" - -# Summarize the results -echo "Summary:" -echo "Violated invariants:" -for invariant in "${violated_invariants[@]}"; do - echo "- $invariant" -done - -echo "Non-violated invariants:" -for invariant in "${nonviolated_invariants[@]}"; do - echo "- $invariant" -done diff --git a/tests/mbt/model/run_invariants.sh b/tests/mbt/model/run_invariants.sh deleted file mode 100755 index bda58d80f6..0000000000 --- a/tests/mbt/model/run_invariants.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -quint test ccv_model.qnt -quint test ccv_test.qnt -quint run --invariant "all{ValidatorUpdatesArePropagatedInv,ValidatorSetHasExistedInv,SameVscPacketsInv,MatureOnTimeInv,EventuallyMatureOnProviderInv}" ccv_model.qnt --max-steps 200 --max-samples 200 -quint run --invariant "all{ValidatorUpdatesArePropagatedKeyAssignmentInv,ValidatorSetHasExistedKeyAssignmentInv,SameVscPacketsKeyAssignmentInv,MatureOnTimeInv,EventuallyMatureOnProviderInv,KeyAssignmentRulesInv}" ccv_model.qnt --step stepKeyAssignment --max-steps 200 --max-samples 200 From 4e51c65d2cd8fe49b96922ce253da1aecdd94a85 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Tue, 23 Apr 2024 11:19:04 +0200 Subject: [PATCH 056/110] Add pss tests to MBT readme --- tests/mbt/model/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/mbt/model/README.md b/tests/mbt/model/README.md index 2c9e07516c..407224bd7a 100644 --- a/tests/mbt/model/README.md +++ b/tests/mbt/model/README.md @@ -82,6 +82,7 @@ traces are not very useful for testing. To run unit tests, run ``` quint test ccv_test.qnt; +quint test ccv_pss_test.qnt; quint test ccv_model.qnt ``` From f2125985902bdf461e2ee3513b9e17aae9097400 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Tue, 23 Apr 2024 11:27:53 +0200 Subject: [PATCH 057/110] Restore MsgSubmitConsumerDoubleVoting handler --- x/ccv/provider/handler.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/x/ccv/provider/handler.go b/x/ccv/provider/handler.go index d361ec34f7..8232ef3b6c 100644 --- a/x/ccv/provider/handler.go +++ b/x/ccv/provider/handler.go @@ -23,6 +23,9 @@ func NewHandler(k *keeper.Keeper) sdk.Handler { case *types.MsgSubmitConsumerMisbehaviour: res, err := msgServer.SubmitConsumerMisbehaviour(sdk.WrapSDKContext(ctx), msg) return sdk.WrapServiceResult(ctx, res, err) + case *types.MsgSubmitConsumerDoubleVoting: + res, err := msgServer.SubmitConsumerDoubleVoting(sdk.WrapSDKContext(ctx), msg) + return sdk.WrapServiceResult(ctx, res, err) case *types.MsgOptIn: res, err := msgServer.OptIn(sdk.WrapSDKContext(ctx), msg) return sdk.WrapServiceResult(ctx, res, err) From 49d7e84c95bc1a4e5079175248e3b2848ba22c27 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Tue, 23 Apr 2024 11:32:49 +0200 Subject: [PATCH 058/110] Remove local driver files --- tests/mbt/driver/determiniser.sh | 22 -- tests/mbt/driver/extract_states.sh | 13 - tests/mbt/driver/get_value.sh | 13 - tests/mbt/driver/out.txt | 387 ----------------------------- 4 files changed, 435 deletions(-) delete mode 100755 tests/mbt/driver/determiniser.sh delete mode 100755 tests/mbt/driver/extract_states.sh delete mode 100755 tests/mbt/driver/get_value.sh delete mode 100644 tests/mbt/driver/out.txt diff --git a/tests/mbt/driver/determiniser.sh b/tests/mbt/driver/determiniser.sh deleted file mode 100755 index 4904453e42..0000000000 --- a/tests/mbt/driver/determiniser.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -# Replace 'your_command_here' with your actual command, ensuring it's properly quoted if it contains spaces or special characters -COMMAND='go test -v' - -EXPECTED_OUT="Running traces from the traces folder done" - - -# Loop 1000 times -for i in {1..100} -do - output=$($COMMAND) - - # Compare the output with the initial output - if ! echo "$output" | grep -q "$EXPECTED_OUT"; then - echo $output - echo "Error: Output at iteration $i does not contain the expected line." - exit 1 - fi -done - -echo "All outputs were consistent across 1000 runs." diff --git a/tests/mbt/driver/extract_states.sh b/tests/mbt/driver/extract_states.sh deleted file mode 100755 index 3e6f1b66dc..0000000000 --- a/tests/mbt/driver/extract_states.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -# Assign the command line arguments to variables -filename=$1 -start_index=$2 -end_index=$3 - -# Loop from start_index to end_index -for ((index=$start_index; index<=$end_index; index++)) -do - # Use jq to extract the state with the current index and save it to a file named ".json" - jq --argjson idx $index '.states[] | select(."#meta".index == $idx)' $filename > "${index}.json" -done diff --git a/tests/mbt/driver/get_value.sh b/tests/mbt/driver/get_value.sh deleted file mode 100755 index d745bc6b06..0000000000 --- a/tests/mbt/driver/get_value.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -# Assign the command line arguments to variables -filename=$1 -start_index=$2 -end_index=$3 - -# Loop from start_index to end_index -for ((index=$start_index; index<=$end_index; index++)) -do - # Use jq to extract the index and the consumersWithPowerChangesInThisEpoch value and print them - jq --argjson idx $index '.states[] | select(."#meta".index == $idx) | .currentState.providerState.consumersWithAddrAssignmentChangesInThisEpoch | "Index: \($idx) Value: \(.)"' $filename -done diff --git a/tests/mbt/driver/out.txt b/tests/mbt/driver/out.txt deleted file mode 100644 index 5c0d69f74c..0000000000 --- a/tests/mbt/driver/out.txt +++ /dev/null @@ -1,387 +0,0 @@ -=== RUN TestMBT -Running trace: traces/bound_mat/trace_0.itf - mbt_test.go:58: 🟡 Testing trace traces/bound_mat/trace_0.itf - mbt_test.go:58: Reading params... - mbt_test.go:58: Chains are: [consumer1 consumer2 consumer3 provider] - mbt_test.go:58: Creating coordinator - setup.go:420: Creating provider chain - mbt_test.go:58: Started chains - mbt_test.go:58: Reading the trace... - mbt_test.go:58: Height modulo epoch length: 3 - mbt_test.go:58: Model height modulo epoch length: 0 - mbt_test.go:58: Reading state 0 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: Initializing... - mbt_test.go:58: Height modulo epoch length: 3 - mbt_test.go:58: Model height modulo epoch length: 0 - mbt_test.go:58: Reading state 1 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: Changing provider voting power of node10 by 50 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 1 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 3 - mbt_test.go:58: Model height modulo epoch length: 1 - mbt_test.go:58: Reading state 2 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForProvider 86400 [{consumer1} {consumer3}] [] - setup.go:459: Starting consumer consumer1 - setup.go:464: Creating consumer chain consumer1 - setup.go:459: Starting consumer consumer3 - setup.go:464: Creating consumer chain consumer3 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 2 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 31 - mbt_test.go:58: Model height modulo epoch length: 1 - mbt_test.go:58: Reading state 3 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: Changing provider voting power of node6 by 50 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 3 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 31 - mbt_test.go:58: Model height modulo epoch length: 2 - mbt_test.go:58: Reading state 4 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForProvider 86400 [] [] - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 4 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 33 - mbt_test.go:58: Model height modulo epoch length: 2 - mbt_test.go:58: Reading state 5 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: Changing provider voting power of node1 by 50 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 5 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 33 - mbt_test.go:58: Model height modulo epoch length: 0 - mbt_test.go:58: Reading state 6 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForProvider 601200 [] [] - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 6 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 2 - mbt_test.go:58: Model height modulo epoch length: 1 - mbt_test.go:58: Reading state 7 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForProvider 86400 [{consumer2}] [] - setup.go:459: Starting consumer consumer2 - setup.go:464: Creating consumer chain consumer2 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 7 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 17 - mbt_test.go:58: Model height modulo epoch length: 2 - mbt_test.go:58: Reading state 8 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForProvider 1 [] [] - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 8 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 19 - mbt_test.go:58: Model height modulo epoch length: 2 - mbt_test.go:58: Reading state 9 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: DeliverVscPacket consumer1 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 9 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 19 - mbt_test.go:58: Model height modulo epoch length: 2 - mbt_test.go:58: Reading state 10 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: Changing provider voting power of node1 by 50 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 10 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 19 - mbt_test.go:58: Model height modulo epoch length: 2 - mbt_test.go:58: Reading state 11 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForConsumer consumer1 86400 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 11 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 19 - mbt_test.go:58: Model height modulo epoch length: 0 - mbt_test.go:58: Reading state 12 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForProvider 86400 [] [] - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 12 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 2 - mbt_test.go:58: Model height modulo epoch length: 0 - mbt_test.go:58: Reading state 13 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: DeliverVscPacket consumer3 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 13 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 2 - mbt_test.go:58: Model height modulo epoch length: 0 - mbt_test.go:58: Reading state 14 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForConsumer consumer2 1 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 14 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 2 - mbt_test.go:58: Model height modulo epoch length: 0 - mbt_test.go:58: Reading state 15 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForConsumer consumer2 1 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 15 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 2 - mbt_test.go:58: Model height modulo epoch length: 1 - mbt_test.go:58: Reading state 16 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForProvider 1 [] [] - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 16 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 4 - mbt_test.go:58: Model height modulo epoch length: 1 - mbt_test.go:58: Reading state 17 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: ConsumerInitiatedSlash consumer1 node8 0 false - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 17 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 4 - mbt_test.go:58: Model height modulo epoch length: 1 - mbt_test.go:58: Reading state 18 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForConsumer consumer1 1 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 18 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 4 - mbt_test.go:58: Model height modulo epoch length: 2 - mbt_test.go:58: Reading state 19 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForProvider 1 [] [] - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 19 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 6 - mbt_test.go:58: Model height modulo epoch length: 2 - mbt_test.go:58: Reading state 20 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: DeliverVscPacket consumer1 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 20 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 6 - mbt_test.go:58: Model height modulo epoch length: 2 - mbt_test.go:58: Reading state 21 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForConsumer consumer1 601200 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 21 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 6 - mbt_test.go:58: Model height modulo epoch length: 2 - mbt_test.go:58: Reading state 22 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForConsumer consumer2 1 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 22 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 6 - mbt_test.go:58: Model height modulo epoch length: 2 - mbt_test.go:58: Reading state 23 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: Changing provider voting power of node3 by -50 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 23 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 6 - mbt_test.go:58: Model height modulo epoch length: 0 - mbt_test.go:58: Reading state 24 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForProvider 86400 [] [] - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 24 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 2 - mbt_test.go:58: Model height modulo epoch length: 0 - mbt_test.go:58: Reading state 25 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: DeliverVscPacket consumer1 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 25 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 2 - mbt_test.go:58: Model height modulo epoch length: 1 - mbt_test.go:58: Reading state 26 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForProvider 86400 [] [] - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 26 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 4 - mbt_test.go:58: Model height modulo epoch length: 2 - mbt_test.go:58: Reading state 27 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForProvider 1 [] [] - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 27 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 6 - mbt_test.go:58: Model height modulo epoch length: 0 - mbt_test.go:58: Reading state 28 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForProvider 1 [] [] - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 28 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 2 - mbt_test.go:58: Model height modulo epoch length: 0 - mbt_test.go:58: Reading state 29 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: DeliverVscPacket consumer2 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 29 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 2 - mbt_test.go:58: Model height modulo epoch length: 1 - mbt_test.go:58: Reading state 30 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForProvider 1 [] [] - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 30 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 4 - mbt_test.go:58: Model height modulo epoch length: 1 - mbt_test.go:58: Reading state 31 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForConsumer consumer3 86400 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 31 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 4 - mbt_test.go:58: Model height modulo epoch length: 1 - mbt_test.go:58: Reading state 32 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForConsumer consumer2 1 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 32 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 4 - mbt_test.go:58: Model height modulo epoch length: 1 - mbt_test.go:58: Reading state 33 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForConsumer consumer1 86400 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 33 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 4 - mbt_test.go:58: Model height modulo epoch length: 2 - mbt_test.go:58: Reading state 34 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForProvider 1 [] [] - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 34 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 6 - mbt_test.go:58: Model height modulo epoch length: 0 - mbt_test.go:58: Reading state 35 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForProvider 1 [] [] - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 35 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 2 - mbt_test.go:58: Model height modulo epoch length: 1 - mbt_test.go:58: Reading state 36 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForProvider 86400 [] [] - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 36 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 4 - mbt_test.go:58: Model height modulo epoch length: 2 - mbt_test.go:58: Reading state 37 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForProvider 1 [] [] - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 37 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 6 - mbt_test.go:58: Model height modulo epoch length: 2 - mbt_test.go:58: Reading state 38 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForConsumer consumer1 86400 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 38 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 6 - mbt_test.go:58: Model height modulo epoch length: 2 - mbt_test.go:58: Reading state 39 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: ConsumerInitiatedSlash consumer1 node8 1 true - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 39 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 6 - mbt_test.go:58: Model height modulo epoch length: 0 - mbt_test.go:58: Reading state 40 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForProvider 1 [] [] - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 40 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 2 - mbt_test.go:58: Model height modulo epoch length: 1 - mbt_test.go:58: Reading state 41 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForProvider 1 [] [] - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 41 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 4 - mbt_test.go:58: Model height modulo epoch length: 1 - mbt_test.go:58: Reading state 42 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: DeliverPacketToProvider consumer1 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 42 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 4 - mbt_test.go:58: Model height modulo epoch length: 1 - mbt_test.go:58: Reading state 43 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: ConsumerInitiatedSlash consumer3 node7 0 false - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 43 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 4 - mbt_test.go:58: Model height modulo epoch length: 1 - mbt_test.go:58: Reading state 44 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: Changing provider voting power of node4 by -50 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 44 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 4 - mbt_test.go:58: Model height modulo epoch length: 1 - mbt_test.go:58: Reading state 45 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForConsumer consumer2 86400 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 45 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 4 - mbt_test.go:58: Model height modulo epoch length: 1 - mbt_test.go:58: Reading state 46 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: Changing provider voting power of node7 by 50 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 46 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 4 - mbt_test.go:58: Model height modulo epoch length: 1 - mbt_test.go:58: Reading state 47 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForConsumer consumer3 601200 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 47 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 4 - mbt_test.go:58: Model height modulo epoch length: 1 - mbt_test.go:58: Reading state 48 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForConsumer consumer3 1 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 48 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 4 - mbt_test.go:58: Model height modulo epoch length: 1 - mbt_test.go:58: Reading state 49 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: Changing provider voting power of node3 by -50 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 49 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 4 - mbt_test.go:58: Model height modulo epoch length: 1 - mbt_test.go:58: Reading state 50 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: DeliverVscPacket consumer3 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 50 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 4 - mbt_test.go:58: Model height modulo epoch length: 2 - mbt_test.go:58: Reading state 51 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForProvider 601200 [] [] - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 51 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 6 - mbt_test.go:58: Model height modulo epoch length: 2 - mbt_test.go:58: Reading state 52 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: DeliverVscPacket consumer3 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 52 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 6 - mbt_test.go:58: Model height modulo epoch length: 2 - mbt_test.go:58: Reading state 53 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: DeliverPacketToProvider consumer3 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 53 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 6 - mbt_test.go:58: Model height modulo epoch length: 0 - mbt_test.go:58: Reading state 54 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForProvider 86400 [] [] - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 54 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 2 - mbt_test.go:58: Model height modulo epoch length: 0 - mbt_test.go:58: Reading state 55 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForConsumer consumer3 1 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 55 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 2 - mbt_test.go:58: Model height modulo epoch length: 1 - mbt_test.go:58: Reading state 56 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForProvider 1 [] [{consumer3}] - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 56 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 4 - mbt_test.go:58: Model height modulo epoch length: 1 - mbt_test.go:58: Reading state 57 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: ConsumerInitiatedSlash consumer2 node2 1 true - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: State 57 of trace traces/bound_mat/trace_0.itf is ok! - mbt_test.go:58: Height modulo epoch length: 4 - mbt_test.go:58: Model height modulo epoch length: 1 - mbt_test.go:58: Reading state 58 of trace traces/bound_mat/trace_0.itf - mbt_test.go:58: EndAndBeginBlockForConsumer consumer1 86400 - mbt_test.go:58: Comparing model state to actual state... - mbt_test.go:58: - Error Trace: /Users/offtermatt/projects/interchain-security/tests/mbt/driver/mbt_test.go:693 - /Users/offtermatt/projects/interchain-security/tests/mbt/driver/mbt_test.go:673 - /Users/offtermatt/projects/interchain-security/tests/mbt/driver/mbt_test.go:521 - /Users/offtermatt/projects/interchain-security/tests/mbt/driver/mbt_test.go:58 - /Users/offtermatt/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.21.6.darwin-arm64/src/path/filepath/path.go:477 - /Users/offtermatt/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.21.6.darwin-arm64/src/path/filepath/path.go:501 - /Users/offtermatt/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.21.6.darwin-arm64/src/path/filepath/path.go:501 - /Users/offtermatt/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.21.6.darwin-arm64/src/path/filepath/path.go:572 - /Users/offtermatt/projects/interchain-security/tests/mbt/driver/mbt_test.go:45 - Error: Not equal: - expected: 0 - actual : 1 - Test: TestMBT - Messages: Packet queue sizes do not match for sender consumer1, receiver provider. - model: [] - actual: ["{\"type\":\"CONSUMER_PACKET_TYPE_SLASH\",\"slashPacketData\":{\"validator\":{\"address\":\"1NkRTLUPQRCVz3VNos06UxrGjgQ=\",\"power\":\"100\"},\"valset_update_id\":\"3\",\"infraction\":\"INFRACTION_TYPE_DOWNTIME\"}}"] ---- FAIL: TestMBT (3.26s) -FAIL -exit status 1 -FAIL github.com/cosmos/interchain-security/v4/tests/mbt/driver 3.965s From 7f0891ae95029ddedaa16046ed1e81d60667382e Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Tue, 23 Apr 2024 11:35:56 +0200 Subject: [PATCH 059/110] Remove Quint guidelines --- tests/mbt/model/HOW_TO_WRITE_QUINT.md | 303 -------------------------- 1 file changed, 303 deletions(-) delete mode 100644 tests/mbt/model/HOW_TO_WRITE_QUINT.md diff --git a/tests/mbt/model/HOW_TO_WRITE_QUINT.md b/tests/mbt/model/HOW_TO_WRITE_QUINT.md deleted file mode 100644 index 5bc56213ad..0000000000 --- a/tests/mbt/model/HOW_TO_WRITE_QUINT.md +++ /dev/null @@ -1,303 +0,0 @@ -# How to Quint well - -This document is supposed to summarize my experience with writing Quint. -It's meant to be high-level. -If one wants to modify the Quint model here, it is probably a good idea to read this document, to -a) understand why the model is currently structured as is; and -b) understand how to efficiently make changes - -This assumes you have a good understanding of the syntax of Quint. -E.g., you know what a "step" action is. - -### Functional layer and state machine layer separation - -The most important thing I have learned about writing Quint models so far: -*Split the functional layer and the state machine layer* - -The basic pattern looks like this: - -Basic functional layer (here, ccv.qnt) -``` -// functional layer defines all the state of your protocol -type State = {...} - -// Very useful to have a way to define an empty, default state object -pure def EmptyState(): State = {...} - -// Functional layer defines a result object, -// which is returned by the "API layer" inside the functional layer. -type Result = {error: string, resultState: State} - -// The API of the functional layer looks like this: -// Pure (=stateless) functions that take a current state and some parameters as arguments, -// the returns a result (=either error, or the new state if no error) -pure def DoFoo(currentState: State, a: Param1, b: Param2, c: Param3): Result { - if(badThing) { - {error: "something bad happened", resultState: emptyState} - } -} -``` -So the main ingredient of the functional layer are stateless functions that take a current state as input, -then return a result, which is either a new state, or an error explaining why that function can't be applied in the given state. - -Basic state-machine layer (here, ccv_model.qnt): -``` -// an action that calls Foo and applies the result to the state. -// the action is stateful, it actually accesses the current state, and will set the next state. -action Foo( - a: Param1, - b: Param2, - c: Param3, -) = -val result = DoFoo(currentState, a, b, c) -all { - result.hasError() = false, // action will only be executed if there is no error - currentState' = result.resultState // set the next state -} - -// sometimes this layer is useful: does Foo, but resolves the parameters according -// to some nondeterministic choice -action NondetFoo() = -// choose a and b nondeterministically from some sets -nondet a = oneOf(PossibleParam1Values) -nondet b = oneOf(PossibleParam2Values) -// as an example, maybe c is derived deterministically by some function from a and b -val c = ComputeC(a, b) -Foo(a, b, c) - -// ... many other actions - -// step chooses any of the Nondet actions -action step = any { - NondetFoo, - NondetBar, - ... -} -``` - -The important thing about the state-machine layer is that it involves nondeterministic choices, -and wraps around the functional layer in a nice way that keeps the two as separated as possible. -The functional layer should contain *no* im-pure (i.e. stateful) definitions. - -All impure definitions should be in the the state machine layer. -(Of course, it doesn't need to exclusively contain impure definitions, the state machine layer indeed -sometimes benefits from having utility functions, but all actual protocol logic should be in the functional layer). - -#### Benefit - -The separation makes it easy to reason about the functional layer: -it's pure functional programming, -the thing you need to care about is how the single function you are writing transforms the current state into the next state, -no need to think about side effects, etc. - -### Making traces usable for testing - -To make traces usable for testing, it is important to keep all information needed to replay traces. -For starters, there needs to be a way to log what actions were taken. - -In the CCV model, in particularly we have: -* a `trace`, which is a list of all actions taken -* an `action` record, which contains the kind of an action (just a string), and also all possible arguments that an action could have. -This is the best way to do this in Quint imo, you just set the parts of the object that are relevant for the action you are taking, all others stay empty. -* a `params` record, which stores all the parameters that are needed to replay the trace, i.e. the set of consumer chains, unbonding periods, etc. - -These things "pollute" the state machine layer a bit, since they need to be touched in every action. -A nice separation between state machine and functional layer makes this less annoying. - -The `trace` record is also sometimes useful for defining invariants of the form -"if action A is ever taken, then it cannot be taken again", etc, -simply by checking the past trace. - -### Abstracting from the implementations - -For the Quint model to be maximally useful, it should prioritize readability a lot. -One of the things that I learned (the hard way) was to -construct sets and maps in advance, not incrementally, whenever possible. -This wasn't done consistently throughout the spec, but probably should be. -As an example, for key assignment, in reality only validators with a key assignment would be entered in some data structure, -and other validators implicitly don't have a key assigned. -In the model, it's better to have a map from all validators to their key assignments, and the default -assignment is just the validator assigns their own key to themselves. - -We shouldn't care about performance of the model too much, and this is exactly one of the ways in which we can -prioritize readability over performance. - -So in general, I'd recommend using idealized data structures that wouldn't be efficient on chain, but are readable and understandable in the model. -In particular, partial maps seem too detailed in general, and should be avoided in favor of full maps that are built -early with default values. - -See a nice blog post by Igor Konnov on the topic: -https://konnov.github.io/protocols-made-fun/quint/2024/01/14/maps.html - -The takeaway: Especially when modelling something where there is already source code, resist the temptation to -stay too close to the source code in terms of data structures. - -### Concrete Style Guide - -Some concrete stylistic decisions, where we know things are up-to-debate: - -#### .with vs {...old, field1:val1} - -There are two possibilities for updating a record in Quint: -``` -val newRecord = {...oldRecord, field1: val1, field2: val2} -``` -or -``` -val newRecord = oldRecord.with("field1", val1).with("field2", val2) -``` - -We should make a decision. I think the first one is less verbose, -but Marius liked the second one more. - -Decision: ??? - -#### Getters/Setters - -In the Quint model, we have a lot of records that are just data structures, -and often we need values from very deep in some record, e.g. -``` -currentState.consumerStates.get(sender).outstandingPacketsToProvider -``` - -This is verbose, and hard to update if we ever change the data structures significantly, e.g. -by adding a new layer of nesting. - -It might be better to have getters and setters for most fields, -e.g. -``` -packets = currentState.getOutstandingPacketsToProvider(consumer) -``` -and -``` -newState = currentState.setOutstandingPacketsToProvider(consumer, newPackets) -``` - -However, this could also have problems, e.g. making things less immediately obvious and more abstract, potentially for little benefit. - -Decision: ??? - -### Testing - -To test Quint specifications, there are two main ways: -1) Use invariants and the simulator. -2) Write test cases. - -My usual way is to write a one or more test cases, then try to formulate invariants and run the simulator. -Typically, I will get some faults that are hard to understand, and I will transform the failures into test cases -in order to understand them better. - -### Modularity in Step functions - -Sometimes, you might have many different actions, -e.g. -``` -votingPowerChange, -optIn, -optOut, -assignKey, -endBlock -``` -but essentially, some of these actions are modular. -E.g. it might make sense to have a run where optIn and optOut are not allowed, -or one where assignKey is not allowed, etc. - -In this case, it might make sense to have one "step function" per module, e.g.: -``` -action stepCommon = any { - votingPowerChange, - endBlock -} - -action stepOptInOptOut = any { - optIn, - optOut -} - -action stepAssignKey = any { - assignKey -} -``` - -When invoking `quint run`, the `--step` argument can take Quint code. -So for example, we can only enable the common and assignKey modules by running: -``` -quint run --step "any{stepCommon, stepAssignKey}" -``` - -The requirement on these "module steps" is that they should -not need any inputs, e.g. they resolve all nondeterminism inside them. -Otherwise, the `--step` argument would need to be more complicated. - -## Nondeterministic Choice from Sets - -Sometimes, you want to finely control nondeterminism, e.g. to have different probability distributions. -For example: - -``` -action goUp(element: E) = {...} - -action goDown(element: E) = {...} - -action step = - mySet.map( - element => - nondet x = oneOf(1.to(100)) - if(x < 50) { - goUp - } else { - goDown - } - ) -``` - -This is ok, but let's step back one meta-layer. -What if you want to have different step functions with different probability distributions, while reusing as much code -as possible from step? - -You might be tempted to pass in a function that generates numbers nondeterministically, -and to have different functions for different probability distributions. -E.g. one could imagine to do this: - -``` -action step(oracle: () => int) = - mySet.map( - element => - val x = oracle() - if(x < 50) { - element.goUp() - } else { - element.goDown() - } - ) - -def mostlyUpOracle(): int = oneOf(1.to(60)) - -def mostlyDownOracle(): int = oneOf(40.to(100)) -``` - -This is not possible, because of technicalities with nondeterminism. - -The basic rule-of-thumb is: -*Nondeterminism can only happen directly in actions* - -We are violating this commandment here, because the nondeterminism would happen in the oracle functions. - -The solution is to use sets instead of functions. -The idea is that we leave the nondeterministic choice inside the step function, but we do oneOf from a set that is passed in. -E.g.: - -``` -action step(oracleDomain: Set[int]) = - nondet x = oneOf(oracleDomain) - if(x < 50) { - goUp - } else { - goDown - } - -val mostlyUpOracleDomain = 1.to(60) -val mostlyDownOracleDomain = 40.to(100) -``` - -We could get more complicated distributions by applying a function to x. \ No newline at end of file From 2262a8b9dd7b4aa53c4b1c636ee058dc92c0932e Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Tue, 23 Apr 2024 11:37:21 +0200 Subject: [PATCH 060/110] Add optin/optout to MBT readme --- tests/mbt/model/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/mbt/model/README.md b/tests/mbt/model/README.md index 407224bd7a..f4add0e213 100644 --- a/tests/mbt/model/README.md +++ b/tests/mbt/model/README.md @@ -32,6 +32,8 @@ All the logic in EndBlock/BeginBlock happens here, like updating the validator s * `DeliverVscPacket(receiver: Chain)`: Delivers a pending VSCPacket from the provider to the consumer `receiver`. * `DeliverPacketToProvider(sender: Chain)`: Delivers a pending packet from the consumer `sender` to the provider. * `KeyAssignment(chain: Chain, validator: Node, consumerAddr: ConsumerAddr)` (only when running with `--step stepKeyAssignment`): Assigns the `consumerAddr` to the `validator` on the `chain`. Note that we use "key" and "consumerAddr" pretty much interchangeably, as the model makes no differentiation between private keys, public keys, addresses, etc, as it doesn't model the cryptography. +* `OptIn(chain: Chain, validator: Node)` (only when running with `--step stepBoundedDriftKeyAndPSS` on `ccv_boundeddrift.qnt`): The `validator` opts in on the `chain`. +* `OptOut(chain: Chain, validator: Node)` (only when running with `--step stepBoundedDriftKeyAndPSS` on `ccv_boundeddrift.qnt`): The `validator` opts out on the `chain`. ### State machines From d53637d114555e1d61d1137d1f9caec5f5673584 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Tue, 23 Apr 2024 14:51:36 +0200 Subject: [PATCH 061/110] Fix types in model --- tests/mbt/model/ccv_model.qnt | 14 +++++++------- tests/mbt/model/ccv_pss.qnt | 4 ++-- tests/mbt/model/ccv_pss_model.qnt | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/mbt/model/ccv_model.qnt b/tests/mbt/model/ccv_model.qnt index 5f93a82970..ecbc926021 100644 --- a/tests/mbt/model/ccv_model.qnt +++ b/tests/mbt/model/ccv_model.qnt @@ -1063,7 +1063,7 @@ module ccv_model { run DowntimeSlashTest = init.then( // start all consumer chains - EndAndBeginBlockForProvider(1 * Second, consumerChains, Set()) + EndAndBeginBlockForProvider(1 * Second, ConsumerChains.map(c => NewFullConsumer(c)), Set()) ).then( // change voting power VotingPowerChange("node1", 50) @@ -1101,7 +1101,7 @@ module ccv_model { init .then( // start consumer 3 - EndAndBeginBlockForProvider(1 * Second, Set("consumer3"), Set()) + EndAndBeginBlockForProvider(1 * Second, Set(NewFullConsumer("consumer3")), Set()) ) .then( // change voting power for node 3 by 50 @@ -1109,7 +1109,7 @@ module ccv_model { ) .then( // start consumer 2 - EndProviderEpoch(3 * Second, Set("consumer2"), Set()) + EndProviderEpoch(3 * Second, Set(NewFullConsumer("consumer2")), Set()) ) .then( // deliver a vsc packet to consumer 3 @@ -1129,7 +1129,7 @@ module ccv_model { ) .then( // start consumer 1 - EndAndBeginBlockForProvider(1 * Second, Set("consumer1"), Set()) + EndAndBeginBlockForProvider(1 * Second, Set(NewFullConsumer("consumer1")), Set()) ) .then( all { @@ -1143,7 +1143,7 @@ module ccv_model { init .then( // start consumer 2 - EndAndBeginBlockForProvider(1 * Second, Set("consumer2"), Set()) + EndAndBeginBlockForProvider(1 * Second, Set(NewFullConsumer("consumer2")), Set()) ) .then( // change vp of node 10 by -50 @@ -1171,7 +1171,7 @@ module ccv_model { ) .then( // end and begin a block on the provider, starting consumer 3 - EndAndBeginBlockForProvider(1 * Second, Set("consumer3"), Set()) + EndAndBeginBlockForProvider(1 * Second, Set(NewFullConsumer("consumer3")), Set()) ) .then( // check the ValidatorSetHasExistedKeyAssignmentInv @@ -1186,7 +1186,7 @@ module ccv_model { init .then( // start consumer 1 - EndAndBeginBlockForProvider(1 * Second, Set("consumer1"), Set()) + EndAndBeginBlockForProvider(1 * Second, Set(NewFullConsumer("consumer1")), Set()) ) .then( // change voting power for node 1 by 50 diff --git a/tests/mbt/model/ccv_pss.qnt b/tests/mbt/model/ccv_pss.qnt index 4759fe6b34..66ffb59668 100644 --- a/tests/mbt/model/ccv_pss.qnt +++ b/tests/mbt/model/ccv_pss.qnt @@ -94,7 +94,7 @@ module ccv_pss { // Returns true if the given validator is in the top N for the given consumer chain, // and false otherwise. pure def IsTopN(currentState: ProtocolState, validator: Node, consumer: Chain): bool = { - val proviValSet = currentState.providerState.chainState.currentValidatorSet + val proviValSet = currentState.providerState.chainState.currentValidatorPowers val N = currentState.providerState.topNByConsumer.get(consumer) val topNValSet = GetTopNVals(proviValSet, N) @@ -144,7 +144,7 @@ module ccv_pss { // Runs the PSS logic for a single consumer. // Should only be run for running chains. pure def endBlockPSS_helper(providerState: ProviderState, consumer: Chain): ProviderState = { - val proviValSet = providerState.chainState.currentValidatorSet + val proviValSet = providerState.chainState.currentValidatorPowers val topNVals = GetTopNVals(proviValSet, providerState.topNByConsumer.get(consumer)) val prevOptedInVals = providerState.optedInVals.getOrElse(consumer, Set()) // opt in all the top N validators, i.e. union the top N vals with the previous opted in vals diff --git a/tests/mbt/model/ccv_pss_model.qnt b/tests/mbt/model/ccv_pss_model.qnt index d2911a0989..0e222df595 100644 --- a/tests/mbt/model/ccv_pss_model.qnt +++ b/tests/mbt/model/ccv_pss_model.qnt @@ -68,7 +68,7 @@ module ccv_pss_model { val AtLeastTopNPower: bool = runningConsumers.forall(consumer => { val topN = currentState.providerState.topNByConsumer.get(consumer) - val totalPowerConsu = currentState.consumerStates.get(consumer).chainState.currentValidatorSet.mapValuesSum() + val totalPowerConsu = currentState.consumerStates.get(consumer).chainState.currentValidatorPowers.mapValuesSum() currentState.providerState.chainState.votingPowerHistory.toSet().exists( valSet => { val totalPowerProvi = valSet.mapValuesSum() From 545c8d94cb9c00973b50e456de5aee8d43b7eb06 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Tue, 23 Apr 2024 15:42:43 +0200 Subject: [PATCH 062/110] Fix model --- tests/mbt/model/ccv_model.qnt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/mbt/model/ccv_model.qnt b/tests/mbt/model/ccv_model.qnt index ecbc926021..af62a8b1bf 100644 --- a/tests/mbt/model/ccv_model.qnt +++ b/tests/mbt/model/ccv_model.qnt @@ -362,7 +362,7 @@ module ccv_model { runningConsumers.forall(chain => // for all running consumers currentState.consumerStates.get(chain).chainState.votingPowerHistory.toSet().forall( // go through all its historical and current validator sets - validatorSet => providerValidatorHistory.toSet().contains(validatorSet) + validatorSet => providerValidatorHistory.toSet().map(v => removeZeroPowers(v)).contains(removeZeroPowers(validatorSet)) // and check that they are also historical or current validator sets on the provider ) ) From c960ed25b2649068b18c394d6890dd592baa8486 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Tue, 23 Apr 2024 17:58:41 +0200 Subject: [PATCH 063/110] Add migration --- x/ccv/provider/migrations/migrator.go | 8 +++++ .../migrations/vPSS/migration_test.go | 30 +++++++++++++++++++ x/ccv/provider/migrations/vPSS/migrations.go | 24 +++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 x/ccv/provider/migrations/vPSS/migration_test.go create mode 100644 x/ccv/provider/migrations/vPSS/migrations.go diff --git a/x/ccv/provider/migrations/migrator.go b/x/ccv/provider/migrations/migrator.go index 7c52ee27ce..29fed46851 100644 --- a/x/ccv/provider/migrations/migrator.go +++ b/x/ccv/provider/migrations/migrator.go @@ -7,6 +7,7 @@ import ( providerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" v3 "github.com/cosmos/interchain-security/v4/x/ccv/provider/migrations/v3" v4 "github.com/cosmos/interchain-security/v4/x/ccv/provider/migrations/v4" + vPSS "github.com/cosmos/interchain-security/v4/x/ccv/provider/migrations/vPSS" ) // Migrator is a struct for handling in-place store migrations. @@ -39,3 +40,10 @@ func (m Migrator) Migrate3to4(ctx sdktypes.Context) error { v4.MigrateParams(ctx, m.paramSpace) return nil } + +// MigrateXtoY migrates x/ccvprovider state from consensus version X to Y. +// The migration consists of setting a top N of 95 for all registered consumer chains. +func (m Migrator) MigrateXtoY(ctx sdktypes.Context) error { + vPSS.MigrateTopNForRegisteredChains(ctx, m.providerKeeper) + return nil +} diff --git a/x/ccv/provider/migrations/vPSS/migration_test.go b/x/ccv/provider/migrations/vPSS/migration_test.go new file mode 100644 index 0000000000..c8760f4979 --- /dev/null +++ b/x/ccv/provider/migrations/vPSS/migration_test.go @@ -0,0 +1,30 @@ +package vPSS + +import ( + "testing" + + "github.com/stretchr/testify/require" + + testutil "github.com/cosmos/interchain-security/v4/testutil/keeper" +) + +func TestMigrateParams(t *testing.T) { + inMemParams := testutil.NewInMemKeeperParams(t) + provKeeper, ctx, ctrl, _ := testutil.GetProviderKeeperAndCtx(t, inMemParams) + defer ctrl.Finish() + + provKeeper.SetConsumerClientId(ctx, "chainID", "clientID") + + // initially top N should not exist + topN, found := provKeeper.GetTopN(ctx, "chainID") + require.False(t, found) + require.Zero(t, topN) + + // migrate + MigrateTopNForRegisteredChains(ctx, provKeeper) + + // after migration, top N should be 95 + topN, found = provKeeper.GetTopN(ctx, "chainID") + require.True(t, found) + require.Equal(t, uint32(95), topN) +} diff --git a/x/ccv/provider/migrations/vPSS/migrations.go b/x/ccv/provider/migrations/vPSS/migrations.go new file mode 100644 index 0000000000..905d59c8e6 --- /dev/null +++ b/x/ccv/provider/migrations/vPSS/migrations.go @@ -0,0 +1,24 @@ +package vPSS + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + providerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" +) + +// This migration only takes already registered chains into account. +// If a chain is in voting while the upgrade happens, this is not sufficient, +// and a migration to rewrite the proposal is needed. +func MigrateTopNForRegisteredChains(ctx sdk.Context, providerKeeper providerkeeper.Keeper) { + // get all consumer chains + registeredConsumerChains := providerKeeper.GetAllConsumerChains(ctx) + + // Set the topN of each chain to 95 + for _, chain := range registeredConsumerChains { + providerKeeper.SetTopN(ctx, chain.ChainId, 95) + } +} + +// // If there are consumer addition proposals in the voting period at the upgrade time, they may need the topN value updated. +// func MigrateTopNForVotingPeriodChains(ctx sdk.Context, govKeeper govkeeper.Keeper, providerKeeper providerkeeper.Keeper) { +// } From 769d52f8457a6ea7cadd20975548fb6b2514e4dd Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Wed, 24 Apr 2024 10:29:57 +0200 Subject: [PATCH 064/110] Ensure SlashAcks are sent even when the valset does not change --- tests/mbt/model/ccv_model.qnt | 82 ++++++++++++++++++++++++++++++++--- tests/mbt/model/ccv_utils.qnt | 3 +- 2 files changed, 79 insertions(+), 6 deletions(-) diff --git a/tests/mbt/model/ccv_model.qnt b/tests/mbt/model/ccv_model.qnt index af62a8b1bf..5f6d8c8db5 100644 --- a/tests/mbt/model/ccv_model.qnt +++ b/tests/mbt/model/ccv_model.qnt @@ -224,11 +224,14 @@ module ccv_model { // stepCommon is the core functionality of steps that does not have anything to do with time. action stepCommon = any { - nondet node = oneOf(nonJailedNodes(currentState.providerState)) - // very restricted set of voting powers. exact values are not important, - // and this keeps the state space smaller. - nondet newVotingPower = oneOf(Set(-50, 50)) - VotingPowerChange(node, newVotingPower), + all { + nonJailedNodes(currentState.providerState).size() > 0, + nondet node = oneOf(nonJailedNodes(currentState.providerState)) + // very restricted set of voting powers. exact values are not important, + // and this keeps the state space smaller. + nondet newVotingPower = oneOf(Set(-50, 50)) + VotingPowerChange(node, newVotingPower), + }, // try to send a packet. we could filter by chains that can actually send, // but it's probably not much faster than just trying and failing. @@ -1182,6 +1185,75 @@ module ccv_model { } ) + // Ensure that SlashAcks are sent even when the validator set does not change due to the slash itself, + // i.e. the validator already had 0 power. + run DeliverSlashAckWithNoVSCUpdateTest = + init + .then( + // start consumer 1 + EndAndBeginBlockForProvider(1 * Second, Set(NewFullConsumer("consumer1")), Set()) + ) + .then( + // change voting power for node 1 by 50 + VotingPowerChange("node1", 50) + ) + .then( + // end and begin a block on the provider + EndProviderEpoch(3 * Second, Set(), Set()) + ) + .then( + // deliver the vsc packet to consumer 1 + DeliverVscPacket("consumer1") + ) + .then( + // begin a new block on the consumer + EndAndBeginBlockForConsumer("consumer1", 1 * Second) + ) + .then( + // initiate a slash for downtime + ConsumerInitiatedSlashDet("consumer1", "node1", 0, true) + ) + .then( + // end a block on the consumer to send the packet + EndAndBeginBlockForConsumer("consumer1", 1 * Second) + ) + .then( + all { + // consumer1 should have sent the slash packet + assert(currentState.consumerStates.get("consumer1").outstandingPacketsToProvider.length() == 1), + assert(currentState.consumerStates.get("consumer1").waitingForSlashPacketAck.size() == 1), + // set the power of node1 to 0 on the provider + VotingPowerChange("node1", -150) + } + ) + .then( + all { + // node1 should have 0 power on the provider + assert(currentState.providerState.chainState.currentValidatorPowers.get("node1") == 0), + // end an epoch on the provider to send another vsc packet + EndProviderEpoch(3 * Second, Set(), Set()) + } + ) + .then( + // deliver the packet + DeliverVscPacket("consumer1") + ) + .then( + // consumer1 should have sent a slash packet to the provider + all { + // deliver the slash request to the provider + DeliverPacketToProvider("consumer1") + } + ) + .then( + // end an epoch on the provider to send the acknowledgement + EndProviderEpoch(1 * Second, Set(), Set()) + ) + .then( + // deliver the acknowledgement to the consumer + DeliverVscPacket("consumer1") + ) + run SlashAckTest = init .then( diff --git a/tests/mbt/model/ccv_utils.qnt b/tests/mbt/model/ccv_utils.qnt index a3f5b15ecf..d8184b91e4 100644 --- a/tests/mbt/model/ccv_utils.qnt +++ b/tests/mbt/model/ccv_utils.qnt @@ -227,7 +227,8 @@ module ccv_utils { (consumer) => // if validator set changed or the key assignments for this chain changed, and the consumer is running, send a packet if ((providerState.consumersWithPowerChangesInThisEpoch.contains(consumer) or - providerState.consumersWithAddrAssignmentChangesInThisEpoch.contains(consumer)) + providerState.consumersWithAddrAssignmentChangesInThisEpoch.contains(consumer) + or providerState.downtimeSlashRequests.getOrElse(consumer, []) != []) and isRunningConsumer(consumer, providerState)) { // send a packet, i.e. use a list with one element (the packet to be sent) From e0e6524f1d91def5a5fa14918e0f100bba8c8f82 Mon Sep 17 00:00:00 2001 From: mpoke Date: Wed, 24 Apr 2024 12:54:50 +0200 Subject: [PATCH 065/110] adding changelog entry --- .changelog/unreleased/features/1809-pss.md | 3 +++ .changelog/unreleased/state-breaking/1809-pss.md | 2 ++ 2 files changed, 5 insertions(+) create mode 100644 .changelog/unreleased/features/1809-pss.md create mode 100644 .changelog/unreleased/state-breaking/1809-pss.md diff --git a/.changelog/unreleased/features/1809-pss.md b/.changelog/unreleased/features/1809-pss.md new file mode 100644 index 0000000000..f7a235c5be --- /dev/null +++ b/.changelog/unreleased/features/1809-pss.md @@ -0,0 +1,3 @@ +- Adding the Partial Set Security (PSS) feature cf. [ADR 015](https://cosmos.github.io/interchain-security/adrs/adr-015-partial-set-security). + PSS enables consumer chains to join ICS as _Top N_ or _Opt In_ chains and enables validators to opt to validate the consumer chains they want. + ([\#1809](https://github.com/cosmos/interchain-security/pull/1809)) \ No newline at end of file diff --git a/.changelog/unreleased/state-breaking/1809-pss.md b/.changelog/unreleased/state-breaking/1809-pss.md new file mode 100644 index 0000000000..c0af9ae11e --- /dev/null +++ b/.changelog/unreleased/state-breaking/1809-pss.md @@ -0,0 +1,2 @@ +- Adding the Partial Set Security feature cf. [ADR 015](https://cosmos.github.io/interchain-security/adrs/adr-015-partial-set-security). + ([\#1809](https://github.com/cosmos/interchain-security/pull/1809)) \ No newline at end of file From 0963f41c9367cf98abdb6949b3b4b9b31157af75 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Wed, 24 Apr 2024 13:06:52 +0200 Subject: [PATCH 066/110] Empty DowntimeSlachAcks on EndBlock --- tests/mbt/model/ccv.qnt | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tests/mbt/model/ccv.qnt b/tests/mbt/model/ccv.qnt index d6da642493..a6e612f67d 100644 --- a/tests/mbt/model/ccv.qnt +++ b/tests/mbt/model/ccv.qnt @@ -607,7 +607,7 @@ module ccv { // acknowledge the packets to be acknowledged on endblock val newConsumerStates = currentState.consumerStates.keys().mapBy( (consumer) => - val consumerState = currentState.consumerStates.get(consumer) + val consumerState = currentState.consumerStates.get(consumer) val packetsToAck = currentProviderState.acksToSendOnEndBlock.getOrElse(consumer, List()) val newConsumerState = packetsToAck.foldl(consumerState, (state, packet) => deliverAck(state, packet) @@ -615,9 +615,14 @@ module ccv { newConsumerState ) + // clear the acksToSendOnEndBlock + val providerStateAfterAcking = providerStateAfterSending.with( + "acksToSendOnEndBlock", Map() + ) + // start/stop chains - val res = providerStateAfterSending.StartStopConsumers( + val res = providerStateAfterAcking.StartStopConsumers( consumersToStart, consumersToStop, timedOutConsumers @@ -661,7 +666,7 @@ module ccv { tmpState.consumerStates.keys().mapBy( (consumer) => if (consumerAdditions.contains(consumer)) { - val currentConsumerState: ConsumerState = tmpState.consumerStates.get(consumer) + val currentConsumerState: ConsumerState = newConsumerStates.get(consumer) // correctly set the state for the new consumer val newConsumerState: ConsumerState = currentConsumerState.with( "chainState", currentConsumerState.chainState.with( @@ -679,7 +684,7 @@ module ccv { ) newConsumerState } else { - tmpState.consumerStates.get(consumer) + newConsumerStates.get(consumer) } ) val newState = tmpState.with( From cdf77901ce14f89cad403f1ed7d975c3ac4cd32a Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Thu, 25 Apr 2024 10:49:26 +0200 Subject: [PATCH 067/110] Remove logs --- tests/mbt/driver/mbt_test.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/mbt/driver/mbt_test.go b/tests/mbt/driver/mbt_test.go index 814a9c3a0b..e1004eb79a 100644 --- a/tests/mbt/driver/mbt_test.go +++ b/tests/mbt/driver/mbt_test.go @@ -241,8 +241,6 @@ func RunItfTrace(t *testing.T, path string) { t.Log("Reading the trace...") for index, state := range trace.States { - t.Log("Height modulo epoch length:", driver.providerChain().CurrentHeader.Height%blocksPerEpoch) - t.Log("Model height modulo epoch length:", ProviderHeight(state.VarValues["currentState"].Value.(itf.MapExprType))%modelBlocksPerEpoch) t.Logf("Reading state %v of trace %v", index, path) // store the height of the provider state before each step. @@ -519,9 +517,6 @@ func RunItfTrace(t *testing.T, path string) { t.Logf("Current actual state: %s", driver.getStateString()) } - // check that the actual state is the same as the model state - t.Logf("Comparing model state to actual state...") - // compare the running consumers modelRunningConsumers := RunningConsumers(currentModelState) @@ -611,8 +606,6 @@ func RunItfTrace(t *testing.T, path string) { // we changed epoch during this step, so ensure that the model also changed epochs require.True(t, ProviderHeight(state.VarValues["currentState"].Value.(itf.MapExprType))%modelBlocksPerEpoch == 0, "Height in model did not change epoch, but did in system. increase blocksPerEpoch in the system") } - - t.Logf("State %v of trace %v is ok!", index, path) } t.Log("🟢 Trace is ok!") } From 3571b7606ce77250a28aef7aa0d363662ee042e7 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Thu, 25 Apr 2024 10:50:09 +0200 Subject: [PATCH 068/110] Change condition for sending slash acks --- tests/mbt/model/ccv.qnt | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/tests/mbt/model/ccv.qnt b/tests/mbt/model/ccv.qnt index a6e612f67d..3ea7862454 100644 --- a/tests/mbt/model/ccv.qnt +++ b/tests/mbt/model/ccv.qnt @@ -939,10 +939,22 @@ module ccv { // if there is no entry for that validator, there is no key assignment .getOrElse(packet.validator, packet.validator) // if the packet is for double-sign, drop it without changing states - if (not(packet.downtime) or - // same if the validator is already jailed: no double-jailing! - not(providerVal.in(nonJailedNodes(currentState.providerState)))) { + if (not(packet.downtime)) { Ok(currentState) + + } else if ( + // if the validator is already jailed... + not(providerVal.in(nonJailedNodes(currentState.providerState))) or + // or it has 0 power... + currentState.providerState.chainState.currentValidatorPowers.getOrElse(providerVal, 0) == 0 or + // or it was not in the last valset we sent to the consumer + not(currentState.providerState.sentVscPacketsToConsumer.get(sender).head().validatorSet.keys().contains(providerVal)) + ) { + // just store that we received the DowntimeSlashRequest, to acknowledge it on EndBlock + val newProviderState = currentState.providerState.with( + "downtimeSlashRequests", currentState.providerState.downtimeSlashRequests.put(sender, currentState.providerState.downtimeSlashRequests.getOrElse(sender, List()).append(packet.validator)) + ) + Ok(currentState.with("providerState", newProviderState)) } else { val jailEndTime = ProviderBlockTime(currentState) + DowntimeJailTime // map the validator to its address on the provider From 19b76720f72682b92abbf759ffc7dcf393080f30 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Thu, 25 Apr 2024 11:16:54 +0200 Subject: [PATCH 069/110] Revert model changes --- tests/mbt/model/ccv.qnt | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/tests/mbt/model/ccv.qnt b/tests/mbt/model/ccv.qnt index 3ea7862454..a6e612f67d 100644 --- a/tests/mbt/model/ccv.qnt +++ b/tests/mbt/model/ccv.qnt @@ -939,22 +939,10 @@ module ccv { // if there is no entry for that validator, there is no key assignment .getOrElse(packet.validator, packet.validator) // if the packet is for double-sign, drop it without changing states - if (not(packet.downtime)) { + if (not(packet.downtime) or + // same if the validator is already jailed: no double-jailing! + not(providerVal.in(nonJailedNodes(currentState.providerState)))) { Ok(currentState) - - } else if ( - // if the validator is already jailed... - not(providerVal.in(nonJailedNodes(currentState.providerState))) or - // or it has 0 power... - currentState.providerState.chainState.currentValidatorPowers.getOrElse(providerVal, 0) == 0 or - // or it was not in the last valset we sent to the consumer - not(currentState.providerState.sentVscPacketsToConsumer.get(sender).head().validatorSet.keys().contains(providerVal)) - ) { - // just store that we received the DowntimeSlashRequest, to acknowledge it on EndBlock - val newProviderState = currentState.providerState.with( - "downtimeSlashRequests", currentState.providerState.downtimeSlashRequests.put(sender, currentState.providerState.downtimeSlashRequests.getOrElse(sender, List()).append(packet.validator)) - ) - Ok(currentState.with("providerState", newProviderState)) } else { val jailEndTime = ProviderBlockTime(currentState) + DowntimeJailTime // map the validator to its address on the provider From 92707670681163aa15082273d61322a2b41eea88 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Fri, 26 Apr 2024 10:22:30 +0200 Subject: [PATCH 070/110] Start fixing PSS issues in model --- tests/mbt/driver/mbt_test.go | 46 +++++++++++++++- tests/mbt/driver/model_viewer.go | 9 +++ tests/mbt/driver/setup.go | 60 ++++++++++++++------ tests/mbt/model/ccv.qnt | 92 +++++++++++++++++-------------- tests/mbt/model/ccv_pss.qnt | 2 +- tests/mbt/model/ccv_pss_model.qnt | 5 +- tests/mbt/model/ccv_pss_test.qnt | 31 ++++++++++- 7 files changed, 179 insertions(+), 66 deletions(-) diff --git a/tests/mbt/driver/mbt_test.go b/tests/mbt/driver/mbt_test.go index e1004eb79a..83b1c40d90 100644 --- a/tests/mbt/driver/mbt_test.go +++ b/tests/mbt/driver/mbt_test.go @@ -544,7 +544,7 @@ func RunItfTrace(t *testing.T, path string) { // check sent packets: we check that the package queues in the model and the system have the same length. for _, consumer := range actualRunningConsumers { - ComparePacketQueues(t, driver, currentModelState, consumer, timeOffset) + ComparePacketQueues(t, driver, currentModelState, consumer, timeOffset, realAddrsToModelConsAddrs) } // compare that the sent packets on the proider match the model CompareSentPacketsOnProvider(driver, currentModelState, timeOffset) @@ -630,7 +630,7 @@ func CompareValidatorSets( driver *Driver, currentModelState map[string]itf.Expr, consumers []string, - // a map from real addresses to the names of those consumer addresses in the model + // a map from real addresses to the names of those consensus addresses in the model keyAddrsToModelConsAddrName map[string]string, ) { t.Helper() @@ -645,6 +645,9 @@ func CompareValidatorSets( actualValSet[valName] = val.Tokens.Int64() } + fmt.Println("Model validator set:", modelValSet) + fmt.Println("Actual validator set:", actualValSet) + require.NoError(t, CompareValSet(modelValSet, actualValSet), "Validator sets do not match") for _, consumer := range consumers { @@ -693,6 +696,7 @@ func ComparePacketQueues( currentModelState map[string]itf.Expr, consumer string, timeOffset time.Time, + realConsAddrToModelValName map[string]string, ) { t.Helper() ComparePacketQueue(t, driver, currentModelState, PROVIDER, consumer, timeOffset) @@ -739,6 +743,44 @@ func ComparePacketQueue( actualPacket, sender, receiver) + + // reconstruct a VSCPacket from the actual packet + var actualPacketData types.ValidatorSetChangePacketData + err := types.ModuleCdc.UnmarshalJSON(actualPacket.Packet.GetData(), &actualPacketData) + require.NoError(t, err, "Error unmarshalling packet data") + + modelPacketValSet := modelPacket["validatorSet"].Value.(itf.MapExprType) + + // check that for all validators in the actual packets validator updates, + // the model has the same power for the validator + // note: we cannot check equivalence, because the system sends only changes, + // whereas the model sends the full set. + for _, valUpdate := range actualPacketData.ValidatorUpdates { + // get the name of the validator in the valUpdate + valPubKey := valUpdate.PubKey + consAddr, err := types.TMCryptoPublicKeyToConsAddr(valPubKey) + + require.NoError(t, err, "Error getting consensus address from pubkey") + + // get the name of the validator in the model + val, found := driver.providerStakingKeeper().GetValidatorByConsAddr(driver.providerCtx(), consAddr) + require.True(t, found, "Error getting validator by consensus address") + + modelValName := val.Description.Moniker + + // get the power of the validator in the model + modelPower := modelPacketValSet[modelValName].Value.(int64) + + // compare the power of the validator in the model to the power of the validator in the actual packet + require.Equal(t, + modelPower, + valUpdate.Power, + "Validator powers do not match for validator %v in packet %v, sender %v, receiver %v", + modelValName, + actualPacket, + sender, + receiver) + } } } diff --git a/tests/mbt/driver/model_viewer.go b/tests/mbt/driver/model_viewer.go index 87ec386382..2ef453e7b8 100644 --- a/tests/mbt/driver/model_viewer.go +++ b/tests/mbt/driver/model_viewer.go @@ -117,3 +117,12 @@ func ProviderJailedValidators(curStateExpr itf.MapExprType) ([]string, []int64) } return jailedValidators, jailEndTimes } + +func OptedInVals(curStateExpr itf.MapExprType, consumer string) []string { + optedInValExpr := ProviderState(curStateExpr)["optedInVals"].Value.(itf.MapExprType)[consumer].Value.(itf.ListExprType) + optedInVals := make([]string, len(optedInValExpr)) + for i, valExpr := range optedInValExpr { + optedInVals[i] = valExpr.Value.(string) + } + return optedInVals +} diff --git a/tests/mbt/driver/setup.go b/tests/mbt/driver/setup.go index 359ee8d3ef..94db0995c7 100644 --- a/tests/mbt/driver/setup.go +++ b/tests/mbt/driver/setup.go @@ -314,7 +314,7 @@ func newChain( // Creates a path for cross-chain validation from the consumer to the provider and configures the channel config of the endpoints // as well as the clients. // this function stops when there is an initialized, ready-to-relay channel between the provider and consumer. -func (s *Driver) ConfigureNewPath(consumerChain, providerChain *ibctesting.TestChain, params ModelParams, topN uint32) *ibctesting.Path { +func (s *Driver) ConfigureNewPath(consumerChain, providerChain *ibctesting.TestChain, params ModelParams, topN uint32, consumerInitialValSet *cmttypes.ValidatorSet) *ibctesting.Path { consumerChainId := ChainId(consumerChain.ChainID) path := ibctesting.NewPath(consumerChain, providerChain) @@ -350,7 +350,7 @@ func (s *Driver) ConfigureNewPath(consumerChain, providerChain *ibctesting.TestC []string{"upgrade", "upgradedIBCState"}, ) - consumerGenesis := createConsumerGenesis(params, providerChain, consumerClientState) + consumerGenesis := createConsumerGenesis(params, providerChain, consumerClientState, consumerInitialValSet) s.consumerKeeper(consumerChainId).InitGenesis(s.ctx(consumerChainId), consumerGenesis) @@ -362,13 +362,10 @@ func (s *Driver) ConfigureNewPath(consumerChain, providerChain *ibctesting.TestC var stakingValidators []stakingtypes.Validator - // set up the current consumer validators by utilizing the initial validator set - for _, val := range consumerGenesisForProvider.Provider.InitialValSet { + // set up the current consumer validators by utilizing the initial valSet on the consumer + for _, val := range consumerInitialValSet.Validators { pubKey := val.PubKey - consAddr, err := ccvtypes.TMCryptoPublicKeyToConsAddr(pubKey) - if err != nil { - continue - } + consAddr := sdk.ConsAddress(pubKey.Address()) v, found := s.providerStakingKeeper().GetValidatorByConsAddr(s.providerCtx(), consAddr) if !found { @@ -388,8 +385,6 @@ func (s *Driver) ConfigureNewPath(consumerChain, providerChain *ibctesting.TestC require.NoError(s.t, err, "Error setting consumer genesis on provider for chain %v", consumerChain.ChainID) // set the top N percentage - // needs to be done before the provider queues the first vsc packet to the consumer - // TODO: might be able to move this into setupConsumer, need to test once more logic is here s.providerKeeper().SetTopN(providerChain.GetContext(), consumerChain.ChainID, topN) // Client ID is set in InitGenesis and we treat it as a black box. So @@ -465,23 +460,54 @@ func (s *Driver) setupConsumer( ) { s.t.Logf("Starting consumer %v", chain) - // TODO: reuse the partial set computation logic to compute the initial validator set - // for top N chains - initValUpdates := cmttypes.TM2PB.ValidatorUpdates(valSet) + minOptInPower := sdk.NewInt(0) + + powers := make([]int64, 0) + for _, val := range valSet.Validators { + power := val.VotingPower + powers = append(powers, power) + } + + // sort by powers descending + sort.Slice(powers, func(i, j int) bool { + return powers[i] > powers[j] + }) + + topNThreshold := sdk.NewDecFromInt(sdk.NewInt(int64(topN))).QuoInt64(int64(100)) + powerSum := sdk.ZeroDec() + totalVotingPower := sdk.NewDecFromInt(sdk.NewInt(valSet.TotalVotingPower())) + for _, power := range powers { + powerSum = powerSum.Add(sdk.NewDecFromInt(sdk.NewInt(power))) + if powerSum.Quo(totalVotingPower).GTE(topNThreshold) { + minOptInPower = sdk.NewInt(power) + break + } + } + // get a new validator set with only the top N validators + topNVals := []*cmttypes.Validator{} + for _, val := range valSet.Validators { + if val.VotingPower >= minOptInPower.Int64() { + topNVals = append(topNVals, val) + } + } + topNValSet := cmttypes.NewValidatorSet(topNVals) + topNValSet.Proposer = topNValSet.Validators[0] + + initValUpdates := cmttypes.TM2PB.ValidatorUpdates(topNValSet) // start consumer chains s.t.Logf("Creating consumer chain %v", chain) - consumerChain := newChain(s.t, params, s.coordinator, icstestingutils.ConsumerAppIniter(initValUpdates), chain, valSet, signers, nodes, valNames) + consumerChain := newChain(s.t, params, s.coordinator, icstestingutils.ConsumerAppIniter(initValUpdates), chain, topNValSet, signers, topNVals, valNames) s.coordinator.Chains[chain] = consumerChain - path := s.ConfigureNewPath(consumerChain, providerChain, params, uint32(topN)) + path := s.ConfigureNewPath(consumerChain, providerChain, params, uint32(topN), topNValSet) s.simibcs[ChainId(chain)] = simibc.MakeRelayedPath(s.t, path) } -func createConsumerGenesis(modelParams ModelParams, providerChain *ibctesting.TestChain, consumerClientState *ibctmtypes.ClientState) *consumertypes.GenesisState { +func createConsumerGenesis(modelParams ModelParams, providerChain *ibctesting.TestChain, consumerClientState *ibctmtypes.ClientState, initialValSet *cmttypes.ValidatorSet) *consumertypes.GenesisState { providerConsState := providerChain.LastHeader.ConsensusState() - valUpdates := cmttypes.TM2PB.ValidatorUpdates(providerChain.Vals) + valUpdates := cmttypes.TM2PB.ValidatorUpdates(initialValSet) params := ccvtypes.NewParams( true, 1000, // ignore distribution diff --git a/tests/mbt/model/ccv.qnt b/tests/mbt/model/ccv.qnt index a6e612f67d..224ef1e33c 100644 --- a/tests/mbt/model/ccv.qnt +++ b/tests/mbt/model/ccv.qnt @@ -615,80 +615,86 @@ module ccv { newConsumerState ) - // clear the acksToSendOnEndBlock - val providerStateAfterAcking = providerStateAfterSending.with( - "acksToSendOnEndBlock", Map() - ) - // start/stop chains - val res = providerStateAfterAcking.StartStopConsumers( + val res = providerStateAfterSending.StartStopConsumers( consumersToStart, consumersToStop, timedOutConsumers ) - val providerStateAfterConsumerAdvancement = res._1 val err = res._2 + val providerStateAfterConsumerAdvancement = res._1.with( + "downtimeSlashRequests", Map() + ).with( + "acksToSendOnEndBlock", Map() + ) - val consumerAdditions = consumersToStart.map(consumer => consumer.chain) + val tmpState2 = tmpState.with( + "providerState", providerStateAfterConsumerAdvancement + ).with( + "consumerStates", newConsumerStates + ) // for each running consumer chain, opt in validators that are in the top N val providerStateAfterPSS = providerStateAfterConsumerAdvancement.endBlockPSS() + // for each consumer chain, apply the key assignment to the current validator set + val currentValSets = ConsumerChains.mapBy( + (consumer) => + val pssValSet = providerStateAfterPSS.GetPSSValidatorSet( + providerStateAfterPSS.chainState.votingPowerHistory.head(), + consumer) + providerStateAfterPSS.applyKeyAssignmentToValSet( + consumer, + pssValSet + ) + ) + // store the current validator set with the key assignments applied in the history + val newKeyAssignedValSetHistory = currentValSets.keys().mapBy( + (consumer) => + providerStateAfterPSS.keyAssignedValSetHistory + .getOrElse(consumer, List()) // get the existing history (empty list if no history yet) + .prepend(currentValSets.get(consumer)) // prepend the current validator set with key assignments applied + ) + if (err != "") { Err(err) - } else if (providerStateAfterConsumerAdvancement.chainState.votingPowerHistory.head().IsEmptyValSet()) { + } else if (providerStateAfterPSS.chainState.votingPowerHistory.head().IsEmptyValSet()) { Err("Validator set would be empty after ending this block!") } else { - // for each consumer chain, apply the key assignment to the current validator set - val currentValSets = getRunningConsumers(providerStateAfterPSS).mapBy( - (consumer) => - providerStateAfterPSS.applyKeyAssignmentToValSet( - consumer, - // get the validator set after partial set security has been applied - GetPSSValidatorSet(providerStateAfterPSS, curValSet, consumer) - ) - ) - - // store the current validator set with the key assignments applied in the history - val newKeyAssignedValSetHistory = currentValSets.keys().mapBy( - (consumer) => - providerStateAfterPSS.keyAssignedValSetHistory - .getOrElse(consumer, List()) // get the existing history (empty list if no history yet) - .prepend(currentValSets.get(consumer)) // prepend the current validator set with key assignments applied - ) - - val providerStateAfterStoringValSets = providerStateAfterPSS.with( - "keyAssignedValSetHistory", newKeyAssignedValSetHistory - ) + // for each consumer we just set to running, set its initial validator set to be the current one on the provider... + val valSet = providerStateAfterPSS.chainState.votingPowerHistory.head() val newConsumerStateMap = - tmpState.consumerStates.keys().mapBy( + tmpState2.consumerStates.keys().mapBy( (consumer) => - if (consumerAdditions.contains(consumer)) { - val currentConsumerState: ConsumerState = newConsumerStates.get(consumer) - // correctly set the state for the new consumer + if (consumersToStart.map(consumer => consumer.chain).contains(consumer)) { + // ...filtered by opted in validators + val pssValSet = GetPSSValidatorSet(providerStateAfterPSS, valSet, consumer) + // ...modified by the key assignments for the consumer + val consValSet = applyKeyAssignmentToValSet(providerStateAfterPSS, consumer, pssValSet) + val currentConsumerState: ConsumerState = tmpState2.consumerStates.get(consumer) val newConsumerState: ConsumerState = currentConsumerState.with( "chainState", currentConsumerState.chainState.with( - "currentValidatorPowers", currentValSets.get(consumer) + "currentValidatorPowers", consValSet ).with( "votingPowerHistory", - List(currentValSets.get(consumer)) + List(consValSet) ).with( "lastTimestamp", - providerStateAfterStoringValSets.chainState.lastTimestamp + providerStateAfterPSS.chainState.lastTimestamp ).with( "runningTimestamp", - providerStateAfterStoringValSets.chainState.runningTimestamp + providerStateAfterPSS.chainState.runningTimestamp ) ) newConsumerState } else { - newConsumerStates.get(consumer) + tmpState2.consumerStates.get(consumer) } ) val newState = tmpState.with( - "providerState", providerStateAfterStoringValSets + "providerState", providerStateAfterPSS ).with( "consumerStates", newConsumerStateMap ) @@ -845,8 +851,10 @@ module ccv { pure val provValSet = currentState.providerState.chainState.currentValidatorPowers pure val provValPower = if (provValSet.keys().contains(providerNode)) provValSet.get(providerNode) else 0 pure val consumersWithAddrAssignmentChangesInThisEpoch = - if (provValPower > 0 and providerNode.in(nonJailedNodes(currentState.providerState))) { - // if the validator has positive power and is not jailed, the relevant key assignment for the consumer changed + if (provValPower > 0 and providerNode.in(nonJailedNodes(currentState.providerState)) and currentState.providerState.optedInVals.getOrElse(consumer, Set()).contains(providerNode)) { + // if the validator has positive power and is not jailed, + // and the validator is opted in on the consumer, + // the relevant key assignment for the consumer changed currentState.providerState.consumersWithAddrAssignmentChangesInThisEpoch.union(Set(consumer)) } else { // otherwise, the consumer doesn't need to know about the change, so no change diff --git a/tests/mbt/model/ccv_pss.qnt b/tests/mbt/model/ccv_pss.qnt index 66ffb59668..26aee28d56 100644 --- a/tests/mbt/model/ccv_pss.qnt +++ b/tests/mbt/model/ccv_pss.qnt @@ -94,7 +94,7 @@ module ccv_pss { // Returns true if the given validator is in the top N for the given consumer chain, // and false otherwise. pure def IsTopN(currentState: ProtocolState, validator: Node, consumer: Chain): bool = { - val proviValSet = currentState.providerState.chainState.currentValidatorPowers + val proviValSet = currentState.providerState.chainState.votingPowerHistory.head() val N = currentState.providerState.topNByConsumer.get(consumer) val topNValSet = GetTopNVals(proviValSet, N) diff --git a/tests/mbt/model/ccv_pss_model.qnt b/tests/mbt/model/ccv_pss_model.qnt index 0e222df595..9e60e241bc 100644 --- a/tests/mbt/model/ccv_pss_model.qnt +++ b/tests/mbt/model/ccv_pss_model.qnt @@ -41,7 +41,8 @@ module ccv_pss_model { action OptOut_Deterministic(consumer: Chain, validator: Node): bool = { val res = OptOut(currentState, consumer, validator) all { - currentState' = res.newState, + // if we expect an error, this should be a noop + currentState' = if (res.error == "") res.newState else currentState, trace' = trace.append( { ...emptyAction, @@ -59,7 +60,7 @@ module ccv_pss_model { val allFullConsumers: Set[int] = Set(100) val allOptIn: Set[int] = Set(0) // only choose a few values for top N here to not make the "edge cases" of 0 and 100 too unlikely - val variousPossibleTopN: Set[int] = Set(0, 50, 70, 80, 90, 100) + val variousPossibleTopN: Set[int] = Set(50, 70, 80, 90, 100) // INVARIANTS diff --git a/tests/mbt/model/ccv_pss_test.qnt b/tests/mbt/model/ccv_pss_test.qnt index 2a84f6dbd4..61a5420150 100644 --- a/tests/mbt/model/ccv_pss_test.qnt +++ b/tests/mbt/model/ccv_pss_test.qnt @@ -10,8 +10,9 @@ module ccv_pss_test { import extraSpells.* from "./libraries/extraSpells" import ccv_utils.* from "./ccv_utils" import ccv_pss.* from "./ccv_pss" + import ccv.* from "./ccv" - run TopNTest = + run TopN1Test = val valSet = Map("d" -> 25, "c1" -> 15, "c" -> 15, "b2" -> 10, "b1" -> 10, "b" -> 10, "a2" -> 5, "a1" -> 5, "a" -> 5) // total power: 5*3 + 10*3 + 15*2 + 25 = 100 @@ -30,5 +31,31 @@ module ccv_pss_test { assert(GetTopNVals(valSet, 86) == valSet.keys()), assert(GetTopNVals(valSet, 95) == valSet.keys()), assert(GetTopNVals(valSet, 100) == valSet.keys()), - } + } + + val providerState = GetEmptyProviderState().with( + "chainState", GetEmptyChainState().with( + "currentValidatorPowers", Map( + "a" -> 5, + "a1" -> 5, + "a2" -> 5, + "b" -> 10, + "b1" -> 10, + "b2" -> 10, + "c" -> 15, + "c1" -> 15, + "d" -> 25 + ) + ) + ).with( + "consumerStatus", Map( + "consumer1" -> "running" + ) + ).with( + "topNByConsumer", Map( + "consumer1" -> 80 + ) + ) + run TopN2Test = + true } \ No newline at end of file From 925ae40eb4509f2ed9511eb0a7565f01f25bd756 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Fri, 26 Apr 2024 16:03:25 +0200 Subject: [PATCH 071/110] Add expected errors to opt out action --- tests/e2e/actions.go | 23 ++++++++++++++--------- tests/e2e/steps_partial_set_security.go | 10 ++++++---- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index f4f159cabc..2fd95abb00 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -2319,8 +2319,9 @@ func (tr TestConfig) optIn(action OptInAction, target ExecutionTarget, verbose b } type OptOutAction struct { - Chain ChainID - Validator ValidatorID + Chain ChainID + Validator ValidatorID + ExpectError bool } func (tr TestConfig) optOut(action OptOutAction, target ExecutionTarget, verbose bool) { @@ -2353,13 +2354,17 @@ func (tr TestConfig) optOut(action OptOutAction, target ExecutionTarget, verbose } bz, err := cmd.CombinedOutput() - if err != nil { - log.Fatal(err, "\n", string(bz)) - } - - if !tr.useCometmock { // error report only works with --gas auto, which does not work with CometMock, so ignore - if verbose { - fmt.Printf("got expected error during opt out | err: %s | output: %s \n", err, string(bz)) + if action.ExpectError { + if err != nil { + if verbose { + fmt.Printf("got expected error during opt out | err: %s | output: %s \n", err, string(bz)) + } + } else { + log.Fatal("expected error during opt-out but got none") + } + } else { + if err != nil { + log.Fatal(err, "\n", string(bz)) } } diff --git a/tests/e2e/steps_partial_set_security.go b/tests/e2e/steps_partial_set_security.go index 751a710499..cf230b999c 100644 --- a/tests/e2e/steps_partial_set_security.go +++ b/tests/e2e/steps_partial_set_security.go @@ -604,15 +604,17 @@ func stepsTopNChain() []Step { }, { Action: OptOutAction{ - Chain: ChainID("consu"), - Validator: ValidatorID("carol"), + Chain: ChainID("consu"), + Validator: ValidatorID("carol"), + ExpectError: true, }, State: State{}, }, { Action: OptOutAction{ - Chain: ChainID("consu"), - Validator: ValidatorID("bob"), + Chain: ChainID("consu"), + Validator: ValidatorID("bob"), + ExpectError: true, }, State: State{}, }, From df516976140b713ad9d30c3f147f74651e6a1ce9 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Mon, 29 Apr 2024 10:24:43 +0200 Subject: [PATCH 072/110] Revert PSS quint model changes --- tests/mbt/driver/core.go | 32 +---- tests/mbt/driver/generate_more_traces.sh | 5 +- tests/mbt/driver/generate_traces.sh | 5 +- tests/mbt/driver/mbt_test.go | 90 ++------------ tests/mbt/driver/model_viewer.go | 9 -- tests/mbt/driver/setup.go | 63 +++------- tests/mbt/model/ccv.qnt | 117 ++++++------------ tests/mbt/model/ccv_boundeddrift.qnt | 60 ++------- tests/mbt/model/ccv_model.qnt | 141 ++++++---------------- tests/mbt/model/ccv_sync.qnt | 2 +- tests/mbt/model/ccv_test.qnt | 22 ++-- tests/mbt/model/ccv_utils.qnt | 51 ++------ tests/mbt/model/libraries/extraSpells.qnt | 104 ---------------- tests/mbt/run_invariants.sh | 1 - 14 files changed, 131 insertions(+), 571 deletions(-) diff --git a/tests/mbt/driver/core.go b/tests/mbt/driver/core.go index 2fedb0f006..3c985cb6fa 100644 --- a/tests/mbt/driver/core.go +++ b/tests/mbt/driver/core.go @@ -391,40 +391,12 @@ func (s *Driver) setTime(chain ChainId, newTime time.Time) { testChain.App.BeginBlock(abcitypes.RequestBeginBlock{Header: testChain.CurrentHeader}) } -func (s *Driver) AssignKey(chain ChainId, valIndex int64, key crypto.PublicKey) error { +func (s *Driver) AssignKey(chain ChainId, valIndex int64, value crypto.PublicKey) error { stakingVal, found := s.stakingValidator(valIndex) if !found { return fmt.Errorf("validator with id %v not found on provider", valIndex) } - return s.providerKeeper().AssignConsumerKey(s.providerCtx(), string(chain), stakingVal, key) -} - -// Opts the given validator into the given consumer chain on the provider. -func (s *Driver) OptIn(chain ChainId, valIndex int64) error { - stakingVal, found := s.stakingValidator(valIndex) - if !found { - return fmt.Errorf("validator with id %v not found on provider", valIndex) - } - consPubKey, err := stakingVal.ConsPubKey() - if err != nil { - return err - } - consAddr := sdk.GetConsAddress(consPubKey) - return s.providerKeeper().HandleOptIn(s.providerCtx(), string(chain), providertypes.NewProviderConsAddress(consAddr), nil) -} - -// Opts the given validator out of the given consumer chain on the provider. -func (s *Driver) OptOut(chain ChainId, valIndex int64) error { - stakingVal, found := s.stakingValidator(valIndex) - if !found { - return fmt.Errorf("validator with id %v not found on provider", valIndex) - } - consPubKey, err := stakingVal.ConsPubKey() - if err != nil { - return err - } - consAddr := sdk.GetConsAddress(consPubKey) - return s.providerKeeper().HandleOptOut(s.providerCtx(), string(chain), providertypes.NewProviderConsAddress(consAddr)) + return s.providerKeeper().AssignConsumerKey(s.providerCtx(), string(chain), stakingVal, value) } // DeliverPacketToConsumer delivers a packet from the provider to the given consumer recipient. diff --git a/tests/mbt/driver/generate_more_traces.sh b/tests/mbt/driver/generate_more_traces.sh index aeba390ab3..d0dc441d81 100755 --- a/tests/mbt/driver/generate_more_traces.sh +++ b/tests/mbt/driver/generate_more_traces.sh @@ -11,6 +11,5 @@ go run ./... -modelPath=../model/ccv_sync.qnt -init initSync -step stepSync -inv echo "Generating traces with jails" go run ./... -modelPath=../model/ccv_sync.qnt -init initSync -step stepSync -invariant CanJail -traceFolder traces/sync_jailmany -numTraces 2 -numSteps 100 -numSamples 20 echo "Generating long synced traces without invariants" -go run ./... -modelPath=../model/ccv_sync.qnt -init initSync -step stepSync -traceFolder traces/sync_noinv -numTraces 20 -numSteps 500 -numSamples 1 -go run ./... -modelPath=../model/ccv_boundeddrift.qnt --step stepBoundedDriftKeyAssignment --traceFolder traces/bound_key -numTraces 20 -numSteps 100 -numSamples 20 -go run ./... -modelPath=../model/ccv_boundeddrift.qnt --step stepBoundedDriftKeyAndPSS --traceFolder traces/bound_pss -numTraces 20 -numSteps 100 -numSamples 20 +go run ./... -modelPath=../model/ccv_sync.qnt -init initSync -step stepSync -traceFolder traces/sync_noinv -numTraces 20 -numSteps 300 -numSamples 1 +go run ./... -modelPath=../model/ccv_boundeddrift.qnt --step stepBoundedDriftKeyAssignment --traceFolder traces/bound_key -numTraces 20 -numSteps 100 -numSamples 20 \ No newline at end of file diff --git a/tests/mbt/driver/generate_traces.sh b/tests/mbt/driver/generate_traces.sh index 653f4016cf..509168543e 100755 --- a/tests/mbt/driver/generate_traces.sh +++ b/tests/mbt/driver/generate_traces.sh @@ -11,6 +11,5 @@ go run ./... -modelPath=../model/ccv_sync.qnt -init initSync -step stepSync -inv echo "Generating traces with many jails" go run ./... -modelPath=../model/ccv_sync.qnt -init initSync -step stepSync -invariant CanJail -traceFolder traces/sync_jailmany -numTraces 2 -numSteps 100 -numSamples 20 echo "Generating long synced traces without invariants" -go run ./... -modelPath=../model/ccv_sync.qnt -init initSync -step stepSync -traceFolder traces/sync_noinv -numTraces 1 -numSteps 500 -numSamples 1 -go run ./... -modelPath=../model/ccv_boundeddrift.qnt --step stepBoundedDriftKeyAssignment --traceFolder traces/bound_key -numTraces 1 -numSteps 100 -numSamples 20 -go run ./... -modelPath=../model/ccv_boundeddrift.qnt --step stepBoundedDriftKeyAndPSS --traceFolder traces/bound_pss -numTraces 1 -numSteps 100 -numSamples 20 +go run ./... -modelPath=../model/ccv_sync.qnt -init initSync -step stepSync -traceFolder traces/sync_noinv -numTraces 2 -numSteps 100 -numSamples 1 +go run ./... -modelPath=../model/ccv_boundeddrift.qnt --step stepBoundedDriftKeyAssignment --traceFolder traces/bound_key -numTraces 2 -numSteps 100 -numSamples 20 \ No newline at end of file diff --git a/tests/mbt/driver/mbt_test.go b/tests/mbt/driver/mbt_test.go index 83b1c40d90..9a82bd7b9b 100644 --- a/tests/mbt/driver/mbt_test.go +++ b/tests/mbt/driver/mbt_test.go @@ -139,10 +139,6 @@ func RunItfTrace(t *testing.T, path string) { // sort the keys sort.Strings(consumerPrivValKeys) - // consumerAddrNames are the human readable names of consumer addresses in the model - // "realAddrs" are the addresses of the consumer keys on chain - // these maps relate the consumerAddrNames to the priv validators (from which one can get the real address) - // and from the real addresses to the consumerAddrNames to allow converting between the two easily consumerAddrNamesToVals := make(map[string]*cmttypes.Validator, len(consumerAddressesExpr)) consumerAddrNamesToPrivVals := make(map[string]cmttypes.PrivValidator, len(consumerAddressesExpr)) realAddrsToModelConsAddrs := make(map[string]string, len(consumerAddressesExpr)) @@ -241,6 +237,8 @@ func RunItfTrace(t *testing.T, path string) { t.Log("Reading the trace...") for index, state := range trace.States { + t.Log("Height modulo epoch length:", driver.providerChain().CurrentHeader.Height%blocksPerEpoch) + t.Log("Model height modulo epoch length:", ProviderHeight(state.VarValues["currentState"].Value.(itf.MapExprType))%modelBlocksPerEpoch) t.Logf("Reading state %v of trace %v", index, path) // store the height of the provider state before each step. @@ -341,17 +339,14 @@ func RunItfTrace(t *testing.T, path string) { driver.coordinator.CurrentTime = driver.runningTime("provider") // start consumers for _, consumer := range consumersToStart { - chainId := consumer.Value.(itf.MapExprType)["chain"].Value.(string) - topN := consumer.Value.(itf.MapExprType)["topN"].Value.(int64) driver.setupConsumer( - chainId, + consumer.Value.(string), modelParams, driver.providerChain().Vals, consumerSigners, nodes, valNames, driver.providerChain(), - topN, ) } @@ -370,8 +365,7 @@ func RunItfTrace(t *testing.T, path string) { // unless it was the last consumer to be started, in which case it already has the header // as we called driver.setupConsumer for _, consumer := range driver.runningConsumers() { - if len(consumersToStart) > 0 && - consumer.ChainId == consumersToStart[len(consumersToStart)-1].Value.(itf.MapExprType)["chain"].Value.(string) { + if len(consumersToStart) > 0 && consumer.ChainId == consumersToStart[len(consumersToStart)-1].Value.(string) { continue } @@ -448,31 +442,6 @@ func RunItfTrace(t *testing.T, path string) { err = driver.AssignKey(ChainId(consumerChain), int64(valIndex), protoPubKey) require.NoError(t, err, "Error assigning key") - case "OptIn": - consumerChain := lastAction["consumerChain"].Value.(string) - validator := lastAction["validator"].Value.(string) - t.Log("OptIn", consumerChain, validator) - - valIndex := getIndexOfString(validator, valNames) - - err := driver.OptIn(ChainId(consumerChain), int64(valIndex)) - require.NoError(t, err, "Error opting in") - - case "OptOut": - consumerChain := lastAction["consumerChain"].Value.(string) - validator := lastAction["validator"].Value.(string) - expectedError := lastAction["expectedError"].Value.(string) - t.Log("OptOut", consumerChain, validator, expectedError) - - valIndex := getIndexOfString(validator, valNames) - - err := driver.OptOut(ChainId(consumerChain), int64(valIndex)) - - if expectedError != "" { - require.Error(t, err, "Expected an error: %v", expectedError) - } else { - require.NoError(t, err, "Error opting out, but expected no error") - } case "ConsumerInitiatedSlash": consumerChain := lastAction["consumerChain"].Value.(string) validatorName := lastAction["validator"].Value.(string) @@ -517,6 +486,9 @@ func RunItfTrace(t *testing.T, path string) { t.Logf("Current actual state: %s", driver.getStateString()) } + // check that the actual state is the same as the model state + t.Logf("Comparing model state to actual state...") + // compare the running consumers modelRunningConsumers := RunningConsumers(currentModelState) @@ -544,7 +516,7 @@ func RunItfTrace(t *testing.T, path string) { // check sent packets: we check that the package queues in the model and the system have the same length. for _, consumer := range actualRunningConsumers { - ComparePacketQueues(t, driver, currentModelState, consumer, timeOffset, realAddrsToModelConsAddrs) + ComparePacketQueues(t, driver, currentModelState, consumer, timeOffset) } // compare that the sent packets on the proider match the model CompareSentPacketsOnProvider(driver, currentModelState, timeOffset) @@ -606,6 +578,8 @@ func RunItfTrace(t *testing.T, path string) { // we changed epoch during this step, so ensure that the model also changed epochs require.True(t, ProviderHeight(state.VarValues["currentState"].Value.(itf.MapExprType))%modelBlocksPerEpoch == 0, "Height in model did not change epoch, but did in system. increase blocksPerEpoch in the system") } + + t.Logf("State %v of trace %v is ok!", index, path) } t.Log("🟢 Trace is ok!") } @@ -630,7 +604,7 @@ func CompareValidatorSets( driver *Driver, currentModelState map[string]itf.Expr, consumers []string, - // a map from real addresses to the names of those consensus addresses in the model + // a map from real addresses to the names of those consumer addresses in the model keyAddrsToModelConsAddrName map[string]string, ) { t.Helper() @@ -645,9 +619,6 @@ func CompareValidatorSets( actualValSet[valName] = val.Tokens.Int64() } - fmt.Println("Model validator set:", modelValSet) - fmt.Println("Actual validator set:", actualValSet) - require.NoError(t, CompareValSet(modelValSet, actualValSet), "Validator sets do not match") for _, consumer := range consumers { @@ -696,7 +667,6 @@ func ComparePacketQueues( currentModelState map[string]itf.Expr, consumer string, timeOffset time.Time, - realConsAddrToModelValName map[string]string, ) { t.Helper() ComparePacketQueue(t, driver, currentModelState, PROVIDER, consumer, timeOffset) @@ -743,44 +713,6 @@ func ComparePacketQueue( actualPacket, sender, receiver) - - // reconstruct a VSCPacket from the actual packet - var actualPacketData types.ValidatorSetChangePacketData - err := types.ModuleCdc.UnmarshalJSON(actualPacket.Packet.GetData(), &actualPacketData) - require.NoError(t, err, "Error unmarshalling packet data") - - modelPacketValSet := modelPacket["validatorSet"].Value.(itf.MapExprType) - - // check that for all validators in the actual packets validator updates, - // the model has the same power for the validator - // note: we cannot check equivalence, because the system sends only changes, - // whereas the model sends the full set. - for _, valUpdate := range actualPacketData.ValidatorUpdates { - // get the name of the validator in the valUpdate - valPubKey := valUpdate.PubKey - consAddr, err := types.TMCryptoPublicKeyToConsAddr(valPubKey) - - require.NoError(t, err, "Error getting consensus address from pubkey") - - // get the name of the validator in the model - val, found := driver.providerStakingKeeper().GetValidatorByConsAddr(driver.providerCtx(), consAddr) - require.True(t, found, "Error getting validator by consensus address") - - modelValName := val.Description.Moniker - - // get the power of the validator in the model - modelPower := modelPacketValSet[modelValName].Value.(int64) - - // compare the power of the validator in the model to the power of the validator in the actual packet - require.Equal(t, - modelPower, - valUpdate.Power, - "Validator powers do not match for validator %v in packet %v, sender %v, receiver %v", - modelValName, - actualPacket, - sender, - receiver) - } } } diff --git a/tests/mbt/driver/model_viewer.go b/tests/mbt/driver/model_viewer.go index 2ef453e7b8..87ec386382 100644 --- a/tests/mbt/driver/model_viewer.go +++ b/tests/mbt/driver/model_viewer.go @@ -117,12 +117,3 @@ func ProviderJailedValidators(curStateExpr itf.MapExprType) ([]string, []int64) } return jailedValidators, jailEndTimes } - -func OptedInVals(curStateExpr itf.MapExprType, consumer string) []string { - optedInValExpr := ProviderState(curStateExpr)["optedInVals"].Value.(itf.MapExprType)[consumer].Value.(itf.ListExprType) - optedInVals := make([]string, len(optedInValExpr)) - for i, valExpr := range optedInValExpr { - optedInVals[i] = valExpr.Value.(string) - } - return optedInVals -} diff --git a/tests/mbt/driver/setup.go b/tests/mbt/driver/setup.go index 94db0995c7..f6f68f14c5 100644 --- a/tests/mbt/driver/setup.go +++ b/tests/mbt/driver/setup.go @@ -314,7 +314,7 @@ func newChain( // Creates a path for cross-chain validation from the consumer to the provider and configures the channel config of the endpoints // as well as the clients. // this function stops when there is an initialized, ready-to-relay channel between the provider and consumer. -func (s *Driver) ConfigureNewPath(consumerChain, providerChain *ibctesting.TestChain, params ModelParams, topN uint32, consumerInitialValSet *cmttypes.ValidatorSet) *ibctesting.Path { +func (s *Driver) ConfigureNewPath(consumerChain, providerChain *ibctesting.TestChain, params ModelParams) *ibctesting.Path { consumerChainId := ChainId(consumerChain.ChainID) path := ibctesting.NewPath(consumerChain, providerChain) @@ -350,7 +350,7 @@ func (s *Driver) ConfigureNewPath(consumerChain, providerChain *ibctesting.TestC []string{"upgrade", "upgradedIBCState"}, ) - consumerGenesis := createConsumerGenesis(params, providerChain, consumerClientState, consumerInitialValSet) + consumerGenesis := createConsumerGenesis(params, providerChain, consumerClientState) s.consumerKeeper(consumerChainId).InitGenesis(s.ctx(consumerChainId), consumerGenesis) @@ -362,10 +362,13 @@ func (s *Driver) ConfigureNewPath(consumerChain, providerChain *ibctesting.TestC var stakingValidators []stakingtypes.Validator - // set up the current consumer validators by utilizing the initial valSet on the consumer - for _, val := range consumerInitialValSet.Validators { + // set up the current consumer validators by utilizing the initial validator set + for _, val := range consumerGenesisForProvider.Provider.InitialValSet { pubKey := val.PubKey - consAddr := sdk.ConsAddress(pubKey.Address()) + consAddr, err := ccvtypes.TMCryptoPublicKeyToConsAddr(pubKey) + if err != nil { + continue + } v, found := s.providerStakingKeeper().GetValidatorByConsAddr(s.providerCtx(), consAddr) if !found { @@ -374,8 +377,7 @@ func (s *Driver) ConfigureNewPath(consumerChain, providerChain *ibctesting.TestC stakingValidators = append(stakingValidators, v) } - considerAll := func(validator stakingtypes.Validator) bool { return true } - nextValidators := s.providerKeeper().ComputeNextEpochConsumerValSet(s.providerCtx(), string(consumerChainId), stakingValidators, considerAll) + nextValidators := s.providerKeeper().ComputeNextEpochConsumerValSet(s.providerCtx(), string(consumerChainId), stakingValidators) s.providerKeeper().SetConsumerValSet(s.providerCtx(), string(consumerChainId), nextValidators) err = s.providerKeeper().SetConsumerGenesis( @@ -384,9 +386,6 @@ func (s *Driver) ConfigureNewPath(consumerChain, providerChain *ibctesting.TestC consumerGenesisForProvider) require.NoError(s.t, err, "Error setting consumer genesis on provider for chain %v", consumerChain.ChainID) - // set the top N percentage - s.providerKeeper().SetTopN(providerChain.GetContext(), consumerChain.ChainID, topN) - // Client ID is set in InitGenesis and we treat it as a black box. So // must query it to use it with the endpoint. clientID, _ := s.consumerKeeper(consumerChainId).GetProviderClientID(s.ctx(consumerChainId)) @@ -456,58 +455,24 @@ func (s *Driver) setupConsumer( nodes []*cmttypes.Validator, // the list of nodes, even ones that have no voting power initially valNames []string, providerChain *ibctesting.TestChain, - topN int64, ) { s.t.Logf("Starting consumer %v", chain) - minOptInPower := sdk.NewInt(0) - - powers := make([]int64, 0) - for _, val := range valSet.Validators { - power := val.VotingPower - powers = append(powers, power) - } - - // sort by powers descending - sort.Slice(powers, func(i, j int) bool { - return powers[i] > powers[j] - }) - - topNThreshold := sdk.NewDecFromInt(sdk.NewInt(int64(topN))).QuoInt64(int64(100)) - powerSum := sdk.ZeroDec() - totalVotingPower := sdk.NewDecFromInt(sdk.NewInt(valSet.TotalVotingPower())) - for _, power := range powers { - powerSum = powerSum.Add(sdk.NewDecFromInt(sdk.NewInt(power))) - if powerSum.Quo(totalVotingPower).GTE(topNThreshold) { - minOptInPower = sdk.NewInt(power) - break - } - } - // get a new validator set with only the top N validators - topNVals := []*cmttypes.Validator{} - for _, val := range valSet.Validators { - if val.VotingPower >= minOptInPower.Int64() { - topNVals = append(topNVals, val) - } - } - topNValSet := cmttypes.NewValidatorSet(topNVals) - topNValSet.Proposer = topNValSet.Validators[0] - - initValUpdates := cmttypes.TM2PB.ValidatorUpdates(topNValSet) + initValUpdates := cmttypes.TM2PB.ValidatorUpdates(valSet) // start consumer chains s.t.Logf("Creating consumer chain %v", chain) - consumerChain := newChain(s.t, params, s.coordinator, icstestingutils.ConsumerAppIniter(initValUpdates), chain, topNValSet, signers, topNVals, valNames) + consumerChain := newChain(s.t, params, s.coordinator, icstestingutils.ConsumerAppIniter(initValUpdates), chain, valSet, signers, nodes, valNames) s.coordinator.Chains[chain] = consumerChain - path := s.ConfigureNewPath(consumerChain, providerChain, params, uint32(topN), topNValSet) + path := s.ConfigureNewPath(consumerChain, providerChain, params) s.simibcs[ChainId(chain)] = simibc.MakeRelayedPath(s.t, path) } -func createConsumerGenesis(modelParams ModelParams, providerChain *ibctesting.TestChain, consumerClientState *ibctmtypes.ClientState, initialValSet *cmttypes.ValidatorSet) *consumertypes.GenesisState { +func createConsumerGenesis(modelParams ModelParams, providerChain *ibctesting.TestChain, consumerClientState *ibctmtypes.ClientState) *consumertypes.GenesisState { providerConsState := providerChain.LastHeader.ConsensusState() - valUpdates := cmttypes.TM2PB.ValidatorUpdates(initialValSet) + valUpdates := cmttypes.TM2PB.ValidatorUpdates(providerChain.Vals) params := ccvtypes.NewParams( true, 1000, // ignore distribution diff --git a/tests/mbt/model/ccv.qnt b/tests/mbt/model/ccv.qnt index 224ef1e33c..87ddc91ea2 100644 --- a/tests/mbt/model/ccv.qnt +++ b/tests/mbt/model/ccv.qnt @@ -157,16 +157,6 @@ module ccv_types { // For every sent VSCPacket, stores the key assignments that were applied to send it. keyAssignmentsForVSCPackets: VscId -> (Chain -> (Node -> ConsumerAddr)), - // For each consumer chain, - // stores the set of validators that are opted into running the chain. - optedInVals: Chain -> Set[Node], - - // for each consumer, stores the top N for that consumer. - // The top N% of the validator set by voting power - // is obliged to run a topN chain. - // If the chain is a pure opt-in chain (where noone is forced to run it), - // this is 0. - topNByConsumer: Chain -> int, // downtimeSlashRequests[chainId] contains all the validator addresses for which the provider chain // received slash requests for downtime from the consumer chain with chainId // in this block. used to acknowledge slash requests upon EndBlock. @@ -188,8 +178,6 @@ module ccv_types { consumerAddrToValidator: Map(), consumerAddrsToPrune: Map(), keyAssignmentsForVSCPackets: Map(), - optedInVals: Map(), - topNByConsumer: Map(), downtimeSlashRequests: Map(), acksToSendOnEndBlock: Map(), consumersWithAddrAssignmentChangesInThisEpoch: Set() @@ -311,33 +299,6 @@ module ccv_types { // given as a pure val so that we can switch cases based on // whether a chain is the provider or not pure val PROVIDER_CHAIN = "provider" - - // A record that keeps the information needed to add a new consumer. - // In particular, holds: - // the chain name/identifier, - // and the top N factor for the chain. - type ConsumerAdditionMsg = { - chain: Chain, - topN: int - } - - // Creates a new ConsumerAdditionMsg with a given top N. - pure def NewTopNConsumer(chain: Chain, topN: int): ConsumerAdditionMsg = { - { - chain: chain, - topN: topN - } - } - - // Creates a new ConsumerAdditionMsg with topN = 0. - pure def NewOptInConsumer(chain: Chain): ConsumerAdditionMsg = { - NewTopNConsumer(chain, 0) - } - - // Creates a new ConsumerAdditionMsg with top N = 100%. - pure def NewFullConsumer(chain: Chain): ConsumerAdditionMsg = { - NewTopNConsumer(chain, 100) - } } module ccv { @@ -358,7 +319,6 @@ module ccv { import Time.* from "./libraries/Time" import extraSpells.* from "./libraries/extraSpells" import ccv_types.* - import ccv_pss.* from "./ccv_pss" import ccv_utils.* from "./ccv_utils" @@ -565,14 +525,13 @@ module ccv { // i.e. the timestamp for the next block is oldTimestamp + timeAdvancement timeAdvancement: Time, // a set of consumers that were not consumers before, but should be set to running now. - consumersToStart: Set[ConsumerAdditionMsg], + consumersToStart: Set[Chain], // a set of consumers that were running before, but should be set to stopped now. // This argument only needs to contain "voluntary" stops - // forced stops, e.g. because a consumer timed out, // will be added automatically. consumersToStop: Set[Chain]): Result = { val currentProviderState = currentState.providerState - val curValSet = currentProviderState.chainState.currentValidatorPowers // check for vsc timeouts val timedOutConsumers = getRunningConsumers(currentProviderState).filter( @@ -584,8 +543,24 @@ module ccv { // run the shared core chainState logic val newChainState = currentProviderState.chainState.endAndBeginBlockShared(timeAdvancement) + // for each consumer chain, apply the key assignment to the current validator set + val currentValSets = ConsumerChains.mapBy( + (consumer) => + currentProviderState.applyKeyAssignmentToValSet( + consumer, + newChainState.votingPowerHistory.head() + ) + ) + // store the current validator set with the key assignments applied in the history + val newKeyAssignedValSetHistory = currentValSets.keys().mapBy( + (consumer) => + currentProviderState.keyAssignedValSetHistory + .getOrElse(consumer, List()) // get the existing history (empty list if no history yet) + .prepend(currentValSets.get(consumer)) // prepend the current validator set with key assignments applied + ) + val providerStateAfterTimeAdvancement = - {...currentProviderState, chainState: newChainState} + {...currentProviderState, chainState: newChainState, keyAssignedValSetHistory: newKeyAssignedValSetHistory} val tmpState = currentState.with( "providerState", providerStateAfterTimeAdvancement ) @@ -607,7 +582,7 @@ module ccv { // acknowledge the packets to be acknowledged on endblock val newConsumerStates = currentState.consumerStates.keys().mapBy( (consumer) => - val consumerState = currentState.consumerStates.get(consumer) + val consumerState = currentState.consumerStates.get(consumer) val packetsToAck = currentProviderState.acksToSendOnEndBlock.getOrElse(consumer, List()) val newConsumerState = packetsToAck.foldl(consumerState, (state, packet) => deliverAck(state, packet) @@ -617,13 +592,16 @@ module ccv { // start/stop chains - val res = providerStateAfterSending.StartStopConsumers( + val res = providerStateAfterSending.consumerStatus.StartStopConsumers( consumersToStart, consumersToStop, timedOutConsumers ) + val newConsumerStatus = res._1 val err = res._2 - val providerStateAfterConsumerAdvancement = res._1.with( + val providerStateAfterConsumerAdvancement = providerStateAfterSending.with( + "consumerStatus", newConsumerStatus + ).with( "downtimeSlashRequests", Map() ).with( "acksToSendOnEndBlock", Map() @@ -635,44 +613,19 @@ module ccv { "consumerStates", newConsumerStates ) - // for each running consumer chain, opt in validators that are in the top N - val providerStateAfterPSS = providerStateAfterConsumerAdvancement.endBlockPSS() - - // for each consumer chain, apply the key assignment to the current validator set - val currentValSets = ConsumerChains.mapBy( - (consumer) => - val pssValSet = providerStateAfterPSS.GetPSSValidatorSet( - providerStateAfterPSS.chainState.votingPowerHistory.head(), - consumer) - providerStateAfterPSS.applyKeyAssignmentToValSet( - consumer, - pssValSet - ) - ) - // store the current validator set with the key assignments applied in the history - val newKeyAssignedValSetHistory = currentValSets.keys().mapBy( - (consumer) => - providerStateAfterPSS.keyAssignedValSetHistory - .getOrElse(consumer, List()) // get the existing history (empty list if no history yet) - .prepend(currentValSets.get(consumer)) // prepend the current validator set with key assignments applied - ) - if (err != "") { Err(err) - } else if (providerStateAfterPSS.chainState.votingPowerHistory.head().IsEmptyValSet()) { + } else if (providerStateAfterConsumerAdvancement.chainState.votingPowerHistory.head().IsEmptyValSet()) { Err("Validator set would be empty after ending this block!") } else { // for each consumer we just set to running, set its initial validator set to be the current one on the provider... - val valSet = providerStateAfterPSS.chainState.votingPowerHistory.head() - + val valSet = providerStateAfterConsumerAdvancement.chainState.votingPowerHistory.head() val newConsumerStateMap = tmpState2.consumerStates.keys().mapBy( (consumer) => - if (consumersToStart.map(consumer => consumer.chain).contains(consumer)) { - // ...filtered by opted in validators - val pssValSet = GetPSSValidatorSet(providerStateAfterPSS, valSet, consumer) + if (consumersToStart.contains(consumer)) { // ...modified by the key assignments for the consumer - val consValSet = applyKeyAssignmentToValSet(providerStateAfterPSS, consumer, pssValSet) + val consValSet = applyKeyAssignmentToValSet(providerStateAfterConsumerAdvancement, consumer, valSet) val currentConsumerState: ConsumerState = tmpState2.consumerStates.get(consumer) val newConsumerState: ConsumerState = currentConsumerState.with( "chainState", currentConsumerState.chainState.with( @@ -682,10 +635,10 @@ module ccv { List(consValSet) ).with( "lastTimestamp", - providerStateAfterPSS.chainState.lastTimestamp + providerStateAfterConsumerAdvancement.chainState.lastTimestamp ).with( "runningTimestamp", - providerStateAfterPSS.chainState.runningTimestamp + providerStateAfterConsumerAdvancement.chainState.runningTimestamp ) ) newConsumerState @@ -693,8 +646,8 @@ module ccv { tmpState2.consumerStates.get(consumer) } ) - val newState = tmpState.with( - "providerState", providerStateAfterPSS + val newState = tmpState2.with( + "providerState", providerStateAfterConsumerAdvancement ).with( "consumerStates", newConsumerStateMap ) @@ -851,10 +804,8 @@ module ccv { pure val provValSet = currentState.providerState.chainState.currentValidatorPowers pure val provValPower = if (provValSet.keys().contains(providerNode)) provValSet.get(providerNode) else 0 pure val consumersWithAddrAssignmentChangesInThisEpoch = - if (provValPower > 0 and providerNode.in(nonJailedNodes(currentState.providerState)) and currentState.providerState.optedInVals.getOrElse(consumer, Set()).contains(providerNode)) { - // if the validator has positive power and is not jailed, - // and the validator is opted in on the consumer, - // the relevant key assignment for the consumer changed + if (provValPower > 0 and providerNode.in(nonJailedNodes(currentState.providerState))) { + // if the validator has positive power and is not jailed, the relevant key assignment for the consumer changed currentState.providerState.consumersWithAddrAssignmentChangesInThisEpoch.union(Set(consumer)) } else { // otherwise, the consumer doesn't need to know about the change, so no change diff --git a/tests/mbt/model/ccv_boundeddrift.qnt b/tests/mbt/model/ccv_boundeddrift.qnt index 2552304816..24db1d3eaf 100644 --- a/tests/mbt/model/ccv_boundeddrift.qnt +++ b/tests/mbt/model/ccv_boundeddrift.qnt @@ -5,7 +5,6 @@ module ccv_boundeddrift { import ccv from "ccv" import Time.* from "./libraries/Time" import extraSpells.* from "./libraries/extraSpells" - import ccv_pss_model.* from "ccv_pss_model" // The boundeddrift module has its own step function. @@ -61,41 +60,8 @@ module ccv_boundeddrift { stepCommon, // allow actions that do not influence time // advance a block for a consumer - stepBoundedDriftConsumer, - - // advance a block for the provider - stepBoundedDriftProvider - } - - action stepBoundedDriftProvider: bool = { - stepBoundedDriftProvider_helper(allFullConsumers) - } - - action stepBoundedDriftProviderPSS: bool = { - stepBoundedDriftProvider_helper(variousPossibleTopN) - } - - // As an argument, takes a function that, when invoked, gives a top N value to use for a new consumer chain. - action stepBoundedDriftProvider_helper(topNOracle: Set[int]): bool = { - val maxAdv = findMaxTimeAdvancement(GetChainState(Ccvt::PROVIDER_CHAIN), GetOtherChainStates(Ccvt::PROVIDER_CHAIN), maxDrift) - val possibleAdvancements = timeAdvancements.filter(t => t <= maxAdv) all { - possibleAdvancements.size() > 0, // ensure there is a possible advancement, otherwise this action does not make sense - // advance a block for the provider - val consumerStatus = currentState.providerState.consumerStatus - nondet consumersToStart = oneOf(nonConsumers.powerset()) - nondet topN = oneOf(topNOracle) - nondet consumerAdditions = consumersToStart.map(c => Ccvt::NewTopNConsumer(c, topN)) - // make it so we stop consumers only with small likelihood: - nondet stopConsumersRand = oneOf(1.to(100)) - nondet consumersToStop = if (stopConsumersRand <= consumerStopChance) oneOf(runningConsumers.powerset()) else Set() - nondet timeAdvancement = oneOf(possibleAdvancements) - EndAndBeginBlockForProvider(timeAdvancement, consumerAdditions, consumersToStop), - } - } - - action stepBoundedDriftConsumer = all { - runningConsumers.size() > 0, // ensure there is a running consumer, otherwise this action does not make sense + runningConsumers.size() > 0, // ensure there is a running consumer, otherwise this action does not make sense nondet chain = runningConsumers.oneOf() val maxAdv = findMaxTimeAdvancement(GetChainState(chain), GetOtherChainStates(chain), maxDrift) val possibleAdvancements = timeAdvancements.filter(t => t <= maxAdv) @@ -104,20 +70,7 @@ module ccv_boundeddrift { nondet timeAdvancement = possibleAdvancements.oneOf() EndAndBeginBlockForConsumer(chain, timeAdvancement), } - } - - action stepBoundedDriftKeyAssignment = any { - stepBoundedDrift, - nondetKeyAssignment, - } - - action stepBoundedDriftKeyAndPSS: bool = any { - stepCommon, - stepBoundedDriftProviderPSS, - stepBoundedDriftConsumer, - nondetKeyAssignment, - StepOptIn, - StepOptOut, + }, // advance a block for the provider val maxAdv = findMaxTimeAdvancement(GetChainState(Ccvt::PROVIDER_CHAIN), GetOtherChainStates(Ccvt::PROVIDER_CHAIN), maxDrift) @@ -127,16 +80,19 @@ module ccv_boundeddrift { // advance a block for the provider val consumerStatus = currentState.providerState.consumerStatus nondet consumersToStart = oneOf(nonConsumers.powerset()) - nondet topN = oneOf(variousPossibleTopN) - nondet consumerAdditions = consumersToStart.map(c => Ccvt::NewTopNConsumer(c, topN)) // make it so we stop consumers only with small likelihood: nondet stopConsumersRand = oneOf(1.to(100)) nondet consumersToStop = if (stopConsumersRand <= consumerStopChance) oneOf(runningConsumers.powerset()) else Set() nondet timeAdvancement = oneOf(possibleAdvancements) - EndAndBeginBlockForProvider(timeAdvancement, consumerAdditions, consumersToStop), + EndAndBeginBlockForProvider(timeAdvancement, consumersToStart, consumersToStop), } } + action stepBoundedDriftKeyAssignment = any { + stepBoundedDrift, + nondetKeyAssignment, + } + // INVARIANT // The maxDrift between chains is never exceeded. // This *should* be ensured by the step function. diff --git a/tests/mbt/model/ccv_model.qnt b/tests/mbt/model/ccv_model.qnt index 5f6d8c8db5..e2b812e212 100644 --- a/tests/mbt/model/ccv_model.qnt +++ b/tests/mbt/model/ccv_model.qnt @@ -61,13 +61,7 @@ module ccv_model { var currentState: ProtocolState - // a type storing the parameters used in actions, - // as well as return values that are not visible from the state, - // i.e. errors. - // Note that whether an error is returned, - // or whether the action is simply not possible when an error occurs, is - // a design choice that is different for each action, - // or can depend on the type of error. + // a type storing the parameters used in actions. // this is used in the trace to store // the name of the last action, plus the parameters we passed to it. // Note: This type holds ALL parameters that are used in ANY action, @@ -77,12 +71,11 @@ module ccv_model { kind: str, consumerChain: Chain, timeAdvancement: Time, - consumersToStart: Set[ConsumerAdditionMsg], + consumersToStart: Set[Chain], consumersToStop: Set[Chain], validator: Node, changeAmount: int, consumerAddr: ConsumerAddr, - expectedError: str, // if the action returns an error, it goes here. vscId: VscId, isDowntime: bool, } @@ -109,7 +102,6 @@ module ccv_model { validator: "", changeAmount: 0, consumerAddr: "", - expectedError: "", vscId: 0, isDowntime: false, } @@ -200,7 +192,7 @@ module ccv_model { action EndAndBeginBlockForProvider( timeAdvancement: Time, - consumersToStart: Set[ConsumerAdditionMsg], + consumersToStart: Set[Chain], consumersToStop: Set[Chain]): bool = val result = endAndBeginBlockForProvider(currentState, timeAdvancement, consumersToStart, consumersToStop) all { @@ -224,14 +216,11 @@ module ccv_model { // stepCommon is the core functionality of steps that does not have anything to do with time. action stepCommon = any { - all { - nonJailedNodes(currentState.providerState).size() > 0, - nondet node = oneOf(nonJailedNodes(currentState.providerState)) - // very restricted set of voting powers. exact values are not important, - // and this keeps the state space smaller. - nondet newVotingPower = oneOf(Set(-50, 50)) - VotingPowerChange(node, newVotingPower), - }, + nondet node = oneOf(nonJailedNodes(currentState.providerState)) + // very restricted set of voting powers. exact values are not important, + // and this keeps the state space smaller. + nondet newVotingPower = oneOf(Set(-50, 50)) + VotingPowerChange(node, newVotingPower), // try to send a packet. we could filter by chains that can actually send, // but it's probably not much faster than just trying and failing. @@ -266,10 +255,9 @@ module ccv_model { val consumerStatus = currentState.providerState.consumerStatus nondet consumersToStart = oneOf(nonConsumers.powerset()) - val consumerAdditions = consumersToStart.map(chain => NewFullConsumer(chain)) nondet consumersToStop = oneOf(runningConsumers.powerset()) nondet timeAdvancement = oneOf(timeAdvancements) - EndAndBeginBlockForProvider(timeAdvancement, consumerAdditions, consumersToStop), + EndAndBeginBlockForProvider(timeAdvancement, consumersToStart, consumersToStop), stepCommon } @@ -281,7 +269,7 @@ module ccv_model { // As a a `Run`, it is only used in tests, not during simulation or verification. run EndProviderEpoch( timeAdvancement: Time, - consumersToStart: Set[ConsumerAdditionMsg], + consumersToStart: Set[Chain], consumersToStop: Set[Chain] ): bool = epochLength.reps( @@ -296,6 +284,18 @@ module ccv_model { // ================== // UTILITY FUNCTIONS // ================== + + pure def removeZeroPowers(valSet: ValidatorSet): ValidatorSet = + valSet.keys().fold( + Map(), + (acc, node) => + if (valSet.get(node) == 0) { + acc + } else { + acc.put(node, valSet.get(node)) + } + ) + pure def oldest(packets: Set[VscPacket]): VscPacket = val newestPossiblePacket: VscPacket = { id: 0, @@ -365,7 +365,7 @@ module ccv_model { runningConsumers.forall(chain => // for all running consumers currentState.consumerStates.get(chain).chainState.votingPowerHistory.toSet().forall( // go through all its historical and current validator sets - validatorSet => providerValidatorHistory.toSet().map(v => removeZeroPowers(v)).contains(removeZeroPowers(validatorSet)) + validatorSet => providerValidatorHistory.toSet().contains(validatorSet) // and check that they are also historical or current validator sets on the provider ) ) @@ -586,7 +586,7 @@ module ccv_model { // the validator set has changed assert(currentState.providerState.chainState.currentValidatorPowers == InitialValidatorSet.put("node1", 150)), // start consumer1 - EndAndBeginBlockForProvider(1 * Second, Set(NewFullConsumer("consumer1")), Set()) + EndAndBeginBlockForProvider(1 * Second, Set("consumer1"), Set()) }) .then( all { @@ -664,7 +664,7 @@ module ccv_model { run SameVscPacketsManualTest = init.then( // start all consumers except for consumer3 - EndAndBeginBlockForProvider(1 * Second, Set(NewFullConsumer("consumer1"), NewFullConsumer("consumer2")), Set()) + EndAndBeginBlockForProvider(1 * Second, Set("consumer1", "consumer2"), Set()) ).then( // change voting power VotingPowerChange("node1", 50) @@ -679,7 +679,7 @@ module ccv_model { DeliverVscPacket("consumer2") ).then( // start consumer3 - EndAndBeginBlockForProvider(1 * Second, Set(NewFullConsumer("consumer3")), Set()) + EndAndBeginBlockForProvider(1 * Second, Set("consumer3"), Set()) ).then( // do another voting power change VotingPowerChange("node2", 50) @@ -710,7 +710,7 @@ module ccv_model { init .then( // start all consumer chains - EndAndBeginBlockForProvider(1 * Second, ConsumerChains.map(c => NewFullConsumer(c)), Set()) + EndAndBeginBlockForProvider(1 * Second, ConsumerChains, Set()) ) .then( // change voting power @@ -980,7 +980,7 @@ module ccv_model { init .then( // start all consumer chains - EndAndBeginBlockForProvider(1 * Second, consumerChains.map(c => NewFullConsumer(c)), Set()) + EndAndBeginBlockForProvider(1 * Second, consumerChains, Set()) ) .then( // node 1 assigns a key on consumer1 @@ -1052,7 +1052,7 @@ module ccv_model { VotingPowerChange("node1", 50) ) .then( - EndAndBeginBlockForProvider(1 * Second, Set(NewFullConsumer("consumer1"), NewFullConsumer("consumer2")), Set()) + EndAndBeginBlockForProvider(1 * Second, Set("consumer1", "consumer2"), Set()) ).then( all { ValidatorSetHasExistedKeyAssignmentInv, @@ -1066,7 +1066,7 @@ module ccv_model { run DowntimeSlashTest = init.then( // start all consumer chains - EndAndBeginBlockForProvider(1 * Second, ConsumerChains.map(c => NewFullConsumer(c)), Set()) + EndAndBeginBlockForProvider(1 * Second, consumerChains, Set()) ).then( // change voting power VotingPowerChange("node1", 50) @@ -1104,7 +1104,7 @@ module ccv_model { init .then( // start consumer 3 - EndAndBeginBlockForProvider(1 * Second, Set(NewFullConsumer("consumer3")), Set()) + EndAndBeginBlockForProvider(1 * Second, Set("consumer3"), Set()) ) .then( // change voting power for node 3 by 50 @@ -1112,7 +1112,7 @@ module ccv_model { ) .then( // start consumer 2 - EndProviderEpoch(3 * Second, Set(NewFullConsumer("consumer2")), Set()) + EndProviderEpoch(3 * Second, Set("consumer2"), Set()) ) .then( // deliver a vsc packet to consumer 3 @@ -1132,7 +1132,7 @@ module ccv_model { ) .then( // start consumer 1 - EndAndBeginBlockForProvider(1 * Second, Set(NewFullConsumer("consumer1")), Set()) + EndAndBeginBlockForProvider(1 * Second, Set("consumer1"), Set()) ) .then( all { @@ -1146,7 +1146,7 @@ module ccv_model { init .then( // start consumer 2 - EndAndBeginBlockForProvider(1 * Second, Set(NewFullConsumer("consumer2")), Set()) + EndAndBeginBlockForProvider(1 * Second, Set("consumer2"), Set()) ) .then( // change vp of node 10 by -50 @@ -1174,7 +1174,7 @@ module ccv_model { ) .then( // end and begin a block on the provider, starting consumer 3 - EndAndBeginBlockForProvider(1 * Second, Set(NewFullConsumer("consumer3")), Set()) + EndAndBeginBlockForProvider(1 * Second, Set("consumer3"), Set()) ) .then( // check the ValidatorSetHasExistedKeyAssignmentInv @@ -1185,80 +1185,11 @@ module ccv_model { } ) - // Ensure that SlashAcks are sent even when the validator set does not change due to the slash itself, - // i.e. the validator already had 0 power. - run DeliverSlashAckWithNoVSCUpdateTest = - init - .then( - // start consumer 1 - EndAndBeginBlockForProvider(1 * Second, Set(NewFullConsumer("consumer1")), Set()) - ) - .then( - // change voting power for node 1 by 50 - VotingPowerChange("node1", 50) - ) - .then( - // end and begin a block on the provider - EndProviderEpoch(3 * Second, Set(), Set()) - ) - .then( - // deliver the vsc packet to consumer 1 - DeliverVscPacket("consumer1") - ) - .then( - // begin a new block on the consumer - EndAndBeginBlockForConsumer("consumer1", 1 * Second) - ) - .then( - // initiate a slash for downtime - ConsumerInitiatedSlashDet("consumer1", "node1", 0, true) - ) - .then( - // end a block on the consumer to send the packet - EndAndBeginBlockForConsumer("consumer1", 1 * Second) - ) - .then( - all { - // consumer1 should have sent the slash packet - assert(currentState.consumerStates.get("consumer1").outstandingPacketsToProvider.length() == 1), - assert(currentState.consumerStates.get("consumer1").waitingForSlashPacketAck.size() == 1), - // set the power of node1 to 0 on the provider - VotingPowerChange("node1", -150) - } - ) - .then( - all { - // node1 should have 0 power on the provider - assert(currentState.providerState.chainState.currentValidatorPowers.get("node1") == 0), - // end an epoch on the provider to send another vsc packet - EndProviderEpoch(3 * Second, Set(), Set()) - } - ) - .then( - // deliver the packet - DeliverVscPacket("consumer1") - ) - .then( - // consumer1 should have sent a slash packet to the provider - all { - // deliver the slash request to the provider - DeliverPacketToProvider("consumer1") - } - ) - .then( - // end an epoch on the provider to send the acknowledgement - EndProviderEpoch(1 * Second, Set(), Set()) - ) - .then( - // deliver the acknowledgement to the consumer - DeliverVscPacket("consumer1") - ) - run SlashAckTest = init .then( // start consumer 1 - EndAndBeginBlockForProvider(1 * Second, Set(NewFullConsumer("consumer1")), Set()) + EndAndBeginBlockForProvider(1 * Second, Set("consumer1"), Set()) ) .then( // change voting power for node 1 by 50 diff --git a/tests/mbt/model/ccv_sync.qnt b/tests/mbt/model/ccv_sync.qnt index 8af76693b8..d828b88a76 100644 --- a/tests/mbt/model/ccv_sync.qnt +++ b/tests/mbt/model/ccv_sync.qnt @@ -25,7 +25,7 @@ module ccv_sync { action initSync = all { init.then( - EndAndBeginBlockForProvider(1 * Second, consumerChains.map(c => ccvt::NewFullConsumer(c)), Set()) + EndAndBeginBlockForProvider(1 * Second, consumerChains, Set()) ), QueuedChainsToEndBlock' = consumerChainList.foldl( List(), diff --git a/tests/mbt/model/ccv_test.qnt b/tests/mbt/model/ccv_test.qnt index 6f453aa9fc..986f8c2532 100644 --- a/tests/mbt/model/ccv_test.qnt +++ b/tests/mbt/model/ccv_test.qnt @@ -262,15 +262,15 @@ module ccv_test { "chain3" -> STOPPED ) val res = StartStopConsumers( - GetEmptyProviderState.with("consumerStatus", currentConsumerStatusMap), - Set(NewOptInConsumer("chain1")), + currentConsumerStatusMap, + Set("chain1"), Set("chain2"), Set() ) res._2 == "" and - res._1.consumerStatus.get("chain1") == RUNNING and - res._1.consumerStatus.get("chain2") == STOPPED and - res._1.consumerStatus.get("chain3") == STOPPED + res._1.get("chain1") == RUNNING and + res._1.get("chain2") == STOPPED and + res._1.get("chain3") == STOPPED } run ConsumerStatusMapAlreadyRunningTest = @@ -281,8 +281,8 @@ module ccv_test { "chain3" -> STOPPED ) val res = StartStopConsumers( - GetEmptyProviderState.with("consumerStatus", currentConsumerStatusMap), - Set(NewOptInConsumer("chain2")), + currentConsumerStatusMap, + Set("chain2"), Set("chain3"), Set() ) @@ -297,8 +297,8 @@ module ccv_test { "chain3" -> STOPPED ) val res = StartStopConsumers( - GetEmptyProviderState.with("consumerStatus", currentConsumerStatusMap), - Set(NewOptInConsumer("chain1")), + currentConsumerStatusMap, + Set("chain1"), Set("chain3"), Set() ) @@ -313,8 +313,8 @@ module ccv_test { "chain3" -> STOPPED ) val res = StartStopConsumers( - GetEmptyProviderState.with("consumerStatus", currentConsumerStatusMap), - Set(NewOptInConsumer("chain1")), + currentConsumerStatusMap, + Set("chain1"), Set("chain1"), Set() ) diff --git a/tests/mbt/model/ccv_utils.qnt b/tests/mbt/model/ccv_utils.qnt index d8184b91e4..ffb22e0dda 100644 --- a/tests/mbt/model/ccv_utils.qnt +++ b/tests/mbt/model/ccv_utils.qnt @@ -142,33 +142,26 @@ module ccv_utils { } pure def StartStopConsumers( - currentProviderState: ProviderState, - consumersToStart: Set[ConsumerAdditionMsg], + currentConsumerStatusMap: Chain -> str, + consumersToStart: Set[Chain], consumersToStop: Set[Chain], consumersToTimeout: Set[Chain] - ): (ProviderState, str) = { - val consumerAdditions = consumersToStart.map( - msg => msg.chain - ) + ): (Chain -> str, str) = { // check if any consumer is both started and stopped - if (consumerAdditions.intersect(consumersToStop).size() > 0) { - (currentProviderState, "Cannot start and stop a consumer at the same time") + if (consumersToStart.intersect(consumersToStop).size() > 0) { + (currentConsumerStatusMap, "Cannot start and stop a consumer at the same time") } else { - val res1 = currentProviderState.consumerStatus.startConsumers(consumerAdditions) + val res1 = currentConsumerStatusMap.startConsumers(consumersToStart) val newConsumerStatus = res1._1 val err1 = res1._2 val res2 = newConsumerStatus.stopConsumers(consumersToStop, consumersToTimeout) val err2 = res2._2 - // set the top N values in the provider correctly - if (err1 != "") { - (currentProviderState, err1) + (currentConsumerStatusMap, err1) } else if (err2 != "") { - (currentProviderState, err2) + (currentConsumerStatusMap, err2) } else { - (currentProviderState - .with("consumerStatus", res2._1) - .SetTopNValues(consumersToStart), "") + (res2._1, "") } } } @@ -227,8 +220,7 @@ module ccv_utils { (consumer) => // if validator set changed or the key assignments for this chain changed, and the consumer is running, send a packet if ((providerState.consumersWithPowerChangesInThisEpoch.contains(consumer) or - providerState.consumersWithAddrAssignmentChangesInThisEpoch.contains(consumer) - or providerState.downtimeSlashRequests.getOrElse(consumer, []) != []) + providerState.consumersWithAddrAssignmentChangesInThisEpoch.contains(consumer)) and isRunningConsumer(consumer, providerState)) { // send a packet, i.e. use a list with one element (the packet to be sent) @@ -429,29 +421,6 @@ module ccv_utils { } } - // Sets the top N values on the provider chain for the given consumer chains, - // taken as consumerAdditionMsgs = chains with the top N values. - // If a chain in the set is already present, the old value will be overwritten. - pure def SetTopNValues(providerState: ProviderState, consumers: Set[ConsumerAdditionMsg]): ProviderState = - providerState.with( - "topNByConsumer", - consumers.fold( - providerState.topNByConsumer, - (acc, consumer) => acc.put(consumer.chain, consumer.topN) - ) - ) - - // From a validator set, removes all validators with zero power. - pure def removeZeroPowers(valSet: ValidatorSet): ValidatorSet = - valSet.keys().fold( - Map(), - (acc, node) => - if (valSet.get(node) == 0) { - acc - } else { - acc.put(node, valSet.get(node)) - } - ) // Transforms a list of VscPackets into a list of the generic // "packet" type. pure def VscPacketListToPacketList(original: List[VscPacket]): List[Packet] = diff --git a/tests/mbt/model/libraries/extraSpells.qnt b/tests/mbt/model/libraries/extraSpells.qnt index 339fe9ec6d..97855f1568 100644 --- a/tests/mbt/model/libraries/extraSpells.qnt +++ b/tests/mbt/model/libraries/extraSpells.qnt @@ -139,72 +139,6 @@ module extraSpells { __set.fold(List(), (__l, __e) => __l.append(__e)) } - /// The type of orderings between comparable things - // Follows https://hackage.haskell.org/package/base-4.19.0.0/docs/Data-Ord.html#t:Ordering - // and we think there are likely benefits to using 3 constant values rather than the more - // common integer range in Apalache. - type Ordering = - | EQ - | LT - | GT - - /// Comparison of integers - pure def intCompare(__a: int, __b:int): Ordering = { - if (__a < __b) - { LT } - else if (__a > __b) - { GT } - else - { EQ } - } - - /// Assuming `__l` is sorted according to `__cmp`, returns a list with the element `__x` - /// inserted in order. - /// - /// If `__l` is not sorted, `__x` will be inserted after the first element less than - /// or equal to it. - /// - /// - @param __l a sorted list - /// - @param __x an element to be inserted - /// - @param __cmp an operator defining an `Ordering` of the elemnts of type `a` - /// - @returns a sorted list that includes `__x` - pure def sortedListInsert(__l: List[a], __x: a, __cmp: (a, a) => Ordering): List[a] = { - // We need to track whether __x has been inserted, and the accumulator for the new list - val __init = { is_inserted: false, acc: List() } - - val __result = __l.foldl(__init, (__state, __y) => - if (__state.is_inserted) - { ...__state, acc: __state.acc.append(__y) } - else - match __cmp(__x, __y) { - | GT => { ...__state, acc: __state.acc.append(__y) } - | _ => { is_inserted: true, acc: __state.acc.append(__x).append(__y) } - }) - - if (not(__result.is_inserted)) - // If __x was not inserted, it was GT than every other element, so it goes at the end - __result.acc.append(__x) - else - __result.acc - } - - run sortedListInsertTest = all { - assert(List().sortedListInsert(3, intCompare) == List(3)), - assert(List(1,2,4).sortedListInsert(3, intCompare) == List(1,2,3,4)), - assert(List(4,1,2).sortedListInsert(3, intCompare) == List(3,4,1,2)), - assert(List(1,2,3).sortedListInsert(4, intCompare) == List(1,2,3,4)), - } - - //// Returns a list of all elements of a set. - //// The ordering will be arbitrary. - //// - //// - @param __set a set - //// - @param __cmp an operator defining an `Ordering` of the elemnts of type `a` - //// - @returns a sorted list of all elements of __set - pure def toSortedList(__set: Set[a], __cmp: (a, a) => Ordering): List[a] = { - __set.fold(List(), (__l, __e) => __l.sortedListInsert(__e, __cmp)) - } - //// Returns a set of the elements in the list. //// //// - @param __list a list @@ -274,44 +208,6 @@ module extraSpells { assert(listForAll(List(), __x => __x > 0)), } - /// Compute the sum of the values over all entries in a map. - /// - /// - @param myMap a map from keys to integers - /// - @returns the sum; when the map is empty, the sum is 0. - pure def mapValuesSum(myMap: a -> int): int = { - myMap.keys().fold(0, ((sum, i) => sum + myMap.get(i))) - } - - run mapValuesSumTest = all { - assert(Map().mapValuesSum() == 0), - assert(2.to(5).mapBy(i => i * 2).mapValuesSum() == 28), - assert(Map(2 -> -4, 4 -> 2).mapValuesSum() == -2), - } - - /// Returns a map of a subset of keys and values from a map, - // where only those keys are included for which the given __f - // returns true. - pure def mapFilter(__map: a -> b, __f: a => bool): a -> b = { - __map.keys().filter(e => __f(e)).mapBy(__k => __map.get(__k)) - } - - /// Compute the minimum of two integers. - /// - /// - @param __i first integer - /// - @param __j second integer - /// - @returns the minimum of __i and __j - pure def min(__i: int, __j: int): int = { - if (__i < __j) __i else __j - } - - run minTest = all { - assert(min(3, 4) == 3), - assert(min(6, 3) == 3), - assert(min(10, 10) == 10), - assert(min(-3, -5) == -5), - assert(min(-5, -3) == -5), - } - /// listMap takes a list __list and a function __f returns a new list R, where /// R.length() == __list.length() and /// R[i] == __f(__list[i]) for all 0 <= i < __list.length() diff --git a/tests/mbt/run_invariants.sh b/tests/mbt/run_invariants.sh index 48af272c90..27ac61ad28 100755 --- a/tests/mbt/run_invariants.sh +++ b/tests/mbt/run_invariants.sh @@ -5,7 +5,6 @@ set -e quint test ccv_model.qnt quint test ccv_test.qnt -quint test ccv_pss_test.qnt quint run --invariant "all{ValidatorUpdatesArePropagatedInv,ValidatorSetHasExistedInv,SameVscPacketsInv,MatureOnTimeInv,EventuallyMatureOnProviderInv,WaitingForSlashPacketAckInv}" ccv_model.qnt --max-steps 200 --max-samples 200 quint run --invariant "all{ValidatorUpdatesArePropagatedKeyAssignmentInv,ValidatorSetHasExistedKeyAssignmentInv,SameVscPacketsKeyAssignmentInv,MatureOnTimeInv,EventuallyMatureOnProviderInv,KeyAssignmentRulesInv,WaitingForSlashPacketAckInv}" ccv_model.qnt --step stepKeyAssignment --max-steps 200 --max-samples 200 From 0a7a85ba0f06f09b385119fc6112acd5274f7657 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Mon, 29 Apr 2024 10:38:31 +0200 Subject: [PATCH 073/110] Add parameter to ComputeNextEpochConsumerValSet --- tests/mbt/driver/setup.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/mbt/driver/setup.go b/tests/mbt/driver/setup.go index f6f68f14c5..93784c9f1f 100644 --- a/tests/mbt/driver/setup.go +++ b/tests/mbt/driver/setup.go @@ -377,7 +377,7 @@ func (s *Driver) ConfigureNewPath(consumerChain, providerChain *ibctesting.TestC stakingValidators = append(stakingValidators, v) } - nextValidators := s.providerKeeper().ComputeNextEpochConsumerValSet(s.providerCtx(), string(consumerChainId), stakingValidators) + nextValidators := s.providerKeeper().ComputeNextEpochConsumerValSet(s.providerCtx(), string(consumerChainId), stakingValidators, func(validator stakingtypes.Validator) bool { return true }) s.providerKeeper().SetConsumerValSet(s.providerCtx(), string(consumerChainId), nextValidators) err = s.providerKeeper().SetConsumerGenesis( From 35a3414f11ccedda4b475e86b7a69ba5a26005d8 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Mon, 29 Apr 2024 10:57:27 +0200 Subject: [PATCH 074/110] Set top N param in setup --- tests/mbt/driver/setup.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/mbt/driver/setup.go b/tests/mbt/driver/setup.go index 93784c9f1f..5a578aaf5d 100644 --- a/tests/mbt/driver/setup.go +++ b/tests/mbt/driver/setup.go @@ -386,6 +386,9 @@ func (s *Driver) ConfigureNewPath(consumerChain, providerChain *ibctesting.TestC consumerGenesisForProvider) require.NoError(s.t, err, "Error setting consumer genesis on provider for chain %v", consumerChain.ChainID) + // set the top N percentage to 100 to simulate a full consumer + s.providerKeeper().SetTopN(providerChain.GetContext(), consumerChain.ChainID, 100) + // Client ID is set in InitGenesis and we treat it as a black box. So // must query it to use it with the endpoint. clientID, _ := s.consumerKeeper(consumerChainId).GetProviderClientID(s.ctx(consumerChainId)) From 1f382c7a1de410f1c6417ae3e3d634551a4351b7 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Mon, 29 Apr 2024 12:45:26 +0200 Subject: [PATCH 075/110] Fix: do not try key assignment if there is no nonjailed validator --- tests/mbt/model/ccv_model.qnt | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tests/mbt/model/ccv_model.qnt b/tests/mbt/model/ccv_model.qnt index e2b812e212..be08feca1c 100644 --- a/tests/mbt/model/ccv_model.qnt +++ b/tests/mbt/model/ccv_model.qnt @@ -216,11 +216,14 @@ module ccv_model { // stepCommon is the core functionality of steps that does not have anything to do with time. action stepCommon = any { - nondet node = oneOf(nonJailedNodes(currentState.providerState)) - // very restricted set of voting powers. exact values are not important, - // and this keeps the state space smaller. - nondet newVotingPower = oneOf(Set(-50, 50)) - VotingPowerChange(node, newVotingPower), + all { + nonJailedNodes(currentState.providerState).size() > 0, + nondet node = oneOf(nonJailedNodes(currentState.providerState)) + // very restricted set of voting powers. exact values are not important, + // and this keeps the state space smaller. + nondet newVotingPower = oneOf(Set(-50, 50)) + VotingPowerChange(node, newVotingPower), + }, // try to send a packet. we could filter by chains that can actually send, // but it's probably not much faster than just trying and failing. From c0eafd0bd9226c3af41daf07dcf632a5407f2cf9 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Mon, 29 Apr 2024 13:34:48 +0200 Subject: [PATCH 076/110] Do not assign keys for jailed validators --- tests/mbt/model/ccv_model.qnt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/mbt/model/ccv_model.qnt b/tests/mbt/model/ccv_model.qnt index be08feca1c..5c818cce64 100644 --- a/tests/mbt/model/ccv_model.qnt +++ b/tests/mbt/model/ccv_model.qnt @@ -752,7 +752,8 @@ module ccv_model { action nondetKeyAssignment = all { runningConsumers.size() > 0, - nondet node = oneOf(nodes) + nonJailedNodes(currentState.providerState).size() > 0, + nondet node = oneOf(nonJailedNodes(currentState.providerState)) nondet consumerAddr = oneOf(consumerAddresses) nondet consumer = oneOf(runningConsumers) KeyAssignment(consumer, node, consumerAddr), From e34f5bb4daeff93061f3cab649b40ffbeb0e8c86 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Mon, 29 Apr 2024 13:53:24 +0200 Subject: [PATCH 077/110] Only jail validators with non-zero-power --- tests/mbt/model/ccv.qnt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/mbt/model/ccv.qnt b/tests/mbt/model/ccv.qnt index 87ddc91ea2..80aed91ec2 100644 --- a/tests/mbt/model/ccv.qnt +++ b/tests/mbt/model/ccv.qnt @@ -908,14 +908,18 @@ module ccv { // (in general, the validator is a consumer address and could be an assigned one) val slashFactor = DowntimeSlashPercentage + + val curValPowerIsZero = currentState.providerState.chainState.currentValidatorPowers.get(providerVal) == 0 - val newProviderState = currentState.providerState - .jailUntil(providerVal, jailEndTime) + val newProviderState = if (not(curValPowerIsZero)) + currentState.providerState + .jailUntil(providerVal, jailEndTime) else + currentState.providerState // validators with zero power are not jailed // // slashing is currently not enabled in ICS // .slash(packet.validator, packet.valPower, slashFactor) // if the validator did not have voting power of 0 or was already jailed before, the validator set will change due to the slash - val valSetChanged = currentState.providerState.chainState.currentValidatorPowers.get(providerVal) != 0 + val valSetChanged = not(curValPowerIsZero) // add the consumer address to the list of acknowledged slashes // for the sender chain of this slash packet and indicate that we need to send a packet at endblock From fc09cf3e707f75318a371d76e97179694fe0cce4 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Mon, 29 Apr 2024 14:20:11 +0200 Subject: [PATCH 078/110] Add unit test --- x/ccv/consumer/keeper/distribution_test.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/x/ccv/consumer/keeper/distribution_test.go b/x/ccv/consumer/keeper/distribution_test.go index 189842a90e..31429b67df 100644 --- a/x/ccv/consumer/keeper/distribution_test.go +++ b/x/ccv/consumer/keeper/distribution_test.go @@ -12,6 +12,7 @@ import ( testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" + providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" ) @@ -90,3 +91,22 @@ func TestAllowedRewardDenoms(t *testing.T) { require.Equal(t, allowedDenoms[0], "ustake") require.True(t, strings.HasPrefix(allowedDenoms[1], "ibc/")) } + +func TestSetConsumerRewardsAllocation(t *testing.T) { + keeperParams := testkeeper.NewInMemKeeperParams(t) + ctx := keeperParams.Ctx + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + mocks := testkeeper.NewMockedKeepers(ctrl) + providerKeeper := testkeeper.NewInMemProviderKeeper(keeperParams, mocks) + + rewardAllocation := providertypes.ConsumerRewardsAllocation{ + Rewards: sdk.NewDecCoins(sdk.NewDecCoin("uatom", sdk.NewInt(1000))), + } + + providerKeeper.SetConsumerRewardsAllocation(ctx, "consumer-1", rewardAllocation) + + alloc := providerKeeper.GetConsumerRewardsAllocation(ctx, "consumer-1") + require.Equal(t, rewardAllocation, alloc) +} From efcc909a108d9358a383eb012ea576443bc3f514 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Mon, 29 Apr 2024 14:23:20 +0200 Subject: [PATCH 079/110] Add unit test for unset case --- x/ccv/consumer/keeper/distribution_test.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/x/ccv/consumer/keeper/distribution_test.go b/x/ccv/consumer/keeper/distribution_test.go index 31429b67df..e706e3e01d 100644 --- a/x/ccv/consumer/keeper/distribution_test.go +++ b/x/ccv/consumer/keeper/distribution_test.go @@ -110,3 +110,20 @@ func TestSetConsumerRewardsAllocation(t *testing.T) { alloc := providerKeeper.GetConsumerRewardsAllocation(ctx, "consumer-1") require.Equal(t, rewardAllocation, alloc) } + +func TestGetConsumerRewardsAllocationNil(t *testing.T) { + keeperParams := testkeeper.NewInMemKeeperParams(t) + ctx := keeperParams.Ctx + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + mocks := testkeeper.NewMockedKeepers(ctrl) + providerKeeper := testkeeper.NewInMemProviderKeeper(keeperParams, mocks) + + alloc := providerKeeper.GetConsumerRewardsAllocation(ctx, "consumer-1") + + expectedRewardAllocation := providertypes.ConsumerRewardsAllocation{ + Rewards: nil, + } + require.Equal(t, expectedRewardAllocation, alloc) +} From e3d676dfca3105807f59c64228a52dbe4389429b Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Mon, 29 Apr 2024 16:26:14 +0200 Subject: [PATCH 080/110] Panic on not being able to unmarshal --- x/ccv/provider/keeper/keeper.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x/ccv/provider/keeper/keeper.go b/x/ccv/provider/keeper/keeper.go index 080bf481c1..523c0029bc 100644 --- a/x/ccv/provider/keeper/keeper.go +++ b/x/ccv/provider/keeper/keeper.go @@ -1222,7 +1222,8 @@ func (k Keeper) IsOptedIn( // GetAllOptedIn returns all the opted-in validators on chain `chainID` func (k Keeper) GetAllOptedIn( ctx sdk.Context, - chainID string) (providerConsAddresses []types.ProviderConsAddress) { + chainID string, +) (providerConsAddresses []types.ProviderConsAddress) { store := ctx.KVStore(k.storeKey) key := types.ChainIdWithLenKey(types.OptedInBytePrefix, chainID) iterator := sdk.KVStorePrefixIterator(store, key) @@ -1267,8 +1268,7 @@ func (k Keeper) GetConsumerCommissionRate( cr := sdk.Dec{} if err := cr.Unmarshal(bz); err != nil { - k.Logger(ctx).Error("consumer commission rate unmarshalling failed: %s", err) - return sdk.ZeroDec(), false + panic(fmt.Sprintf("consumer commission rate unmarshalling failed: %s", err)) } return cr, true From 6971ed3d45f719ee08f55b587609fd3b9b5f6e92 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Mon, 29 Apr 2024 16:30:58 +0200 Subject: [PATCH 081/110] Move packet handling into ack.Success block --- x/ccv/provider/ibc_middleware.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/x/ccv/provider/ibc_middleware.go b/x/ccv/provider/ibc_middleware.go index 5a3331df2e..fb4d96890f 100644 --- a/x/ccv/provider/ibc_middleware.go +++ b/x/ccv/provider/ibc_middleware.go @@ -116,17 +116,17 @@ func (im IBCMiddleware) OnRecvPacket( // executes the IBC transfer OnRecv logic ack := im.app.OnRecvPacket(ctx, packet, relayer) - // execute the middleware logic only if the sender is a consumer chain - consumerID, err := im.keeper.IdentifyConsumerChainIDFromIBCPacket(ctx, packet) - if err != nil { - return ack - } - // Note that inside the below if condition statement, // we know that the IBC transfer succeeded. That entails // that the packet data is valid and can be safely // deserialized without checking errors. if ack.Success() { + // execute the middleware logic only if the sender is a consumer chain + consumerID, err := im.keeper.IdentifyConsumerChainIDFromIBCPacket(ctx, packet) + if err != nil { + return ack + } + // extract the coin info received from the packet data var data ibctransfertypes.FungibleTokenPacketData _ = types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data) From e5072b5f76642cf9cdc332fd8a34ac8240bdf91a Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Mon, 29 Apr 2024 16:32:46 +0200 Subject: [PATCH 082/110] Format --- x/ccv/provider/keeper/distribution.go | 1 - x/ccv/provider/keeper/hooks_test.go | 1 + x/ccv/provider/keeper/keeper_test.go | 15 ++++++++------- x/ccv/provider/keeper/partial_set_security.go | 2 ++ .../provider/keeper/partial_set_security_test.go | 7 ++++--- x/ccv/provider/keeper/proposal_test.go | 2 +- x/ccv/provider/proposal_handler_test.go | 2 +- 7 files changed, 17 insertions(+), 13 deletions(-) diff --git a/x/ccv/provider/keeper/distribution.go b/x/ccv/provider/keeper/distribution.go index cd7755ac3e..2bf0ba2a24 100644 --- a/x/ccv/provider/keeper/distribution.go +++ b/x/ccv/provider/keeper/distribution.go @@ -17,7 +17,6 @@ import ( // BeginBlockRD executes BeginBlock logic for the Reward Distribution sub-protocol. func (k Keeper) BeginBlockRD(ctx sdk.Context, req abci.RequestBeginBlock) { - // TODO this is Tendermint-dependent // ref https://github.com/cosmos/cosmos-sdk/issues/3095 if ctx.BlockHeight() > 1 { diff --git a/x/ccv/provider/keeper/hooks_test.go b/x/ccv/provider/keeper/hooks_test.go index a9cf69b350..931667fac4 100644 --- a/x/ccv/provider/keeper/hooks_test.go +++ b/x/ccv/provider/keeper/hooks_test.go @@ -14,6 +14,7 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + cryptotestutil "github.com/cosmos/interchain-security/v4/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" providerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" diff --git a/x/ccv/provider/keeper/keeper_test.go b/x/ccv/provider/keeper/keeper_test.go index c2cbc386de..2e31265d4c 100644 --- a/x/ccv/provider/keeper/keeper_test.go +++ b/x/ccv/provider/keeper/keeper_test.go @@ -7,11 +7,12 @@ import ( "testing" "time" - cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" - sdk "github.com/cosmos/cosmos-sdk/types" ibctesting "github.com/cosmos/ibc-go/v7/testing" "github.com/stretchr/testify/require" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + abci "github.com/cometbft/cometbft/abci/types" tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" @@ -670,19 +671,19 @@ func TestGetAllOptedIn(t *testing.T) { expectedOptedInValidators := []types.ProviderConsAddress{ types.NewProviderConsAddress([]byte("providerAddr1")), types.NewProviderConsAddress([]byte("providerAddr2")), - types.NewProviderConsAddress([]byte("providerAddr3"))} + types.NewProviderConsAddress([]byte("providerAddr3")), + } for _, expectedOptedInValidator := range expectedOptedInValidators { providerKeeper.SetOptedIn(ctx, "chainID", expectedOptedInValidator) - } actualOptedInValidators := providerKeeper.GetAllOptedIn(ctx, "chainID") // sort validators first to be able to compare - sortOptedInValidators := func(addressess []types.ProviderConsAddress) { - sort.Slice(addressess, func(i int, j int) bool { - return bytes.Compare(addressess[i].ToSdkConsAddr(), addressess[j].ToSdkConsAddr()) < 0 + sortOptedInValidators := func(addresses []types.ProviderConsAddress) { + sort.Slice(addressess, func(i, j int) bool { + return bytes.Compare(addresses[i].ToSdkConsAddr(), addresses[j].ToSdkConsAddr()) < 0 }) } sortOptedInValidators(expectedOptedInValidators) diff --git a/x/ccv/provider/keeper/partial_set_security.go b/x/ccv/provider/keeper/partial_set_security.go index 7c2e6a9723..b5ad53a72d 100644 --- a/x/ccv/provider/keeper/partial_set_security.go +++ b/x/ccv/provider/keeper/partial_set_security.go @@ -5,8 +5,10 @@ import ( "sort" errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" ) diff --git a/x/ccv/provider/keeper/partial_set_security_test.go b/x/ccv/provider/keeper/partial_set_security_test.go index 303bdd633f..b18acb56ce 100644 --- a/x/ccv/provider/keeper/partial_set_security_test.go +++ b/x/ccv/provider/keeper/partial_set_security_test.go @@ -195,7 +195,8 @@ func TestOptInTopNValidators(t *testing.T) { types.NewProviderConsAddress(valAConsAddr), types.NewProviderConsAddress(valBConsAddr), types.NewProviderConsAddress(valCConsAddr), - types.NewProviderConsAddress(valDConsAddr)} + types.NewProviderConsAddress(valDConsAddr), + } actualOptedInValidators := providerKeeper.GetAllOptedIn(ctx, "chainID") // sort validators first to be able to compare @@ -232,7 +233,8 @@ func TestOptInTopNValidators(t *testing.T) { providerKeeper.OptInTopNValidators(ctx, "chainID", []stakingtypes.Validator{valA, valB, valC, valD}, 2) expectedOptedInValidators = []types.ProviderConsAddress{ types.NewProviderConsAddress(valBConsAddr), - types.NewProviderConsAddress(valCConsAddr)} + types.NewProviderConsAddress(valCConsAddr), + } actualOptedInValidators = providerKeeper.GetAllOptedIn(ctx, "chainID") // sort validators first to be able to compare @@ -298,5 +300,4 @@ func TestShouldConsiderOnlyOptIn(t *testing.T) { require.False(t, providerKeeper.IsOptedIn(ctx, "chainID", types.NewProviderConsAddress(consAddr))) providerKeeper.SetOptedIn(ctx, "chainID", types.NewProviderConsAddress(consAddr)) require.True(t, providerKeeper.IsOptedIn(ctx, "chainID", types.NewProviderConsAddress(consAddr))) - } diff --git a/x/ccv/provider/keeper/proposal_test.go b/x/ccv/provider/keeper/proposal_test.go index 69534326e0..189ec82a0c 100644 --- a/x/ccv/provider/keeper/proposal_test.go +++ b/x/ccv/provider/keeper/proposal_test.go @@ -1034,7 +1034,7 @@ func TestBeginBlockInit(t *testing.T) { ctx, pendingProps[3].SpawnTime, pendingProps[3].ChainId) require.False(t, found) // Note that we do not check that `GetConsumerGenesis(ctx, pendingProps[3].ChainId)` returns `false` here because - //`pendingProps[3]` is an invalid proposal due to the chain id already existing so the consumer genesis also exists + // `pendingProps[3]` is an invalid proposal due to the chain id already existing so the consumer genesis also exists // fifth proposal is dropped due to it being an Opt-In chain with no validators opted in _, found = providerKeeper.GetPendingConsumerAdditionProp( diff --git a/x/ccv/provider/proposal_handler_test.go b/x/ccv/provider/proposal_handler_test.go index 30c1793360..90edec8bee 100644 --- a/x/ccv/provider/proposal_handler_test.go +++ b/x/ccv/provider/proposal_handler_test.go @@ -71,7 +71,7 @@ func TestProviderProposalHandler(t *testing.T) { { name: "unsupported proposal type", // lint rule disabled because this is a test case for an unsupported proposal type - // nolint:staticcheck + content: &distributiontypes.CommunityPoolSpendProposal{ Title: "title", Description: "desc", From b13322022a210c6ff281ae04671dbe48c3e4614d Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Mon, 29 Apr 2024 17:22:35 +0200 Subject: [PATCH 083/110] Remove unnecessary comment --- x/ccv/provider/keeper/keeper.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/x/ccv/provider/keeper/keeper.go b/x/ccv/provider/keeper/keeper.go index 523c0029bc..e3ad29beeb 100644 --- a/x/ccv/provider/keeper/keeper.go +++ b/x/ccv/provider/keeper/keeper.go @@ -249,9 +249,6 @@ func (k Keeper) GetAllConsumerChains(ctx sdk.Context) (chains []types.Chain) { chainID := string(iterator.Key()[1:]) clientID := string(iterator.Value()) - // Get the consumer TopN value by checking - // if the chain is a TopN chain, - // otherwise it's a OptIn chain topN, _ := k.GetTopN(ctx, chainID) chains = append(chains, types.Chain{ From c075ffa649e7a8ab5aee18491711f8d277315907 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Mon, 29 Apr 2024 18:09:41 +0200 Subject: [PATCH 084/110] Add parens for clarity --- x/ccv/provider/types/proposal.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/ccv/provider/types/proposal.go b/x/ccv/provider/types/proposal.go index 10f3a88865..8dfb67f644 100644 --- a/x/ccv/provider/types/proposal.go +++ b/x/ccv/provider/types/proposal.go @@ -139,7 +139,7 @@ func (cccp *ConsumerAdditionProposal) ValidateBasic() error { // Top N corresponds to the top N% of validators that have to validate the consumer chain and can only be 0 (for an // Opt In chain) or in the range [50, 100] (for a Top N chain). - if cccp.Top_N != 0 && cccp.Top_N < 50 || cccp.Top_N > 100 { + if cccp.Top_N != 0 && (cccp.Top_N < 50 || cccp.Top_N > 100) { return errorsmod.Wrap(ErrInvalidConsumerAdditionProposal, "Top N can either be 0 or in the range [50, 100]") } From e92a58f35cfd2c67985bee84f33a2fab5504abea Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Tue, 30 Apr 2024 10:38:06 +0200 Subject: [PATCH 085/110] Format and fix typo --- x/ccv/provider/keeper/keeper_test.go | 2 +- x/ccv/provider/proposal_handler_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x/ccv/provider/keeper/keeper_test.go b/x/ccv/provider/keeper/keeper_test.go index 2e31265d4c..691dd07731 100644 --- a/x/ccv/provider/keeper/keeper_test.go +++ b/x/ccv/provider/keeper/keeper_test.go @@ -682,7 +682,7 @@ func TestGetAllOptedIn(t *testing.T) { // sort validators first to be able to compare sortOptedInValidators := func(addresses []types.ProviderConsAddress) { - sort.Slice(addressess, func(i, j int) bool { + sort.Slice(addresses, func(i, j int) bool { return bytes.Compare(addresses[i].ToSdkConsAddr(), addresses[j].ToSdkConsAddr()) < 0 }) } diff --git a/x/ccv/provider/proposal_handler_test.go b/x/ccv/provider/proposal_handler_test.go index 90edec8bee..b6930288d1 100644 --- a/x/ccv/provider/proposal_handler_test.go +++ b/x/ccv/provider/proposal_handler_test.go @@ -71,7 +71,7 @@ func TestProviderProposalHandler(t *testing.T) { { name: "unsupported proposal type", // lint rule disabled because this is a test case for an unsupported proposal type - + content: &distributiontypes.CommunityPoolSpendProposal{ Title: "title", Description: "desc", From 1105c4bfa895158f68086de81c588a65674f7d38 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Tue, 30 Apr 2024 10:39:48 +0200 Subject: [PATCH 086/110] Move OptIn/OptOut events to provider events --- x/ccv/provider/keeper/msg_server.go | 4 ++-- x/ccv/provider/types/events.go | 2 ++ x/ccv/types/events.go | 2 -- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/x/ccv/provider/keeper/msg_server.go b/x/ccv/provider/keeper/msg_server.go index 7bbf270ef9..1f7f51b589 100644 --- a/x/ccv/provider/keeper/msg_server.go +++ b/x/ccv/provider/keeper/msg_server.go @@ -169,7 +169,7 @@ func (k msgServer) OptIn(goCtx context.Context, msg *types.MsgOptIn) (*types.Msg ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( - ccvtypes.EventTypeOptIn, + types.EventTypeOptIn, sdk.NewAttribute(types.AttributeProviderValidatorAddress, msg.ProviderAddr), sdk.NewAttribute(types.AttributeConsumerConsensusPubKey, msg.ConsumerKey), ), @@ -205,7 +205,7 @@ func (k msgServer) OptOut(goCtx context.Context, msg *types.MsgOptOut) (*types.M ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( - ccvtypes.EventTypeOptOut, + types.EventTypeOptOut, sdk.NewAttribute(types.AttributeProviderValidatorAddress, msg.ProviderAddr), ), }) diff --git a/x/ccv/provider/types/events.go b/x/ccv/provider/types/events.go index 4838c1ba43..8701821c52 100644 --- a/x/ccv/provider/types/events.go +++ b/x/ccv/provider/types/events.go @@ -8,6 +8,8 @@ const ( EventTypeRemoveConsumerRewardDenom = "remove_consumer_reward_denom" EventTypeExecuteConsumerChainSlash = "execute_consumer_chain_slash" EventTypeSetConsumerCommissionRate = "set_consumer_commission_rate" + EventTypeOptIn = "opt_in" + EventTypeOptOut = "opt_out" AttributeInfractionHeight = "infraction_height" AttributeInitialHeight = "initial_height" AttributeInitializationTimeout = "initialization_timeout" diff --git a/x/ccv/types/events.go b/x/ccv/types/events.go index 2fa584dd40..4c597ded56 100644 --- a/x/ccv/types/events.go +++ b/x/ccv/types/events.go @@ -12,8 +12,6 @@ const ( EventTypeRemoveConsumerRewardDenom = "remove_consumer_reward_denom" EventTypeSubmitConsumerMisbehaviour = "submit_consumer_misbehaviour" EventTypeSubmitConsumerDoubleVoting = "submit_consumer_double_voting" - EventTypeOptIn = "opt_in" - EventTypeOptOut = "opt_out" EventTypeExecuteConsumerChainSlash = "execute_consumer_chain_slash" EventTypeFeeDistribution = "fee_distribution" EventTypeConsumerSlashRequest = "consumer_slash_request" From 9e91c2a2a74d47cb388d7564ecc171d6d4dfd06b Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Tue, 30 Apr 2024 10:40:17 +0200 Subject: [PATCH 087/110] Remove unused function --- x/ccv/provider/types/consumer.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/x/ccv/provider/types/consumer.go b/x/ccv/provider/types/consumer.go index da23cb2970..4c43bd58e7 100644 --- a/x/ccv/provider/types/consumer.go +++ b/x/ccv/provider/types/consumer.go @@ -1,8 +1,6 @@ package types import ( - sdk "github.com/cosmos/cosmos-sdk/types" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" ) @@ -27,10 +25,3 @@ func NewConsumerStates( SlashDowntimeAck: slashDowntimeAck, } } - -// zero consumer rewards allocation -func InitialConsumerRewardsAllocation() ConsumerRewardsAllocation { - return ConsumerRewardsAllocation{ - Rewards: sdk.DecCoins{}, - } -} From 90c54c60e6bb561e6030b33bbc6135121c9d9efe Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Tue, 30 Apr 2024 10:42:45 +0200 Subject: [PATCH 088/110] Improve comments for keys --- x/ccv/provider/types/keys.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/x/ccv/provider/types/keys.go b/x/ccv/provider/types/keys.go index 1e2516ba07..7dfd77ab6b 100644 --- a/x/ccv/provider/types/keys.go +++ b/x/ccv/provider/types/keys.go @@ -147,8 +147,7 @@ const ( // ProposedConsumerChainByteKey is the byte prefix storing the consumer chainId in consumerAddition gov proposal submitted before voting finishes ProposedConsumerChainByteKey - // OptedInBytePrefix is the byte prefix used when storing for each consumer chain the validators that - // are opted in but not necessarily the ones that are validating. + // OptedInBytePrefix is the byte prefix for storing whether a validator is opted in to validate on a consumer chain OptedInBytePrefix // ConsumerValidatorBytePrefix is the byte prefix used when storing for each consumer chain all the consumer @@ -159,12 +158,12 @@ const ( // that corresponds to the N% of the top validators that have to validate this consumer chain TopNBytePrefix - // ConsumerRewardsAllocationBytePrefix is the byte prefix used when storing for each consumer the rewards - // it allocated to the consumer rewards pool + // ConsumerRewardsAllocationBytePrefix is the byte prefix for storing for each consumer the ICS rewards + // allocated to the consumer rewards pool ConsumerRewardsAllocationBytePrefix - // ConsumerCommissionRatePrefix is the byte prefix used when storing a validator a per-consumer chain commission rate - // for a validator address + // ConsumerCommissionRatePrefix is the byte prefix for storing the commission rate + // per validator per consumer chain ConsumerCommissionRatePrefix // NOTE: DO NOT ADD NEW BYTE PREFIXES HERE WITHOUT ADDING THEM TO getAllKeyPrefixes() IN keys_test.go From 0d4e7f3160c4b93e4a2753bd44060df463e6fbcd Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Tue, 30 Apr 2024 10:44:03 +0200 Subject: [PATCH 089/110] Improve comments for key getter functions --- x/ccv/provider/types/keys.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/x/ccv/provider/types/keys.go b/x/ccv/provider/types/keys.go index 7dfd77ab6b..b6602f75af 100644 --- a/x/ccv/provider/types/keys.go +++ b/x/ccv/provider/types/keys.go @@ -538,23 +538,24 @@ func ConsumerValidatorKey(chainID string, providerAddr []byte) []byte { return append(prefix, providerAddr...) } -// TopNKey returns the key of consumer chain `chainID` +// TopNKey returns the key used to store the Top N value per consumer chain. +// This value corresponds to the N% of the top validators that have to validate the consumer chain. func TopNKey(chainID string) []byte { return ChainIdWithLenKey(TopNBytePrefix, chainID) } -// OptedInKey returns the key of consumer chain `chainID` and validator with `providerAddr` +// OptedInKey returns the key used to store whether a validator is opted in on a consumer chain. func OptedInKey(chainID string, providerAddr ProviderConsAddress) []byte { prefix := ChainIdWithLenKey(OptedInBytePrefix, chainID) return append(prefix, providerAddr.ToSdkConsAddr().Bytes()...) } -// ConsumerModuleAccount returns the module account byte prefix for a consumer chain +// ConsumerRewardsAllocationKey returns the key used to store the ICS rewards per consumer chain func ConsumerRewardsAllocationKey(chainID string) []byte { return append([]byte{ConsumerRewardsAllocationBytePrefix}, []byte(chainID)...) } -// ConsumerCommissionRateKey returns the key of consumer chain `chainID` and validator with `providerAddr` +// ConsumerCommissionRateKey returns the key used to store the commission rate per validator per consumer chain. func ConsumerCommissionRateKey(chainID string, providerAddr ProviderConsAddress) []byte { return ChainIdAndConsAddrKey( ConsumerCommissionRatePrefix, From 7b9842f6fe51c76c0c7f00b62d6264c86cb023e9 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Tue, 30 Apr 2024 10:46:46 +0200 Subject: [PATCH 090/110] Remove order change for existing keys --- x/ccv/provider/types/keys.go | 6 +++--- x/ccv/provider/types/keys_test.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/x/ccv/provider/types/keys.go b/x/ccv/provider/types/keys.go index b6602f75af..62ce861c75 100644 --- a/x/ccv/provider/types/keys.go +++ b/x/ccv/provider/types/keys.go @@ -147,13 +147,13 @@ const ( // ProposedConsumerChainByteKey is the byte prefix storing the consumer chainId in consumerAddition gov proposal submitted before voting finishes ProposedConsumerChainByteKey - // OptedInBytePrefix is the byte prefix for storing whether a validator is opted in to validate on a consumer chain - OptedInBytePrefix - // ConsumerValidatorBytePrefix is the byte prefix used when storing for each consumer chain all the consumer // validators in this epoch that are validating the consumer chain ConsumerValidatorBytePrefix + // OptedInBytePrefix is the byte prefix for storing whether a validator is opted in to validate on a consumer chain + OptedInBytePrefix + // TopNBytePrefix is the byte prefix storing the mapping from a consumer chain to the N value of this chain, // that corresponds to the N% of the top validators that have to validate this consumer chain TopNBytePrefix diff --git a/x/ccv/provider/types/keys_test.go b/x/ccv/provider/types/keys_test.go index d37482e50e..eac11a0993 100644 --- a/x/ccv/provider/types/keys_test.go +++ b/x/ccv/provider/types/keys_test.go @@ -56,8 +56,8 @@ func getAllKeyPrefixes() []byte { providertypes.VSCMaturedHandledThisBlockBytePrefix, providertypes.EquivocationEvidenceMinHeightBytePrefix, providertypes.ProposedConsumerChainByteKey, - providertypes.OptedInBytePrefix, providertypes.ConsumerValidatorBytePrefix, + providertypes.OptedInBytePrefix, providertypes.TopNBytePrefix, providertypes.ConsumerRewardsAllocationBytePrefix, providertypes.ConsumerCommissionRatePrefix, From d7ac7e7540cfb7961bc7e4c2595ced4c4c15b0a0 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Tue, 30 Apr 2024 10:58:28 +0200 Subject: [PATCH 091/110] Re-add nolint instruction --- x/ccv/provider/proposal_handler_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/ccv/provider/proposal_handler_test.go b/x/ccv/provider/proposal_handler_test.go index b6930288d1..30c1793360 100644 --- a/x/ccv/provider/proposal_handler_test.go +++ b/x/ccv/provider/proposal_handler_test.go @@ -71,7 +71,7 @@ func TestProviderProposalHandler(t *testing.T) { { name: "unsupported proposal type", // lint rule disabled because this is a test case for an unsupported proposal type - + // nolint:staticcheck content: &distributiontypes.CommunityPoolSpendProposal{ Title: "title", Description: "desc", From 1e1e285fdb8b4f34dfe4dd7803b7f364e8e5b93d Mon Sep 17 00:00:00 2001 From: insumity Date: Tue, 30 Apr 2024 15:38:16 +0200 Subject: [PATCH 092/110] nit comment fix --- proto/interchain_security/ccv/provider/v1/tx.proto | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/proto/interchain_security/ccv/provider/v1/tx.proto b/proto/interchain_security/ccv/provider/v1/tx.proto index 59590f7c5b..8e8aab5408 100644 --- a/proto/interchain_security/ccv/provider/v1/tx.proto +++ b/proto/interchain_security/ccv/provider/v1/tx.proto @@ -72,9 +72,10 @@ message MsgOptIn { string chain_id = 1; // the validator address on the provider string provider_addr = 2 [ (gogoproto.moretags) = "yaml:\"address\"" ]; - // (optional) the consensus public key to use on the consumer in json string format corresponding to proto-any, - // for example `{"@type":"/cosmos.crypto.ed25519.PubKey","key":"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is="}` - // we can set `consumer_key = ""` if we do not consider the `consumer_key` + // (optional) The consensus public key to use on the consumer in json string format corresponding to proto-any, + // for example `{"@type":"/cosmos.crypto.ed25519.PubKey","key":"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is="}`. + // This field is optional and can remain empty (i.e., `consumer_key = ""`). A validator can always change the + // consumer public key at a later stage by issuing a `MsgAssignConsumerKey` message. string consumer_key = 3; } From fb4fc55669c02041fcc93211c62f4c278ec88cf8 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Tue, 30 Apr 2024 15:42:28 +0200 Subject: [PATCH 093/110] Move ConsumerAllocationTests to correct folder --- x/ccv/consumer/keeper/distribution_test.go | 37 ---------------------- x/ccv/provider/keeper/distribution_test.go | 37 ++++++++++++++++++++++ 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/x/ccv/consumer/keeper/distribution_test.go b/x/ccv/consumer/keeper/distribution_test.go index e706e3e01d..189842a90e 100644 --- a/x/ccv/consumer/keeper/distribution_test.go +++ b/x/ccv/consumer/keeper/distribution_test.go @@ -12,7 +12,6 @@ import ( testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" - providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" ) @@ -91,39 +90,3 @@ func TestAllowedRewardDenoms(t *testing.T) { require.Equal(t, allowedDenoms[0], "ustake") require.True(t, strings.HasPrefix(allowedDenoms[1], "ibc/")) } - -func TestSetConsumerRewardsAllocation(t *testing.T) { - keeperParams := testkeeper.NewInMemKeeperParams(t) - ctx := keeperParams.Ctx - - ctrl := gomock.NewController(t) - defer ctrl.Finish() - mocks := testkeeper.NewMockedKeepers(ctrl) - providerKeeper := testkeeper.NewInMemProviderKeeper(keeperParams, mocks) - - rewardAllocation := providertypes.ConsumerRewardsAllocation{ - Rewards: sdk.NewDecCoins(sdk.NewDecCoin("uatom", sdk.NewInt(1000))), - } - - providerKeeper.SetConsumerRewardsAllocation(ctx, "consumer-1", rewardAllocation) - - alloc := providerKeeper.GetConsumerRewardsAllocation(ctx, "consumer-1") - require.Equal(t, rewardAllocation, alloc) -} - -func TestGetConsumerRewardsAllocationNil(t *testing.T) { - keeperParams := testkeeper.NewInMemKeeperParams(t) - ctx := keeperParams.Ctx - - ctrl := gomock.NewController(t) - defer ctrl.Finish() - mocks := testkeeper.NewMockedKeepers(ctrl) - providerKeeper := testkeeper.NewInMemProviderKeeper(keeperParams, mocks) - - alloc := providerKeeper.GetConsumerRewardsAllocation(ctx, "consumer-1") - - expectedRewardAllocation := providertypes.ConsumerRewardsAllocation{ - Rewards: nil, - } - require.Equal(t, expectedRewardAllocation, alloc) -} diff --git a/x/ccv/provider/keeper/distribution_test.go b/x/ccv/provider/keeper/distribution_test.go index 1e37b1112e..d95ae598c0 100644 --- a/x/ccv/provider/keeper/distribution_test.go +++ b/x/ccv/provider/keeper/distribution_test.go @@ -16,6 +16,7 @@ import ( testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" ) func TestComputeConsumerTotalVotingPower(t *testing.T) { @@ -233,3 +234,39 @@ func TestIdentifyConsumerChainIDFromIBCPacket(t *testing.T) { }) } } + +func TestSetConsumerRewardsAllocation(t *testing.T) { + keeperParams := testkeeper.NewInMemKeeperParams(t) + ctx := keeperParams.Ctx + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + mocks := testkeeper.NewMockedKeepers(ctrl) + providerKeeper := testkeeper.NewInMemProviderKeeper(keeperParams, mocks) + + rewardAllocation := providertypes.ConsumerRewardsAllocation{ + Rewards: sdk.NewDecCoins(sdk.NewDecCoin("uatom", sdk.NewInt(1000))), + } + + providerKeeper.SetConsumerRewardsAllocation(ctx, "consumer-1", rewardAllocation) + + alloc := providerKeeper.GetConsumerRewardsAllocation(ctx, "consumer-1") + require.Equal(t, rewardAllocation, alloc) +} + +func TestGetConsumerRewardsAllocationNil(t *testing.T) { + keeperParams := testkeeper.NewInMemKeeperParams(t) + ctx := keeperParams.Ctx + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + mocks := testkeeper.NewMockedKeepers(ctrl) + providerKeeper := testkeeper.NewInMemProviderKeeper(keeperParams, mocks) + + alloc := providerKeeper.GetConsumerRewardsAllocation(ctx, "consumer-1") + + expectedRewardAllocation := providertypes.ConsumerRewardsAllocation{ + Rewards: nil, + } + require.Equal(t, expectedRewardAllocation, alloc) +} From 92fc432ab6aa93b373e3ee925e53030ed5a1b178 Mon Sep 17 00:00:00 2001 From: insumity Date: Tue, 30 Apr 2024 15:46:59 +0200 Subject: [PATCH 094/110] nit comment fix --- x/ccv/provider/keeper/keeper.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/x/ccv/provider/keeper/keeper.go b/x/ccv/provider/keeper/keeper.go index e3ad29beeb..fd13423948 100644 --- a/x/ccv/provider/keeper/keeper.go +++ b/x/ccv/provider/keeper/keeper.go @@ -189,7 +189,10 @@ func (k Keeper) SetProposedConsumerChain(ctx sdk.Context, chainID string, propos func (k Keeper) GetProposedConsumerChain(ctx sdk.Context, proposalID uint64) (string, bool) { store := ctx.KVStore(k.storeKey) consumerChain := store.Get(types.ProposedConsumerChainKey(proposalID)) - return string(consumerChain), consumerChain != nil + if consumerChain != nil { + return string(consumerChain), true + } + return "", false } // DeleteProposedConsumerChainInStore deletes the consumer chainID from store From d2a904d30a5c88ab056a3345f00c851c2a8f0e9c Mon Sep 17 00:00:00 2001 From: Simon Noetzlin Date: Tue, 30 Apr 2024 16:15:13 +0200 Subject: [PATCH 095/110] fix!: handle consumer commission marshalling errors gracefully (#1836) * handle consumer commission setter/getter gracefully to avoid BeginBlock panic + add msg in codec * fix consumer commission query rest path --- proto/interchain_security/ccv/provider/v1/query.proto | 2 +- tests/integration/distribution.go | 3 ++- x/ccv/provider/keeper/distribution.go | 4 +--- x/ccv/provider/keeper/keeper.go | 11 ++++++++--- x/ccv/provider/types/codec.go | 4 ++++ 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/proto/interchain_security/ccv/provider/v1/query.proto b/proto/interchain_security/ccv/provider/v1/query.proto index 9b00989f6d..c58833e0e1 100644 --- a/proto/interchain_security/ccv/provider/v1/query.proto +++ b/proto/interchain_security/ccv/provider/v1/query.proto @@ -125,7 +125,7 @@ service Query { QueryValidatorConsumerCommissionRateRequest) returns (QueryValidatorConsumerCommissionRateResponse) { option (google.api.http).get = - "/interchain_security/ccv/provider/consumer_commission_rate"; + "/interchain_security/ccv/provider/consumer_commission_rate/{chain_id}/{provider_address}"; } // QueryOldestUnconfirmedVsc returns the send timestamp of the oldest unconfirmed VSCPacket for a given chainID diff --git a/tests/integration/distribution.go b/tests/integration/distribution.go index d3111a39a5..5d62b2ee35 100644 --- a/tests/integration/distribution.go +++ b/tests/integration/distribution.go @@ -989,12 +989,13 @@ func (s *CCVTestSuite) TestAllocateTokensToValidator() { // set the same consumer commission rate for all consumer validators for _, v := range consuVals { provAddr := providertypes.NewProviderConsAddress(sdk.ConsAddress(v.ProviderConsAddr)) - providerKeeper.SetConsumerCommissionRate( + err := providerKeeper.SetConsumerCommissionRate( ctx, chainID, provAddr, tc.rate, ) + s.Require().NoError(err) } // allocate tokens diff --git a/x/ccv/provider/keeper/distribution.go b/x/ccv/provider/keeper/distribution.go index 2bf0ba2a24..84f4efcc19 100644 --- a/x/ccv/provider/keeper/distribution.go +++ b/x/ccv/provider/keeper/distribution.go @@ -280,12 +280,10 @@ func (k Keeper) HandleSetConsumerCommissionRate(ctx sdk.Context, chainID string, "unknown consumer chain, with id: %s", chainID) } // set per-consumer chain commission rate for the validator address - k.SetConsumerCommissionRate( + return k.SetConsumerCommissionRate( ctx, chainID, providerAddr, commissionRate, ) - - return nil } diff --git a/x/ccv/provider/keeper/keeper.go b/x/ccv/provider/keeper/keeper.go index fd13423948..d7b37fef46 100644 --- a/x/ccv/provider/keeper/keeper.go +++ b/x/ccv/provider/keeper/keeper.go @@ -1243,14 +1243,17 @@ func (k Keeper) SetConsumerCommissionRate( chainID string, providerAddr types.ProviderConsAddress, commissionRate sdk.Dec, -) { +) error { store := ctx.KVStore(k.storeKey) bz, err := commissionRate.Marshal() if err != nil { - panic(fmt.Errorf("consumer commission rate marshalling failed: %s", err)) + err = fmt.Errorf("consumer commission rate marshalling failed: %s", err) + k.Logger(ctx).Error(err.Error()) + return err } store.Set(types.ConsumerCommissionRateKey(chainID, providerAddr), bz) + return nil } // GetConsumerCommissionRate returns the per-consumer commission rate set @@ -1267,8 +1270,10 @@ func (k Keeper) GetConsumerCommissionRate( } cr := sdk.Dec{} + // handle error gracefully since it's called in BeginBlockRD if err := cr.Unmarshal(bz); err != nil { - panic(fmt.Sprintf("consumer commission rate unmarshalling failed: %s", err)) + k.Logger(ctx).Error("consumer commission rate unmarshalling failed: %s", err) + return sdk.ZeroDec(), false } return cr, true diff --git a/x/ccv/provider/types/codec.go b/x/ccv/provider/types/codec.go index 5f45c43fdf..cc842276fb 100644 --- a/x/ccv/provider/types/codec.go +++ b/x/ccv/provider/types/codec.go @@ -58,6 +58,10 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { (*exported.ClientMessage)(nil), &tendermint.Misbehaviour{}, ) + registry.RegisterImplementations( + (*sdk.Msg)(nil), + &MsgSetConsumerCommissionRate{}, + ) msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) } From d2cedd06b51c1410c1fddd638dbe74411f51668c Mon Sep 17 00:00:00 2001 From: Simon Noetzlin Date: Tue, 30 Apr 2024 16:24:28 +0200 Subject: [PATCH 096/110] fix: update queries REST path for PSS (#1839) update queries rest path --- proto/interchain_security/ccv/provider/v1/query.proto | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proto/interchain_security/ccv/provider/v1/query.proto b/proto/interchain_security/ccv/provider/v1/query.proto index c58833e0e1..139a7386de 100644 --- a/proto/interchain_security/ccv/provider/v1/query.proto +++ b/proto/interchain_security/ccv/provider/v1/query.proto @@ -107,7 +107,7 @@ service Query { QueryConsumerChainOptedInValidatorsRequest) returns (QueryConsumerChainOptedInValidatorsResponse) { option (google.api.http).get = - "/interchain_security/ccv/provider/opted_in_validators"; + "/interchain_security/ccv/provider/opted_in_validators/{chain_id}"; } // QueryConsumerChainsValidatorHasToValidate returns a list of consumer chains @@ -116,7 +116,7 @@ service Query { QueryConsumerChainsValidatorHasToValidateRequest) returns (QueryConsumerChainsValidatorHasToValidateResponse) { option (google.api.http).get = - "/interchain_security/ccv/provider/consumer_chains_per_validator"; + "/interchain_security/ccv/provider/consumer_chains_per_validator/{provider_address}"; } // QueryValidatorConsumerCommissionRate returns the commission rate a given From eab6b8bb4651253397a2b210142e6d53a9fa1eb9 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Tue, 30 Apr 2024 17:05:51 +0200 Subject: [PATCH 097/110] Clarify that GetProposedConsumerChain is test-only --- x/ccv/provider/keeper/keeper.go | 1 + 1 file changed, 1 insertion(+) diff --git a/x/ccv/provider/keeper/keeper.go b/x/ccv/provider/keeper/keeper.go index d7b37fef46..4b519f459f 100644 --- a/x/ccv/provider/keeper/keeper.go +++ b/x/ccv/provider/keeper/keeper.go @@ -186,6 +186,7 @@ func (k Keeper) SetProposedConsumerChain(ctx sdk.Context, chainID string, propos } // GetProposedConsumerChain returns the proposed chainID for the given consumerAddition proposal ID. +// This method is only used for testing. func (k Keeper) GetProposedConsumerChain(ctx sdk.Context, proposalID uint64) (string, bool) { store := ctx.KVStore(k.storeKey) consumerChain := store.Get(types.ProposedConsumerChainKey(proposalID)) From 8b7b938585f022d2ea464b34fa54cd070aef0abe Mon Sep 17 00:00:00 2001 From: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Date: Tue, 30 Apr 2024 17:30:21 +0200 Subject: [PATCH 098/110] fix: Fix has-to-validate query (#1823) * Fix has-to-validate query * Flip comparison sign for checking minPower * Regenerate traces * Remove unnecessary print * Address comments --- tests/e2e/state.go | 32 +++++ tests/e2e/steps_partial_set_security.go | 134 +++++++++++++++++- .../e2e/tracehandler_testdata/changeover.json | 17 +++ .../consumer-double-sign.json | 14 ++ .../consumer-misbehaviour.json | 13 ++ .../e2e/tracehandler_testdata/democracy.json | 29 ++++ .../democracyRewardsSteps.json | 29 ++++ .../e2e/tracehandler_testdata/happyPath.json | 58 ++++++++ .../multipleConsumers.json | 99 +++++++++++++ .../e2e/tracehandler_testdata/shorthappy.json | 41 ++++++ .../tracehandler_testdata/slashThrottle.json | 29 ++++ x/ccv/provider/keeper/grpc_query.go | 28 ++-- x/ccv/provider/keeper/keeper.go | 29 ++++ 13 files changed, 529 insertions(+), 23 deletions(-) diff --git a/tests/e2e/state.go b/tests/e2e/state.go index 91379a0705..7b674b0df8 100644 --- a/tests/e2e/state.go +++ b/tests/e2e/state.go @@ -31,6 +31,7 @@ type ChainState struct { ConsumerPendingPacketQueueSize *uint // Only relevant to consumer chains RegisteredConsumerRewardDenoms *[]string ClientsFrozenHeights *map[string]clienttypes.Height + HasToValidate *map[ValidatorID][]ChainID // only relevant to provider chain } type Proposal interface { @@ -180,6 +181,14 @@ func (tr TestConfig) getChainState(chain ChainID, modelState ChainState) ChainSt chainState.ClientsFrozenHeights = &chainClientsFrozenHeights } + if modelState.HasToValidate != nil { + hasToValidate := map[ValidatorID][]ChainID{} + for validatorId := range *modelState.HasToValidate { + hasToValidate[validatorId] = tr.getHasToValidate(validatorId) + } + chainState.HasToValidate = &hasToValidate + } + if modelState.ConsumerPendingPacketQueueSize != nil { pendingPacketQueueSize := tr.getPendingPacketQueueSize(chain) chainState.ConsumerPendingPacketQueueSize = &pendingPacketQueueSize @@ -833,6 +842,29 @@ func (tc TestConfig) getClientFrozenHeight(chain ChainID, clientID string) clien return clienttypes.Height{RevisionHeight: uint64(revHeight), RevisionNumber: uint64(revNumber)} } +func (tr TestConfig) getHasToValidate( + validatorId ValidatorID, +) []ChainID { + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + bz, err := exec.Command("docker", "exec", tr.containerConfig.InstanceName, tr.chainConfigs[ChainID("provi")].BinaryName, + "query", "provider", "has-to-validate", + tr.validatorConfigs[validatorId].ValconsAddress, + `--node`, tr.getQueryNode(ChainID("provi")), + `-o`, `json`, + ).CombinedOutput() + if err != nil { + log.Fatal(err, "\n", string(bz)) + } + + arr := gjson.Get(string(bz), "consumer_chain_ids").Array() + chains := []ChainID{} + for _, c := range arr { + chains = append(chains, ChainID(c.String())) + } + + return chains +} + func (tc TestConfig) getTrustedHeight( chain ChainID, clientID string, diff --git a/tests/e2e/steps_partial_set_security.go b/tests/e2e/steps_partial_set_security.go index cf230b999c..73bb929387 100644 --- a/tests/e2e/steps_partial_set_security.go +++ b/tests/e2e/steps_partial_set_security.go @@ -45,6 +45,11 @@ func stepsOptInChain() []Step { Status: "PROPOSAL_STATUS_VOTING_PERIOD", }, }, + HasToValidate: &map[ValidatorID][]ChainID{ + ValidatorID("alice"): {}, + ValidatorID("bob"): {}, + ValidatorID("carol"): {}, + }, }, }, }, @@ -56,14 +61,30 @@ func stepsOptInChain() []Step { Chain: ChainID("consu"), Validator: ValidatorID("alice"), }, - State: State{}, + State: State{ + ChainID("provi"): ChainState{ + HasToValidate: &map[ValidatorID][]ChainID{ + ValidatorID("alice"): {}, // chain is not running yet + ValidatorID("bob"): {}, + ValidatorID("carol"): {}, + }, + }, + }, }, { Action: OptInAction{ Chain: ChainID("consu"), Validator: ValidatorID("bob"), }, - State: State{}, + State: State{ + ChainID("provi"): ChainState{ + HasToValidate: &map[ValidatorID][]ChainID{ + ValidatorID("alice"): {}, + ValidatorID("bob"): {}, + ValidatorID("carol"): {}, + }, + }, + }, }, { Action: VoteGovProposalAction{ @@ -149,6 +170,13 @@ func stepsOptInChain() []Step { ValidatorID("carol"): 0, }, }, + ChainID("provi"): ChainState{ + HasToValidate: &map[ValidatorID][]ChainID{ + ValidatorID("alice"): {"consu"}, + ValidatorID("bob"): {"consu"}, + ValidatorID("carol"): {"consu"}, + }, + }, }, }, { @@ -179,6 +207,13 @@ func stepsOptInChain() []Step { ValidatorID("carol"): 300, }, }, + ChainID("provi"): ChainState{ + HasToValidate: &map[ValidatorID][]ChainID{ + ValidatorID("alice"): {"consu"}, + ValidatorID("bob"): {"consu"}, + ValidatorID("carol"): {"consu"}, + }, + }, }, }, { @@ -213,6 +248,13 @@ func stepsOptInChain() []Step { ValidatorID("carol"): 300, }, }, + ChainID("provi"): ChainState{ + HasToValidate: &map[ValidatorID][]ChainID{ + ValidatorID("alice"): {"consu"}, + ValidatorID("bob"): {}, + ValidatorID("carol"): {"consu"}, + }, + }, }, }, { @@ -229,6 +271,11 @@ func stepsOptInChain() []Step { ValidatorID("bob"): 0, ValidatorID("carol"): 300, }, + HasToValidate: &map[ValidatorID][]ChainID{ + ValidatorID("alice"): {"consu"}, + ValidatorID("bob"): {"consu"}, // but has to validate is true because bob opted in on the provider + ValidatorID("carol"): {"consu"}, + }, }, }, }, @@ -271,6 +318,11 @@ func stepsOptInChain() []Step { ValidatorID("bob"): 200, ValidatorID("carol"): 300, }, + HasToValidate: &map[ValidatorID][]ChainID{ + ValidatorID("alice"): {"consu"}, + ValidatorID("bob"): {"consu"}, + ValidatorID("carol"): {"consu"}, + }, }, }, }, @@ -290,6 +342,11 @@ func stepsOptInChain() []Step { ValidatorID("bob"): 200, ValidatorID("carol"): 300, }, + HasToValidate: &map[ValidatorID][]ChainID{ + ValidatorID("alice"): {"consu"}, // but alice still is in the consumer valset so has to validate + ValidatorID("bob"): {"consu"}, + ValidatorID("carol"): {"consu"}, + }, }, }, }, @@ -309,6 +366,11 @@ func stepsOptInChain() []Step { ValidatorID("bob"): 200, ValidatorID("carol"): 300, }, + HasToValidate: &map[ValidatorID][]ChainID{ + ValidatorID("alice"): {"consu"}, + ValidatorID("bob"): {"consu"}, + ValidatorID("carol"): {"consu"}, + }, }, ChainID("consu"): ChainState{ ValPowers: &map[ValidatorID]uint{ @@ -334,6 +396,11 @@ func stepsOptInChain() []Step { ValidatorID("bob"): 200, ValidatorID("carol"): 300, }, + HasToValidate: &map[ValidatorID][]ChainID{ + ValidatorID("alice"): {"consu"}, + ValidatorID("bob"): {"consu"}, + ValidatorID("carol"): {"consu"}, + }, }, // still 0 power on the consumer ChainID("consu"): ChainState{ @@ -385,6 +452,11 @@ func stepsOptInChain() []Step { ValidatorID("bob"): 200, ValidatorID("carol"): 300, }, + HasToValidate: &map[ValidatorID][]ChainID{ + ValidatorID("alice"): {"consu"}, + ValidatorID("bob"): {"consu"}, + ValidatorID("carol"): {"consu"}, + }, }, }, }, @@ -404,6 +476,11 @@ func stepsOptInChain() []Step { ValidatorID("bob"): 200, ValidatorID("carol"): 300, }, + HasToValidate: &map[ValidatorID][]ChainID{ + ValidatorID("alice"): {"consu"}, + ValidatorID("bob"): {"consu"}, + ValidatorID("carol"): {"consu"}, + }, }, }, }, @@ -430,6 +507,11 @@ func stepsOptInChain() []Step { ValidatorID("bob"): 200, ValidatorID("carol"): 300, }, + HasToValidate: &map[ValidatorID][]ChainID{ + ValidatorID("alice"): {"consu"}, + ValidatorID("bob"): {"consu"}, + ValidatorID("carol"): {"consu"}, + }, }, }, }, @@ -582,6 +664,13 @@ func stepsTopNChain() []Step { ValidatorID("carol"): 500, }, }, + ChainID("provi"): ChainState{ + HasToValidate: &map[ValidatorID][]ChainID{ + ValidatorID("alice"): {"consu"}, + ValidatorID("bob"): {"consu"}, + ValidatorID("carol"): {"consu"}, + }, + }, }, }, { @@ -616,7 +705,15 @@ func stepsTopNChain() []Step { Validator: ValidatorID("bob"), ExpectError: true, }, - State: State{}, + State: State{ + ChainID("provi"): ChainState{ + HasToValidate: &map[ValidatorID][]ChainID{ + ValidatorID("alice"): {"consu"}, + ValidatorID("bob"): {"consu"}, + ValidatorID("carol"): {"consu"}, + }, + }, + }, }, { // opting out "bob" or "carol" does not work because they belong to the Top N validators @@ -634,6 +731,13 @@ func stepsTopNChain() []Step { ValidatorID("carol"): 500, }, }, + ChainID("provi"): ChainState{ + HasToValidate: &map[ValidatorID][]ChainID{ + ValidatorID("alice"): {"consu"}, + ValidatorID("bob"): {"consu"}, + ValidatorID("carol"): {"consu"}, + }, + }, }, }, { @@ -659,6 +763,13 @@ func stepsTopNChain() []Step { ValidatorID("carol"): 500, }, }, + ChainID("provi"): ChainState{ + HasToValidate: &map[ValidatorID][]ChainID{ + ValidatorID("alice"): {}, // alice has opted out and the epoch is over, so definitely does not have to validate anymore + ValidatorID("bob"): {"consu"}, + ValidatorID("carol"): {"consu"}, + }, + }, }, }, // opt alice back in @@ -667,7 +778,15 @@ func stepsTopNChain() []Step { Chain: ChainID("consu"), Validator: ValidatorID("alice"), }, - State: State{}, + State: State{ + ChainID("provi"): ChainState{ + HasToValidate: &map[ValidatorID][]ChainID{ + ValidatorID("alice"): {"consu"}, // alice has to validate again + ValidatorID("bob"): {"consu"}, + ValidatorID("carol"): {"consu"}, + }, + }, + }, }, { Action: RelayPacketsAction{ @@ -685,6 +804,13 @@ func stepsTopNChain() []Step { ValidatorID("carol"): 500, }, }, + ChainID("provi"): ChainState{ + HasToValidate: &map[ValidatorID][]ChainID{ + ValidatorID("alice"): {"consu"}, + ValidatorID("bob"): {"consu"}, + ValidatorID("carol"): {"consu"}, + }, + }, }, }, { diff --git a/tests/e2e/tracehandler_testdata/changeover.json b/tests/e2e/tracehandler_testdata/changeover.json index ca6552e059..1b6ae37ae1 100644 --- a/tests/e2e/tracehandler_testdata/changeover.json +++ b/tests/e2e/tracehandler_testdata/changeover.json @@ -28,6 +28,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -58,6 +59,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -104,6 +106,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -151,6 +154,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "1": { "RawProposal": { @@ -193,6 +197,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "1": { "RawProposal": { @@ -249,6 +254,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "1": { "RawProposal": { @@ -299,6 +305,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "1": { "RawProposal": { @@ -358,6 +365,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "sover": { @@ -377,6 +385,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -428,6 +437,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -458,6 +468,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "sover": { @@ -477,6 +488,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -507,6 +519,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -535,6 +548,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -565,6 +579,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "sover": { @@ -584,6 +599,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -614,6 +630,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } diff --git a/tests/e2e/tracehandler_testdata/consumer-double-sign.json b/tests/e2e/tracehandler_testdata/consumer-double-sign.json index b72d020990..290f351875 100644 --- a/tests/e2e/tracehandler_testdata/consumer-double-sign.json +++ b/tests/e2e/tracehandler_testdata/consumer-double-sign.json @@ -41,6 +41,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -79,6 +80,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "1": { "RawProposal": { @@ -124,6 +126,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -156,6 +159,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -189,6 +193,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -226,6 +231,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "1": { "RawProposal": { @@ -285,6 +291,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -304,6 +311,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -355,6 +363,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -378,6 +387,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -405,6 +415,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -428,6 +439,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -458,6 +470,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -481,6 +494,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } diff --git a/tests/e2e/tracehandler_testdata/consumer-misbehaviour.json b/tests/e2e/tracehandler_testdata/consumer-misbehaviour.json index 5c839c35a6..b0c64232e2 100644 --- a/tests/e2e/tracehandler_testdata/consumer-misbehaviour.json +++ b/tests/e2e/tracehandler_testdata/consumer-misbehaviour.json @@ -35,6 +35,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -71,6 +72,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "1": { "RawProposal": { @@ -116,6 +118,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -151,6 +154,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "1": { "RawProposal": { @@ -198,6 +202,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -216,6 +221,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -268,6 +274,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -286,6 +293,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -315,6 +323,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -356,6 +365,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -377,6 +387,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -406,6 +417,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -431,6 +443,7 @@ "revision_height": 1 } }, + "HasToValidate": null, "Proposals": null } } diff --git a/tests/e2e/tracehandler_testdata/democracy.json b/tests/e2e/tracehandler_testdata/democracy.json index 427066d0c2..bcfcd0bcd4 100644 --- a/tests/e2e/tracehandler_testdata/democracy.json +++ b/tests/e2e/tracehandler_testdata/democracy.json @@ -41,6 +41,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -79,6 +80,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "1": { "RawProposal": { @@ -124,6 +126,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -156,6 +159,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -189,6 +193,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -226,6 +231,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "1": { "RawProposal": { @@ -285,6 +291,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -304,6 +311,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -371,6 +379,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -390,6 +399,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -419,6 +429,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -449,6 +460,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -478,6 +490,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -520,6 +533,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -561,6 +575,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -598,6 +613,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "1": { "RawProposal": { @@ -650,6 +666,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "1": { "RawProposal": { @@ -695,6 +712,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": [], "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -720,6 +738,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": [], "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -756,6 +775,7 @@ "ibc/3C3D7B3BE4ECC85A0E5B52A3AEC3B7DFC2AA9CA47C37821E57020D6807043BE9" ], "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -790,6 +810,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -818,6 +839,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -837,6 +859,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -867,6 +890,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -886,6 +910,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -916,6 +941,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -944,6 +970,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -963,6 +990,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -996,6 +1024,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } diff --git a/tests/e2e/tracehandler_testdata/democracyRewardsSteps.json b/tests/e2e/tracehandler_testdata/democracyRewardsSteps.json index e9210fe0cd..83b1f326d9 100644 --- a/tests/e2e/tracehandler_testdata/democracyRewardsSteps.json +++ b/tests/e2e/tracehandler_testdata/democracyRewardsSteps.json @@ -41,6 +41,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -79,6 +80,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "1": { "RawProposal": { @@ -124,6 +126,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -156,6 +159,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -189,6 +193,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -226,6 +231,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "1": { "RawProposal": { @@ -285,6 +291,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -304,6 +311,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -371,6 +379,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -390,6 +399,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -419,6 +429,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -449,6 +460,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -478,6 +490,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -520,6 +533,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -561,6 +575,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -598,6 +613,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "1": { "RawProposal": { @@ -650,6 +666,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "1": { "RawProposal": { @@ -695,6 +712,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": [], "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -720,6 +738,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": [], "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -756,6 +775,7 @@ "ibc/3C3D7B3BE4ECC85A0E5B52A3AEC3B7DFC2AA9CA47C37821E57020D6807043BE9" ], "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -790,6 +810,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -818,6 +839,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -837,6 +859,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -867,6 +890,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -886,6 +910,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -916,6 +941,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -944,6 +970,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -963,6 +990,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -996,6 +1024,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } diff --git a/tests/e2e/tracehandler_testdata/happyPath.json b/tests/e2e/tracehandler_testdata/happyPath.json index 6a99e3c97d..0109d72501 100644 --- a/tests/e2e/tracehandler_testdata/happyPath.json +++ b/tests/e2e/tracehandler_testdata/happyPath.json @@ -41,6 +41,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -79,6 +80,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "1": { "RawProposal": { @@ -124,6 +126,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -156,6 +159,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -189,6 +193,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -226,6 +231,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "1": { "RawProposal": { @@ -285,6 +291,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -304,6 +311,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -357,6 +365,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -376,6 +385,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -405,6 +415,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -435,6 +446,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -464,6 +476,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -502,6 +515,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -521,6 +535,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -557,6 +572,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -576,6 +592,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -606,6 +623,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -625,6 +643,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -655,6 +674,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -685,6 +705,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -704,6 +725,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -734,6 +756,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -764,6 +787,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -783,6 +807,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -813,6 +838,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -844,6 +870,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -863,6 +890,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -893,6 +921,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -921,6 +950,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -940,6 +970,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -970,6 +1001,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -989,6 +1021,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1020,6 +1053,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -1039,6 +1073,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1069,6 +1104,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1097,6 +1133,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -1116,6 +1153,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1145,6 +1183,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -1164,6 +1203,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1194,6 +1234,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1222,6 +1263,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -1241,6 +1283,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1271,6 +1314,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1299,6 +1343,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -1318,6 +1363,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1348,6 +1394,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1376,6 +1423,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -1395,6 +1443,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1425,6 +1474,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1453,6 +1503,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -1472,6 +1523,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1502,6 +1554,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -1521,6 +1574,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1557,6 +1611,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "2": { "RawProposal": { @@ -1605,6 +1660,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "2": { "RawProposal": { @@ -1646,6 +1702,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "3": { "RawProposal": { @@ -1692,6 +1749,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "3": { "RawProposal": { diff --git a/tests/e2e/tracehandler_testdata/multipleConsumers.json b/tests/e2e/tracehandler_testdata/multipleConsumers.json index 5d51282c0d..b8bffb9cde 100644 --- a/tests/e2e/tracehandler_testdata/multipleConsumers.json +++ b/tests/e2e/tracehandler_testdata/multipleConsumers.json @@ -41,6 +41,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -79,6 +80,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "1": { "RawProposal": { @@ -124,6 +126,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -156,6 +159,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -189,6 +193,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -226,6 +231,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "1": { "RawProposal": { @@ -285,6 +291,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -304,6 +311,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -365,6 +373,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "2": { "RawProposal": { @@ -410,6 +419,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -442,6 +452,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -475,6 +486,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -512,6 +524,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "2": { "RawProposal": { @@ -571,6 +584,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -590,6 +604,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -643,6 +658,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "densu": { @@ -662,6 +678,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -681,6 +698,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -711,6 +729,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "densu": { @@ -730,6 +749,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -749,6 +769,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -779,6 +800,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "densu": { @@ -798,6 +820,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -817,6 +840,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -847,6 +871,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "densu": { @@ -866,6 +891,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -885,6 +911,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -915,6 +942,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "densu": { @@ -934,6 +962,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -953,6 +982,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -983,6 +1013,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "densu": { @@ -1002,6 +1033,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -1021,6 +1053,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1052,6 +1085,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "densu": { @@ -1071,6 +1105,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -1090,6 +1125,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1120,6 +1156,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "densu": { @@ -1139,6 +1176,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -1158,6 +1196,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1188,6 +1227,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "densu": { @@ -1207,6 +1247,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -1226,6 +1267,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1254,6 +1296,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "densu": { @@ -1273,6 +1316,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -1292,6 +1336,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1322,6 +1367,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "densu": { @@ -1341,6 +1387,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -1360,6 +1407,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1390,6 +1438,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "densu": { @@ -1409,6 +1458,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1439,6 +1489,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "densu": { @@ -1458,6 +1509,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1486,6 +1538,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "densu": { @@ -1505,6 +1558,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -1524,6 +1578,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1554,6 +1609,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "densu": { @@ -1573,6 +1629,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -1592,6 +1649,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1622,6 +1680,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "densu": { @@ -1641,6 +1700,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -1660,6 +1720,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1688,6 +1749,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "densu": { @@ -1707,6 +1769,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -1726,6 +1789,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1756,6 +1820,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "densu": { @@ -1775,6 +1840,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -1794,6 +1860,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1824,6 +1891,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "densu": { @@ -1843,6 +1911,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -1862,6 +1931,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1890,6 +1960,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "densu": { @@ -1909,6 +1980,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -1928,6 +2000,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1958,6 +2031,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "densu": { @@ -1977,6 +2051,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -1996,6 +2071,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -2026,6 +2102,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "densu": { @@ -2045,6 +2122,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -2064,6 +2142,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -2092,6 +2171,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "densu": { @@ -2111,6 +2191,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -2130,6 +2211,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -2160,6 +2242,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "densu": { @@ -2179,6 +2262,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -2198,6 +2282,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -2228,6 +2313,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "densu": { @@ -2247,6 +2333,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -2266,6 +2353,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -2294,6 +2382,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "densu": { @@ -2313,6 +2402,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -2332,6 +2422,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -2362,6 +2453,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "densu": { @@ -2381,6 +2473,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -2400,6 +2493,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -2430,6 +2524,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "densu": { @@ -2449,6 +2544,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -2468,6 +2564,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -2498,6 +2595,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "densu": { @@ -2517,6 +2615,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } diff --git a/tests/e2e/tracehandler_testdata/shorthappy.json b/tests/e2e/tracehandler_testdata/shorthappy.json index 4b228b7e29..e029c5951b 100644 --- a/tests/e2e/tracehandler_testdata/shorthappy.json +++ b/tests/e2e/tracehandler_testdata/shorthappy.json @@ -41,6 +41,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -79,6 +80,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "1": { "RawProposal": { @@ -124,6 +126,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -156,6 +159,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -189,6 +193,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -226,6 +231,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "1": { "RawProposal": { @@ -285,6 +291,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -304,6 +311,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -357,6 +365,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -376,6 +385,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -405,6 +415,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -435,6 +446,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -464,6 +476,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -494,6 +507,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -513,6 +527,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -543,6 +558,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -574,6 +590,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -593,6 +610,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -623,6 +641,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -651,6 +670,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -670,6 +690,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -699,6 +720,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -718,6 +740,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -748,6 +771,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -776,6 +800,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -795,6 +820,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -825,6 +851,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -853,6 +880,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -872,6 +900,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -902,6 +931,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -930,6 +960,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -949,6 +980,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -979,6 +1011,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1007,6 +1040,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -1026,6 +1060,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1056,6 +1091,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -1075,6 +1111,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -1111,6 +1148,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "2": { "RawProposal": { @@ -1159,6 +1197,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "2": { "RawProposal": { @@ -1200,6 +1239,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "3": { "RawProposal": { @@ -1246,6 +1286,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "3": { "RawProposal": { diff --git a/tests/e2e/tracehandler_testdata/slashThrottle.json b/tests/e2e/tracehandler_testdata/slashThrottle.json index d347c551a2..fb701a4dc1 100644 --- a/tests/e2e/tracehandler_testdata/slashThrottle.json +++ b/tests/e2e/tracehandler_testdata/slashThrottle.json @@ -41,6 +41,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -79,6 +80,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "1": { "RawProposal": { @@ -124,6 +126,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -156,6 +159,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -189,6 +193,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -226,6 +231,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "1": { "RawProposal": { @@ -285,6 +291,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -304,6 +311,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -357,6 +365,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -376,6 +385,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -405,6 +415,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -435,6 +446,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -464,6 +476,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -492,6 +505,7 @@ "ConsumerPendingPacketQueueSize": 1, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -511,6 +525,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -541,6 +556,7 @@ "ConsumerPendingPacketQueueSize": 0, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -560,6 +576,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -588,6 +605,7 @@ "ConsumerPendingPacketQueueSize": 1, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -607,6 +625,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -637,6 +656,7 @@ "ConsumerPendingPacketQueueSize": 1, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -656,6 +676,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -684,6 +705,7 @@ "ConsumerPendingPacketQueueSize": 1, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -703,6 +725,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -726,6 +749,7 @@ "ConsumerPendingPacketQueueSize": 1, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -745,6 +769,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -771,6 +796,7 @@ "ConsumerPendingPacketQueueSize": 0, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null }, "provi": { @@ -790,6 +816,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": null } } @@ -821,6 +848,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "2": { "RawProposal": { @@ -867,6 +895,7 @@ "ConsumerPendingPacketQueueSize": null, "RegisteredConsumerRewardDenoms": null, "ClientsFrozenHeights": null, + "HasToValidate": null, "Proposals": { "2": { "RawProposal": { diff --git a/x/ccv/provider/keeper/grpc_query.go b/x/ccv/provider/keeper/grpc_query.go index 76ef217dfe..4adbcf5cc7 100644 --- a/x/ccv/provider/keeper/grpc_query.go +++ b/x/ccv/provider/keeper/grpc_query.go @@ -270,31 +270,21 @@ func (k Keeper) QueryConsumerChainsValidatorHasToValidate(goCtx context.Context, ctx := sdk.UnwrapSDKContext(goCtx) + provAddr := types.NewProviderConsAddress(consAddr) + // get all the consumer chains for which the validator is either already // opted-in, currently a consumer validator or if its voting power is within the TopN validators consumersToValidate := []string{} for _, consumer := range k.GetAllConsumerChains(ctx) { chainID := consumer.ChainId - provAddr := types.NewProviderConsAddress(consAddr) - if !k.IsOptedIn(ctx, chainID, provAddr) && !k.IsConsumerValidator(ctx, chainID, provAddr) { - // check that the validator voting power isn't in the TopN - if topN, found := k.GetTopN(ctx, chainID); found && topN > 0 { - val, found := k.stakingKeeper.GetValidatorByConsAddr(ctx, consAddr) - if !found { - return nil, status.Error(codes.InvalidArgument, "invalid provider address") - } - power := k.stakingKeeper.GetLastValidatorPower(ctx, val.GetOperator()) - minPowerToOptIn := k.ComputeMinPowerToOptIn(ctx, chainID, k.stakingKeeper.GetLastValidators(ctx), topN) - - // Check if the validator's voting power is smaller - // than the minimum and hence not automatically opted in - if power < minPowerToOptIn { - continue - } - } - } - consumersToValidate = append(consumersToValidate, chainID) + hasToValidate, err := k.HasToValidate(ctx, provAddr, chainID) + if err != nil { + return nil, err + } + if hasToValidate { + consumersToValidate = append(consumersToValidate, chainID) + } } return &types.QueryConsumerChainsValidatorHasToValidateResponse{ diff --git a/x/ccv/provider/keeper/keeper.go b/x/ccv/provider/keeper/keeper.go index d7b37fef46..05829b3b49 100644 --- a/x/ccv/provider/keeper/keeper.go +++ b/x/ccv/provider/keeper/keeper.go @@ -1236,6 +1236,35 @@ func (k Keeper) GetAllOptedIn( return providerConsAddresses } +func (k Keeper) HasToValidate( + ctx sdk.Context, + provAddr types.ProviderConsAddress, + chainID string, +) (bool, error) { + // if the validator is opted in or was sent as part of the packet in the last epoch, they have to validate + if k.IsOptedIn(ctx, chainID, provAddr) || k.IsConsumerValidator(ctx, chainID, provAddr) { + return true, nil + } + // otherwise, check whether the validator will be automatically opted in at the end of this epoch + // assuming all powers stay the same + val, found := k.stakingKeeper.GetValidatorByConsAddr(ctx, provAddr.ToSdkConsAddr()) + if !found { + return false, fmt.Errorf("validator not found for address %s", provAddr) + } + power := k.stakingKeeper.GetLastValidatorPower(ctx, val.GetOperator()) + topN, found := k.GetTopN(ctx, chainID) + if !found || topN == 0 { + return false, nil + } + + minPowerToOptIn := k.ComputeMinPowerToOptIn(ctx, chainID, k.stakingKeeper.GetLastValidators(ctx), topN) + + if power < minPowerToOptIn { + return false, nil + } + return true, nil +} + // SetConsumerCommissionRate sets a per-consumer chain commission rate // for the given validator address func (k Keeper) SetConsumerCommissionRate( From 31a7aa3ded362844ba37d51e37a908160cfcfc7a Mon Sep 17 00:00:00 2001 From: Simon Noetzlin Date: Wed, 1 May 2024 11:05:58 +0200 Subject: [PATCH 099/110] fix!: fix slashing in PSS (#1838) * drop slash packet for opted-out validators before updating slash meter * fix integration test * fix ut * update UT --- tests/integration/slashing.go | 9 +++++++++ x/ccv/provider/keeper/relay.go | 19 ++++++++++--------- x/ccv/provider/keeper/relay_test.go | 27 ++++++++++----------------- 3 files changed, 29 insertions(+), 26 deletions(-) diff --git a/tests/integration/slashing.go b/tests/integration/slashing.go index e7f585f756..19805a49ad 100644 --- a/tests/integration/slashing.go +++ b/tests/integration/slashing.go @@ -406,6 +406,15 @@ func (suite *CCVTestSuite) TestOnRecvSlashPacketErrors() { // Check expected behavior for handling SlashPackets for downtime infractions slashPacketData.Infraction = stakingtypes.Infraction_INFRACTION_DOWNTIME + // Expect packet to be handled if the validator didn't opt in + ackResult, err = providerKeeper.OnRecvSlashPacket(ctx, packet, *slashPacketData) + suite.Require().NoError(err, "no error expected") + suite.Require().Equal(ccv.SlashPacketHandledResult, ackResult, "expected successful ack") + + providerKeeper.SetConsumerValidator(ctx, firstBundle.Chain.ChainID, providertypes.ConsumerValidator{ + ProviderConsAddr: validAddress, + }) + // Expect the packet to bounce if the slash meter is negative providerKeeper.SetSlashMeter(ctx, sdk.NewInt(-1)) ackResult, err = providerKeeper.OnRecvSlashPacket(ctx, packet, *slashPacketData) diff --git a/x/ccv/provider/keeper/relay.go b/x/ccv/provider/keeper/relay.go index 35c98aa088..5dde197289 100644 --- a/x/ccv/provider/keeper/relay.go +++ b/x/ccv/provider/keeper/relay.go @@ -338,6 +338,16 @@ func (k Keeper) OnRecvSlashPacket( return ccv.V1Result, nil } + // Check that the validator belongs to the consumer chain valset + if !k.IsConsumerValidator(ctx, chainID, providerConsAddr) { + k.Logger(ctx).Error("cannot jail validator %s that does not belong to consumer %s valset", + providerConsAddr.String(), chainID) + // drop packet but return a slash ack so that the consumer can send another slash packet + k.AppendSlashAck(ctx, chainID, consumerConsAddr.String()) + + return ccv.SlashPacketHandledResult, nil + } + meter := k.GetSlashMeter(ctx) // Return bounce ack if meter is negative in value if meter.IsNegative() { @@ -401,15 +411,6 @@ func (k Keeper) HandleSlashPacket(ctx sdk.Context, chainID string, data ccv.Slas "infractionType", data.Infraction, ) - // Check that the validator belongs to the consumer chain valset - if !k.IsConsumerValidator(ctx, chainID, providerConsAddr) { - k.Logger(ctx).Error("cannot jail validator %s that does not belong to consumer %s valset", - providerConsAddr.String(), chainID) - // drop packet but return a slash ack so that the consumer can send another slash packet - k.AppendSlashAck(ctx, chainID, consumerConsAddr.String()) - return - } - // Obtain validator from staking keeper validator, found := k.stakingKeeper.GetValidatorByConsAddr(ctx, providerConsAddr.ToSdkConsAddr()) diff --git a/x/ccv/provider/keeper/relay_test.go b/x/ccv/provider/keeper/relay_test.go index 5afbf70248..b300916a2e 100644 --- a/x/ccv/provider/keeper/relay_test.go +++ b/x/ccv/provider/keeper/relay_test.go @@ -125,12 +125,22 @@ func TestOnRecvDowntimeSlashPacket(t *testing.T) { // Set a block height for the valset update id in the generated packet data providerKeeper.SetValsetUpdateBlockHeight(ctx, packetData.ValsetUpdateId, uint64(15)) + // Set consumer validator + providerKeeper.SetConsumerValidator(ctx, "chain-1", providertypes.ConsumerValidator{ + ProviderConsAddr: packetData.Validator.Address, + }) + // Set slash meter to negative value and assert a bounce ack is returned providerKeeper.SetSlashMeter(ctx, math.NewInt(-5)) ackResult, err := executeOnRecvSlashPacket(t, &providerKeeper, ctx, "channel-1", 1, packetData) require.Equal(t, ccv.SlashPacketBouncedResult, ackResult) require.NoError(t, err) + // Set consumer validator + providerKeeper.SetConsumerValidator(ctx, "chain-2", providertypes.ConsumerValidator{ + ProviderConsAddr: packetData.Validator.Address, + }) + // Also bounced for chain-2 ackResult, err = executeOnRecvSlashPacket(t, &providerKeeper, ctx, "channel-2", 2, packetData) require.Equal(t, ccv.SlashPacketBouncedResult, ackResult) @@ -298,8 +308,6 @@ func TestHandleSlashPacket(t *testing.T) { providerConsAddr := cryptotestutil.NewCryptoIdentityFromIntSeed(7842334).ProviderConsAddress() consumerConsAddr := cryptotestutil.NewCryptoIdentityFromIntSeed(784987634).ConsumerConsAddress() - // this "dummy" consensus address won't be stored on the provider states - dummyConsAddr := cryptotestutil.NewCryptoIdentityFromIntSeed(784987639).ConsumerConsAddress() testCases := []struct { name string @@ -309,21 +317,6 @@ func TestHandleSlashPacket(t *testing.T) { expectedSlashAcksLen int expectedSlashAckConsumerConsAddress types.ConsumerConsAddress }{ - { - "validator isn't a consumer validator", - ccv.SlashPacketData{ - Validator: abci.Validator{Address: dummyConsAddr.ToSdkConsAddr()}, - ValsetUpdateId: validVscID, - Infraction: stakingtypes.Infraction_INFRACTION_DOWNTIME, - }, - func(ctx sdk.Context, mocks testkeeper.MockedKeepers, - expectedPacketData ccv.SlashPacketData, - ) []*gomock.Call { - return []*gomock.Call{} - }, - 1, - dummyConsAddr, - }, { "unfound validator", ccv.SlashPacketData{ From 922faa88f0ef5f1de1be076a19b65c17ab4d3093 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Date: Wed, 1 May 2024 11:14:08 +0200 Subject: [PATCH 100/110] Update x/ccv/provider/types/msg.go Co-authored-by: Marius Poke --- x/ccv/provider/types/msg.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/ccv/provider/types/msg.go b/x/ccv/provider/types/msg.go index 70f090a971..b80e608785 100644 --- a/x/ccv/provider/types/msg.go +++ b/x/ccv/provider/types/msg.go @@ -244,7 +244,7 @@ func (msg MsgOptIn) ValidateBasic() error { if strings.TrimSpace(msg.ChainId) == "" { return errorsmod.Wrapf(ErrInvalidConsumerChainID, "chainId cannot be blank") } - // It is possible to assign keys for consumer chains that are not yet approved. + // It is possible to opt in to validate on consumer chains that are not yet approved. // This can only be done by a signing validator, but it is still sensible // to limit the chainID size to prevent abuse. if 128 < len(msg.ChainId) { From daedac974f0f08ed450e545d2d7bd8726ebb40d2 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Wed, 1 May 2024 11:23:29 +0200 Subject: [PATCH 101/110] Remove BlockValidatorUpdate from expected staking keeper --- testutil/keeper/mocks.go | 14 -------------- x/ccv/types/expected_keepers.go | 1 - 2 files changed, 15 deletions(-) diff --git a/testutil/keeper/mocks.go b/testutil/keeper/mocks.go index 7abadd63d5..12ab5ceb17 100644 --- a/testutil/keeper/mocks.go +++ b/testutil/keeper/mocks.go @@ -49,20 +49,6 @@ func (m *MockStakingKeeper) EXPECT() *MockStakingKeeperMockRecorder { return m.recorder } -// BlockValidatorUpdates mocks base method. -func (m *MockStakingKeeper) BlockValidatorUpdates(ctx types0.Context) []types.ValidatorUpdate { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BlockValidatorUpdates", ctx) - ret0, _ := ret[0].([]types.ValidatorUpdate) - return ret0 -} - -// BlockValidatorUpdates indicates an expected call of BlockValidatorUpdates. -func (mr *MockStakingKeeperMockRecorder) BlockValidatorUpdates(ctx interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockValidatorUpdates", reflect.TypeOf((*MockStakingKeeper)(nil).BlockValidatorUpdates), ctx) -} - // BondDenom mocks base method. func (m *MockStakingKeeper) BondDenom(ctx types0.Context) string { m.ctrl.T.Helper() diff --git a/x/ccv/types/expected_keepers.go b/x/ccv/types/expected_keepers.go index 7b77ebd095..b2d21dbbe8 100644 --- a/x/ccv/types/expected_keepers.go +++ b/x/ccv/types/expected_keepers.go @@ -57,7 +57,6 @@ type StakingKeeper interface { GetUnbondingDelegationsFromValidator(ctx sdk.Context, valAddr sdk.ValAddress) (ubds []stakingtypes.UnbondingDelegation) GetRedelegationsFromSrcValidator(ctx sdk.Context, valAddr sdk.ValAddress) (reds []stakingtypes.Redelegation) GetUnbondingType(ctx sdk.Context, id uint64) (unbondingType stakingtypes.UnbondingType, found bool) - BlockValidatorUpdates(ctx sdk.Context) []abci.ValidatorUpdate } // SlashingKeeper defines the contract expected to perform ccv slashing From 97d62bc1f489ba5a599b772c8e0dd2e2b029d753 Mon Sep 17 00:00:00 2001 From: insumity Date: Wed, 1 May 2024 12:14:42 +0200 Subject: [PATCH 102/110] added an error response value to ComputeMinPowerToOptIn --- x/ccv/provider/keeper/keeper.go | 4 +- x/ccv/provider/keeper/partial_set_security.go | 28 ++++----- .../keeper/partial_set_security_test.go | 60 ++++++++++++++----- x/ccv/provider/keeper/proposal.go | 6 +- x/ccv/provider/keeper/relay.go | 6 +- 5 files changed, 66 insertions(+), 38 deletions(-) diff --git a/x/ccv/provider/keeper/keeper.go b/x/ccv/provider/keeper/keeper.go index 38674cf807..ff179ed3b7 100644 --- a/x/ccv/provider/keeper/keeper.go +++ b/x/ccv/provider/keeper/keeper.go @@ -1258,9 +1258,9 @@ func (k Keeper) HasToValidate( return false, nil } - minPowerToOptIn := k.ComputeMinPowerToOptIn(ctx, chainID, k.stakingKeeper.GetLastValidators(ctx), topN) + minPowerToOptIn, err := k.ComputeMinPowerToOptIn(ctx, chainID, k.stakingKeeper.GetLastValidators(ctx), topN) - if power < minPowerToOptIn { + if err != nil || power < minPowerToOptIn { return false, nil } return true, nil diff --git a/x/ccv/provider/keeper/partial_set_security.go b/x/ccv/provider/keeper/partial_set_security.go index b5ad53a72d..703dcf8b76 100644 --- a/x/ccv/provider/keeper/partial_set_security.go +++ b/x/ccv/provider/keeper/partial_set_security.go @@ -1,7 +1,7 @@ package keeper import ( - "math" + "fmt" "sort" errorsmod "cosmossdk.io/errors" @@ -63,9 +63,9 @@ func (k Keeper) HandleOptOut(ctx sdk.Context, chainID string, providerAddr types "validator with consensus address %s could not be found", providerAddr.ToSdkConsAddr()) } power := k.stakingKeeper.GetLastValidatorPower(ctx, validator.GetOperator()) - minPowerToOptIn := k.ComputeMinPowerToOptIn(ctx, chainID, k.stakingKeeper.GetLastValidators(ctx), topN) + minPowerToOptIn, err := k.ComputeMinPowerToOptIn(ctx, chainID, k.stakingKeeper.GetLastValidators(ctx), topN) - if power >= minPowerToOptIn { + if err != nil || power >= minPowerToOptIn { return errorsmod.Wrapf( types.ErrCannotOptOutFromTopN, "validator with power (%d) cannot opt out from Top N chain because all validators"+ @@ -98,13 +98,10 @@ func (k Keeper) OptInTopNValidators(ctx sdk.Context, chainID string, bondedValid // ComputeMinPowerToOptIn returns the minimum power needed for a validator (from the bonded validators) // to belong to the `topN` validators. `chainID` is only used for logging purposes. -func (k Keeper) ComputeMinPowerToOptIn(ctx sdk.Context, chainID string, bondedValidators []stakingtypes.Validator, topN uint32) int64 { - if topN == 0 { - // This should never happen but because `ComputeMinPowerToOptIn` is called during an `EndBlock` we do want - // to `panic` here. Instead, we log an error and return the maximum possible `int64`. - k.Logger(ctx).Error("trying to compute minimum power to opt in for a non-Top-N chain", - "chainID", chainID) - return math.MaxInt64 +func (k Keeper) ComputeMinPowerToOptIn(ctx sdk.Context, chainID string, bondedValidators []stakingtypes.Validator, topN uint32) (int64, error) { + if topN == 0 || topN > 100 { + return 0, fmt.Errorf("trying to compute minimum power with an incorrect topN value (%d)."+ + "topN has to be between (0, 100]", topN) } totalPower := sdk.ZeroDec() @@ -126,18 +123,13 @@ func (k Keeper) ComputeMinPowerToOptIn(ctx sdk.Context, chainID string, bondedVa for _, power := range powers { powerSum = powerSum.Add(sdk.NewDecFromInt(sdk.NewInt(power))) if powerSum.Quo(totalPower).GTE(topNThreshold) { - return power + return power, nil } } // We should never reach this point because the topN can be up to 1.0 (100%) and in the above `for` loop we - // perform an equal comparison as well (`GTE`). In any case, we do not have to panic here because we can return 0 - // as the smallest possible power. - k.Logger(ctx).Error("should never reach this point", - "topN", topN, - "totalPower", totalPower, - "powerSum", powerSum) - return 0 + // perform an equal comparison as well (`GTE`). + return 0, fmt.Errorf("should never reach this point with topN (%d), totalPower (%d), and powerSum (%d)", topN, totalPower, powerSum) } // ShouldConsiderOnlyOptIn returns true if `validator` is opted in, in `chainID. diff --git a/x/ccv/provider/keeper/partial_set_security_test.go b/x/ccv/provider/keeper/partial_set_security_test.go index b18acb56ce..18720606e8 100644 --- a/x/ccv/provider/keeper/partial_set_security_test.go +++ b/x/ccv/provider/keeper/partial_set_security_test.go @@ -2,7 +2,6 @@ package keeper_test import ( "bytes" - "math" "sort" "testing" @@ -274,19 +273,52 @@ func TestComputeMinPowerToOptIn(t *testing.T) { createStakingValidator(ctx, mocks, 5, 6), } - require.Equal(t, int64(1), providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 100)) - require.Equal(t, int64(1), providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 97)) - require.Equal(t, int64(3), providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 96)) - require.Equal(t, int64(3), providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 85)) - require.Equal(t, int64(5), providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 84)) - require.Equal(t, int64(5), providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 65)) - require.Equal(t, int64(6), providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 64)) - require.Equal(t, int64(6), providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 41)) - require.Equal(t, int64(10), providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 40)) - require.Equal(t, int64(10), providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 1)) - - // exceptional case when we erroneously call with `topN == 0` - require.Equal(t, int64(math.MaxInt64), providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 0)) + m, err := providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 100) + require.NoError(t, err) + require.Equal(t, int64(1), m) + + m, err = providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 97) + require.NoError(t, err) + require.Equal(t, int64(1), m) + + m, err = providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 96) + require.NoError(t, err) + require.Equal(t, int64(3), m) + + m, err = providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 85) + require.NoError(t, err) + require.Equal(t, int64(3), m) + + m, err = providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 84) + require.NoError(t, err) + require.Equal(t, int64(5), m) + + m, err = providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 65) + require.NoError(t, err) + require.Equal(t, int64(5), m) + + m, err = providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 64) + require.NoError(t, err) + require.Equal(t, int64(6), m) + + m, err = providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 41) + require.NoError(t, err) + require.Equal(t, int64(6), m) + + m, err = providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 40) + require.NoError(t, err) + require.Equal(t, int64(10), m) + + m, err = providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 1) + require.NoError(t, err) + require.Equal(t, int64(10), m) + + // exceptional case when we erroneously call with `topN == 0` or `topN > 100` + _, err = providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 0) + require.Error(t, err) + + _, err = providerKeeper.ComputeMinPowerToOptIn(ctx, "chainID", bondedValidators, 101) + require.Error(t, err) } // TestShouldConsiderOnlyOptIn returns true if `validator` is opted in, in `chainID. diff --git a/x/ccv/provider/keeper/proposal.go b/x/ccv/provider/keeper/proposal.go index f167c2c33b..5485e6cc38 100644 --- a/x/ccv/provider/keeper/proposal.go +++ b/x/ccv/provider/keeper/proposal.go @@ -279,8 +279,10 @@ func (k Keeper) MakeConsumerGenesis( if prop.Top_N > 0 { // in a Top-N chain, we automatically opt in all validators that belong to the top N - minPower := k.ComputeMinPowerToOptIn(ctx, chainID, bondedValidators, prop.Top_N) - k.OptInTopNValidators(ctx, chainID, bondedValidators, minPower) + minPower, err := k.ComputeMinPowerToOptIn(ctx, chainID, bondedValidators, prop.Top_N) + if err == nil { + k.OptInTopNValidators(ctx, chainID, bondedValidators, minPower) + } } nextValidators := k.ComputeNextEpochConsumerValSet(ctx, chainID, bondedValidators, diff --git a/x/ccv/provider/keeper/relay.go b/x/ccv/provider/keeper/relay.go index 5dde197289..7812081918 100644 --- a/x/ccv/provider/keeper/relay.go +++ b/x/ccv/provider/keeper/relay.go @@ -225,8 +225,10 @@ func (k Keeper) QueueVSCPackets(ctx sdk.Context) { if topN, found := k.GetTopN(ctx, chain.ChainId); found && topN > 0 { // in a Top-N chain, we automatically opt in all validators that belong to the top N - minPower := k.ComputeMinPowerToOptIn(ctx, chain.ChainId, bondedValidators, topN) - k.OptInTopNValidators(ctx, chain.ChainId, bondedValidators, minPower) + minPower, err := k.ComputeMinPowerToOptIn(ctx, chain.ChainId, bondedValidators, topN) + if err == nil { + k.OptInTopNValidators(ctx, chain.ChainId, bondedValidators, minPower) + } } nextValidators := k.ComputeNextEpochConsumerValSet(ctx, chain.ChainId, bondedValidators, From cac367ecd8efc17020f75dfd54828b96975336a3 Mon Sep 17 00:00:00 2001 From: insumity Date: Wed, 1 May 2024 12:21:38 +0200 Subject: [PATCH 103/110] delete additional state when we stop a chain --- x/ccv/provider/keeper/keeper.go | 19 +++++++++++++++++++ x/ccv/provider/keeper/keeper_test.go | 25 +++++++++++++++++-------- x/ccv/provider/keeper/proposal.go | 2 ++ 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/x/ccv/provider/keeper/keeper.go b/x/ccv/provider/keeper/keeper.go index ff179ed3b7..ec0334b4a5 100644 --- a/x/ccv/provider/keeper/keeper.go +++ b/x/ccv/provider/keeper/keeper.go @@ -1237,6 +1237,25 @@ func (k Keeper) GetAllOptedIn( return providerConsAddresses } +// DeleteAllOptedIn deletes all the opted-in validators for chain with `chainID` +func (k Keeper) DeleteAllOptedIn( + ctx sdk.Context, + chainID string, +) { + store := ctx.KVStore(k.storeKey) + key := types.ChainIdWithLenKey(types.OptedInBytePrefix, chainID) + iterator := sdk.KVStorePrefixIterator(store, key) + + var keysToDel [][]byte + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + keysToDel = append(keysToDel, iterator.Key()) + } + for _, delKey := range keysToDel { + store.Delete(delKey) + } +} + func (k Keeper) HasToValidate( ctx sdk.Context, provAddr types.ProviderConsAddress, diff --git a/x/ccv/provider/keeper/keeper_test.go b/x/ccv/provider/keeper/keeper_test.go index 691dd07731..04a4ffd2fb 100644 --- a/x/ccv/provider/keeper/keeper_test.go +++ b/x/ccv/provider/keeper/keeper_test.go @@ -691,18 +691,27 @@ func TestGetAllOptedIn(t *testing.T) { require.Equal(t, expectedOptedInValidators, actualOptedInValidators) } -// TestOptedIn tests the `SetOptedIn`, `IsOptedIn`, and `RemoveOptedIn` methods +// TestOptedIn tests the `SetOptedIn`, `IsOptedIn`, `DeleteOptedIn` and `DeleteAllOptedIn` methods func TestOptedIn(t *testing.T) { providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - optedInValidator := types.NewProviderConsAddress([]byte("providerAddr")) - - require.False(t, providerKeeper.IsOptedIn(ctx, "chainID", optedInValidator)) - providerKeeper.SetOptedIn(ctx, "chainID", optedInValidator) - require.True(t, providerKeeper.IsOptedIn(ctx, "chainID", optedInValidator)) - providerKeeper.DeleteOptedIn(ctx, "chainID", optedInValidator) - require.False(t, providerKeeper.IsOptedIn(ctx, "chainID", optedInValidator)) + optedInValidator1 := types.NewProviderConsAddress([]byte("providerAddr1")) + optedInValidator2 := types.NewProviderConsAddress([]byte("providerAddr2")) + + require.False(t, providerKeeper.IsOptedIn(ctx, "chainID", optedInValidator1)) + providerKeeper.SetOptedIn(ctx, "chainID", optedInValidator1) + require.True(t, providerKeeper.IsOptedIn(ctx, "chainID", optedInValidator1)) + providerKeeper.DeleteOptedIn(ctx, "chainID", optedInValidator1) + require.False(t, providerKeeper.IsOptedIn(ctx, "chainID", optedInValidator1)) + + providerKeeper.SetOptedIn(ctx, "chainID", optedInValidator1) + providerKeeper.SetOptedIn(ctx, "chainID", optedInValidator2) + require.True(t, providerKeeper.IsOptedIn(ctx, "chainID", optedInValidator1)) + require.True(t, providerKeeper.IsOptedIn(ctx, "chainID", optedInValidator2)) + providerKeeper.DeleteAllOptedIn(ctx, "chainID") + require.False(t, providerKeeper.IsOptedIn(ctx, "chainID", optedInValidator1)) + require.False(t, providerKeeper.IsOptedIn(ctx, "chainID", optedInValidator2)) } // TestConsumerCommissionRate tests the `SetConsumerCommissionRate`, `GetConsumerCommissionRate`, and `DeleteConsumerCommissionRate` methods diff --git a/x/ccv/provider/keeper/proposal.go b/x/ccv/provider/keeper/proposal.go index 5485e6cc38..41e104e52f 100644 --- a/x/ccv/provider/keeper/proposal.go +++ b/x/ccv/provider/keeper/proposal.go @@ -220,6 +220,8 @@ func (k Keeper) StopConsumerChain(ctx sdk.Context, chainID string, closeChan boo } k.DeleteTopN(ctx, chainID) + k.DeleteAllOptedIn(ctx, chainID) + k.DeleteConsumerValSet(ctx, chainID) k.Logger(ctx).Info("consumer chain removed from provider", "chainID", chainID) From e8eaa4f20ee70cae14be8c8887a41236fe87c362 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Wed, 1 May 2024 12:40:44 +0200 Subject: [PATCH 104/110] Assign keys and change voting power only for unjailed nodes with >0 power --- tests/mbt/model/ccv_model.qnt | 8 ++++---- tests/mbt/model/ccv_utils.qnt | 5 +++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/tests/mbt/model/ccv_model.qnt b/tests/mbt/model/ccv_model.qnt index 5c818cce64..312f6a5bdb 100644 --- a/tests/mbt/model/ccv_model.qnt +++ b/tests/mbt/model/ccv_model.qnt @@ -217,8 +217,8 @@ module ccv_model { // stepCommon is the core functionality of steps that does not have anything to do with time. action stepCommon = any { all { - nonJailedNodes(currentState.providerState).size() > 0, - nondet node = oneOf(nonJailedNodes(currentState.providerState)) + currentState.providerState.validatorsWithPower().size() > 0, + nondet node = oneOf(currentState.providerState.validatorsWithPower()) // very restricted set of voting powers. exact values are not important, // and this keeps the state space smaller. nondet newVotingPower = oneOf(Set(-50, 50)) @@ -752,8 +752,8 @@ module ccv_model { action nondetKeyAssignment = all { runningConsumers.size() > 0, - nonJailedNodes(currentState.providerState).size() > 0, - nondet node = oneOf(nonJailedNodes(currentState.providerState)) + currentState.providerState.validatorsWithPower().size() > 0, + nondet node = oneOf(currentState.providerState.validatorsWithPower()) nondet consumerAddr = oneOf(consumerAddresses) nondet consumer = oneOf(runningConsumers) KeyAssignment(consumer, node, consumerAddr), diff --git a/tests/mbt/model/ccv_utils.qnt b/tests/mbt/model/ccv_utils.qnt index ffb22e0dda..6c0f18b44c 100644 --- a/tests/mbt/model/ccv_utils.qnt +++ b/tests/mbt/model/ccv_utils.qnt @@ -531,6 +531,11 @@ module ccv_utils { ) } + // Returns the set of all nodes that are neither jailed nor have 0 power on the provider. + pure def validatorsWithPower(providerState: ProviderState): Set[Node] = { + nonJailedNodes(providerState).filter(node => providerState.chainState.currentValidatorPowers.get(node) != 0) + } + pure def IsEmptyValSet(valSet: ValidatorSet): bool = { valSet.keys().filter( node => valSet.get(node) > 0 From b3d47ed04fd171d1ed815a815ec97632d43ace01 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Date: Wed, 1 May 2024 13:47:14 +0200 Subject: [PATCH 105/110] fix: Validate consumer commission rate against minimal rate (#1834) * Validate consumer commission rate * Add test for commission rates * Remove static minimum commission rate validation from Set --- testutil/keeper/mocks.go | 14 +++++++++++ x/ccv/provider/keeper/distribution.go | 9 ++++++++ .../keeper/partial_set_security_test.go | 23 ++++++++++++++++++- x/ccv/types/expected_keepers.go | 1 + 4 files changed, 46 insertions(+), 1 deletion(-) diff --git a/testutil/keeper/mocks.go b/testutil/keeper/mocks.go index 12ab5ceb17..ffa76ad40c 100644 --- a/testutil/keeper/mocks.go +++ b/testutil/keeper/mocks.go @@ -315,6 +315,20 @@ func (mr *MockStakingKeeperMockRecorder) MaxValidators(ctx interface{}) *gomock. return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MaxValidators", reflect.TypeOf((*MockStakingKeeper)(nil).MaxValidators), ctx) } +// MinCommissionRate mocks base method. +func (m *MockStakingKeeper) MinCommissionRate(ctx types0.Context) math.LegacyDec { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "MinCommissionRate", ctx) + ret0, _ := ret[0].(math.LegacyDec) + return ret0 +} + +// MinCommissionRate indicates an expected call of MinCommissionRate. +func (mr *MockStakingKeeperMockRecorder) MinCommissionRate(ctx interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MinCommissionRate", reflect.TypeOf((*MockStakingKeeper)(nil).MinCommissionRate), ctx) +} + // PowerReduction mocks base method. func (m *MockStakingKeeper) PowerReduction(ctx types0.Context) math.Int { m.ctrl.T.Helper() diff --git a/x/ccv/provider/keeper/distribution.go b/x/ccv/provider/keeper/distribution.go index 84f4efcc19..67e6193e5d 100644 --- a/x/ccv/provider/keeper/distribution.go +++ b/x/ccv/provider/keeper/distribution.go @@ -279,6 +279,15 @@ func (k Keeper) HandleSetConsumerCommissionRate(ctx sdk.Context, chainID string, types.ErrUnknownConsumerChainId, "unknown consumer chain, with id: %s", chainID) } + + // validate against the minimum commission rate + minRate := k.stakingKeeper.MinCommissionRate(ctx) + if commissionRate.LT(minRate) { + return errorsmod.Wrapf( + stakingtypes.ErrCommissionLTMinRate, + "commission rate cannot be less than %s", minRate, + ) + } // set per-consumer chain commission rate for the validator address return k.SetConsumerCommissionRate( ctx, diff --git a/x/ccv/provider/keeper/partial_set_security_test.go b/x/ccv/provider/keeper/partial_set_security_test.go index 18720606e8..b8e4d705ef 100644 --- a/x/ccv/provider/keeper/partial_set_security_test.go +++ b/x/ccv/provider/keeper/partial_set_security_test.go @@ -150,7 +150,7 @@ func TestHandleOptOutFromTopNChain(t *testing.T) { } func TestHandleSetConsumerCommissionRate(t *testing.T) { - providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + providerKeeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() providerAddr := types.NewProviderConsAddress([]byte("providerAddr")) @@ -166,12 +166,33 @@ func TestHandleSetConsumerCommissionRate(t *testing.T) { _, found := providerKeeper.GetConsumerCommissionRate(ctx, chainID, providerAddr) require.False(t, found) + mocks.MockStakingKeeper.EXPECT().MinCommissionRate(ctx).Return(sdk.ZeroDec()).Times(1) require.NoError(t, providerKeeper.HandleSetConsumerCommissionRate(ctx, chainID, providerAddr, sdk.OneDec())) // check that the commission rate is now set cr, found := providerKeeper.GetConsumerCommissionRate(ctx, chainID, providerAddr) require.Equal(t, sdk.OneDec(), cr) require.True(t, found) + + // set minimum rate of 1/2 + commissionRate := sdk.NewDec(1).Quo(sdk.NewDec(2)) + mocks.MockStakingKeeper.EXPECT().MinCommissionRate(ctx).Return(commissionRate).AnyTimes() + + // try to set a rate slightly below the minimum + require.Error(t, providerKeeper.HandleSetConsumerCommissionRate( + ctx, + chainID, + providerAddr, + commissionRate.Sub(sdk.NewDec(1).Quo(sdk.NewDec(100)))), // 0.5 - 0.01 + "commission rate should be rejected (below min), but is not", + ) + + // set a valid commission equal to the minimum + require.NoError(t, providerKeeper.HandleSetConsumerCommissionRate(ctx, chainID, providerAddr, commissionRate)) + // check that the rate was set + cr, found = providerKeeper.GetConsumerCommissionRate(ctx, chainID, providerAddr) + require.Equal(t, commissionRate, cr) + require.True(t, found) } func TestOptInTopNValidators(t *testing.T) { diff --git a/x/ccv/types/expected_keepers.go b/x/ccv/types/expected_keepers.go index b2d21dbbe8..b3815b6d65 100644 --- a/x/ccv/types/expected_keepers.go +++ b/x/ccv/types/expected_keepers.go @@ -57,6 +57,7 @@ type StakingKeeper interface { GetUnbondingDelegationsFromValidator(ctx sdk.Context, valAddr sdk.ValAddress) (ubds []stakingtypes.UnbondingDelegation) GetRedelegationsFromSrcValidator(ctx sdk.Context, valAddr sdk.ValAddress) (reds []stakingtypes.Redelegation) GetUnbondingType(ctx sdk.Context, id uint64) (unbondingType stakingtypes.UnbondingType, found bool) + MinCommissionRate(ctx sdk.Context) math.LegacyDec } // SlashingKeeper defines the contract expected to perform ccv slashing From b13185243c8fdc28654244714b2171832e333311 Mon Sep 17 00:00:00 2001 From: insumity Date: Wed, 1 May 2024 16:05:20 +0200 Subject: [PATCH 106/110] feat!: introduce power shaping (#1830) * added power shaping * fixes * Add property based test for power cap * fixed tests & added algorithm's idea * nit changes * Update x/ccv/provider/keeper/proposal.go Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * remove empty-validator-set check * implicit memory aliasing issue fixed * added keeper tests * updated HasToValidate query * Update x/ccv/provider/keeper/keeper.go Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * Update x/ccv/provider/keeper/keeper.go Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * took into account comments * do not use cached ctx * Fix E2E test. A jailed validator does not have to validate. * fix merge issue and format --------- Co-authored-by: Philip Offtermatt Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> --- .../ccv/provider/v1/provider.proto | 14 + tests/e2e/actions.go | 4 +- tests/e2e/steps_partial_set_security.go | 10 +- tests/mbt/driver/setup.go | 4 +- testutil/ibc_testing/generic_setup.go | 8 + testutil/keeper/unit_test_helpers.go | 4 + x/ccv/provider/client/proposal_handler.go | 16 +- x/ccv/provider/keeper/grpc_query.go | 6 +- x/ccv/provider/keeper/keeper.go | 212 ++++++++- x/ccv/provider/keeper/keeper_test.go | 88 ++++ x/ccv/provider/keeper/key_assignment_test.go | 4 +- x/ccv/provider/keeper/partial_set_security.go | 165 ++++++- .../keeper/partial_set_security_test.go | 328 +++++++++++++- x/ccv/provider/keeper/proposal.go | 50 ++- x/ccv/provider/keeper/proposal_test.go | 61 +-- x/ccv/provider/keeper/relay.go | 6 +- x/ccv/provider/keeper/relay_test.go | 78 ++++ x/ccv/provider/keeper/validator_set_update.go | 17 +- .../keeper/validator_set_update_test.go | 24 +- x/ccv/provider/proposal_handler_test.go | 4 + x/ccv/provider/types/keys.go | 37 ++ x/ccv/provider/types/proposal.go | 12 + x/ccv/provider/types/proposal_test.go | 106 ++++- x/ccv/provider/types/provider.pb.go | 408 +++++++++++++----- x/ccv/provider/types/query.pb.go | 231 +++++----- x/ccv/provider/types/query.pb.gw.go | 154 +++++-- x/ccv/provider/types/tx.pb.go | 7 +- 27 files changed, 1661 insertions(+), 397 deletions(-) diff --git a/proto/interchain_security/ccv/provider/v1/provider.proto b/proto/interchain_security/ccv/provider/v1/provider.proto index 1b5f7a515f..139cc9d25f 100644 --- a/proto/interchain_security/ccv/provider/v1/provider.proto +++ b/proto/interchain_security/ccv/provider/v1/provider.proto @@ -90,6 +90,20 @@ message ConsumerAdditionProposal { // have to validate the proposed consumer chain. top_N can either be 0 or any value in [50, 100]. // A chain can join with top_N == 0 as an Opt In chain, or with top_N ∈ [50, 100] as a Top N chain. uint32 top_N = 15; + // Corresponds to the maximum power (percentage-wise) a validator can have on the consumer chain. For instance, if + // `validators_power_cap` is set to 32, it means that no validator can have more than 32% of the voting power on the + // consumer chain. Note that this might not be feasible. For example, think of a consumer chain with only + // 5 validators and with `validators_power_cap` set to 10%. In such a scenario, at least one validator would need + // to have more than 20% of the total voting power. Therefore, `validators_power_cap` operates on a best-effort basis. + uint32 validators_power_cap = 16; + // Corresponds to the maximum number of validators that can validate a consumer chain. + // Only applicable to Opt In chains. Setting `validator_set_cap` on a Top N chain is a no-op. + uint32 validator_set_cap = 17; + // Corresponds to a list of provider consensus addresses of validators that are the ONLY ones that can validate + // the consumer chain. + repeated string allowlist = 18; + // Corresponds to a list of provider consensus addresses of validators that CANNOT validate the consumer chain. + repeated string denylist = 19; } // ConsumerRemovalProposal is a governance proposal on the provider chain to diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index 2fd95abb00..1587608177 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -2309,8 +2309,8 @@ func (tr TestConfig) optIn(action OptInAction, target ExecutionTarget, verbose b } if !tr.useCometmock { // error report only works with --gas auto, which does not work with CometMock, so ignore - if verbose { - fmt.Printf("got expected error during opt in | err: %s | output: %s \n", err, string(bz)) + if err != nil && verbose { + fmt.Printf("got error during opt in | err: %s | output: %s \n", err, string(bz)) } } diff --git a/tests/e2e/steps_partial_set_security.go b/tests/e2e/steps_partial_set_security.go index 73bb929387..4c63e479df 100644 --- a/tests/e2e/steps_partial_set_security.go +++ b/tests/e2e/steps_partial_set_security.go @@ -343,7 +343,7 @@ func stepsOptInChain() []Step { ValidatorID("carol"): 300, }, HasToValidate: &map[ValidatorID][]ChainID{ - ValidatorID("alice"): {"consu"}, // but alice still is in the consumer valset so has to validate + ValidatorID("alice"): {}, // alice is jailed on the provider and does not have to validate ValidatorID("bob"): {"consu"}, ValidatorID("carol"): {"consu"}, }, @@ -367,7 +367,7 @@ func stepsOptInChain() []Step { ValidatorID("carol"): 300, }, HasToValidate: &map[ValidatorID][]ChainID{ - ValidatorID("alice"): {"consu"}, + ValidatorID("alice"): {}, // alice is jailed on the provider and does not have to validate ValidatorID("bob"): {"consu"}, ValidatorID("carol"): {"consu"}, }, @@ -397,7 +397,7 @@ func stepsOptInChain() []Step { ValidatorID("carol"): 300, }, HasToValidate: &map[ValidatorID][]ChainID{ - ValidatorID("alice"): {"consu"}, + ValidatorID("alice"): {"consu"}, // alice is unjailed and hence has to validate again ValidatorID("bob"): {"consu"}, ValidatorID("carol"): {"consu"}, }, @@ -477,7 +477,7 @@ func stepsOptInChain() []Step { ValidatorID("carol"): 300, }, HasToValidate: &map[ValidatorID][]ChainID{ - ValidatorID("alice"): {"consu"}, + ValidatorID("alice"): {}, // alice is jailed on the provider and does not have to validate ValidatorID("bob"): {"consu"}, ValidatorID("carol"): {"consu"}, }, @@ -508,7 +508,7 @@ func stepsOptInChain() []Step { ValidatorID("carol"): 300, }, HasToValidate: &map[ValidatorID][]ChainID{ - ValidatorID("alice"): {"consu"}, + ValidatorID("alice"): {}, // alice is jailed on the provider and does not have to validate ValidatorID("bob"): {"consu"}, ValidatorID("carol"): {"consu"}, }, diff --git a/tests/mbt/driver/setup.go b/tests/mbt/driver/setup.go index 5a578aaf5d..a49a1ac000 100644 --- a/tests/mbt/driver/setup.go +++ b/tests/mbt/driver/setup.go @@ -34,6 +34,7 @@ import ( "github.com/cosmos/interchain-security/v4/testutil/integration" simibc "github.com/cosmos/interchain-security/v4/testutil/simibc" consumertypes "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" + "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" ) @@ -377,7 +378,8 @@ func (s *Driver) ConfigureNewPath(consumerChain, providerChain *ibctesting.TestC stakingValidators = append(stakingValidators, v) } - nextValidators := s.providerKeeper().ComputeNextEpochConsumerValSet(s.providerCtx(), string(consumerChainId), stakingValidators, func(validator stakingtypes.Validator) bool { return true }) + considerAll := func(providerAddr types.ProviderConsAddress) bool { return true } + nextValidators := s.providerKeeper().FilterValidators(s.providerCtx(), string(consumerChainId), stakingValidators, considerAll) s.providerKeeper().SetConsumerValSet(s.providerCtx(), string(consumerChainId), nextValidators) err = s.providerKeeper().SetConsumerGenesis( diff --git a/testutil/ibc_testing/generic_setup.go b/testutil/ibc_testing/generic_setup.go index dbc71beb1f..09dfa62140 100644 --- a/testutil/ibc_testing/generic_setup.go +++ b/testutil/ibc_testing/generic_setup.go @@ -19,6 +19,7 @@ import ( testutil "github.com/cosmos/interchain-security/v4/testutil/integration" testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" consumerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/consumer/keeper" + providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" ) type ( @@ -140,6 +141,13 @@ func AddConsumer[Tp testutil.ProviderApp, Tc testutil.ConsumerApp]( prop := testkeeper.GetTestConsumerAdditionProp() prop.ChainId = chainID prop.Top_N = consumerTopNParams[index] // isn't used in CreateConsumerClient + + // opt-in all validators + for _, v := range providerApp.GetTestStakingKeeper().GetLastValidators(providerChain.GetContext()) { + consAddr, _ := v.GetConsAddr() + providerKeeper.SetOptedIn(providerChain.GetContext(), chainID, providertypes.NewProviderConsAddress(consAddr)) + } + // NOTE: the initial height passed to CreateConsumerClient // must be the height on the consumer when InitGenesis is called prop.InitialHeight = clienttypes.Height{RevisionNumber: 0, RevisionHeight: 3} diff --git a/testutil/keeper/unit_test_helpers.go b/testutil/keeper/unit_test_helpers.go index 1bb1f7f3ee..abba1a23c9 100644 --- a/testutil/keeper/unit_test_helpers.go +++ b/testutil/keeper/unit_test_helpers.go @@ -277,6 +277,10 @@ func GetTestConsumerAdditionProp() *providertypes.ConsumerAdditionProposal { types.DefaultTransferTimeoutPeriod, types.DefaultConsumerUnbondingPeriod, 0, + 0, + 0, + nil, + nil, ).(*providertypes.ConsumerAdditionProposal) return prop diff --git a/x/ccv/provider/client/proposal_handler.go b/x/ccv/provider/client/proposal_handler.go index 9b5674f4c7..bb88276393 100644 --- a/x/ccv/provider/client/proposal_handler.go +++ b/x/ccv/provider/client/proposal_handler.go @@ -65,7 +65,11 @@ Where proposal.json contains: "ccv_timeout_period": 2419200000000000, "unbonding_period": 1728000000000000, "deposit": "10000stake", - "top_n": 0, + "top_n": 0, + "validators_power_cap": 32, + "validator_set_cap": 50, + "allowlist": [], + "denylist": ["validatorAConsensusAddress", "validatorBConsensusAddress"] } `, RunE: func(cmd *cobra.Command, args []string) error { @@ -87,7 +91,8 @@ Where proposal.json contains: proposal.GenesisHash, proposal.BinaryHash, proposal.SpawnTime, proposal.ConsumerRedistributionFraction, proposal.BlocksPerDistributionTransmission, proposal.DistributionTransmissionChannel, proposal.HistoricalEntries, - proposal.CcvTimeoutPeriod, proposal.TransferTimeoutPeriod, proposal.UnbondingPeriod, proposal.TopN) + proposal.CcvTimeoutPeriod, proposal.TransferTimeoutPeriod, proposal.UnbondingPeriod, proposal.TopN, + proposal.ValidatorsPowerCap, proposal.ValidatorSetCap, proposal.Allowlist, proposal.Denylist) from := clientCtx.GetFromAddress() @@ -242,7 +247,12 @@ type ConsumerAdditionProposalJSON struct { UnbondingPeriod time.Duration `json:"unbonding_period"` Deposit string `json:"deposit"` - TopN uint32 `json:"top_N"` + + TopN uint32 `json:"top_N"` + ValidatorsPowerCap uint32 `json:"validators_power_cap"` + ValidatorSetCap uint32 `json:"validator_set_cap"` + Allowlist []string `json:"allowlist"` + Denylist []string `json:"denylist"` } type ConsumerAdditionProposalReq struct { diff --git a/x/ccv/provider/keeper/grpc_query.go b/x/ccv/provider/keeper/grpc_query.go index 4adbcf5cc7..84c5928fea 100644 --- a/x/ccv/provider/keeper/grpc_query.go +++ b/x/ccv/provider/keeper/grpc_query.go @@ -278,11 +278,7 @@ func (k Keeper) QueryConsumerChainsValidatorHasToValidate(goCtx context.Context, for _, consumer := range k.GetAllConsumerChains(ctx) { chainID := consumer.ChainId - hasToValidate, err := k.HasToValidate(ctx, provAddr, chainID) - if err != nil { - return nil, err - } - if hasToValidate { + if hasToValidate, err := k.HasToValidate(ctx, provAddr, chainID); err == nil && hasToValidate { consumersToValidate = append(consumersToValidate, chainID) } } diff --git a/x/ccv/provider/keeper/keeper.go b/x/ccv/provider/keeper/keeper.go index ec0334b4a5..bc3664bfd7 100644 --- a/x/ccv/provider/keeper/keeper.go +++ b/x/ccv/provider/keeper/keeper.go @@ -1261,28 +1261,34 @@ func (k Keeper) HasToValidate( provAddr types.ProviderConsAddress, chainID string, ) (bool, error) { - // if the validator is opted in or was sent as part of the packet in the last epoch, they have to validate - if k.IsOptedIn(ctx, chainID, provAddr) || k.IsConsumerValidator(ctx, chainID, provAddr) { + // if the validator was sent as part of the packet in the last epoch, it has to validate + if k.IsConsumerValidator(ctx, chainID, provAddr) { return true, nil } - // otherwise, check whether the validator will be automatically opted in at the end of this epoch - // assuming all powers stay the same - val, found := k.stakingKeeper.GetValidatorByConsAddr(ctx, provAddr.ToSdkConsAddr()) - if !found { - return false, fmt.Errorf("validator not found for address %s", provAddr) - } - power := k.stakingKeeper.GetLastValidatorPower(ctx, val.GetOperator()) - topN, found := k.GetTopN(ctx, chainID) - if !found || topN == 0 { - return false, nil - } - minPowerToOptIn, err := k.ComputeMinPowerToOptIn(ctx, chainID, k.stakingKeeper.GetLastValidators(ctx), topN) + // if the validator was not part of the last epoch, check if the validator is going to be part of te next epoch + bondedValidators := k.stakingKeeper.GetLastValidators(ctx) + if topN, found := k.GetTopN(ctx, chainID); found && topN > 0 { + // in a Top-N chain, we automatically opt in all validators that belong to the top N + minPower, err := k.ComputeMinPowerToOptIn(ctx, chainID, bondedValidators, topN) + if err == nil { + k.OptInTopNValidators(ctx, chainID, bondedValidators, minPower) + } + } - if err != nil || power < minPowerToOptIn { - return false, nil + // if the validator is opted in and belongs to the validators of the next epoch, then if nothing changes + // the validator would have to validate in the next epoch + if k.IsOptedIn(ctx, chainID, provAddr) { + nextValidators := k.ComputeNextValidators(ctx, chainID, k.stakingKeeper.GetLastValidators(ctx)) + for _, v := range nextValidators { + consAddr := sdk.ConsAddress(v.ProviderConsAddr) + if provAddr.ToSdkConsAddr().Equals(consAddr) { + return true, nil + } + } } - return true, nil + + return false, nil } // SetConsumerCommissionRate sets a per-consumer chain commission rate @@ -1357,3 +1363,175 @@ func (k Keeper) DeleteConsumerCommissionRate( store := ctx.KVStore(k.storeKey) store.Delete(types.ConsumerCommissionRateKey(chainID, providerAddr)) } + +// SetValidatorsPowerCap sets the power-cap value `p` associated to chain with `chainID` +func (k Keeper) SetValidatorsPowerCap( + ctx sdk.Context, + chainID string, + p uint32, +) { + store := ctx.KVStore(k.storeKey) + + buf := make([]byte, 4) + binary.BigEndian.PutUint32(buf, p) + + store.Set(types.ValidatorsPowerCapKey(chainID), buf) +} + +// DeleteValidatorsPowerCap removes the power-cap value associated to chain with `chainID` +func (k Keeper) DeleteValidatorsPowerCap( + ctx sdk.Context, + chainID string, +) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.ValidatorsPowerCapKey(chainID)) +} + +// GetValidatorsPowerCap returns `(p, true)` if chain `chainID` has power cap `p` associated with it, and (0, false) otherwise +func (k Keeper) GetValidatorsPowerCap( + ctx sdk.Context, + chainID string, +) (uint32, bool) { + store := ctx.KVStore(k.storeKey) + buf := store.Get(types.ValidatorsPowerCapKey(chainID)) + if buf == nil { + return 0, false + } + return binary.BigEndian.Uint32(buf), true +} + +// SetValidatorSetCap stores the validator-set cap value `c` associated to chain with `chainID` +func (k Keeper) SetValidatorSetCap( + ctx sdk.Context, + chainID string, + c uint32, +) { + store := ctx.KVStore(k.storeKey) + + buf := make([]byte, 4) + binary.BigEndian.PutUint32(buf, c) + + store.Set(types.ValidatorSetCapKey(chainID), buf) +} + +// DeleteValidatorSetCap removes the validator-set cap value associated to chain with `chainID` +func (k Keeper) DeleteValidatorSetCap( + ctx sdk.Context, + chainID string, +) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.ValidatorSetCapKey(chainID)) +} + +// GetValidatorSetCap returns `(c, true)` if chain `chainID` has validator-set cap `c` associated with it, and (0, false) otherwise +func (k Keeper) GetValidatorSetCap( + ctx sdk.Context, + chainID string, +) (uint32, bool) { + store := ctx.KVStore(k.storeKey) + buf := store.Get(types.ValidatorSetCapKey(chainID)) + if buf == nil { + return 0, false + } + return binary.BigEndian.Uint32(buf), true +} + +// SetAllowlist allowlists validator with `providerAddr` address on chain `chainID` +func (k Keeper) SetAllowlist( + ctx sdk.Context, + chainID string, + providerAddr types.ProviderConsAddress, +) { + store := ctx.KVStore(k.storeKey) + store.Set(types.AllowlistCapKey(chainID, providerAddr), []byte{}) +} + +// IsAllowlisted returns `true` if validator with `providerAddr` has been allowlisted on chain `chainID` +func (k Keeper) IsAllowlisted( + ctx sdk.Context, + chainID string, + providerAddr types.ProviderConsAddress, +) bool { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.AllowlistCapKey(chainID, providerAddr)) + return bz != nil +} + +// DeleteAllowlist deletes all allowlisted validators +func (k Keeper) DeleteAllowlist(ctx sdk.Context, chainID string) { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, types.ChainIdWithLenKey(types.AllowlistPrefix, chainID)) + defer iterator.Close() + + keysToDel := [][]byte{} + for ; iterator.Valid(); iterator.Next() { + keysToDel = append(keysToDel, iterator.Key()) + } + + for _, key := range keysToDel { + store.Delete(key) + } +} + +// IsAllowlistEmpty returns `true` if no validator is allowlisted on chain `chainID` +func (k Keeper) IsAllowlistEmpty(ctx sdk.Context, chainID string) bool { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, types.ChainIdWithLenKey(types.AllowlistPrefix, chainID)) + defer iterator.Close() + + if iterator.Valid() { + return false + } + + return true +} + +// SetDenylist denylists validator with `providerAddr` address on chain `chainID` +func (k Keeper) SetDenylist( + ctx sdk.Context, + chainID string, + providerAddr types.ProviderConsAddress, +) { + store := ctx.KVStore(k.storeKey) + store.Set(types.DenylistCapKey(chainID, providerAddr), []byte{}) +} + +// IsDenylisted returns `true` if validator with `providerAddr` has been denylisted on chain `chainID` +func (k Keeper) IsDenylisted( + ctx sdk.Context, + chainID string, + providerAddr types.ProviderConsAddress, +) bool { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.DenylistCapKey(chainID, providerAddr)) + return bz != nil +} + +// DeleteDenylist deletes all denylisted validators +func (k Keeper) DeleteDenylist(ctx sdk.Context, chainID string) { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, types.ChainIdWithLenKey(types.DenylistPrefix, chainID)) + defer iterator.Close() + + keysToDel := [][]byte{} + for ; iterator.Valid(); iterator.Next() { + keysToDel = append(keysToDel, iterator.Key()) + } + + for _, key := range keysToDel { + store.Delete(key) + } +} + +// IsDenylistEmpty returns `true` if no validator is denylisted on chain `chainID` +func (k Keeper) IsDenylistEmpty(ctx sdk.Context, chainID string) bool { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, types.ChainIdWithLenKey(types.DenylistPrefix, chainID)) + defer iterator.Close() + + if iterator.Valid() { + return false + } + + return true +} diff --git a/x/ccv/provider/keeper/keeper_test.go b/x/ccv/provider/keeper/keeper_test.go index 04a4ffd2fb..d172a96dba 100644 --- a/x/ccv/provider/keeper/keeper_test.go +++ b/x/ccv/provider/keeper/keeper_test.go @@ -749,3 +749,91 @@ func TestConsumerCommissionRate(t *testing.T) { _, found = providerKeeper.GetConsumerCommissionRate(ctx, "chainID", providerAddr2) require.False(t, found) } + +// TestValidatorsPowerCap tests the `SetValidatorsPowerCap`, `GetValidatorsPowerCap`, and `DeleteValidatorsPowerCap` methods +func TestValidatorsPowerCap(t *testing.T) { + providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + expectedPowerCap := uint32(10) + providerKeeper.SetValidatorsPowerCap(ctx, "chainID", expectedPowerCap) + powerCap, found := providerKeeper.GetValidatorsPowerCap(ctx, "chainID") + require.Equal(t, expectedPowerCap, powerCap) + require.True(t, found) + + providerKeeper.DeleteValidatorsPowerCap(ctx, "chainID") + _, found = providerKeeper.GetValidatorsPowerCap(ctx, "chainID") + require.False(t, found) +} + +// TestValidatorSetCap tests the `SetValidatorSetCap`, `GetValidatorSetCap`, and `DeleteValidatorSetCap` methods +func TestValidatorSetCap(t *testing.T) { + providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + expectedPowerCap := uint32(10) + providerKeeper.SetValidatorSetCap(ctx, "chainID", expectedPowerCap) + powerCap, found := providerKeeper.GetValidatorSetCap(ctx, "chainID") + require.Equal(t, expectedPowerCap, powerCap) + require.True(t, found) + + providerKeeper.DeleteValidatorSetCap(ctx, "chainID") + _, found = providerKeeper.GetValidatorSetCap(ctx, "chainID") + require.False(t, found) +} + +// TestAllowlist tests the `SetAllowlist`, `IsAllowlisted`, `DeleteAllowlist`, and `IsAllowlistEmpty` methods +func TestAllowlist(t *testing.T) { + providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + chainID := "chainID" + + // no validator was allowlisted and hence the allowlist is empty + require.True(t, providerKeeper.IsAllowlistEmpty(ctx, chainID)) + + providerAddr1 := types.NewProviderConsAddress([]byte("providerAddr1")) + providerKeeper.SetAllowlist(ctx, chainID, providerAddr1) + require.True(t, providerKeeper.IsAllowlisted(ctx, chainID, providerAddr1)) + + // allowlist is not empty anymore + require.False(t, providerKeeper.IsAllowlistEmpty(ctx, chainID)) + + providerAddr2 := types.NewProviderConsAddress([]byte("providerAddr2")) + providerKeeper.SetAllowlist(ctx, chainID, providerAddr2) + require.True(t, providerKeeper.IsAllowlisted(ctx, chainID, providerAddr2)) + require.False(t, providerKeeper.IsAllowlistEmpty(ctx, chainID)) + + providerKeeper.DeleteAllowlist(ctx, chainID) + require.False(t, providerKeeper.IsAllowlisted(ctx, chainID, providerAddr1)) + require.False(t, providerKeeper.IsAllowlisted(ctx, chainID, providerAddr2)) + require.True(t, providerKeeper.IsAllowlistEmpty(ctx, chainID)) +} + +// TestDenylist tests the `SetDenylist`, `IsDenylisted`, `DeleteDenylist`, and `IsDenylistEmpty` methods +func TestDenylist(t *testing.T) { + providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + chainID := "chainID" + + // no validator was denylisted and hence the denylist is empty + require.True(t, providerKeeper.IsDenylistEmpty(ctx, chainID)) + + providerAddr1 := types.NewProviderConsAddress([]byte("providerAddr1")) + providerKeeper.SetDenylist(ctx, chainID, providerAddr1) + require.True(t, providerKeeper.IsDenylisted(ctx, chainID, providerAddr1)) + + // denylist is not empty anymore + require.False(t, providerKeeper.IsDenylistEmpty(ctx, chainID)) + + providerAddr2 := types.NewProviderConsAddress([]byte("providerAddr2")) + providerKeeper.SetDenylist(ctx, chainID, providerAddr2) + require.True(t, providerKeeper.IsDenylisted(ctx, chainID, providerAddr2)) + require.False(t, providerKeeper.IsDenylistEmpty(ctx, chainID)) + + providerKeeper.DeleteDenylist(ctx, chainID) + require.False(t, providerKeeper.IsDenylisted(ctx, chainID, providerAddr1)) + require.False(t, providerKeeper.IsDenylisted(ctx, chainID, providerAddr2)) + require.True(t, providerKeeper.IsDenylistEmpty(ctx, chainID)) +} diff --git a/x/ccv/provider/keeper/key_assignment_test.go b/x/ccv/provider/keeper/key_assignment_test.go index 0e7b950822..abf7858d40 100644 --- a/x/ccv/provider/keeper/key_assignment_test.go +++ b/x/ccv/provider/keeper/key_assignment_test.go @@ -768,8 +768,8 @@ func TestSimulatedAssignmentsAndUpdateApplication(t *testing.T) { }) } - nextValidators := k.ComputeNextEpochConsumerValSet(ctx, CHAINID, bondedValidators, - func(validator stakingtypes.Validator) bool { + nextValidators := k.FilterValidators(ctx, CHAINID, bondedValidators, + func(providerAddr types.ProviderConsAddress) bool { return true }) updates = providerkeeper.DiffValidators(k.GetConsumerValSet(ctx, CHAINID), nextValidators) diff --git a/x/ccv/provider/keeper/partial_set_security.go b/x/ccv/provider/keeper/partial_set_security.go index 703dcf8b76..0d5177089a 100644 --- a/x/ccv/provider/keeper/partial_set_security.go +++ b/x/ccv/provider/keeper/partial_set_security.go @@ -132,11 +132,164 @@ func (k Keeper) ComputeMinPowerToOptIn(ctx sdk.Context, chainID string, bondedVa return 0, fmt.Errorf("should never reach this point with topN (%d), totalPower (%d), and powerSum (%d)", topN, totalPower, powerSum) } -// ShouldConsiderOnlyOptIn returns true if `validator` is opted in, in `chainID. -func (k Keeper) ShouldConsiderOnlyOptIn(ctx sdk.Context, chainID string, validator stakingtypes.Validator) bool { - consAddr, err := validator.GetConsAddr() - if err != nil { - return false +// CapValidatorSet caps the provided `validators` if chain `chainID` 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. +func (k Keeper) CapValidatorSet(ctx sdk.Context, chainID string, validators []types.ConsumerValidator) []types.ConsumerValidator { + if topN, found := k.GetTopN(ctx, chainID); found && topN > 0 { + // is a no-op if the chain is a Top N chain + return validators + } + + if validatorSetCap, found := k.GetValidatorSetCap(ctx, chainID); found && validatorSetCap != 0 { + sort.Slice(validators, func(i, j int) bool { + return validators[i].Power > validators[j].Power + }) + + minNumberOfValidators := 0 + if len(validators) < int(validatorSetCap) { + minNumberOfValidators = len(validators) + } else { + minNumberOfValidators = int(validatorSetCap) + } + return validators[:minNumberOfValidators] + } else { + return validators + } +} + +// CapValidatorsPower caps the power of the validators on chain `chainID` and returns an updated slice of validators +// with their new powers. Works on a best-basis effort because there are cases where we cannot guarantee that all validators +// on the consumer chain have less power than the set validators-power cap. For example, if we have 10 validators and +// the power cap is set to 5%, we need at least one validator to have more than 10% of the voting power on the consumer chain. +func (k Keeper) CapValidatorsPower(ctx sdk.Context, chainID string, validators []types.ConsumerValidator) []types.ConsumerValidator { + if p, found := k.GetValidatorsPowerCap(ctx, chainID); found && p > 0 { + return NoMoreThanPercentOfTheSum(validators, p) + } else { + // is a no-op if power cap is not set for `chainID` + return validators + } +} + +// sum is a helper function to sum all the validators' power +func sum(validators []types.ConsumerValidator) int64 { + s := int64(0) + for _, v := range validators { + s = s + v.Power + } + return s +} + +// NoMoreThanPercentOfTheSum returns a set of validators with updated powers such that no validator has more than the +// provided `percent` of the sum of all validators' powers. Operates on a best-effort basis. +func NoMoreThanPercentOfTheSum(validators []types.ConsumerValidator, percent uint32) []types.ConsumerValidator { + // Algorithm's idea + // ---------------- + // Consider the validators' powers to be `a_1, a_2, ... a_n` and `p` to be the percent in [1, 100]. Now, consider + // the sum `s = a_1 + a_2 + ... + a_n`. Then `maxPower = s * p / 100 <=> 100 * maxPower = s * p`. + // The problem of capping the validators' powers to be no more than `p` has no solution if `(100 / n) > p`. For example, + // for n = 10 and p = 5 we do not have a solution. We would need at least one validator with power greater than 10% + // for a solution to exist. + // So, if `(100 / n) > p` there's no solution. We know that `100 * maxPower = s * p` and so `(100 / n) > (100 * maxPower) / s` + // `100 * s > 100 * maxPower * n <=> s > maxPower * n`. Thus, we do not have a solution if `s > n * maxPower`. + + // If `s <= n * maxPower` the idea of the algorithm is rather simple. + // - Compute the `maxPower` a validator must have so that it does not have more than `percent` of the voting power. + // - If a validator `v` has power `p`, then: + // - if `p > maxPower` we set `v`'s power to `maxPower` and distribute the `p - maxPower` to validators that + // have less than `maxPower` power. This way, the total sum remains the same and no validator has more than + // `maxPower` and so the power capping is satisfied. + // - Note that in order to avoid setting multiple validators to `maxPower`, we first compute all the `remainingPower` + // we have to distribute and then attempt to add `remainingPower / validatorsWithPowerLessThanMaxPower` to each validator. + // To guarantee that the sum remains the same after the distribution of powers, we sort the powers in descending + // order. This way, we first attempt to add `remainingPower / validatorsWithPowerLessThanMaxPower` to validators + // with greater power and if we cannot add the `remainingPower / validatorsWithPowerLessThanMaxPower` without + // exceeding `maxPower`, we just add enough to reach `maxPower` and add the remaining power to validators with smaller + // power. + + // If `s > n * maxPower` there's no solution and the algorithm would set everything to `maxPower`. + // ---------------- + + // Computes `(sum(validators) * percent) / 100`. Because `sdk.Dec` does not provide a `Floor` function, but only + // a `Ceil` one, we use `Ceil` and subtract one. + maxPower := sdk.NewDec(sum(validators)).Mul(sdk.NewDec(int64(percent))).QuoInt64(100).Ceil().RoundInt64() - 1 + + if maxPower == 0 { + // edge case: set `maxPower` to 1 to avoid setting the power of a validator to 0 + maxPower = 1 } - return k.IsOptedIn(ctx, chainID, types.NewProviderConsAddress(consAddr)) + + // Sort by `.Power` in decreasing order. Sorting in descending order is needed because otherwise we would have cases + // like this `powers =[60, 138, 559]` and `p = 35%` where sum is `757` and `maxValue = 264`. + // Because `559 - 264 = 295` we have to distribute 295 to the first 2 numbers (`295/2 = 147` to each number). However, + // note that `138 + 147 > 264`. If we were to add 147 to 60 first, then we cannot give the remaining 147 to 138. + // So, the idea is to first give `126 (= 264 - 138)` to 138, so it becomes 264, and then add `21 (=147 - 26) + 147` to 60. + sort.Slice(validators, func(i, j int) bool { + return validators[i].Power > validators[j].Power + }) + + // `remainingPower` is to be distributed to validators that have power less than `maxPower` + remainingPower := int64(0) + validatorsWithPowerLessThanMaxPower := 0 + for _, v := range validators { + if v.Power >= maxPower { + remainingPower = remainingPower + (v.Power - maxPower) + } else { + validatorsWithPowerLessThanMaxPower++ + } + } + + updatedValidators := make([]types.ConsumerValidator, len(validators)) + + powerPerValidator := int64(0) + remainingValidators := int64(validatorsWithPowerLessThanMaxPower) + if remainingValidators != 0 { + // power to give to each validator in order to distribute the `remainingPower` + powerPerValidator = remainingPower / remainingValidators + } + + for i, v := range validators { + if v.Power >= maxPower { + updatedValidators[i] = validators[i] + updatedValidators[i].Power = maxPower + } else if v.Power+powerPerValidator >= maxPower { + updatedValidators[i] = validators[i] + updatedValidators[i].Power = maxPower + remainingPower = remainingPower - (maxPower - v.Power) + remainingValidators-- + } else { + updatedValidators[i] = validators[i] + updatedValidators[i].Power = v.Power + powerPerValidator + remainingPower = remainingPower - (updatedValidators[i].Power - validators[i].Power) + remainingValidators-- + } + if remainingValidators == 0 { + continue + } + powerPerValidator = remainingPower / remainingValidators + } + + return updatedValidators +} + +// FilterOptedInAndAllowAndDenylistedPredicate filters the opted-in validators that are allowlisted and not denylisted +func (k Keeper) FilterOptedInAndAllowAndDenylistedPredicate(ctx sdk.Context, chainID string, providerAddr types.ProviderConsAddress) bool { + // only consider opted-in validators + return k.IsOptedIn(ctx, chainID, providerAddr) && + // if an allowlist is declared, only consider allowlisted validators + (k.IsAllowlistEmpty(ctx, chainID) || + k.IsAllowlisted(ctx, chainID, providerAddr)) && + // if a denylist is declared, only consider denylisted validators + (k.IsDenylistEmpty(ctx, chainID) || + !k.IsDenylisted(ctx, chainID, providerAddr)) +} + +// ComputeNextValidators computes the validators for the upcoming epoch based on the currently `bondedValidators`. +func (k Keeper) ComputeNextValidators(ctx sdk.Context, chainID string, bondedValidators []stakingtypes.Validator) []types.ConsumerValidator { + nextValidators := k.FilterValidators(ctx, chainID, bondedValidators, + func(providerAddr types.ProviderConsAddress) bool { + return k.FilterOptedInAndAllowAndDenylistedPredicate(ctx, chainID, providerAddr) + }) + + nextValidators = k.CapValidatorSet(ctx, chainID, nextValidators) + return k.CapValidatorsPower(ctx, chainID, nextValidators) } diff --git a/x/ccv/provider/keeper/partial_set_security_test.go b/x/ccv/provider/keeper/partial_set_security_test.go index b8e4d705ef..afbd420e7f 100644 --- a/x/ccv/provider/keeper/partial_set_security_test.go +++ b/x/ccv/provider/keeper/partial_set_security_test.go @@ -2,18 +2,23 @@ package keeper_test import ( "bytes" + "math" "sort" "testing" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" + "pgregory.net/rapid" codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/cometbft/cometbft/proto/tendermint/crypto" + testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" + "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" ) @@ -342,15 +347,330 @@ func TestComputeMinPowerToOptIn(t *testing.T) { require.Error(t, err) } -// TestShouldConsiderOnlyOptIn returns true if `validator` is opted in, in `chainID. -func TestShouldConsiderOnlyOptIn(t *testing.T) { +// TestFilterOptedInAndAllowAndDenylistedPredicate returns true if `validator` is opted in, in `chainID. +func TestFilterOptedInAndAllowAndDenylistedPredicate(t *testing.T) { providerKeeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() validator := createStakingValidator(ctx, mocks, 0, 1) consAddr, _ := validator.GetConsAddr() + providerAddr := types.NewProviderConsAddress(consAddr) - require.False(t, providerKeeper.IsOptedIn(ctx, "chainID", types.NewProviderConsAddress(consAddr))) + // with no allowlist or denylist, the validator has to be opted in, in order to consider it + require.False(t, providerKeeper.FilterOptedInAndAllowAndDenylistedPredicate(ctx, "chainID", providerAddr)) providerKeeper.SetOptedIn(ctx, "chainID", types.NewProviderConsAddress(consAddr)) - require.True(t, providerKeeper.IsOptedIn(ctx, "chainID", types.NewProviderConsAddress(consAddr))) + require.True(t, providerKeeper.FilterOptedInAndAllowAndDenylistedPredicate(ctx, "chainID", providerAddr)) + + // create an allow list but do not add the validator `providerAddr` to it + validatorA := createStakingValidator(ctx, mocks, 1, 1) + consAddrA, _ := validatorA.GetConsAddr() + providerKeeper.SetAllowlist(ctx, "chainID", types.NewProviderConsAddress(consAddrA)) + require.False(t, providerKeeper.FilterOptedInAndAllowAndDenylistedPredicate(ctx, "chainID", providerAddr)) + providerKeeper.SetAllowlist(ctx, "chainID", types.NewProviderConsAddress(consAddr)) + require.True(t, providerKeeper.FilterOptedInAndAllowAndDenylistedPredicate(ctx, "chainID", providerAddr)) + + // create a denylist but do not add validator `providerAddr` to it + providerKeeper.SetDenylist(ctx, "chainID", types.NewProviderConsAddress(consAddrA)) + require.True(t, providerKeeper.FilterOptedInAndAllowAndDenylistedPredicate(ctx, "chainID", providerAddr)) + // add validator `providerAddr` to the denylist + providerKeeper.SetDenylist(ctx, "chainID", types.NewProviderConsAddress(consAddr)) + require.False(t, providerKeeper.FilterOptedInAndAllowAndDenylistedPredicate(ctx, "chainID", providerAddr)) +} + +func TestCapValidatorSet(t *testing.T) { + providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + validatorA := types.ConsumerValidator{ + ProviderConsAddr: []byte("providerConsAddrA"), + Power: 1, + ConsumerPublicKey: &crypto.PublicKey{}, + } + + validatorB := types.ConsumerValidator{ + ProviderConsAddr: []byte("providerConsAddrB"), + Power: 2, + ConsumerPublicKey: &crypto.PublicKey{}, + } + + validatorC := types.ConsumerValidator{ + ProviderConsAddr: []byte("providerConsAddrC"), + Power: 3, + ConsumerPublicKey: &crypto.PublicKey{}, + } + validators := []types.ConsumerValidator{validatorA, validatorB, validatorC} + + consumerValidators := providerKeeper.CapValidatorSet(ctx, "chainID", validators) + require.Equal(t, validators, consumerValidators) + + providerKeeper.SetValidatorSetCap(ctx, "chainID", 0) + consumerValidators = providerKeeper.CapValidatorSet(ctx, "chainID", validators) + require.Equal(t, validators, consumerValidators) + + providerKeeper.SetValidatorSetCap(ctx, "chainID", 100) + consumerValidators = providerKeeper.CapValidatorSet(ctx, "chainID", validators) + require.Equal(t, validators, consumerValidators) + + providerKeeper.SetValidatorSetCap(ctx, "chainID", 1) + consumerValidators = providerKeeper.CapValidatorSet(ctx, "chainID", validators) + require.Equal(t, []types.ConsumerValidator{validatorC}, consumerValidators) + + providerKeeper.SetValidatorSetCap(ctx, "chainID", 2) + consumerValidators = providerKeeper.CapValidatorSet(ctx, "chainID", validators) + require.Equal(t, []types.ConsumerValidator{validatorC, validatorB}, consumerValidators) + + providerKeeper.SetValidatorSetCap(ctx, "chainID", 3) + consumerValidators = providerKeeper.CapValidatorSet(ctx, "chainID", validators) + require.Equal(t, []types.ConsumerValidator{validatorC, validatorB, validatorA}, consumerValidators) +} + +func TestCapValidatorsPower(t *testing.T) { + providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + validatorA := types.ConsumerValidator{ + ProviderConsAddr: []byte("providerConsAddrA"), + Power: 1, + ConsumerPublicKey: &crypto.PublicKey{}, + } + + validatorB := types.ConsumerValidator{ + ProviderConsAddr: []byte("providerConsAddrB"), + Power: 2, + ConsumerPublicKey: &crypto.PublicKey{}, + } + + validatorC := types.ConsumerValidator{ + ProviderConsAddr: []byte("providerConsAddrC"), + Power: 3, + ConsumerPublicKey: &crypto.PublicKey{}, + } + + validatorD := types.ConsumerValidator{ + ProviderConsAddr: []byte("providerConsAddrD"), + Power: 4, + ConsumerPublicKey: &crypto.PublicKey{}, + } + + validators := []types.ConsumerValidator{validatorA, validatorB, validatorC, validatorD} + + expectedValidators := make([]types.ConsumerValidator, len(validators)) + copy(expectedValidators, validators) + expectedValidators[0].Power = 2 + expectedValidators[1].Power = 2 + expectedValidators[2].Power = 3 + expectedValidators[3].Power = 3 + + sortValidators := func(validators []types.ConsumerValidator) { + sort.Slice(validators, func(i, j int) bool { + return bytes.Compare(validators[i].ProviderConsAddr, validators[j].ProviderConsAddr) < 0 + }) + } + + // no capping takes place because validators power-cap is not set + cappedValidators := providerKeeper.CapValidatorsPower(ctx, "chainID", validators) + sortValidators(validators) + sortValidators(cappedValidators) + require.Equal(t, validators, cappedValidators) + + providerKeeper.SetValidatorsPowerCap(ctx, "chainID", 33) + cappedValidators = providerKeeper.CapValidatorsPower(ctx, "chainID", validators) + sortValidators(expectedValidators) + sortValidators(cappedValidators) + require.Equal(t, expectedValidators, cappedValidators) +} + +func TestNoMoreThanPercentOfTheSum(t *testing.T) { + // **impossible** case where we only have 9 powers, and we want that no number has more than 10% of the total sum + powers := []int64{1, 2, 3, 4, 5, 6, 7, 8, 9} + percent := uint32(10) + require.False(t, noMoreThanPercent(keeper.NoMoreThanPercentOfTheSum(createConsumerValidators(powers), percent), percent)) + + powers = []int64{1, 2, 3, 4, 5} + percent = 20 + require.True(t, noMoreThanPercent(keeper.NoMoreThanPercentOfTheSum(createConsumerValidators(powers), percent), percent)) + + powers = []int64{1, 2, 3, 4, 5} + percent = 21 + require.True(t, noMoreThanPercent(keeper.NoMoreThanPercentOfTheSum(createConsumerValidators(powers), percent), percent)) + + powers = []int64{1, 2, 3, 4, 5} + percent = 25 + require.True(t, noMoreThanPercent(keeper.NoMoreThanPercentOfTheSum(createConsumerValidators(powers), percent), percent)) + + powers = []int64{1, 2, 3, 4, 5} + percent = 32 + require.True(t, noMoreThanPercent(keeper.NoMoreThanPercentOfTheSum(createConsumerValidators(powers), percent), percent)) + + powers = []int64{1, 2, 3, 4, 5} + percent = 33 + require.True(t, noMoreThanPercent(keeper.NoMoreThanPercentOfTheSum(createConsumerValidators(powers), percent), percent)) + + powers = []int64{1, 2, 3, 4, 5} + percent = 34 + require.True(t, noMoreThanPercent(keeper.NoMoreThanPercentOfTheSum(createConsumerValidators(powers), percent), percent)) + + powers = []int64{1, 2, 3, 4, 5} + percent = 50 + require.True(t, noMoreThanPercent(keeper.NoMoreThanPercentOfTheSum(createConsumerValidators(powers), percent), percent)) +} + +func createConsumerValidators(powers []int64) []types.ConsumerValidator { + var validators []types.ConsumerValidator + for _, p := range powers { + validators = append(validators, types.ConsumerValidator{ + ProviderConsAddr: []byte("providerConsAddr"), + Power: p, + ConsumerPublicKey: &crypto.PublicKey{}, + }) + } + return validators +} + +// returns `true` if no validator in `validators` corresponds to more than `percent` of the total sum of all +// validators' powers +func noMoreThanPercent(validators []types.ConsumerValidator, percent uint32) bool { + sum := int64(0) + for _, v := range validators { + sum = sum + v.Power + } + + for _, v := range validators { + if (float64(v.Power)/float64(sum))*100.0 > float64(percent) { + return false + } + } + return true +} + +func sumPowers(vals []types.ConsumerValidator) int64 { + sum := int64(0) + for _, v := range vals { + sum += v.Power + } + return sum +} + +func CapSatisfiable(vals []types.ConsumerValidator, percent uint32) bool { + // 100 / len(vals) is what each validator gets if each has the same power. + // if this is more than the cap, it cannot be satisfied. + return float64(100)/float64(len(vals)) < float64(percent) +} + +func TestNoMoreThanPercentOfTheSumProps(t *testing.T) { + // define properties to test + + // capRespectedIfSatisfiable: if the cap can be respected, then it will be respected + capRespectedIfSatisfiable := func(valsBefore, valsAfter []types.ConsumerValidator, percent uint32) bool { + if CapSatisfiable(valsBefore, percent) { + return noMoreThanPercent(valsAfter, percent) + } + return true + } + + evenPowersIfCapCannotBeSatisfied := func(valsBefore, valsAfter []types.ConsumerValidator, percent uint32) bool { + if !CapSatisfiable(valsBefore, percent) { + // if the cap cannot be satisfied, each validator should have the same power + for _, valAfter := range valsAfter { + if valAfter.Power != valsAfter[0].Power { + return false + } + } + } + return true + } + + // fairness: if before, v1 has more power than v2, then afterwards v1 will not have less power than v2 + // (they might get the same power if they are both capped) + fairness := func(valsBefore, valsAfter []types.ConsumerValidator) bool { + for i, v := range valsBefore { + // find the validator after with the same address + vAfter := findConsumerValidator(t, v, valsAfter) + + // go through all other validators before (after this one, to avoid double checking) + for j := i + 1; j < len(valsBefore); j++ { + otherV := valsBefore[j] + otherVAfter := findConsumerValidator(t, otherV, valsAfter) + + // v has at least as much power before + if v.Power >= otherV.Power { + // then otherV should not have more power after + if vAfter.Power < otherVAfter.Power { + return false + } + } else { + // v has less power before + // then v should not have more power after + if vAfter.Power > otherVAfter.Power { + return false + } + } + } + } + return true + } + + // non-zero: v has non-zero power before IFF it has non-zero power after + nonZero := func(valsBefore, valsAfter []types.ConsumerValidator) bool { + for _, v := range valsBefore { + vAfter := findConsumerValidator(t, v, valsAfter) + if (v.Power == 0) != (vAfter.Power == 0) { + return false + } + } + return true + } + + // equalSumIfCapSatisfiable: the sum of the powers of the validators will not change if the cap can be satisfied + // (except for small changes by rounding errors) + equalSumIfCapSatisfiable := func(valsBefore, valsAfter []types.ConsumerValidator, percent uint32) bool { + if CapSatisfiable(valsBefore, percent) { + difference := math.Abs(float64(sumPowers(valsBefore) - sumPowers(valsAfter))) + if difference > 1 { + // if the difference is more than a rounding error, they are not equal + return false + } + } + return true + } + + // num validators: the number of validators will not change + equalNumVals := func(valsBefore, valsAfter []types.ConsumerValidator) bool { + return len(valsBefore) == len(valsAfter) + } + + // test setup for pbt + rapid.Check(t, func(t *rapid.T) { + powers := rapid.SliceOf(rapid.Int64Range(1, 1000000000000)).Draw(t, "powers") + percent := uint32(rapid.Int32Range(1, 100).Draw(t, "percent")) + + consumerValidators := createConsumerValidators(powers) + cappedValidators := keeper.NoMoreThanPercentOfTheSum(consumerValidators, percent) + + t.Log("can the cap be satisfied: ", CapSatisfiable(consumerValidators, percent)) + t.Log("before: ", consumerValidators) + t.Log("after: ", cappedValidators) + + // check properties + require.True(t, capRespectedIfSatisfiable(consumerValidators, cappedValidators, percent)) + require.True(t, evenPowersIfCapCannotBeSatisfied(consumerValidators, cappedValidators, percent)) + require.True(t, fairness(consumerValidators, cappedValidators)) + require.True(t, nonZero(consumerValidators, cappedValidators)) + require.True(t, equalSumIfCapSatisfiable(consumerValidators, cappedValidators, percent), "sum before: %v, sum after: %v", sumPowers(consumerValidators), sumPowers(cappedValidators)) + require.True(t, equalNumVals(consumerValidators, cappedValidators), "num before: %v, num after: %v", len(consumerValidators), len(cappedValidators)) + }) +} + +func findConsumerValidator(t *testing.T, v types.ConsumerValidator, valsAfter []types.ConsumerValidator) *types.ConsumerValidator { + var vAfter *types.ConsumerValidator + for _, vA := range valsAfter { + if bytes.Equal(v.ProviderConsAddr, vA.ProviderConsAddr) { + vAfter = &vA + break + } + } + if vAfter == nil { + t.Fatalf("could not find validator with address %v in validators after \n validators after capping: %v", v.ProviderConsAddr, valsAfter) + } + return vAfter } diff --git a/x/ccv/provider/keeper/proposal.go b/x/ccv/provider/keeper/proposal.go index 41e104e52f..1d2bf19a4f 100644 --- a/x/ccv/provider/keeper/proposal.go +++ b/x/ccv/provider/keeper/proposal.go @@ -220,6 +220,11 @@ func (k Keeper) StopConsumerChain(ctx sdk.Context, chainID string, closeChan boo } k.DeleteTopN(ctx, chainID) + k.DeleteValidatorsPowerCap(ctx, chainID) + k.DeleteValidatorSetCap(ctx, chainID) + k.DeleteAllowlist(ctx, chainID) + k.DeleteDenylist(ctx, chainID) + k.DeleteAllOptedIn(ctx, chainID) k.DeleteConsumerValSet(ctx, chainID) @@ -279,7 +284,7 @@ func (k Keeper) MakeConsumerGenesis( bondedValidators = append(bondedValidators, val) } - if prop.Top_N > 0 { + if topN, found := k.GetTopN(ctx, chainID); found && topN > 0 { // in a Top-N chain, we automatically opt in all validators that belong to the top N minPower, err := k.ComputeMinPowerToOptIn(ctx, chainID, bondedValidators, prop.Top_N) if err == nil { @@ -287,10 +292,8 @@ func (k Keeper) MakeConsumerGenesis( } } - nextValidators := k.ComputeNextEpochConsumerValSet(ctx, chainID, bondedValidators, - func(validator stakingtypes.Validator) bool { - return k.ShouldConsiderOnlyOptIn(ctx, chainID, validator) - }) + nextValidators := k.ComputeNextValidators(ctx, chainID, bondedValidators) + k.SetConsumerValSet(ctx, chainID, nextValidators) // get the initial updates with the latest set consumer public keys @@ -374,26 +377,39 @@ func (k Keeper) GetPendingConsumerAdditionProp(ctx sdk.Context, spawnTime time.T func (k Keeper) BeginBlockInit(ctx sdk.Context) { propsToExecute := k.GetConsumerAdditionPropsToExecute(ctx) - for _, prop := range propsToExecute { - if prop.Top_N == 0 && len(k.GetAllOptedIn(ctx, prop.ChainId)) == 0 { - // drop the proposal - ctx.Logger().Info("consumer client could not be created because no validator has"+ - " opted in for the Opt-In chain: %s", prop.ChainId) - continue + for i, prop := range propsToExecute { + // create consumer client in a cached context to handle errors + cachedCtx, writeFn := ctx.CacheContext() + + k.SetTopN(cachedCtx, prop.ChainId, prop.Top_N) + k.SetValidatorSetCap(cachedCtx, prop.ChainId, prop.ValidatorSetCap) + k.SetValidatorsPowerCap(cachedCtx, prop.ChainId, prop.ValidatorsPowerCap) + + for _, address := range prop.Allowlist { + consAddr, err := sdk.ConsAddressFromBech32(address) + if err != nil { + continue + } + + k.SetAllowlist(cachedCtx, prop.ChainId, types.NewProviderConsAddress(consAddr)) } - // create consumer client in a cached context to handle errors - cachedCtx, writeFn, err := k.CreateConsumerClientInCachedCtx(ctx, prop) + for _, address := range prop.Denylist { + consAddr, err := sdk.ConsAddressFromBech32(address) + if err != nil { + continue + } + + k.SetDenylist(cachedCtx, prop.ChainId, types.NewProviderConsAddress(consAddr)) + } + + err := k.CreateConsumerClient(cachedCtx, &propsToExecute[i]) if err != nil { // drop the proposal ctx.Logger().Info("consumer client could not be created: %w", err) continue } - // Only set Top N at the moment a chain starts. If we were to do this earlier (e.g., during the proposal), - // then someone could create a bogus ConsumerAdditionProposal to override the Top N for a specific chain. - k.SetTopN(cachedCtx, prop.ChainId, prop.Top_N) - // The cached context is created with a new EventManager so we merge the event // into the original context ctx.EventManager().EmitEvents(cachedCtx.EventManager().Events()) diff --git a/x/ccv/provider/keeper/proposal_test.go b/x/ccv/provider/keeper/proposal_test.go index 189ec82a0c..9b769d2f94 100644 --- a/x/ccv/provider/keeper/proposal_test.go +++ b/x/ccv/provider/keeper/proposal_test.go @@ -17,6 +17,7 @@ import ( abci "github.com/cometbft/cometbft/abci/types" + cryptotestutil "github.com/cosmos/interchain-security/v4/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" providerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" @@ -65,6 +66,10 @@ func TestHandleConsumerAdditionProposal(t *testing.T) { 100000000000, 100000000000, 0, + 0, + 0, + nil, + nil, ).(*providertypes.ConsumerAdditionProposal), blockTime: now, expAppendProp: true, @@ -91,6 +96,10 @@ func TestHandleConsumerAdditionProposal(t *testing.T) { 100000000000, 100000000000, 0, + 0, + 0, + nil, + nil, ).(*providertypes.ConsumerAdditionProposal), blockTime: now, expAppendProp: false, @@ -927,6 +936,10 @@ func TestBeginBlockInit(t *testing.T) { 100000000000, 100000000000, 50, + 0, + 0, + nil, + nil, ).(*providertypes.ConsumerAdditionProposal), providertypes.NewConsumerAdditionProposal( "title", "spawn time passed", "chain2", clienttypes.NewHeight(3, 4), []byte{}, []byte{}, @@ -939,6 +952,10 @@ func TestBeginBlockInit(t *testing.T) { 100000000000, 100000000000, 50, + 0, + 0, + nil, + nil, ).(*providertypes.ConsumerAdditionProposal), providertypes.NewConsumerAdditionProposal( "title", "spawn time not passed", "chain3", clienttypes.NewHeight(3, 4), []byte{}, []byte{}, @@ -951,6 +968,10 @@ func TestBeginBlockInit(t *testing.T) { 100000000000, 100000000000, 50, + 0, + 0, + nil, + nil, ).(*providertypes.ConsumerAdditionProposal), providertypes.NewConsumerAdditionProposal( "title", "invalid proposal: chain id already exists", "chain2", clienttypes.NewHeight(4, 5), []byte{}, []byte{}, @@ -963,18 +984,10 @@ func TestBeginBlockInit(t *testing.T) { 100000000000, 100000000000, 50, - ).(*providertypes.ConsumerAdditionProposal), - providertypes.NewConsumerAdditionProposal( - "title", "opt-in chain with no validator opted in", "chain4", clienttypes.NewHeight(3, 4), []byte{}, []byte{}, - now.Add(-time.Hour*2).UTC(), - "0.75", - 10, - "", - 10000, - 100000000000, - 100000000000, - 100000000000, 0, + 0, + nil, + nil, ).(*providertypes.ConsumerAdditionProposal), providertypes.NewConsumerAdditionProposal( "title", "opt-in chain with at least one validator opted in", "chain5", clienttypes.NewHeight(3, 4), []byte{}, []byte{}, @@ -987,10 +1000,14 @@ func TestBeginBlockInit(t *testing.T) { 100000000000, 100000000000, 0, + 0, + 0, + nil, + nil, ).(*providertypes.ConsumerAdditionProposal), } - // Expect client creation for only the first, second, and sixth proposals (spawn time already passed and valid) + // Expect client creation for only the first, second, and fifth proposals (spawn time already passed and valid) expectedCalls := testkeeper.GetMocksForCreateConsumerClient(ctx, &mocks, "chain1", clienttypes.NewHeight(3, 4)) expectedCalls = append(expectedCalls, testkeeper.GetMocksForCreateConsumerClient(ctx, &mocks, "chain2", clienttypes.NewHeight(3, 4))...) expectedCalls = append(expectedCalls, testkeeper.GetMocksForCreateConsumerClient(ctx, &mocks, "chain5", clienttypes.NewHeight(3, 4))...) @@ -1002,7 +1019,10 @@ func TestBeginBlockInit(t *testing.T) { } // opt in a sample validator so the chain's proposal can successfully execute - providerKeeper.SetOptedIn(ctx, pendingProps[5].ChainId, providertypes.NewProviderConsAddress([]byte("providerAddr"))) + validator := cryptotestutil.NewCryptoIdentityFromIntSeed(0).SDKStakingValidator() + consAddr, _ := validator.GetConsAddr() + providerKeeper.SetOptedIn(ctx, pendingProps[4].ChainId, providertypes.NewProviderConsAddress(consAddr)) + providerKeeper.BeginBlockInit(ctx) // first proposal is not pending anymore because its spawn time already passed and was executed @@ -1036,21 +1056,13 @@ func TestBeginBlockInit(t *testing.T) { // Note that we do not check that `GetConsumerGenesis(ctx, pendingProps[3].ChainId)` returns `false` here because // `pendingProps[3]` is an invalid proposal due to the chain id already existing so the consumer genesis also exists - // fifth proposal is dropped due to it being an Opt-In chain with no validators opted in - _, found = providerKeeper.GetPendingConsumerAdditionProp( - ctx, pendingProps[4].SpawnTime, pendingProps[4].ChainId) - require.False(t, found) - // because the proposal is dropped, no consumer genesis was created - _, found = providerKeeper.GetConsumerGenesis(ctx, pendingProps[4].ChainId) - require.False(t, found) - - // sixth proposal corresponds to an Opt-In chain with one opted-in validator and hence the proposal gets + // fifth proposal corresponds to an Opt-In chain with one opted-in validator and hence the proposal gets // successfully executed _, found = providerKeeper.GetPendingConsumerAdditionProp( - ctx, pendingProps[5].SpawnTime, pendingProps[5].ChainId) + ctx, pendingProps[4].SpawnTime, pendingProps[4].ChainId) require.False(t, found) // sixth proposal was successfully executed and hence consumer genesis was created - _, found = providerKeeper.GetConsumerGenesis(ctx, pendingProps[5].ChainId) + _, found = providerKeeper.GetConsumerGenesis(ctx, pendingProps[4].ChainId) require.True(t, found) // test that Top N is set correctly @@ -1110,6 +1122,7 @@ func TestBeginBlockCCR(t *testing.T) { additionProp := testkeeper.GetTestConsumerAdditionProp() additionProp.ChainId = prop.ChainId additionProp.InitialHeight = clienttypes.NewHeight(2, 3) + err := providerKeeper.CreateConsumerClient(ctx, additionProp) require.NoError(t, err) err = providerKeeper.SetConsumerChain(ctx, "channelID") diff --git a/x/ccv/provider/keeper/relay.go b/x/ccv/provider/keeper/relay.go index 7812081918..230ed0a96a 100644 --- a/x/ccv/provider/keeper/relay.go +++ b/x/ccv/provider/keeper/relay.go @@ -231,10 +231,8 @@ func (k Keeper) QueueVSCPackets(ctx sdk.Context) { } } - nextValidators := k.ComputeNextEpochConsumerValSet(ctx, chain.ChainId, bondedValidators, - func(validator stakingtypes.Validator) bool { - return k.ShouldConsiderOnlyOptIn(ctx, chain.ChainId, validator) - }) + nextValidators := k.ComputeNextValidators(ctx, chain.ChainId, bondedValidators) + valUpdates := DiffValidators(currentValidators, nextValidators) k.SetConsumerValSet(ctx, chain.ChainId, nextValidators) diff --git a/x/ccv/provider/keeper/relay_test.go b/x/ccv/provider/keeper/relay_test.go index b300916a2e..5f74d93424 100644 --- a/x/ccv/provider/keeper/relay_test.go +++ b/x/ccv/provider/keeper/relay_test.go @@ -794,3 +794,81 @@ func TestEndBlockVSU(t *testing.T) { providerKeeper.EndBlockVSU(ctx) require.Equal(t, 1, len(providerKeeper.GetPendingVSCPackets(ctx, chainID))) } + +// TestQueueVSCPacketsWithPowerCapping tests queueing validator set updates with power capping +func TestQueueVSCPacketsWithPowerCapping(t *testing.T) { + providerKeeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + providerKeeper.SetValidatorSetUpdateId(ctx, 1) + + valA := createStakingValidator(ctx, mocks, 1, 1) // 3.125% of the total voting power + valAConsAddr, _ := valA.GetConsAddr() + valAPubKey, _ := valA.TmConsPublicKey() + mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, valAConsAddr).Return(valA, true).AnyTimes() + valB := createStakingValidator(ctx, mocks, 2, 3) // 9.375% of the total voting power + valBConsAddr, _ := valB.GetConsAddr() + valBPubKey, _ := valB.TmConsPublicKey() + mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, valBConsAddr).Return(valB, true).AnyTimes() + valC := createStakingValidator(ctx, mocks, 3, 4) // 12.5% of the total voting power + valCConsAddr, _ := valC.GetConsAddr() + valCPubKey, _ := valC.TmConsPublicKey() + mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, valCConsAddr).Return(valC, true).AnyTimes() + valD := createStakingValidator(ctx, mocks, 4, 8) // 25% of the total voting power + valDConsAddr, _ := valD.GetConsAddr() + mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, valDConsAddr).Return(valD, true).AnyTimes() + valE := createStakingValidator(ctx, mocks, 5, 16) // 50% of the total voting power + valEConsAddr, _ := valE.GetConsAddr() + valEPubKey, _ := valE.TmConsPublicKey() + mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, valEConsAddr).Return(valE, true).AnyTimes() + + mocks.MockStakingKeeper.EXPECT().GetLastValidators(ctx).Return([]stakingtypes.Validator{valA, valB, valC, valD, valE}).AnyTimes() + + // add a consumer chain + providerKeeper.SetConsumerClientId(ctx, "chainID", "clientID") + + providerKeeper.SetTopN(ctx, "chainID", 50) // would opt in E + + // opt in all validators + providerKeeper.SetOptedIn(ctx, "chainID", providertypes.NewProviderConsAddress(valAConsAddr)) + providerKeeper.SetOptedIn(ctx, "chainID", providertypes.NewProviderConsAddress(valBConsAddr)) + providerKeeper.SetOptedIn(ctx, "chainID", providertypes.NewProviderConsAddress(valCConsAddr)) + providerKeeper.SetOptedIn(ctx, "chainID", providertypes.NewProviderConsAddress(valDConsAddr)) + + // denylist validator D + providerKeeper.SetDenylist(ctx, "chainID", providertypes.NewProviderConsAddress(valDConsAddr)) + + // set a power-capping of 40% + providerKeeper.SetValidatorsPowerCap(ctx, "chainID", 40) + + providerKeeper.QueueVSCPackets(ctx) + + actualQueuedVSCPackets := providerKeeper.GetPendingVSCPackets(ctx, "chainID") + expectedQueuedVSCPackets := []ccv.ValidatorSetChangePacketData{ + ccv.NewValidatorSetChangePacketData( + []abci.ValidatorUpdate{ + // validator D is not here because it was denylisted + // powers have changed because of power capping + { + PubKey: valEPubKey, + Power: 9, + }, + { + PubKey: valCPubKey, + Power: 6, + }, + { + PubKey: valBPubKey, + Power: 5, + }, + { + PubKey: valAPubKey, + Power: 4, + }, + }, + 1, + nil), + } + + require.Equal(t, expectedQueuedVSCPackets, actualQueuedVSCPackets) +} diff --git a/x/ccv/provider/keeper/validator_set_update.go b/x/ccv/provider/keeper/validator_set_update.go index d1910c9bcd..264fdd67f2 100644 --- a/x/ccv/provider/keeper/validator_set_update.go +++ b/x/ccv/provider/keeper/validator_set_update.go @@ -27,7 +27,7 @@ func (k Keeper) SetConsumerValidator( } // SetConsumerValSet resets the current consumer validators with the `nextValidators` computed by -// `ComputeNextEpochConsumerValSet` and hence this method should only be called after `ComputeNextEpochConsumerValSet` has completed. +// `FilterValidators` and hence this method should only be called after `FilterValidators` has completed. func (k Keeper) SetConsumerValSet(ctx sdk.Context, chainID string, nextValidators []types.ConsumerValidator) { k.DeleteConsumerValSet(ctx, chainID) for _, val := range nextValidators { @@ -158,17 +158,22 @@ func (k Keeper) CreateConsumerValidator(ctx sdk.Context, chainID string, validat }, nil } -// ComputeNextEpochConsumerValSet returns the next validator set that is responsible for validating consumer -// chain `chainID`. The next validator set corresponds to the `bondedValidator`s that `shouldConsider` evaluates to `true`. -func (k Keeper) ComputeNextEpochConsumerValSet( +// FilterValidators filters the provided `bondedValidators` according to `predicate` and returns +// the filtered set. +func (k Keeper) FilterValidators( ctx sdk.Context, chainID string, bondedValidators []stakingtypes.Validator, - shouldConsider func(validator stakingtypes.Validator) bool, + predicate func(providerAddr types.ProviderConsAddress) bool, ) []types.ConsumerValidator { var nextValidators []types.ConsumerValidator for _, val := range bondedValidators { - if shouldConsider(val) { + consAddr, err := val.GetConsAddr() + if err != nil { + continue + } + + if predicate(types.NewProviderConsAddress(consAddr)) { nextValidator, err := k.CreateConsumerValidator(ctx, chainID, val) if err != nil { // this should never happen but is recoverable if we exclude this validator from the next validator set diff --git a/x/ccv/provider/keeper/validator_set_update_test.go b/x/ccv/provider/keeper/validator_set_update_test.go index 6883fc3b50..396a74fb1f 100644 --- a/x/ccv/provider/keeper/validator_set_update_test.go +++ b/x/ccv/provider/keeper/validator_set_update_test.go @@ -334,8 +334,8 @@ func TestComputeNextEpochConsumerValSetConsiderAll(t *testing.T) { chainID := "chainID" // no consumer validators returned if we have no bonded validators - considerAll := func(validator stakingtypes.Validator) bool { return true } - require.Empty(t, providerKeeper.ComputeNextEpochConsumerValSet(ctx, chainID, []stakingtypes.Validator{}, considerAll)) + considerAll := func(providerAddr types.ProviderConsAddress) bool { return true } + require.Empty(t, providerKeeper.FilterValidators(ctx, chainID, []stakingtypes.Validator{}, considerAll)) var expectedValidators []types.ConsumerValidator @@ -363,7 +363,7 @@ func TestComputeNextEpochConsumerValSetConsiderAll(t *testing.T) { }) bondedValidators := []stakingtypes.Validator{valA, valB} - actualValidators := providerKeeper.ComputeNextEpochConsumerValSet(ctx, chainID, bondedValidators, considerAll) + actualValidators := providerKeeper.FilterValidators(ctx, chainID, bondedValidators, considerAll) require.Equal(t, expectedValidators, actualValidators) } @@ -374,9 +374,9 @@ func TestComputeNextEpochConsumerValSetConsiderOnlyOptIn(t *testing.T) { chainID := "chainID" // no consumer validators returned if we have no opted-in validators - require.Empty(t, providerKeeper.ComputeNextEpochConsumerValSet(ctx, chainID, []stakingtypes.Validator{}, - func(validator stakingtypes.Validator) bool { - return providerKeeper.ShouldConsiderOnlyOptIn(ctx, chainID, validator) + require.Empty(t, providerKeeper.FilterValidators(ctx, chainID, []stakingtypes.Validator{}, + func(providerAddr types.ProviderConsAddress) bool { + return providerKeeper.IsOptedIn(ctx, chainID, providerAddr) })) var expectedValidators []types.ConsumerValidator @@ -412,9 +412,9 @@ func TestComputeNextEpochConsumerValSetConsiderOnlyOptIn(t *testing.T) { // the expected actual validators are the opted-in validators but with the correct power and consumer public keys set bondedValidators := []stakingtypes.Validator{valA, valB} - actualValidators := providerKeeper.ComputeNextEpochConsumerValSet(ctx, "chainID", bondedValidators, - func(validator stakingtypes.Validator) bool { - return providerKeeper.ShouldConsiderOnlyOptIn(ctx, "chainID", validator) + actualValidators := providerKeeper.FilterValidators(ctx, "chainID", bondedValidators, + func(providerAddr types.ProviderConsAddress) bool { + return providerKeeper.IsOptedIn(ctx, chainID, providerAddr) }) // sort validators first to be able to compare @@ -431,9 +431,9 @@ func TestComputeNextEpochConsumerValSetConsiderOnlyOptIn(t *testing.T) { // create a staking validator C that is not opted in, hence `expectedValidators` remains the same valC := createStakingValidator(ctx, mocks, 3, 3) bondedValidators = []stakingtypes.Validator{valA, valB, valC} - actualValidators = providerKeeper.ComputeNextEpochConsumerValSet(ctx, "chainID", bondedValidators, - func(validator stakingtypes.Validator) bool { - return providerKeeper.ShouldConsiderOnlyOptIn(ctx, "chainID", validator) + actualValidators = providerKeeper.FilterValidators(ctx, "chainID", bondedValidators, + func(providerAddr types.ProviderConsAddress) bool { + return providerKeeper.IsOptedIn(ctx, chainID, providerAddr) }) sortValidators(actualValidators) diff --git a/x/ccv/provider/proposal_handler_test.go b/x/ccv/provider/proposal_handler_test.go index 30c1793360..185db25b07 100644 --- a/x/ccv/provider/proposal_handler_test.go +++ b/x/ccv/provider/proposal_handler_test.go @@ -45,6 +45,10 @@ func TestProviderProposalHandler(t *testing.T) { 100000000000, 100000000000, 0, + 0, + 0, + nil, + nil, ), blockTime: hourFromNow, // ctx blocktime is after proposal's spawn time expValidConsumerAddition: true, diff --git a/x/ccv/provider/types/keys.go b/x/ccv/provider/types/keys.go index 62ce861c75..14521b9289 100644 --- a/x/ccv/provider/types/keys.go +++ b/x/ccv/provider/types/keys.go @@ -158,6 +158,23 @@ const ( // that corresponds to the N% of the top validators that have to validate this consumer chain TopNBytePrefix + // ValidatorsPowerCapPrefix is the byte prefix storing the mapping from a consumer chain to the power-cap value of this chain, + // that corresponds to p% such that no validator can have more than p% of the voting power on the consumer chain. + // Operates on a best-effort basis. + ValidatorsPowerCapPrefix + + // ValidatorSetCapPrefix is the byte prefix storing the mapping from a consumer chain to the validator-set cap value + // of this chain. + ValidatorSetCapPrefix + + // AllowlistPrefix is the byte prefix storing the mapping from a consumer chain to the set of validators that are + // allowlisted. + AllowlistPrefix + + // DenylistPrefix is the byte prefix storing the mapping from a consumer chain to the set of validators that are + // denylisted. + DenylistPrefix + // ConsumerRewardsAllocationBytePrefix is the byte prefix for storing for each consumer the ICS rewards // allocated to the consumer rewards pool ConsumerRewardsAllocationBytePrefix @@ -544,6 +561,26 @@ func TopNKey(chainID string) []byte { return ChainIdWithLenKey(TopNBytePrefix, chainID) } +// ValidatorSetPowerKey returns the key of consumer chain `chainID` +func ValidatorsPowerCapKey(chainID string) []byte { + return ChainIdWithLenKey(ValidatorsPowerCapPrefix, chainID) +} + +// ValidatorSetCapKey returns the key of consumer chain `chainID` +func ValidatorSetCapKey(chainID string) []byte { + return ChainIdWithLenKey(ValidatorSetCapPrefix, chainID) +} + +// AllowlistCapKey returns the key to a validator's slash log +func AllowlistCapKey(chainID string, providerAddr ProviderConsAddress) []byte { + return append(ChainIdWithLenKey(AllowlistPrefix, chainID), providerAddr.ToSdkConsAddr().Bytes()...) +} + +// DenylistCapKey returns the key to a validator's slash log +func DenylistCapKey(chainID string, providerAddr ProviderConsAddress) []byte { + return append(ChainIdWithLenKey(DenylistPrefix, chainID), providerAddr.ToSdkConsAddr().Bytes()...) +} + // OptedInKey returns the key used to store whether a validator is opted in on a consumer chain. func OptedInKey(chainID string, providerAddr ProviderConsAddress) []byte { prefix := ChainIdWithLenKey(OptedInBytePrefix, chainID) diff --git a/x/ccv/provider/types/proposal.go b/x/ccv/provider/types/proposal.go index 8dfb67f644..fa6483acd1 100644 --- a/x/ccv/provider/types/proposal.go +++ b/x/ccv/provider/types/proposal.go @@ -50,6 +50,10 @@ func NewConsumerAdditionProposal(title, description, chainID string, transferTimeoutPeriod time.Duration, unbondingPeriod time.Duration, topN uint32, + validatorsPowerCap uint32, + validatorSetCap uint32, + allowlist []string, + denylist []string, ) govv1beta1.Content { return &ConsumerAdditionProposal{ Title: title, @@ -67,6 +71,10 @@ func NewConsumerAdditionProposal(title, description, chainID string, TransferTimeoutPeriod: transferTimeoutPeriod, UnbondingPeriod: unbondingPeriod, Top_N: topN, + ValidatorsPowerCap: validatorsPowerCap, + ValidatorSetCap: validatorSetCap, + Allowlist: allowlist, + Denylist: denylist, } } @@ -143,6 +151,10 @@ func (cccp *ConsumerAdditionProposal) ValidateBasic() error { return errorsmod.Wrap(ErrInvalidConsumerAdditionProposal, "Top N can either be 0 or in the range [50, 100]") } + if cccp.ValidatorsPowerCap != 0 && cccp.ValidatorSetCap > 100 { + return errorsmod.Wrap(ErrInvalidConsumerAdditionProposal, "validators' power cap has to be in the range [1, 100]") + } + return nil } diff --git a/x/ccv/provider/types/proposal_test.go b/x/ccv/provider/types/proposal_test.go index 13e7edb11e..465a376b47 100644 --- a/x/ccv/provider/types/proposal_test.go +++ b/x/ccv/provider/types/proposal_test.go @@ -37,6 +37,10 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { 100000000000, 100000000000, 0, + 0, + 0, + nil, + nil, ), true, }, @@ -50,7 +54,12 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { 100000000000, 100000000000, 100000000000, - 0), + 0, + 0, + 0, + nil, + nil, + ), true, }, { @@ -63,7 +72,12 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { 100000000000, 100000000000, 100000000000, - 0), + 0, + 0, + 0, + nil, + nil, + ), false, }, { @@ -76,7 +90,12 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { 100000000000, 100000000000, 100000000000, - 0), + 0, + 0, + 0, + nil, + nil, + ), false, }, { @@ -109,7 +128,12 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { 100000000000, 100000000000, 100000000000, - 0), + 0, + 0, + 0, + nil, + nil, + ), false, }, { @@ -122,7 +146,11 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { 100000000000, 100000000000, 100000000000, - 0), + 0, + 0, + 0, + nil, + nil), false, }, { @@ -135,7 +163,12 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { 100000000000, 100000000000, 100000000000, - 0), + 0, + 0, + 0, + nil, + nil, + ), false, }, { @@ -148,7 +181,12 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { 100000000000, 100000000000, 100000000000, - 0), + 0, + 0, + 0, + nil, + nil, + ), false, }, { @@ -161,7 +199,12 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { 10000, 100000000000, 100000000000, - 0), + 0, + 0, + 0, + nil, + nil, + ), false, }, { @@ -174,7 +217,12 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { 100000000000, 100000000000, 100000000000, - 0), + 0, + 0, + 0, + nil, + nil, + ), false, }, { @@ -187,7 +235,12 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { 100000000000, 100000000000, 100000000000, - 0), + 0, + 0, + 0, + nil, + nil, + ), false, }, { @@ -200,7 +253,12 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { 0, 100000000000, 100000000000, - 0), + 0, + 0, + 0, + nil, + nil, + ), false, }, { @@ -213,7 +271,12 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { 100000000000, 0, 100000000000, - 0), + 0, + 0, + 0, + nil, + nil, + ), false, }, { @@ -226,7 +289,12 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { 100000000000, 100000000000, 0, - 0), + 0, + 0, + 0, + nil, + nil, + ), false, }, } @@ -251,7 +319,11 @@ func TestMarshalConsumerAdditionProposal(t *testing.T) { 100000000000, 100000000000, 100000000000, - 0) + 0, + 0, + 0, + nil, + nil) cccp, ok := content.(*types.ConsumerAdditionProposal) require.True(t, ok) @@ -294,7 +366,11 @@ func TestConsumerAdditionProposalString(t *testing.T) { 100000000000, 10000000000, 100000000000, - 0) + 0, + 0, + 0, + []string{}, + []string{}) expect := fmt.Sprintf(`CreateConsumerChain Proposal Title: title diff --git a/x/ccv/provider/types/provider.pb.go b/x/ccv/provider/types/provider.pb.go index dee8a9520a..4f0a2fd605 100644 --- a/x/ccv/provider/types/provider.pb.go +++ b/x/ccv/provider/types/provider.pb.go @@ -97,6 +97,20 @@ type ConsumerAdditionProposal struct { // have to validate the proposed consumer chain. top_N can either be 0 or any value in [50, 100]. // A chain can join with top_N == 0 as an Opt In chain, or with top_N ∈ [50, 100] as a Top N chain. Top_N uint32 `protobuf:"varint,15,opt,name=top_N,json=topN,proto3" json:"top_N,omitempty"` + // Corresponds to the maximum power (percentage-wise) a validator can have on the consumer chain. For instance, if + // `validators_power_cap` is set to 32, it means that no validator can have more than 32% of the voting power on the + // consumer chain. Note that this might not be feasible. For example, think of a consumer chain with only + // 5 validators and with `validators_power_cap` set to 10%. In such a scenario, at least one validator would need + // to have more than 20% of the total voting power. Therefore, `validators_power_cap` operates on a best-effort basis. + ValidatorsPowerCap uint32 `protobuf:"varint,16,opt,name=validators_power_cap,json=validatorsPowerCap,proto3" json:"validators_power_cap,omitempty"` + // Corresponds to the maximum number of validators that can validate a consumer chain. + // Only applicable to Opt In chains. Setting `validator_set_cap` on a Top N chain is a no-op. + ValidatorSetCap uint32 `protobuf:"varint,17,opt,name=validator_set_cap,json=validatorSetCap,proto3" json:"validator_set_cap,omitempty"` + // Corresponds to a list of provider consensus addresses of validators that are the ONLY ones that can validate + // the consumer chain. + Allowlist []string `protobuf:"bytes,18,rep,name=allowlist,proto3" json:"allowlist,omitempty"` + // Corresponds to a list of provider consensus addresses of validators that CANNOT validate the consumer chain. + Denylist []string `protobuf:"bytes,19,rep,name=denylist,proto3" json:"denylist,omitempty"` } func (m *ConsumerAdditionProposal) Reset() { *m = ConsumerAdditionProposal{} } @@ -1545,123 +1559,127 @@ func init() { } var fileDescriptor_f22ec409a72b7b72 = []byte{ - // 1852 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0x4d, 0x6f, 0x1c, 0xc7, - 0xd1, 0xe6, 0x70, 0x97, 0x1f, 0x5b, 0xcb, 0xcf, 0x21, 0x6d, 0x0d, 0xf5, 0xf2, 0x5d, 0x52, 0xe3, - 0xd8, 0x61, 0xa2, 0x68, 0x26, 0xa4, 0x13, 0x40, 0x10, 0x62, 0x18, 0xe4, 0x52, 0xb6, 0x28, 0xda, - 0x12, 0x3d, 0x64, 0x28, 0x24, 0x39, 0x0c, 0x7a, 0x7b, 0x5a, 0xbb, 0x0d, 0xce, 0x4e, 0x8f, 0xba, - 0x7b, 0x47, 0xde, 0x4b, 0xce, 0xb9, 0x04, 0x70, 0x6e, 0x46, 0x2e, 0x71, 0x02, 0x04, 0x08, 0x72, - 0x49, 0x7e, 0x86, 0x8f, 0x3e, 0xe6, 0x64, 0x07, 0xd2, 0x21, 0x87, 0x5c, 0xf3, 0x03, 0x82, 0xee, - 0xf9, 0xdc, 0x25, 0xa9, 0xac, 0xe0, 0xe4, 0x42, 0xce, 0x54, 0x57, 0x3d, 0x55, 0xdd, 0x55, 0xf5, - 0x54, 0xef, 0xc0, 0x1e, 0x8d, 0x24, 0xe1, 0xb8, 0x87, 0x68, 0xe4, 0x0b, 0x82, 0x07, 0x9c, 0xca, - 0xa1, 0x8b, 0x71, 0xe2, 0xc6, 0x9c, 0x25, 0x34, 0x20, 0xdc, 0x4d, 0x76, 0x8b, 0x67, 0x27, 0xe6, - 0x4c, 0x32, 0xf3, 0xad, 0x2b, 0x6c, 0x1c, 0x8c, 0x13, 0xa7, 0xd0, 0x4b, 0x76, 0x6f, 0xbe, 0x7d, - 0x1d, 0x70, 0xb2, 0xeb, 0x3e, 0xa7, 0x9c, 0xa4, 0x58, 0x37, 0xd7, 0xbb, 0xac, 0xcb, 0xf4, 0xa3, - 0xab, 0x9e, 0x32, 0xe9, 0x56, 0x97, 0xb1, 0x6e, 0x48, 0x5c, 0xfd, 0xd6, 0x19, 0x3c, 0x75, 0x25, - 0xed, 0x13, 0x21, 0x51, 0x3f, 0xce, 0x14, 0x5a, 0xe3, 0x0a, 0xc1, 0x80, 0x23, 0x49, 0x59, 0x94, - 0x03, 0xd0, 0x0e, 0x76, 0x31, 0xe3, 0xc4, 0xc5, 0x21, 0x25, 0x91, 0x54, 0x5e, 0xd3, 0xa7, 0x4c, - 0xc1, 0x55, 0x0a, 0x21, 0xed, 0xf6, 0x64, 0x2a, 0x16, 0xae, 0x24, 0x51, 0x40, 0x78, 0x9f, 0xa6, - 0xca, 0xe5, 0x5b, 0x66, 0xb0, 0x59, 0x59, 0xc7, 0x7c, 0x18, 0x4b, 0xe6, 0x5e, 0x90, 0xa1, 0xc8, - 0x56, 0xdf, 0xc1, 0x4c, 0xf4, 0x99, 0x70, 0x89, 0xda, 0x7f, 0x84, 0x89, 0x9b, 0xec, 0x76, 0x88, - 0x44, 0xbb, 0x85, 0x20, 0x8f, 0x3b, 0xd3, 0xeb, 0x20, 0x51, 0xea, 0x60, 0x46, 0xf3, 0xb8, 0x57, - 0x51, 0x9f, 0x46, 0xcc, 0xd5, 0x7f, 0x53, 0x91, 0xfd, 0xaf, 0x59, 0xb0, 0xda, 0x2c, 0x12, 0x83, - 0x3e, 0xe1, 0xfb, 0x41, 0x40, 0xd5, 0x2e, 0x4f, 0x38, 0x8b, 0x99, 0x40, 0xa1, 0xb9, 0x0e, 0x33, - 0x92, 0xca, 0x90, 0x58, 0xc6, 0xb6, 0xb1, 0xd3, 0xf0, 0xd2, 0x17, 0x73, 0x1b, 0x9a, 0x01, 0x11, - 0x98, 0xd3, 0x58, 0x29, 0x5b, 0xd3, 0x7a, 0xad, 0x2a, 0x32, 0x37, 0x60, 0x3e, 0x4d, 0x0d, 0x0d, - 0xac, 0x9a, 0x5e, 0x9e, 0xd3, 0xef, 0x47, 0x81, 0xf9, 0x21, 0x2c, 0xd1, 0x88, 0x4a, 0x8a, 0x42, - 0xbf, 0x47, 0xd4, 0x01, 0x59, 0xf5, 0x6d, 0x63, 0xa7, 0xb9, 0x77, 0xd3, 0xa1, 0x1d, 0xec, 0xa8, - 0x33, 0x75, 0xb2, 0x93, 0x4c, 0x76, 0x9d, 0x07, 0x5a, 0xe3, 0xa0, 0xfe, 0xe5, 0xd7, 0x5b, 0x53, - 0xde, 0x62, 0x66, 0x97, 0x0a, 0xcd, 0x5b, 0xb0, 0xd0, 0x25, 0x11, 0x11, 0x54, 0xf8, 0x3d, 0x24, - 0x7a, 0xd6, 0xcc, 0xb6, 0xb1, 0xb3, 0xe0, 0x35, 0x33, 0xd9, 0x03, 0x24, 0x7a, 0xe6, 0x16, 0x34, - 0x3b, 0x34, 0x42, 0x7c, 0x98, 0x6a, 0xcc, 0x6a, 0x0d, 0x48, 0x45, 0x5a, 0xa1, 0x0d, 0x20, 0x62, - 0xf4, 0x3c, 0xf2, 0x55, 0x01, 0x58, 0x73, 0x59, 0x20, 0x69, 0xf2, 0x9d, 0x3c, 0xf9, 0xce, 0x59, - 0x5e, 0x1d, 0x07, 0xf3, 0x2a, 0x90, 0xcf, 0xbe, 0xd9, 0x32, 0xbc, 0x86, 0xb6, 0x53, 0x2b, 0xe6, - 0x23, 0x58, 0x19, 0x44, 0x1d, 0x16, 0x05, 0x34, 0xea, 0xfa, 0x31, 0xe1, 0x94, 0x05, 0xd6, 0xbc, - 0x86, 0xda, 0xb8, 0x04, 0x75, 0x98, 0xd5, 0x51, 0x8a, 0xf4, 0xb9, 0x42, 0x5a, 0x2e, 0x8c, 0x4f, - 0xb4, 0xad, 0xf9, 0x09, 0x98, 0x18, 0x27, 0x3a, 0x24, 0x36, 0x90, 0x39, 0x62, 0x63, 0x72, 0xc4, - 0x15, 0x8c, 0x93, 0xb3, 0xd4, 0x3a, 0x83, 0xfc, 0x05, 0xdc, 0x90, 0x1c, 0x45, 0xe2, 0x29, 0xe1, - 0xe3, 0xb8, 0x30, 0x39, 0xee, 0x1b, 0x39, 0xc6, 0x28, 0xf8, 0x03, 0xd8, 0xc6, 0x59, 0x01, 0xf9, - 0x9c, 0x04, 0x54, 0x48, 0x4e, 0x3b, 0x03, 0x65, 0xeb, 0x3f, 0xe5, 0x08, 0xeb, 0x1a, 0x69, 0xea, - 0x22, 0x68, 0xe5, 0x7a, 0xde, 0x88, 0xda, 0x07, 0x99, 0x96, 0xf9, 0x18, 0xbe, 0xd3, 0x09, 0x19, - 0xbe, 0x10, 0x2a, 0x38, 0x7f, 0x04, 0x49, 0xbb, 0xee, 0x53, 0x21, 0x14, 0xda, 0xc2, 0xb6, 0xb1, - 0x53, 0xf3, 0x6e, 0xa5, 0xba, 0x27, 0x84, 0x1f, 0x56, 0x34, 0xcf, 0x2a, 0x8a, 0xe6, 0x1d, 0x30, - 0x7b, 0x54, 0x48, 0xc6, 0x29, 0x46, 0xa1, 0x4f, 0x22, 0xc9, 0x29, 0x11, 0xd6, 0xa2, 0x36, 0x5f, - 0x2d, 0x57, 0xee, 0xa7, 0x0b, 0xe6, 0x43, 0xb8, 0x75, 0xad, 0x53, 0x1f, 0xf7, 0x50, 0x14, 0x91, - 0xd0, 0x5a, 0xd2, 0x5b, 0xd9, 0x0a, 0xae, 0xf1, 0xd9, 0x4e, 0xd5, 0xcc, 0x35, 0x98, 0x91, 0x2c, - 0xf6, 0x1f, 0x59, 0xcb, 0xdb, 0xc6, 0xce, 0xa2, 0x57, 0x97, 0x2c, 0x7e, 0x74, 0x6f, 0xfe, 0x57, - 0x5f, 0x6c, 0x4d, 0x7d, 0xfe, 0xc5, 0xd6, 0x94, 0xfd, 0x17, 0x03, 0x6e, 0xb4, 0x8b, 0xd3, 0xe8, - 0xb3, 0x04, 0x85, 0xff, 0xcb, 0xae, 0xdb, 0x87, 0x86, 0x50, 0xe1, 0xe8, 0x3a, 0xaf, 0xbf, 0x46, - 0x9d, 0xcf, 0x2b, 0x33, 0xb5, 0x60, 0xff, 0xce, 0x80, 0xf5, 0xfb, 0xcf, 0x06, 0x34, 0x61, 0x18, - 0xfd, 0x57, 0x48, 0xe2, 0x18, 0x16, 0x49, 0x05, 0x4f, 0x58, 0xb5, 0xed, 0xda, 0x4e, 0x73, 0xef, - 0x6d, 0x27, 0x25, 0x31, 0xa7, 0xe0, 0xb6, 0x8c, 0xc8, 0x9c, 0xaa, 0x77, 0x6f, 0xd4, 0xf6, 0xde, - 0xb4, 0x65, 0xd8, 0x7f, 0x30, 0xe0, 0xa6, 0x3a, 0xfe, 0x2e, 0xf1, 0xc8, 0x73, 0xc4, 0x83, 0x43, - 0x12, 0xb1, 0xbe, 0xf8, 0xd6, 0x71, 0xda, 0xb0, 0x18, 0x68, 0x24, 0x5f, 0x32, 0x1f, 0x05, 0x81, - 0x8e, 0x53, 0xeb, 0x28, 0xe1, 0x19, 0xdb, 0x0f, 0x02, 0x73, 0x07, 0x56, 0x4a, 0x1d, 0xae, 0xf2, - 0xa9, 0x8e, 0x59, 0xa9, 0x2d, 0xe5, 0x6a, 0x3a, 0xcb, 0xc4, 0xfe, 0xa7, 0x01, 0x2b, 0x1f, 0x86, - 0xac, 0x83, 0xc2, 0xd3, 0x10, 0x89, 0x9e, 0x2a, 0xbd, 0xa1, 0x4a, 0x0f, 0x27, 0x59, 0xcf, 0xeb, - 0xf0, 0x26, 0x4e, 0x8f, 0x32, 0xd3, 0x2c, 0xf4, 0x3e, 0xac, 0x16, 0x5d, 0x58, 0x54, 0x81, 0xde, - 0xcd, 0xc1, 0xda, 0x8b, 0xaf, 0xb7, 0x96, 0xf3, 0x62, 0x6b, 0xeb, 0x8a, 0x38, 0xf4, 0x96, 0xf1, - 0x88, 0x20, 0x30, 0x5b, 0xd0, 0xa4, 0x1d, 0xec, 0x0b, 0xf2, 0xcc, 0x8f, 0x06, 0x7d, 0x5d, 0x40, - 0x75, 0xaf, 0x41, 0x3b, 0xf8, 0x94, 0x3c, 0x7b, 0x34, 0xe8, 0x9b, 0xef, 0xc2, 0x9b, 0xf9, 0x00, - 0xf6, 0x13, 0x14, 0xfa, 0xca, 0x5e, 0x1d, 0x07, 0xd7, 0xf5, 0xb4, 0xe0, 0xad, 0xe5, 0xab, 0xe7, - 0x28, 0x54, 0xce, 0xf6, 0x83, 0x80, 0xdb, 0x2f, 0x67, 0x60, 0xf6, 0x04, 0x71, 0xd4, 0x17, 0xe6, - 0x19, 0x2c, 0x4b, 0xd2, 0x8f, 0x43, 0x24, 0x89, 0x9f, 0x32, 0x7c, 0xb6, 0xd3, 0xdb, 0x9a, 0xf9, - 0xab, 0xc3, 0xd2, 0xa9, 0x8c, 0xc7, 0x64, 0xd7, 0x69, 0x6b, 0xe9, 0xa9, 0x44, 0x92, 0x78, 0x4b, - 0x39, 0x46, 0x2a, 0x34, 0xef, 0x82, 0x25, 0xf9, 0x40, 0xc8, 0x92, 0x7b, 0x4b, 0xd2, 0x49, 0x73, - 0xf9, 0x66, 0xbe, 0x9e, 0xd2, 0x55, 0x41, 0x36, 0x57, 0xd3, 0x6c, 0xed, 0xdb, 0xd0, 0xec, 0x29, - 0xac, 0xa9, 0x19, 0x35, 0x8e, 0x59, 0x9f, 0x1c, 0x73, 0x55, 0xd9, 0x8f, 0x82, 0x7e, 0x02, 0x66, - 0x22, 0xf0, 0x38, 0xe6, 0xcc, 0x6b, 0xc4, 0x99, 0x08, 0x3c, 0x0a, 0x19, 0xc0, 0xa6, 0x50, 0xc5, - 0xe7, 0xf7, 0x89, 0xd4, 0xa4, 0x1d, 0x87, 0x24, 0xa2, 0xa2, 0x97, 0x83, 0xcf, 0x4e, 0x0e, 0xbe, - 0xa1, 0x81, 0x3e, 0x56, 0x38, 0x5e, 0x0e, 0x93, 0x79, 0x69, 0x43, 0xeb, 0x6a, 0x2f, 0x45, 0x82, - 0xe6, 0x74, 0x82, 0xfe, 0xef, 0x0a, 0x88, 0x22, 0x4b, 0x02, 0xde, 0xa9, 0x0c, 0x17, 0xd5, 0xd5, - 0xbe, 0x6e, 0x28, 0x9f, 0x93, 0xae, 0x62, 0x60, 0x94, 0xce, 0x19, 0x42, 0x8a, 0x01, 0x99, 0xb1, - 0x87, 0xba, 0x02, 0x15, 0xcc, 0xd1, 0x66, 0x34, 0xca, 0x6e, 0x11, 0x76, 0x39, 0x83, 0x0a, 0x8e, - 0xf0, 0x2a, 0x58, 0x1f, 0x10, 0xa2, 0xba, 0xb9, 0x32, 0x87, 0x48, 0xcc, 0x70, 0x4f, 0xcf, 0xc9, - 0x9a, 0xb7, 0x54, 0xcc, 0x9c, 0xfb, 0x4a, 0xfa, 0xb0, 0x3e, 0x3f, 0xbf, 0xd2, 0xb0, 0xbf, 0x07, - 0x0d, 0xdd, 0xcc, 0xfb, 0xf8, 0x42, 0x98, 0x9b, 0xd0, 0x50, 0x5d, 0x41, 0x84, 0x20, 0xc2, 0x32, - 0x34, 0x07, 0x94, 0x02, 0x5b, 0xc2, 0xc6, 0x75, 0xb7, 0x2d, 0x61, 0x3e, 0x81, 0xb9, 0x98, 0xe8, - 0xab, 0x80, 0x36, 0x6c, 0xee, 0xbd, 0xe7, 0x4c, 0x70, 0x17, 0x76, 0xae, 0x03, 0xf4, 0x72, 0x34, - 0x9b, 0x97, 0x77, 0xbc, 0xb1, 0x61, 0x23, 0xcc, 0xf3, 0x71, 0xa7, 0x3f, 0x79, 0x2d, 0xa7, 0x63, - 0x78, 0xa5, 0xcf, 0xdb, 0xd0, 0xdc, 0x4f, 0xb7, 0xfd, 0x11, 0x15, 0xf2, 0xf2, 0xb1, 0x2c, 0x54, - 0x8f, 0xe5, 0x21, 0x2c, 0x65, 0x83, 0xf3, 0x8c, 0x69, 0x42, 0x32, 0xff, 0x1f, 0x20, 0x9b, 0xb8, - 0x8a, 0xc8, 0x52, 0xca, 0x6e, 0x64, 0x92, 0xa3, 0x60, 0x64, 0xd6, 0x4d, 0x8f, 0xcc, 0x3a, 0xdb, - 0x83, 0xe5, 0x73, 0x81, 0x7f, 0x9a, 0xdf, 0xaa, 0x1e, 0xc7, 0xc2, 0x7c, 0x03, 0x66, 0x55, 0x0f, - 0x65, 0x40, 0x75, 0x6f, 0x26, 0x11, 0xf8, 0x48, 0xb3, 0x76, 0x79, 0x73, 0x63, 0xb1, 0x4f, 0x03, - 0x61, 0x4d, 0x6f, 0xd7, 0x76, 0xea, 0xde, 0xd2, 0xa0, 0x34, 0x3f, 0x0a, 0x84, 0xfd, 0x33, 0x68, - 0x56, 0x00, 0xcd, 0x25, 0x98, 0x2e, 0xb0, 0xa6, 0x69, 0x60, 0xde, 0x83, 0x8d, 0x12, 0x68, 0x94, - 0x86, 0x53, 0xc4, 0x86, 0x77, 0xa3, 0x50, 0x18, 0x61, 0x62, 0x61, 0x3f, 0x86, 0xf5, 0xa3, 0xb2, - 0xe9, 0x0b, 0x92, 0x1f, 0xd9, 0xa1, 0x31, 0x3a, 0xcd, 0x37, 0xa1, 0x51, 0xfc, 0x62, 0xd1, 0xbb, - 0xaf, 0x7b, 0xa5, 0xc0, 0xee, 0xc3, 0xca, 0xb9, 0xc0, 0xa7, 0x24, 0x0a, 0x4a, 0xb0, 0x6b, 0x0e, - 0xe0, 0x60, 0x1c, 0x68, 0xe2, 0xeb, 0x6f, 0xe9, 0x8e, 0xc1, 0xc6, 0x39, 0x0a, 0x69, 0x80, 0x24, - 0xe3, 0xa7, 0x44, 0xa6, 0x03, 0xf8, 0x04, 0xe1, 0x0b, 0x22, 0x85, 0xe9, 0x41, 0x3d, 0xa4, 0x42, - 0x66, 0x95, 0x75, 0xf7, 0xda, 0xca, 0x4a, 0x76, 0x9d, 0xeb, 0x40, 0x0e, 0x91, 0x44, 0x59, 0xef, - 0x6a, 0x2c, 0xfb, 0xbb, 0xb0, 0xf6, 0x31, 0x92, 0x03, 0x4e, 0x82, 0x91, 0x1c, 0xaf, 0x40, 0x4d, - 0xe5, 0xcf, 0xd0, 0xf9, 0x53, 0x8f, 0xea, 0x3e, 0x60, 0xdd, 0xff, 0x34, 0x66, 0x5c, 0x92, 0xe0, - 0xd2, 0x89, 0xbc, 0xe2, 0x78, 0x2f, 0x60, 0x4d, 0x1d, 0x96, 0x20, 0x51, 0xe0, 0x17, 0xfb, 0x4c, - 0xf3, 0xd8, 0xdc, 0xfb, 0xf1, 0x44, 0xdd, 0x31, 0xee, 0x2e, 0xdb, 0xc0, 0x6a, 0x32, 0x26, 0x17, - 0xf6, 0x6f, 0x0c, 0xb0, 0x8e, 0xc9, 0x70, 0x5f, 0x08, 0xda, 0x8d, 0xfa, 0x24, 0x92, 0x8a, 0x03, - 0x11, 0x26, 0xea, 0xd1, 0x7c, 0x0b, 0x16, 0x8b, 0x99, 0xab, 0x47, 0xad, 0xa1, 0x47, 0xed, 0x42, - 0x2e, 0x54, 0x0d, 0x66, 0xde, 0x03, 0x88, 0x39, 0x49, 0x7c, 0xec, 0x5f, 0x90, 0x61, 0x96, 0xc5, - 0xcd, 0xea, 0x08, 0x4d, 0x7f, 0x4f, 0x3a, 0x27, 0x83, 0x4e, 0x48, 0xf1, 0x31, 0x19, 0x7a, 0xf3, - 0x4a, 0xbf, 0x7d, 0x4c, 0x86, 0xea, 0x4e, 0x14, 0xb3, 0xe7, 0x84, 0xeb, 0xb9, 0x57, 0xf3, 0xd2, - 0x17, 0xfb, 0xb7, 0x06, 0xdc, 0x28, 0xd2, 0x91, 0x97, 0xeb, 0xc9, 0xa0, 0xa3, 0x2c, 0x5e, 0x71, - 0x6e, 0x97, 0xa2, 0x9d, 0xbe, 0x22, 0xda, 0xf7, 0x61, 0xa1, 0x68, 0x10, 0x15, 0x6f, 0x6d, 0x82, - 0x78, 0x9b, 0xb9, 0xc5, 0x31, 0x19, 0xda, 0xbf, 0xac, 0xc4, 0x76, 0x30, 0xac, 0x70, 0x1f, 0xff, - 0x0f, 0xb1, 0x15, 0x6e, 0xab, 0xb1, 0xe1, 0xaa, 0xfd, 0xa5, 0x0d, 0xd4, 0x2e, 0x6f, 0xc0, 0xfe, - 0xbd, 0x01, 0xeb, 0x55, 0xaf, 0xe2, 0x8c, 0x9d, 0xf0, 0x41, 0x44, 0x5e, 0xe5, 0xbd, 0x6c, 0xbf, - 0xe9, 0x6a, 0xfb, 0x3d, 0x81, 0xa5, 0x91, 0xa0, 0x44, 0x76, 0x1a, 0x3f, 0x9c, 0xa8, 0xc6, 0x2a, - 0xec, 0xea, 0x2d, 0x56, 0xf7, 0x21, 0xec, 0x3f, 0x1a, 0xb0, 0x9a, 0xc7, 0x58, 0x1c, 0x96, 0xf9, - 0x03, 0x30, 0x8b, 0xed, 0x95, 0xb7, 0xb7, 0xb4, 0xa4, 0x56, 0xf2, 0x95, 0xfc, 0xea, 0x56, 0x96, - 0xc6, 0x74, 0xa5, 0x34, 0xcc, 0x8f, 0x60, 0xad, 0x08, 0x39, 0xd6, 0x09, 0x9a, 0x38, 0x8b, 0xc5, - 0xfd, 0xb4, 0x10, 0xd9, 0xbf, 0x36, 0xca, 0x71, 0x98, 0xce, 0x63, 0xb1, 0x1f, 0x86, 0xd9, 0xa5, - 0xde, 0x8c, 0x61, 0x2e, 0x1d, 0xf9, 0x22, 0xe3, 0x8f, 0xcd, 0x2b, 0x87, 0xfb, 0x21, 0xc1, 0x7a, - 0xbe, 0xdf, 0x55, 0x2d, 0xf6, 0xe7, 0x6f, 0xb6, 0x6e, 0x77, 0xa9, 0xec, 0x0d, 0x3a, 0x0e, 0x66, - 0x7d, 0x37, 0xfb, 0x1e, 0x92, 0xfe, 0xbb, 0x23, 0x82, 0x0b, 0x57, 0x0e, 0x63, 0x22, 0x72, 0x1b, - 0xf1, 0xa7, 0x7f, 0xfc, 0xf5, 0xfb, 0x86, 0x97, 0xbb, 0x39, 0x78, 0xf2, 0xe5, 0x8b, 0x96, 0xf1, - 0xd5, 0x8b, 0x96, 0xf1, 0xf7, 0x17, 0x2d, 0xe3, 0xb3, 0x97, 0xad, 0xa9, 0xaf, 0x5e, 0xb6, 0xa6, - 0xfe, 0xf6, 0xb2, 0x35, 0xf5, 0xf3, 0xf7, 0x2e, 0x83, 0x96, 0x39, 0xba, 0x53, 0x7c, 0x81, 0x4a, - 0x7e, 0xe4, 0x7e, 0x3a, 0xfa, 0x7d, 0x4b, 0xfb, 0xeb, 0xcc, 0x6a, 0x36, 0x7d, 0xf7, 0xdf, 0x01, - 0x00, 0x00, 0xff, 0xff, 0x8f, 0xff, 0x87, 0xe4, 0x10, 0x13, 0x00, 0x00, + // 1919 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0x4f, 0x6f, 0x1b, 0xc7, + 0x15, 0xd7, 0x8a, 0x94, 0x45, 0x0e, 0xf5, 0x77, 0xa4, 0xc4, 0x2b, 0x55, 0xa5, 0xe8, 0x4d, 0x93, + 0xaa, 0x71, 0xbd, 0x1b, 0x29, 0x2d, 0x60, 0x18, 0x0d, 0x02, 0x89, 0x72, 0x62, 0x59, 0x89, 0xcd, + 0xac, 0x54, 0x19, 0x6d, 0x0f, 0x8b, 0xe1, 0xec, 0x98, 0x1c, 0x68, 0xb9, 0xb3, 0x9e, 0x19, 0xae, + 0xc2, 0x4b, 0xcf, 0x3d, 0xb4, 0x40, 0x7a, 0x0b, 0x7a, 0x69, 0x5a, 0xa0, 0x40, 0xd1, 0x4b, 0xfb, + 0x31, 0x72, 0xcc, 0xb1, 0xa7, 0xa4, 0xb0, 0x0f, 0x3d, 0xf4, 0x4b, 0x14, 0x33, 0xfb, 0x97, 0x94, + 0xe4, 0xd2, 0x48, 0x73, 0x91, 0x76, 0xdf, 0xbc, 0xf7, 0x7b, 0x6f, 0xe6, 0xbd, 0x79, 0xbf, 0xc7, + 0x05, 0x7b, 0x34, 0x94, 0x84, 0xe3, 0x3e, 0xa2, 0xa1, 0x27, 0x08, 0x1e, 0x72, 0x2a, 0x47, 0x0e, + 0xc6, 0xb1, 0x13, 0x71, 0x16, 0x53, 0x9f, 0x70, 0x27, 0xde, 0xcd, 0x9f, 0xed, 0x88, 0x33, 0xc9, + 0xe0, 0x1b, 0x57, 0xd8, 0xd8, 0x18, 0xc7, 0x76, 0xae, 0x17, 0xef, 0x6e, 0xbe, 0x79, 0x1d, 0x70, + 0xbc, 0xeb, 0x5c, 0x50, 0x4e, 0x12, 0xac, 0xcd, 0xf5, 0x1e, 0xeb, 0x31, 0xfd, 0xe8, 0xa8, 0xa7, + 0x54, 0xba, 0xdd, 0x63, 0xac, 0x17, 0x10, 0x47, 0xbf, 0x75, 0x87, 0x4f, 0x1d, 0x49, 0x07, 0x44, + 0x48, 0x34, 0x88, 0x52, 0x85, 0xe6, 0xa4, 0x82, 0x3f, 0xe4, 0x48, 0x52, 0x16, 0x66, 0x00, 0xb4, + 0x8b, 0x1d, 0xcc, 0x38, 0x71, 0x70, 0x40, 0x49, 0x28, 0x95, 0xd7, 0xe4, 0x29, 0x55, 0x70, 0x94, + 0x42, 0x40, 0x7b, 0x7d, 0x99, 0x88, 0x85, 0x23, 0x49, 0xe8, 0x13, 0x3e, 0xa0, 0x89, 0x72, 0xf1, + 0x96, 0x1a, 0x6c, 0x95, 0xd6, 0x31, 0x1f, 0x45, 0x92, 0x39, 0xe7, 0x64, 0x24, 0xd2, 0xd5, 0xb7, + 0x30, 0x13, 0x03, 0x26, 0x1c, 0xa2, 0xf6, 0x1f, 0x62, 0xe2, 0xc4, 0xbb, 0x5d, 0x22, 0xd1, 0x6e, + 0x2e, 0xc8, 0xe2, 0x4e, 0xf5, 0xba, 0x48, 0x14, 0x3a, 0x98, 0xd1, 0x2c, 0xee, 0x55, 0x34, 0xa0, + 0x21, 0x73, 0xf4, 0xdf, 0x44, 0x64, 0xfd, 0xb6, 0x06, 0xcc, 0x36, 0x0b, 0xc5, 0x70, 0x40, 0xf8, + 0xbe, 0xef, 0x53, 0xb5, 0xcb, 0x0e, 0x67, 0x11, 0x13, 0x28, 0x80, 0xeb, 0x60, 0x4e, 0x52, 0x19, + 0x10, 0xd3, 0x68, 0x19, 0x3b, 0x75, 0x37, 0x79, 0x81, 0x2d, 0xd0, 0xf0, 0x89, 0xc0, 0x9c, 0x46, + 0x4a, 0xd9, 0x9c, 0xd5, 0x6b, 0x65, 0x11, 0xdc, 0x00, 0xb5, 0x24, 0x35, 0xd4, 0x37, 0x2b, 0x7a, + 0x79, 0x5e, 0xbf, 0x1f, 0xf9, 0xf0, 0x43, 0xb0, 0x44, 0x43, 0x2a, 0x29, 0x0a, 0xbc, 0x3e, 0x51, + 0x07, 0x64, 0x56, 0x5b, 0xc6, 0x4e, 0x63, 0x6f, 0xd3, 0xa6, 0x5d, 0x6c, 0xab, 0x33, 0xb5, 0xd3, + 0x93, 0x8c, 0x77, 0xed, 0x07, 0x5a, 0xe3, 0xa0, 0xfa, 0xe5, 0xd7, 0xdb, 0x33, 0xee, 0x62, 0x6a, + 0x97, 0x08, 0xe1, 0x2d, 0xb0, 0xd0, 0x23, 0x21, 0x11, 0x54, 0x78, 0x7d, 0x24, 0xfa, 0xe6, 0x5c, + 0xcb, 0xd8, 0x59, 0x70, 0x1b, 0xa9, 0xec, 0x01, 0x12, 0x7d, 0xb8, 0x0d, 0x1a, 0x5d, 0x1a, 0x22, + 0x3e, 0x4a, 0x34, 0x6e, 0x68, 0x0d, 0x90, 0x88, 0xb4, 0x42, 0x1b, 0x00, 0x11, 0xa1, 0x8b, 0xd0, + 0x53, 0x05, 0x60, 0xce, 0xa7, 0x81, 0x24, 0xc9, 0xb7, 0xb3, 0xe4, 0xdb, 0xa7, 0x59, 0x75, 0x1c, + 0xd4, 0x54, 0x20, 0x9f, 0x7d, 0xb3, 0x6d, 0xb8, 0x75, 0x6d, 0xa7, 0x56, 0xe0, 0x23, 0xb0, 0x32, + 0x0c, 0xbb, 0x2c, 0xf4, 0x69, 0xd8, 0xf3, 0x22, 0xc2, 0x29, 0xf3, 0xcd, 0x9a, 0x86, 0xda, 0xb8, + 0x04, 0x75, 0x98, 0xd6, 0x51, 0x82, 0xf4, 0xb9, 0x42, 0x5a, 0xce, 0x8d, 0x3b, 0xda, 0x16, 0x7e, + 0x02, 0x20, 0xc6, 0xb1, 0x0e, 0x89, 0x0d, 0x65, 0x86, 0x58, 0x9f, 0x1e, 0x71, 0x05, 0xe3, 0xf8, + 0x34, 0xb1, 0x4e, 0x21, 0x7f, 0x05, 0x6e, 0x4a, 0x8e, 0x42, 0xf1, 0x94, 0xf0, 0x49, 0x5c, 0x30, + 0x3d, 0xee, 0x6b, 0x19, 0xc6, 0x38, 0xf8, 0x03, 0xd0, 0xc2, 0x69, 0x01, 0x79, 0x9c, 0xf8, 0x54, + 0x48, 0x4e, 0xbb, 0x43, 0x65, 0xeb, 0x3d, 0xe5, 0x08, 0xeb, 0x1a, 0x69, 0xe8, 0x22, 0x68, 0x66, + 0x7a, 0xee, 0x98, 0xda, 0x07, 0xa9, 0x16, 0x7c, 0x0c, 0x7e, 0xd0, 0x0d, 0x18, 0x3e, 0x17, 0x2a, + 0x38, 0x6f, 0x0c, 0x49, 0xbb, 0x1e, 0x50, 0x21, 0x14, 0xda, 0x42, 0xcb, 0xd8, 0xa9, 0xb8, 0xb7, + 0x12, 0xdd, 0x0e, 0xe1, 0x87, 0x25, 0xcd, 0xd3, 0x92, 0x22, 0xbc, 0x03, 0x60, 0x9f, 0x0a, 0xc9, + 0x38, 0xc5, 0x28, 0xf0, 0x48, 0x28, 0x39, 0x25, 0xc2, 0x5c, 0xd4, 0xe6, 0xab, 0xc5, 0xca, 0xfd, + 0x64, 0x01, 0x3e, 0x04, 0xb7, 0xae, 0x75, 0xea, 0xe1, 0x3e, 0x0a, 0x43, 0x12, 0x98, 0x4b, 0x7a, + 0x2b, 0xdb, 0xfe, 0x35, 0x3e, 0xdb, 0x89, 0x1a, 0x5c, 0x03, 0x73, 0x92, 0x45, 0xde, 0x23, 0x73, + 0xb9, 0x65, 0xec, 0x2c, 0xba, 0x55, 0xc9, 0xa2, 0x47, 0xf0, 0x1d, 0xb0, 0x1e, 0xa3, 0x80, 0xfa, + 0x48, 0x32, 0x2e, 0xbc, 0x88, 0x5d, 0x10, 0xee, 0x61, 0x14, 0x99, 0x2b, 0x5a, 0x07, 0x16, 0x6b, + 0x1d, 0xb5, 0xd4, 0x46, 0x11, 0x7c, 0x1b, 0xac, 0xe6, 0x52, 0x4f, 0x10, 0xa9, 0xd5, 0x57, 0xb5, + 0xfa, 0x72, 0xbe, 0x70, 0x42, 0xa4, 0xd2, 0xdd, 0x02, 0x75, 0x14, 0x04, 0xec, 0x22, 0xa0, 0x42, + 0x9a, 0xb0, 0x55, 0xd9, 0xa9, 0xbb, 0x85, 0x00, 0x6e, 0x82, 0x9a, 0x4f, 0xc2, 0x91, 0x5e, 0x5c, + 0xd3, 0x8b, 0xf9, 0xfb, 0xbd, 0xda, 0x6f, 0xbe, 0xd8, 0x9e, 0xf9, 0xfc, 0x8b, 0xed, 0x19, 0xeb, + 0xef, 0x06, 0xb8, 0xd9, 0xce, 0xb3, 0x34, 0x60, 0x31, 0x0a, 0xbe, 0xcb, 0x6e, 0xb0, 0x0f, 0xea, + 0x42, 0x1d, 0x93, 0xbe, 0x7f, 0xd5, 0x57, 0xb8, 0x7f, 0x35, 0x65, 0xa6, 0x16, 0xac, 0x3f, 0x1a, + 0x60, 0xfd, 0xfe, 0xb3, 0x21, 0x8d, 0x19, 0x46, 0xff, 0x97, 0xe6, 0x75, 0x0c, 0x16, 0x49, 0x09, + 0x4f, 0x98, 0x95, 0x56, 0x65, 0xa7, 0xb1, 0xf7, 0xa6, 0x9d, 0x34, 0x57, 0x3b, 0xef, 0xb9, 0x69, + 0x83, 0xb5, 0xcb, 0xde, 0xdd, 0x71, 0xdb, 0x7b, 0xb3, 0xa6, 0x61, 0xfd, 0xd9, 0x00, 0x9b, 0xaa, + 0x2c, 0x7a, 0xc4, 0x25, 0x17, 0x88, 0xfb, 0x87, 0x24, 0x64, 0x03, 0xf1, 0xad, 0xe3, 0xb4, 0xc0, + 0xa2, 0xaf, 0x91, 0x3c, 0xc9, 0x3c, 0xe4, 0xfb, 0x3a, 0x4e, 0xad, 0xa3, 0x84, 0xa7, 0x6c, 0xdf, + 0xf7, 0xe1, 0x0e, 0x58, 0x29, 0x74, 0xb8, 0xca, 0xa7, 0x3a, 0x66, 0xa5, 0xb6, 0x94, 0xa9, 0xe9, + 0x2c, 0x13, 0xeb, 0x3f, 0x06, 0x58, 0xf9, 0x30, 0x60, 0x5d, 0x14, 0x9c, 0x04, 0x48, 0xf4, 0xd5, + 0x95, 0x18, 0xa9, 0xf4, 0x70, 0x92, 0xf6, 0x22, 0x1d, 0xde, 0xd4, 0xe9, 0x51, 0x66, 0xba, 0x3b, + 0xbe, 0x0f, 0x56, 0xf3, 0xee, 0x90, 0x57, 0x81, 0xde, 0xcd, 0xc1, 0xda, 0xf3, 0xaf, 0xb7, 0x97, + 0xb3, 0x62, 0x6b, 0xeb, 0x8a, 0x38, 0x74, 0x97, 0xf1, 0x98, 0xc0, 0x87, 0x4d, 0xd0, 0xa0, 0x5d, + 0xec, 0x09, 0xf2, 0xcc, 0x0b, 0x87, 0x03, 0x5d, 0x40, 0x55, 0xb7, 0x4e, 0xbb, 0xf8, 0x84, 0x3c, + 0x7b, 0x34, 0x1c, 0xc0, 0x77, 0xc1, 0xeb, 0xd9, 0x60, 0xe0, 0xc5, 0x28, 0xf0, 0x94, 0xbd, 0x3a, + 0x0e, 0xae, 0xeb, 0x69, 0xc1, 0x5d, 0xcb, 0x56, 0xcf, 0x50, 0xa0, 0x9c, 0xed, 0xfb, 0x3e, 0xb7, + 0x5e, 0xcc, 0x81, 0x1b, 0x1d, 0xc4, 0xd1, 0x40, 0xc0, 0x53, 0xb0, 0x2c, 0xc9, 0x20, 0x0a, 0x90, + 0x24, 0x5e, 0xc2, 0x3c, 0xe9, 0x4e, 0x6f, 0x6b, 0x46, 0x2a, 0x93, 0xb8, 0x5d, 0xa2, 0xed, 0x78, + 0xd7, 0x6e, 0x6b, 0xe9, 0x89, 0x44, 0x92, 0xb8, 0x4b, 0x19, 0x46, 0x22, 0x84, 0x77, 0x81, 0x29, + 0xf9, 0x50, 0xc8, 0x82, 0x13, 0x8a, 0x66, 0x98, 0xe4, 0xf2, 0xf5, 0x6c, 0x3d, 0x69, 0xa3, 0x79, + 0x13, 0xbc, 0xba, 0xfd, 0x57, 0xbe, 0x4d, 0xfb, 0x3f, 0x01, 0x6b, 0x8a, 0x3b, 0x27, 0x31, 0xab, + 0xd3, 0x63, 0xae, 0x2a, 0xfb, 0x71, 0xd0, 0x4f, 0x00, 0x8c, 0x05, 0x9e, 0xc4, 0x9c, 0x7b, 0x85, + 0x38, 0x63, 0x81, 0xc7, 0x21, 0x7d, 0xb0, 0x25, 0x54, 0xf1, 0x79, 0x03, 0x22, 0x35, 0x99, 0x44, + 0x01, 0x09, 0xa9, 0xe8, 0x67, 0xe0, 0x37, 0xa6, 0x07, 0xdf, 0xd0, 0x40, 0x1f, 0x2b, 0x1c, 0x37, + 0x83, 0x49, 0xbd, 0xb4, 0x41, 0xf3, 0x6a, 0x2f, 0x79, 0x82, 0xe6, 0x75, 0x82, 0xbe, 0x77, 0x05, + 0x44, 0x9e, 0x25, 0x01, 0xde, 0x2a, 0x91, 0x9e, 0xba, 0xd5, 0x9e, 0xbe, 0x50, 0x1e, 0x27, 0x3d, + 0xc5, 0x0c, 0x28, 0xe1, 0x3f, 0x42, 0x72, 0xe2, 0x4e, 0xbb, 0x87, 0x1a, 0xcd, 0xf2, 0xce, 0xd1, + 0x66, 0x34, 0x4c, 0xa7, 0x1b, 0xab, 0xe0, 0xc6, 0xbc, 0x47, 0xb8, 0x25, 0xac, 0x0f, 0x08, 0x51, + 0xb7, 0xb9, 0xc4, 0x8f, 0x24, 0x62, 0xb8, 0xaf, 0xf9, 0xbb, 0xe2, 0x2e, 0xe5, 0x5c, 0x78, 0x5f, + 0x49, 0x1f, 0x56, 0x6b, 0xb5, 0x95, 0xba, 0xf5, 0x23, 0x50, 0xd7, 0x97, 0x79, 0x1f, 0x9f, 0x0b, + 0xcd, 0x0e, 0xbe, 0xcf, 0x89, 0x10, 0x44, 0x98, 0x46, 0xca, 0x0e, 0x99, 0xc0, 0x92, 0x60, 0xe3, + 0xba, 0x29, 0x50, 0xc0, 0x27, 0x60, 0x3e, 0x22, 0x7a, 0x44, 0xd1, 0x86, 0x8d, 0xbd, 0xf7, 0xec, + 0x29, 0x66, 0x74, 0xfb, 0x3a, 0x40, 0x37, 0x43, 0xb3, 0x78, 0x31, 0x7b, 0x4e, 0x90, 0x8d, 0x80, + 0x67, 0x93, 0x4e, 0x7f, 0xf6, 0x4a, 0x4e, 0x27, 0xf0, 0x0a, 0x9f, 0xb7, 0x41, 0x63, 0x3f, 0xd9, + 0xf6, 0x47, 0x8a, 0x16, 0x2f, 0x1d, 0xcb, 0x42, 0xf9, 0x58, 0x1e, 0x82, 0xa5, 0x94, 0xd0, 0x4f, + 0x99, 0x6e, 0x48, 0xf0, 0xfb, 0x00, 0xa4, 0x93, 0x80, 0x6a, 0x64, 0x49, 0xcb, 0xae, 0xa7, 0x92, + 0x23, 0x7f, 0x8c, 0xeb, 0x66, 0xc7, 0xb8, 0xce, 0x72, 0xc1, 0xf2, 0x99, 0xc0, 0x3f, 0xcf, 0xa6, + 0xbd, 0xc7, 0x91, 0x80, 0xaf, 0x81, 0x1b, 0xea, 0x0e, 0xa5, 0x40, 0x55, 0x77, 0x2e, 0x16, 0xf8, + 0x48, 0x77, 0xed, 0x62, 0xa2, 0x64, 0x91, 0x47, 0x7d, 0x61, 0xce, 0xb6, 0x2a, 0x3b, 0x55, 0x77, + 0x69, 0x58, 0x98, 0x1f, 0xf9, 0xc2, 0xfa, 0x05, 0x68, 0x94, 0x00, 0xe1, 0x12, 0x98, 0xcd, 0xb1, + 0x66, 0xa9, 0x0f, 0xef, 0x81, 0x8d, 0x02, 0x68, 0xbc, 0x0d, 0x27, 0x88, 0x75, 0xf7, 0x66, 0xae, + 0x30, 0xd6, 0x89, 0x85, 0xf5, 0x18, 0xac, 0x1f, 0x15, 0x97, 0x3e, 0x6f, 0xf2, 0x63, 0x3b, 0x34, + 0xc6, 0xd9, 0x7c, 0x0b, 0xd4, 0xf3, 0x5f, 0x52, 0x7a, 0xf7, 0x55, 0xb7, 0x10, 0x58, 0x03, 0xb0, + 0x72, 0x26, 0xf0, 0x09, 0x09, 0xfd, 0x02, 0xec, 0x9a, 0x03, 0x38, 0x98, 0x04, 0x9a, 0x7a, 0x2c, + 0x2f, 0xdc, 0x31, 0xb0, 0x71, 0x56, 0x1e, 0x90, 0x34, 0x01, 0x77, 0x10, 0x3e, 0x27, 0x52, 0x40, + 0x17, 0x54, 0xf5, 0x20, 0x94, 0x54, 0xd6, 0xdd, 0x6b, 0x2b, 0x2b, 0xde, 0xb5, 0xaf, 0x03, 0x39, + 0x44, 0x12, 0xa5, 0x77, 0x57, 0x63, 0x59, 0x3f, 0x04, 0x6b, 0x1f, 0x23, 0x39, 0xe4, 0xc4, 0x1f, + 0xcb, 0xf1, 0x0a, 0xa8, 0xa8, 0xfc, 0x19, 0x3a, 0x7f, 0xea, 0x51, 0xcd, 0x03, 0xe6, 0xfd, 0x4f, + 0x23, 0xc6, 0x25, 0xf1, 0x2f, 0x9d, 0xc8, 0x4b, 0x8e, 0xf7, 0x1c, 0xac, 0xa9, 0xc3, 0x12, 0x24, + 0xf4, 0xbd, 0x7c, 0x9f, 0x49, 0x1e, 0x1b, 0x7b, 0x3f, 0x9d, 0xea, 0x76, 0x4c, 0xba, 0x4b, 0x37, + 0xb0, 0x1a, 0x4f, 0xc8, 0x85, 0xf5, 0x7b, 0x03, 0x98, 0xc7, 0x64, 0xb4, 0x2f, 0x04, 0xed, 0x85, + 0x03, 0x12, 0x4a, 0xd5, 0x03, 0x11, 0x26, 0xea, 0x11, 0xbe, 0x01, 0x16, 0x73, 0xce, 0xd5, 0x54, + 0x6b, 0x68, 0xaa, 0x5d, 0xc8, 0x84, 0xea, 0x82, 0xc1, 0x7b, 0x00, 0x44, 0x9c, 0xc4, 0x1e, 0xf6, + 0xce, 0xc9, 0x28, 0xcd, 0xe2, 0x56, 0x99, 0x42, 0x93, 0xdf, 0xb9, 0x76, 0x67, 0xd8, 0x0d, 0x28, + 0x3e, 0x26, 0x23, 0xb7, 0xa6, 0xf4, 0xdb, 0xc7, 0x64, 0xa4, 0x66, 0x22, 0x3d, 0x1d, 0x6b, 0xde, + 0xab, 0xb8, 0xc9, 0x8b, 0xf5, 0x07, 0x03, 0xdc, 0xcc, 0xd3, 0x91, 0x95, 0x6b, 0x67, 0xd8, 0x55, + 0x16, 0x2f, 0x39, 0xb7, 0x4b, 0xd1, 0xce, 0x5e, 0x11, 0xed, 0xfb, 0x60, 0x21, 0xbf, 0x20, 0x2a, + 0xde, 0xca, 0x14, 0xf1, 0x36, 0x32, 0x8b, 0x63, 0x32, 0xb2, 0x7e, 0x5d, 0x8a, 0xed, 0x60, 0x54, + 0xea, 0x7d, 0xfc, 0x7f, 0xc4, 0x96, 0xbb, 0x2d, 0xc7, 0x86, 0xcb, 0xf6, 0x97, 0x36, 0x50, 0xb9, + 0xbc, 0x01, 0xeb, 0x4f, 0x06, 0x58, 0x2f, 0x7b, 0x15, 0xa7, 0xac, 0xc3, 0x87, 0x21, 0x79, 0x99, + 0xf7, 0xe2, 0xfa, 0xcd, 0x96, 0xaf, 0xdf, 0x13, 0xb0, 0x34, 0x16, 0x94, 0x48, 0x4f, 0xe3, 0x9d, + 0xa9, 0x6a, 0xac, 0xd4, 0x5d, 0xdd, 0xc5, 0xf2, 0x3e, 0x84, 0xf5, 0x17, 0x03, 0xac, 0x66, 0x31, + 0xe6, 0x87, 0x05, 0x7f, 0x0c, 0x60, 0xbe, 0xbd, 0x62, 0x7a, 0x4b, 0x4a, 0x6a, 0x25, 0x5b, 0xc9, + 0x46, 0xb7, 0xa2, 0x34, 0x66, 0x4b, 0xa5, 0x01, 0x3f, 0x02, 0x6b, 0x79, 0xc8, 0x91, 0x4e, 0xd0, + 0xd4, 0x59, 0xcc, 0xe7, 0xd3, 0x5c, 0x64, 0xfd, 0xce, 0x28, 0xe8, 0x30, 0xe1, 0x63, 0xb1, 0x1f, + 0x04, 0xe9, 0x50, 0x0f, 0x23, 0x30, 0x9f, 0x50, 0xbe, 0x48, 0xfb, 0xc7, 0xd6, 0x95, 0xe4, 0x7e, + 0x48, 0xb0, 0xe6, 0xf7, 0xbb, 0xea, 0x8a, 0xfd, 0xed, 0x9b, 0xed, 0xdb, 0x3d, 0x2a, 0xfb, 0xc3, + 0xae, 0x8d, 0xd9, 0xc0, 0x49, 0xbf, 0xd3, 0x24, 0xff, 0xee, 0x08, 0xff, 0xdc, 0x91, 0xa3, 0x88, + 0x88, 0xcc, 0x46, 0xfc, 0xf5, 0xdf, 0xff, 0x78, 0xdb, 0x70, 0x33, 0x37, 0x07, 0x4f, 0xbe, 0x7c, + 0xde, 0x34, 0xbe, 0x7a, 0xde, 0x34, 0xfe, 0xf5, 0xbc, 0x69, 0x7c, 0xf6, 0xa2, 0x39, 0xf3, 0xd5, + 0x8b, 0xe6, 0xcc, 0x3f, 0x5f, 0x34, 0x67, 0x7e, 0xf9, 0xde, 0x65, 0xd0, 0x22, 0x47, 0x77, 0xf2, + 0x2f, 0x63, 0xf1, 0x4f, 0x9c, 0x4f, 0xc7, 0xbf, 0xbb, 0x69, 0x7f, 0xdd, 0x1b, 0xba, 0x9b, 0xbe, + 0xfb, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x6d, 0xb7, 0x45, 0x0f, 0xa8, 0x13, 0x00, 0x00, } func (m *ConsumerAdditionProposal) Marshal() (dAtA []byte, err error) { @@ -1684,6 +1702,42 @@ func (m *ConsumerAdditionProposal) MarshalToSizedBuffer(dAtA []byte) (int, error _ = i var l int _ = l + if len(m.Denylist) > 0 { + for iNdEx := len(m.Denylist) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Denylist[iNdEx]) + copy(dAtA[i:], m.Denylist[iNdEx]) + i = encodeVarintProvider(dAtA, i, uint64(len(m.Denylist[iNdEx]))) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x9a + } + } + if len(m.Allowlist) > 0 { + for iNdEx := len(m.Allowlist) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Allowlist[iNdEx]) + copy(dAtA[i:], m.Allowlist[iNdEx]) + i = encodeVarintProvider(dAtA, i, uint64(len(m.Allowlist[iNdEx]))) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x92 + } + } + if m.ValidatorSetCap != 0 { + i = encodeVarintProvider(dAtA, i, uint64(m.ValidatorSetCap)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x88 + } + if m.ValidatorsPowerCap != 0 { + i = encodeVarintProvider(dAtA, i, uint64(m.ValidatorsPowerCap)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x80 + } if m.Top_N != 0 { i = encodeVarintProvider(dAtA, i, uint64(m.Top_N)) i-- @@ -2883,6 +2937,24 @@ func (m *ConsumerAdditionProposal) Size() (n int) { if m.Top_N != 0 { n += 1 + sovProvider(uint64(m.Top_N)) } + if m.ValidatorsPowerCap != 0 { + n += 2 + sovProvider(uint64(m.ValidatorsPowerCap)) + } + if m.ValidatorSetCap != 0 { + n += 2 + sovProvider(uint64(m.ValidatorSetCap)) + } + if len(m.Allowlist) > 0 { + for _, s := range m.Allowlist { + l = len(s) + n += 2 + l + sovProvider(uint64(l)) + } + } + if len(m.Denylist) > 0 { + for _, s := range m.Denylist { + l = len(s) + n += 2 + l + sovProvider(uint64(l)) + } + } return n } @@ -3813,6 +3885,108 @@ func (m *ConsumerAdditionProposal) Unmarshal(dAtA []byte) error { break } } + case 16: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorsPowerCap", wireType) + } + m.ValidatorsPowerCap = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProvider + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ValidatorsPowerCap |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 17: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorSetCap", wireType) + } + m.ValidatorSetCap = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProvider + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ValidatorSetCap |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 18: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Allowlist", 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.Allowlist = append(m.Allowlist, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 19: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denylist", 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.Denylist = append(m.Denylist, 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 49c580244a..dbca4d229d 100644 --- a/x/ccv/provider/types/query.pb.go +++ b/x/ccv/provider/types/query.pb.go @@ -1586,121 +1586,122 @@ func init() { } var fileDescriptor_422512d7b7586cd7 = []byte{ - // 1811 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0xdb, 0x6f, 0xdc, 0x4e, - 0x15, 0x8e, 0x93, 0x34, 0x24, 0x93, 0xde, 0x98, 0x96, 0x36, 0x75, 0xd2, 0xdd, 0xd4, 0x85, 0x92, - 0xde, 0xec, 0x64, 0x4b, 0xd5, 0x6b, 0x9a, 0x66, 0xb3, 0x49, 0xba, 0x4a, 0xdb, 0x6c, 0xdd, 0x34, - 0x48, 0x80, 0x70, 0x1d, 0x7b, 0xba, 0xb1, 0xea, 0xf5, 0x38, 0x1e, 0xef, 0xb6, 0xab, 0x0a, 0x89, - 0xf2, 0x40, 0x2b, 0x21, 0x41, 0x25, 0xe0, 0xbd, 0x12, 0xe2, 0x1f, 0x40, 0xfc, 0x11, 0x7d, 0xa3, - 0xd0, 0x17, 0xc4, 0x43, 0x40, 0x29, 0x0f, 0x88, 0x27, 0x54, 0x21, 0xf1, 0x84, 0xf4, 0x93, 0xc7, - 0x63, 0x7b, 0xbd, 0xeb, 0xec, 0x7a, 0x37, 0xf9, 0x3d, 0x25, 0x3b, 0x97, 0xef, 0x9c, 0xef, 0xcc, - 0x39, 0x67, 0xe6, 0x33, 0x90, 0x0c, 0xcb, 0x45, 0x8e, 0xb6, 0xa9, 0x1a, 0x96, 0x42, 0x90, 0x56, - 0x75, 0x0c, 0xb7, 0x2e, 0x69, 0x5a, 0x4d, 0xb2, 0x1d, 0x5c, 0x33, 0x74, 0xe4, 0x48, 0xb5, 0x19, - 0x69, 0xab, 0x8a, 0x9c, 0xba, 0x68, 0x3b, 0xd8, 0xc5, 0xf0, 0x6c, 0xc2, 0x06, 0x51, 0xd3, 0x6a, - 0x62, 0xb0, 0x41, 0xac, 0xcd, 0xf0, 0x13, 0x65, 0x8c, 0xcb, 0x26, 0x92, 0x54, 0xdb, 0x90, 0x54, - 0xcb, 0xc2, 0xae, 0xea, 0x1a, 0xd8, 0x22, 0x3e, 0x04, 0x7f, 0xbc, 0x8c, 0xcb, 0x98, 0xfe, 0x2b, - 0x79, 0xff, 0xb1, 0xd1, 0x2c, 0xdb, 0x43, 0x7f, 0x6d, 0x54, 0x9f, 0x49, 0xae, 0x51, 0x41, 0xc4, - 0x55, 0x2b, 0x36, 0x5b, 0x90, 0x4b, 0xe3, 0x6a, 0xe8, 0x85, 0xbf, 0x67, 0x7a, 0xb7, 0x3d, 0xb5, - 0x19, 0x89, 0x6c, 0xaa, 0x0e, 0xd2, 0x15, 0x0d, 0x5b, 0xa4, 0x5a, 0x09, 0x77, 0x7c, 0xa7, 0xcd, - 0x8e, 0x17, 0x86, 0x83, 0xd8, 0xb2, 0x09, 0x17, 0x59, 0x3a, 0x72, 0x2a, 0x86, 0xe5, 0x4a, 0x9a, - 0x53, 0xb7, 0x5d, 0x2c, 0x3d, 0x47, 0xf5, 0x80, 0xe1, 0x29, 0x0d, 0x93, 0x0a, 0x26, 0x8a, 0x4f, - 0xd2, 0xff, 0xe1, 0x4f, 0x09, 0xd7, 0xc1, 0xf8, 0x23, 0x2f, 0x9c, 0x0b, 0xcc, 0xec, 0x32, 0xb2, - 0x10, 0x31, 0x88, 0x8c, 0xb6, 0xaa, 0x88, 0xb8, 0xf0, 0x14, 0x18, 0xf6, 0x6d, 0x1b, 0xfa, 0x18, - 0x37, 0xc9, 0x4d, 0x8d, 0xc8, 0xdf, 0xa0, 0xbf, 0x8b, 0xba, 0xf0, 0x0a, 0x4c, 0x24, 0xef, 0x24, - 0x36, 0xb6, 0x08, 0x82, 0x3f, 0x04, 0x87, 0xca, 0xfe, 0x90, 0x42, 0x5c, 0xd5, 0x45, 0x74, 0xff, - 0x68, 0x6e, 0x5a, 0xdc, 0xed, 0xc4, 0x6a, 0x33, 0x62, 0x13, 0xd6, 0x63, 0x6f, 0x5f, 0x7e, 0xf0, - 0xc3, 0x76, 0xb6, 0x4f, 0x3e, 0x58, 0x6e, 0x18, 0x13, 0x26, 0x00, 0x1f, 0x33, 0xbe, 0xe0, 0xc1, - 0x05, 0x5e, 0x0b, 0x6a, 0x13, 0xa9, 0x60, 0x96, 0x79, 0x96, 0x07, 0x43, 0xd4, 0x3c, 0x19, 0xe3, - 0x26, 0x07, 0xa6, 0x46, 0x73, 0x17, 0xc4, 0x14, 0x49, 0x24, 0x52, 0x10, 0x99, 0xed, 0x14, 0xce, - 0x83, 0xef, 0xb6, 0x9a, 0x78, 0xec, 0xaa, 0x8e, 0x5b, 0x72, 0xb0, 0x8d, 0x89, 0x6a, 0x86, 0xde, - 0xbc, 0xe5, 0xc0, 0x54, 0xe7, 0xb5, 0xcc, 0xb7, 0x1f, 0x81, 0x11, 0x3b, 0x18, 0x64, 0x11, 0xbb, - 0x93, 0xce, 0x3d, 0x06, 0x3e, 0xaf, 0xeb, 0x86, 0x97, 0xdd, 0x11, 0x74, 0x04, 0x28, 0x4c, 0x81, - 0x73, 0x49, 0x9e, 0x60, 0xbb, 0xc5, 0xe9, 0x9f, 0x73, 0xc9, 0x04, 0x63, 0x4b, 0xc3, 0x93, 0x6e, - 0xf1, 0x79, 0xb6, 0x2b, 0x9f, 0x65, 0x54, 0xc1, 0x35, 0xd5, 0x4c, 0x74, 0x79, 0x0d, 0x1c, 0xa0, - 0xa6, 0xdb, 0xa4, 0x22, 0x1c, 0x07, 0x23, 0x9a, 0x69, 0x20, 0xcb, 0xf5, 0xe6, 0xfa, 0xe9, 0xdc, - 0xb0, 0x3f, 0x50, 0xd4, 0xe1, 0x31, 0x70, 0xc0, 0xc5, 0xb6, 0xf2, 0x70, 0x6c, 0x60, 0x92, 0x9b, - 0x3a, 0x24, 0x0f, 0xba, 0xd8, 0x7e, 0x28, 0xbc, 0xe1, 0xc0, 0x19, 0x4a, 0x6f, 0x5d, 0x35, 0x0d, - 0x5d, 0x75, 0xb1, 0xd3, 0x10, 0x3f, 0xa7, 0x73, 0xf6, 0xc3, 0x59, 0x70, 0x34, 0x60, 0xa2, 0xa8, - 0xba, 0xee, 0x20, 0x42, 0x7c, 0xcb, 0x79, 0xf8, 0x65, 0x3b, 0x7b, 0xb8, 0xae, 0x56, 0xcc, 0x9b, - 0x02, 0x9b, 0x10, 0xe4, 0x23, 0xc1, 0xda, 0x79, 0x7f, 0xe4, 0xe6, 0xf0, 0xdb, 0xf7, 0xd9, 0xbe, - 0x7f, 0xbd, 0xcf, 0xf6, 0x09, 0xab, 0x40, 0x68, 0xe7, 0x08, 0x0b, 0xf1, 0x79, 0x70, 0x34, 0x68, - 0x0c, 0xa1, 0x39, 0xdf, 0xa3, 0x23, 0x5a, 0xc3, 0x7a, 0xcf, 0x58, 0x2b, 0xb5, 0x52, 0x83, 0xf1, - 0x74, 0xd4, 0x5a, 0x6c, 0xb5, 0xa1, 0xd6, 0x64, 0xbf, 0x1d, 0xb5, 0xb8, 0x23, 0x11, 0xb5, 0x96, - 0x48, 0x32, 0x6a, 0x4d, 0x51, 0x13, 0xc6, 0xc1, 0x29, 0x0a, 0xb8, 0xb6, 0xe9, 0x60, 0xd7, 0x35, - 0x11, 0xed, 0x05, 0x41, 0xc6, 0xfe, 0x99, 0x63, 0x3d, 0xa1, 0x69, 0x96, 0x99, 0xc9, 0x82, 0x51, - 0x62, 0xaa, 0x64, 0x53, 0xa9, 0x20, 0x17, 0x39, 0xd4, 0xc2, 0x80, 0x0c, 0xe8, 0xd0, 0x03, 0x6f, - 0x04, 0xe6, 0xc0, 0xb7, 0x1a, 0x16, 0x28, 0xaa, 0x69, 0xe2, 0x17, 0xaa, 0xa5, 0x21, 0xca, 0x7d, - 0x40, 0x3e, 0x16, 0x2d, 0x9d, 0x0f, 0xa6, 0xe0, 0x8f, 0xc1, 0x98, 0x85, 0x5e, 0xba, 0x8a, 0x83, - 0x6c, 0x13, 0x59, 0x06, 0xd9, 0x54, 0x34, 0xd5, 0xd2, 0x3d, 0xb2, 0x88, 0xa6, 0xdb, 0x68, 0x8e, - 0x17, 0xfd, 0x7b, 0x44, 0x0c, 0xee, 0x11, 0x71, 0x2d, 0xb8, 0x47, 0xf2, 0xc3, 0x5e, 0x63, 0x7b, - 0xf7, 0xf7, 0x2c, 0x27, 0x9f, 0xf0, 0x50, 0xe4, 0x00, 0x64, 0x21, 0xc0, 0x10, 0x2e, 0x81, 0x0b, - 0x94, 0x92, 0x8c, 0xca, 0x06, 0x71, 0x91, 0x83, 0xf4, 0xa8, 0x64, 0x5e, 0xa8, 0x8e, 0x5e, 0x40, - 0x16, 0xae, 0x84, 0x35, 0xbb, 0x08, 0x2e, 0xa6, 0x5a, 0xcd, 0x22, 0x72, 0x02, 0x0c, 0xe9, 0x74, - 0x84, 0xb6, 0xc1, 0x11, 0x99, 0xfd, 0x12, 0x32, 0xac, 0xb1, 0xfb, 0xe5, 0x88, 0x74, 0x5a, 0x7e, - 0xc5, 0x42, 0x68, 0xe6, 0x35, 0x07, 0x4e, 0xef, 0xb2, 0x80, 0x21, 0x3f, 0x05, 0x87, 0xed, 0xc6, - 0xb9, 0xa0, 0xd1, 0xe6, 0x52, 0x75, 0x85, 0x18, 0x2c, 0xeb, 0xfe, 0x4d, 0x78, 0x42, 0x11, 0x1c, - 0x8a, 0x2d, 0x83, 0x63, 0x80, 0xe5, 0x6f, 0x21, 0x9e, 0xce, 0x05, 0x98, 0x01, 0x20, 0xe8, 0x26, - 0xc5, 0x02, 0x3d, 0xcc, 0x41, 0xb9, 0x61, 0x44, 0xb8, 0x0f, 0x24, 0xca, 0x66, 0xde, 0x34, 0x4b, - 0xaa, 0xe1, 0x90, 0x75, 0xd5, 0x5c, 0xc0, 0x96, 0x97, 0x72, 0xf9, 0x78, 0xf3, 0x2b, 0x16, 0x52, - 0xdc, 0x8a, 0xbf, 0xe7, 0xc0, 0x74, 0x7a, 0x38, 0x16, 0xaf, 0x2d, 0xf0, 0x4d, 0x5b, 0x35, 0x1c, - 0xa5, 0xa6, 0x9a, 0xde, 0xfd, 0x4f, 0xcb, 0x80, 0x85, 0x6c, 0x29, 0x5d, 0xc8, 0x54, 0xc3, 0x89, - 0x0c, 0x85, 0x65, 0x66, 0x45, 0x09, 0x70, 0xd8, 0x8e, 0x2d, 0x11, 0xfe, 0xcb, 0x81, 0x33, 0x1d, - 0x77, 0xc1, 0xa5, 0xdd, 0x6a, 0x33, 0x3f, 0xfe, 0x65, 0x3b, 0x7b, 0xd2, 0x6f, 0x05, 0xcd, 0x2b, - 0x5a, 0xdb, 0x9d, 0x87, 0xb3, 0x4b, 0x4b, 0x69, 0xc0, 0x69, 0x5e, 0xd1, 0xda, 0x5b, 0xe0, 0x1c, - 0x38, 0x18, 0xae, 0x7a, 0x8e, 0xea, 0xac, 0xc6, 0x26, 0xc4, 0xe8, 0xf5, 0x23, 0xfa, 0xaf, 0x1f, - 0xb1, 0x54, 0xdd, 0x30, 0x0d, 0x6d, 0x05, 0xd5, 0xe5, 0xd1, 0x60, 0xc7, 0x0a, 0xaa, 0x0b, 0xc7, - 0x01, 0xf4, 0x53, 0x57, 0x75, 0xd4, 0xa8, 0x70, 0x9e, 0x82, 0x63, 0xb1, 0x51, 0x76, 0x2c, 0x45, - 0x30, 0x64, 0xd3, 0x11, 0x76, 0xa9, 0x5d, 0x4c, 0x79, 0x16, 0xde, 0x16, 0x96, 0xb7, 0x0c, 0x40, - 0x58, 0x66, 0x85, 0x1c, 0xcb, 0x80, 0x55, 0xdb, 0x45, 0x7a, 0xd1, 0x0a, 0xdb, 0x63, 0x9a, 0x57, - 0xd7, 0x16, 0xab, 0xf1, 0x4e, 0x40, 0xe1, 0x53, 0xe7, 0x74, 0x2d, 0x1c, 0x55, 0x9a, 0x4f, 0x0a, - 0x05, 0xa5, 0x3f, 0x1e, 0x2d, 0x2a, 0xc5, 0x8f, 0x0e, 0x11, 0x61, 0x8b, 0x65, 0x74, 0xfc, 0x35, - 0x15, 0x1a, 0xbb, 0xa7, 0x92, 0x35, 0xcc, 0x7e, 0x05, 0xcd, 0x38, 0xf1, 0x7a, 0xe4, 0x52, 0x5f, - 0x8f, 0x82, 0x0a, 0x66, 0xba, 0x30, 0xc9, 0xb8, 0x5e, 0x02, 0x30, 0x4c, 0x8e, 0x20, 0x7c, 0x01, - 0xc1, 0x30, 0xfd, 0xfc, 0xd2, 0xd3, 0xe9, 0x35, 0x79, 0x31, 0xf9, 0xe2, 0x5d, 0xc0, 0x95, 0x8a, - 0x41, 0x88, 0x81, 0x2d, 0xb9, 0x81, 0xd1, 0xd7, 0xf6, 0x16, 0x10, 0x7e, 0xca, 0x81, 0x4b, 0xe9, - 0x3c, 0x61, 0x44, 0x4b, 0x60, 0xd0, 0x09, 0x1e, 0xd4, 0x23, 0xf9, 0xdb, 0x5e, 0xa2, 0xfd, 0x6d, - 0x3b, 0x7b, 0xae, 0x6c, 0xb8, 0x9b, 0xd5, 0x0d, 0x51, 0xc3, 0x15, 0xf6, 0xc4, 0x67, 0x7f, 0x2e, - 0x13, 0xfd, 0xb9, 0xe4, 0xd6, 0x6d, 0x44, 0xc4, 0x02, 0xd2, 0xfe, 0xf2, 0xc7, 0xcb, 0x80, 0x29, - 0x80, 0x02, 0xd2, 0x64, 0x8a, 0x24, 0xcc, 0x82, 0x49, 0xea, 0xc1, 0xaa, 0xa9, 0x23, 0xe2, 0x3e, - 0xb1, 0x34, 0x6c, 0x3d, 0x33, 0x9c, 0x0a, 0xd2, 0xd7, 0x89, 0x96, 0x22, 0x29, 0x7f, 0x19, 0x3c, - 0x39, 0x92, 0xf7, 0x33, 0xb7, 0x0d, 0x00, 0x6b, 0x44, 0x53, 0x08, 0xb2, 0x74, 0x25, 0x14, 0x53, - 0xac, 0xb4, 0xae, 0xa6, 0x2a, 0xad, 0x75, 0xa2, 0x3d, 0x46, 0x96, 0x1e, 0xdd, 0xa0, 0x7e, 0x91, - 0x1d, 0xad, 0x35, 0x8d, 0xe7, 0x7e, 0x71, 0x1a, 0x1c, 0xa0, 0x0e, 0xc1, 0x1d, 0x0e, 0x1c, 0x4f, - 0x92, 0x29, 0xf0, 0x6e, 0x2a, 0x8b, 0x6d, 0xb4, 0x11, 0x3f, 0xbf, 0x07, 0x04, 0x3f, 0x24, 0xc2, - 0xe2, 0xcf, 0x3e, 0xfd, 0xf3, 0xd7, 0xfd, 0x73, 0x70, 0xb6, 0xb3, 0xee, 0x0d, 0x53, 0x9b, 0xe9, - 0x20, 0xe9, 0x55, 0x70, 0x1a, 0x3f, 0x81, 0x9f, 0x38, 0xd6, 0xc0, 0xe2, 0xf5, 0x02, 0xe7, 0xba, - 0xf7, 0x30, 0x26, 0xa4, 0xf8, 0xbb, 0xbd, 0x03, 0x30, 0x86, 0x37, 0x28, 0xc3, 0x2b, 0x70, 0xa6, - 0x0b, 0x86, 0xbe, 0xc4, 0x82, 0xaf, 0xfb, 0xc1, 0xd8, 0x2e, 0xba, 0x89, 0xc0, 0xfb, 0x3d, 0x7a, - 0x96, 0x28, 0xd1, 0xf8, 0x07, 0xfb, 0x84, 0xc6, 0x48, 0xdf, 0xa3, 0xa4, 0xf3, 0xf0, 0x6e, 0xb7, - 0xa4, 0x3d, 0xa5, 0xec, 0xb8, 0x4a, 0xa8, 0x7e, 0xe0, 0xff, 0x39, 0x70, 0x32, 0x59, 0x86, 0x11, - 0xb8, 0xd2, 0xb3, 0xd3, 0xad, 0x7a, 0x8f, 0xbf, 0xbf, 0x3f, 0x60, 0x2c, 0x00, 0xcb, 0x34, 0x00, - 0xf3, 0x70, 0xae, 0x87, 0x00, 0x60, 0xbb, 0x81, 0xff, 0x7f, 0x82, 0x47, 0x7d, 0xa2, 0x3c, 0x82, - 0x4b, 0xe9, 0xbd, 0x6e, 0x27, 0xf4, 0xf8, 0xe5, 0x3d, 0xe3, 0x30, 0xe2, 0xf3, 0x94, 0xf8, 0x2d, - 0x78, 0x23, 0xc5, 0x87, 0xac, 0x00, 0x48, 0x89, 0x3d, 0x7c, 0x12, 0x28, 0x37, 0x5e, 0xc9, 0x3d, - 0x51, 0x4e, 0x10, 0x80, 0x3d, 0x51, 0x4e, 0xd2, 0x6f, 0xbd, 0x51, 0x8e, 0xdd, 0x97, 0xf0, 0x4f, - 0x1c, 0x7b, 0x96, 0xc5, 0xa4, 0x1b, 0xbc, 0x93, 0xde, 0xc5, 0x24, 0x45, 0xc8, 0xcf, 0xf5, 0xbc, - 0x9f, 0x51, 0xbb, 0x4e, 0xa9, 0xe5, 0xe0, 0x74, 0x67, 0x6a, 0x2e, 0x03, 0xf0, 0xbf, 0x75, 0xc1, - 0xdf, 0xf6, 0x83, 0xb3, 0x29, 0xb4, 0x18, 0x5c, 0x4d, 0xef, 0x62, 0x2a, 0x0d, 0xc8, 0x97, 0xf6, - 0x0f, 0x90, 0x05, 0x61, 0x85, 0x06, 0x61, 0x11, 0x2e, 0x74, 0x0e, 0x82, 0x13, 0x22, 0x46, 0x39, - 0xed, 0x50, 0x4c, 0xc5, 0xd7, 0x96, 0xf0, 0xdf, 0x2d, 0xda, 0x31, 0x2e, 0x89, 0x08, 0xec, 0xe2, - 0x56, 0xdd, 0x45, 0xa0, 0xf2, 0xf9, 0xbd, 0x40, 0x30, 0xd6, 0x79, 0xca, 0xfa, 0x36, 0xbc, 0xd9, - 0x99, 0x75, 0x20, 0x4d, 0x95, 0xe6, 0x0b, 0xec, 0x37, 0xfd, 0xec, 0xc3, 0x5f, 0x0a, 0x2d, 0x08, - 0xd7, 0xd2, 0x3b, 0x9d, 0x5e, 0xa9, 0xf2, 0x4f, 0xf6, 0x19, 0x95, 0x45, 0xe7, 0x16, 0x8d, 0xce, - 0x55, 0x78, 0xa5, 0xeb, 0xfe, 0x6e, 0xe8, 0xf0, 0x0f, 0x1c, 0x18, 0x6d, 0x90, 0x5b, 0xf0, 0x5a, - 0x17, 0xc7, 0xd5, 0x28, 0xdb, 0xf8, 0xeb, 0xdd, 0x6f, 0x64, 0xfe, 0x4f, 0x53, 0xff, 0x2f, 0xc0, - 0xa9, 0x14, 0xa7, 0xeb, 0x3b, 0xf9, 0x26, 0x28, 0xe8, 0xf6, 0xc2, 0xab, 0x9b, 0x82, 0x4e, 0xa5, - 0x05, 0xbb, 0x29, 0xe8, 0x74, 0x9a, 0x50, 0x98, 0xa5, 0xe4, 0xaf, 0xc1, 0xab, 0x9d, 0xc9, 0x63, - 0x0f, 0x44, 0x31, 0x2c, 0x25, 0xd2, 0x87, 0xf0, 0x77, 0xfd, 0xe0, 0x7c, 0x6a, 0x71, 0x06, 0x9f, - 0xf4, 0xfa, 0x82, 0x6c, 0xab, 0x2f, 0xf9, 0xf5, 0xfd, 0x86, 0xdd, 0xeb, 0xc3, 0x85, 0x28, 0x36, - 0x72, 0xa2, 0x30, 0xc1, 0x5f, 0xf5, 0x83, 0x6f, 0xa7, 0x11, 0x75, 0xb0, 0xb4, 0x87, 0xa7, 0x47, - 0xa2, 0x52, 0xe5, 0x1f, 0xed, 0x23, 0x62, 0xf7, 0xdd, 0x30, 0x0a, 0x4b, 0x08, 0xa5, 0x78, 0x1a, - 0x13, 0xfe, 0x8f, 0x63, 0x5f, 0x6f, 0x93, 0x44, 0x22, 0x5c, 0x4c, 0xef, 0x74, 0x1b, 0x91, 0xca, - 0x2f, 0xed, 0x15, 0xa6, 0xfb, 0x4b, 0x0f, 0x53, 0x1c, 0xa5, 0x1a, 0x01, 0x29, 0x35, 0xa2, 0x35, - 0xc8, 0xb3, 0xfc, 0xf7, 0x3f, 0xec, 0x64, 0xb8, 0x8f, 0x3b, 0x19, 0xee, 0x1f, 0x3b, 0x19, 0xee, - 0xdd, 0xe7, 0x4c, 0xdf, 0xc7, 0xcf, 0x99, 0xbe, 0xbf, 0x7e, 0xce, 0xf4, 0xfd, 0x60, 0xb6, 0x55, - 0xb3, 0x47, 0xf6, 0x2e, 0x87, 0xf6, 0x6a, 0xdf, 0x93, 0x5e, 0x36, 0x3d, 0x37, 0x3c, 0x39, 0xbf, - 0x31, 0x44, 0x3f, 0x2a, 0x5f, 0xf9, 0x2a, 0x00, 0x00, 0xff, 0xff, 0x2d, 0xeb, 0x2b, 0x80, 0x36, - 0x1d, 0x00, 0x00, + // 1834 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0xcd, 0x6f, 0xdc, 0x5a, + 0x15, 0x8f, 0x93, 0x34, 0x24, 0x37, 0xaf, 0x7d, 0xe5, 0xb6, 0xbc, 0x97, 0x3a, 0xe9, 0x4c, 0x9e, + 0x1f, 0x3c, 0xd2, 0x2f, 0x3b, 0x99, 0xf2, 0x44, 0xbf, 0xd2, 0x34, 0x93, 0x49, 0xd2, 0x51, 0xda, + 0x66, 0xea, 0xa6, 0x01, 0x15, 0x84, 0xeb, 0xd8, 0xb7, 0x13, 0xab, 0x1e, 0x5f, 0xc7, 0xd7, 0x33, + 0xed, 0xa8, 0xaa, 0x44, 0x59, 0x40, 0x57, 0xa8, 0xe2, 0x63, 0xdf, 0x0d, 0x4b, 0x36, 0x08, 0xf1, + 0x2f, 0xd0, 0x1d, 0x85, 0x6e, 0x10, 0x8b, 0x80, 0x52, 0x16, 0x88, 0x15, 0xaa, 0x90, 0x58, 0x21, + 0x21, 0x5f, 0x5f, 0x7f, 0xcd, 0x38, 0x33, 0x9e, 0x49, 0x58, 0x25, 0x73, 0x7d, 0xef, 0xef, 0x9c, + 0xdf, 0xf1, 0x39, 0xe7, 0x9e, 0x9f, 0x81, 0x64, 0x58, 0x2e, 0x72, 0xb4, 0x6d, 0xd5, 0xb0, 0x14, + 0x82, 0xb4, 0xba, 0x63, 0xb8, 0x4d, 0x49, 0xd3, 0x1a, 0x92, 0xed, 0xe0, 0x86, 0xa1, 0x23, 0x47, + 0x6a, 0xcc, 0x49, 0x3b, 0x75, 0xe4, 0x34, 0x45, 0xdb, 0xc1, 0x2e, 0x86, 0x9f, 0xa7, 0x1c, 0x10, + 0x35, 0xad, 0x21, 0x06, 0x07, 0xc4, 0xc6, 0x1c, 0x3f, 0x55, 0xc5, 0xb8, 0x6a, 0x22, 0x49, 0xb5, + 0x0d, 0x49, 0xb5, 0x2c, 0xec, 0xaa, 0xae, 0x81, 0x2d, 0xe2, 0x43, 0xf0, 0x27, 0xab, 0xb8, 0x8a, + 0xe9, 0xbf, 0x92, 0xf7, 0x1f, 0x5b, 0xcd, 0xb3, 0x33, 0xf4, 0xd7, 0x56, 0xfd, 0x91, 0xe4, 0x1a, + 0x35, 0x44, 0x5c, 0xb5, 0x66, 0xb3, 0x0d, 0x85, 0x2c, 0xae, 0x86, 0x5e, 0xf8, 0x67, 0x66, 0xf7, + 0x3b, 0xd3, 0x98, 0x93, 0xc8, 0xb6, 0xea, 0x20, 0x5d, 0xd1, 0xb0, 0x45, 0xea, 0xb5, 0xf0, 0xc4, + 0x37, 0x3a, 0x9c, 0x78, 0x62, 0x38, 0x88, 0x6d, 0x9b, 0x72, 0x91, 0xa5, 0x23, 0xa7, 0x66, 0x58, + 0xae, 0xa4, 0x39, 0x4d, 0xdb, 0xc5, 0xd2, 0x63, 0xd4, 0x0c, 0x18, 0x9e, 0xd2, 0x30, 0xa9, 0x61, + 0xa2, 0xf8, 0x24, 0xfd, 0x1f, 0xfe, 0x23, 0xe1, 0x12, 0x98, 0xbc, 0xeb, 0x85, 0x73, 0x89, 0x99, + 0x5d, 0x45, 0x16, 0x22, 0x06, 0x91, 0xd1, 0x4e, 0x1d, 0x11, 0x17, 0x9e, 0x02, 0xa3, 0xbe, 0x6d, + 0x43, 0x9f, 0xe0, 0xa6, 0xb9, 0x99, 0x31, 0xf9, 0x2b, 0xf4, 0x77, 0x59, 0x17, 0x9e, 0x81, 0xa9, + 0xf4, 0x93, 0xc4, 0xc6, 0x16, 0x41, 0xf0, 0x7b, 0xe0, 0x68, 0xd5, 0x5f, 0x52, 0x88, 0xab, 0xba, + 0x88, 0x9e, 0x1f, 0x2f, 0xcc, 0x8a, 0xfb, 0xbd, 0xb1, 0xc6, 0x9c, 0xd8, 0x82, 0x75, 0xcf, 0x3b, + 0x57, 0x1c, 0x7e, 0xb3, 0x9b, 0x1f, 0x90, 0x3f, 0xaa, 0xc6, 0xd6, 0x84, 0x29, 0xc0, 0x27, 0x8c, + 0x2f, 0x79, 0x70, 0x81, 0xd7, 0x82, 0xda, 0x42, 0x2a, 0x78, 0xca, 0x3c, 0x2b, 0x82, 0x11, 0x6a, + 0x9e, 0x4c, 0x70, 0xd3, 0x43, 0x33, 0xe3, 0x85, 0xb3, 0x62, 0x86, 0x24, 0x12, 0x29, 0x88, 0xcc, + 0x4e, 0x0a, 0x67, 0xc0, 0x37, 0xdb, 0x4d, 0xdc, 0x73, 0x55, 0xc7, 0xad, 0x38, 0xd8, 0xc6, 0x44, + 0x35, 0x43, 0x6f, 0x5e, 0x72, 0x60, 0xa6, 0xfb, 0x5e, 0xe6, 0xdb, 0xf7, 0xc1, 0x98, 0x1d, 0x2c, + 0xb2, 0x88, 0x5d, 0xcf, 0xe6, 0x1e, 0x03, 0x5f, 0xd4, 0x75, 0xc3, 0xcb, 0xee, 0x08, 0x3a, 0x02, + 0x14, 0x66, 0xc0, 0x17, 0x69, 0x9e, 0x60, 0xbb, 0xcd, 0xe9, 0x1f, 0x73, 0xe9, 0x04, 0x13, 0x5b, + 0xc3, 0x37, 0xdd, 0xe6, 0xf3, 0x7c, 0x4f, 0x3e, 0xcb, 0xa8, 0x86, 0x1b, 0xaa, 0x99, 0xea, 0xf2, + 0x06, 0x38, 0x42, 0x4d, 0x77, 0x48, 0x45, 0x38, 0x09, 0xc6, 0x34, 0xd3, 0x40, 0x96, 0xeb, 0x3d, + 0x1b, 0xa4, 0xcf, 0x46, 0xfd, 0x85, 0xb2, 0x0e, 0x4f, 0x80, 0x23, 0x2e, 0xb6, 0x95, 0x3b, 0x13, + 0x43, 0xd3, 0xdc, 0xcc, 0x51, 0x79, 0xd8, 0xc5, 0xf6, 0x1d, 0xe1, 0x27, 0x1c, 0xf8, 0x8c, 0xd2, + 0xdb, 0x54, 0x4d, 0x43, 0x57, 0x5d, 0xec, 0xc4, 0xe2, 0xe7, 0x74, 0xcf, 0x7e, 0x38, 0x0f, 0x8e, + 0x07, 0x4c, 0x14, 0x55, 0xd7, 0x1d, 0x44, 0x88, 0x6f, 0xb9, 0x08, 0x3f, 0xec, 0xe6, 0x8f, 0x35, + 0xd5, 0x9a, 0x79, 0x45, 0x60, 0x0f, 0x04, 0xf9, 0xe3, 0x60, 0xef, 0xa2, 0xbf, 0x72, 0x65, 0xf4, + 0xe5, 0xeb, 0xfc, 0xc0, 0x3f, 0x5e, 0xe7, 0x07, 0x84, 0x75, 0x20, 0x74, 0x72, 0x84, 0x85, 0xf8, + 0x0c, 0x38, 0x1e, 0x34, 0x86, 0xd0, 0x9c, 0xef, 0xd1, 0xc7, 0x5a, 0x6c, 0xbf, 0x67, 0xac, 0x9d, + 0x5a, 0x25, 0x66, 0x3c, 0x1b, 0xb5, 0x36, 0x5b, 0x1d, 0xa8, 0xb5, 0xd8, 0xef, 0x44, 0x2d, 0xe9, + 0x48, 0x44, 0xad, 0x2d, 0x92, 0x8c, 0x5a, 0x4b, 0xd4, 0x84, 0x49, 0x70, 0x8a, 0x02, 0x6e, 0x6c, + 0x3b, 0xd8, 0x75, 0x4d, 0x44, 0x7b, 0x41, 0x90, 0xb1, 0x7f, 0xe4, 0x58, 0x4f, 0x68, 0x79, 0xca, + 0xcc, 0xe4, 0xc1, 0x38, 0x31, 0x55, 0xb2, 0xad, 0xd4, 0x90, 0x8b, 0x1c, 0x6a, 0x61, 0x48, 0x06, + 0x74, 0xe9, 0xb6, 0xb7, 0x02, 0x0b, 0xe0, 0x6b, 0xb1, 0x0d, 0x8a, 0x6a, 0x9a, 0xf8, 0x89, 0x6a, + 0x69, 0x88, 0x72, 0x1f, 0x92, 0x4f, 0x44, 0x5b, 0x17, 0x83, 0x47, 0xf0, 0x07, 0x60, 0xc2, 0x42, + 0x4f, 0x5d, 0xc5, 0x41, 0xb6, 0x89, 0x2c, 0x83, 0x6c, 0x2b, 0x9a, 0x6a, 0xe9, 0x1e, 0x59, 0x44, + 0xd3, 0x6d, 0xbc, 0xc0, 0x8b, 0xfe, 0x3d, 0x22, 0x06, 0xf7, 0x88, 0xb8, 0x11, 0xdc, 0x23, 0xc5, + 0x51, 0xaf, 0xb1, 0xbd, 0xfa, 0x6b, 0x9e, 0x93, 0x3f, 0xf1, 0x50, 0xe4, 0x00, 0x64, 0x29, 0xc0, + 0x10, 0xce, 0x83, 0xb3, 0x94, 0x92, 0x8c, 0xaa, 0x06, 0x71, 0x91, 0x83, 0xf4, 0xa8, 0x64, 0x9e, + 0xa8, 0x8e, 0x5e, 0x42, 0x16, 0xae, 0x85, 0x35, 0xbb, 0x0c, 0xce, 0x65, 0xda, 0xcd, 0x22, 0xf2, + 0x09, 0x18, 0xd1, 0xe9, 0x0a, 0x6d, 0x83, 0x63, 0x32, 0xfb, 0x25, 0xe4, 0x58, 0x63, 0xf7, 0xcb, + 0x11, 0xe9, 0xb4, 0xfc, 0xca, 0xa5, 0xd0, 0xcc, 0x0b, 0x0e, 0x9c, 0xde, 0x67, 0x03, 0x43, 0x7e, + 0x08, 0x8e, 0xd9, 0xf1, 0x67, 0x41, 0xa3, 0x2d, 0x64, 0xea, 0x0a, 0x09, 0x58, 0xd6, 0xfd, 0x5b, + 0xf0, 0x84, 0x32, 0x38, 0x9a, 0xd8, 0x06, 0x27, 0x00, 0xcb, 0xdf, 0x52, 0x32, 0x9d, 0x4b, 0x30, + 0x07, 0x40, 0xd0, 0x4d, 0xca, 0x25, 0xfa, 0x32, 0x87, 0xe5, 0xd8, 0x8a, 0x70, 0x0b, 0x48, 0x94, + 0xcd, 0xa2, 0x69, 0x56, 0x54, 0xc3, 0x21, 0x9b, 0xaa, 0xb9, 0x84, 0x2d, 0x2f, 0xe5, 0x8a, 0xc9, + 0xe6, 0x57, 0x2e, 0x65, 0xb8, 0x15, 0x7f, 0xc5, 0x81, 0xd9, 0xec, 0x70, 0x2c, 0x5e, 0x3b, 0xe0, + 0xab, 0xb6, 0x6a, 0x38, 0x4a, 0x43, 0x35, 0xbd, 0xfb, 0x9f, 0x96, 0x01, 0x0b, 0xd9, 0x4a, 0xb6, + 0x90, 0xa9, 0x86, 0x13, 0x19, 0x0a, 0xcb, 0xcc, 0x8a, 0x12, 0xe0, 0x98, 0x9d, 0xd8, 0x22, 0xfc, + 0x9b, 0x03, 0x9f, 0x75, 0x3d, 0x05, 0x57, 0xf6, 0xab, 0xcd, 0xe2, 0xe4, 0x87, 0xdd, 0xfc, 0xa7, + 0x7e, 0x2b, 0x68, 0xdd, 0xd1, 0xde, 0xee, 0x3c, 0x9c, 0x7d, 0x5a, 0x4a, 0x0c, 0xa7, 0x75, 0x47, + 0x7b, 0x6f, 0x81, 0x0b, 0xe0, 0xa3, 0x70, 0xd7, 0x63, 0xd4, 0x64, 0x35, 0x36, 0x25, 0x46, 0xd3, + 0x8f, 0xe8, 0x4f, 0x3f, 0x62, 0xa5, 0xbe, 0x65, 0x1a, 0xda, 0x1a, 0x6a, 0xca, 0xe3, 0xc1, 0x89, + 0x35, 0xd4, 0x14, 0x4e, 0x02, 0xe8, 0xa7, 0xae, 0xea, 0xa8, 0x51, 0xe1, 0x3c, 0x04, 0x27, 0x12, + 0xab, 0xec, 0xb5, 0x94, 0xc1, 0x88, 0x4d, 0x57, 0xd8, 0xa5, 0x76, 0x2e, 0xe3, 0xbb, 0xf0, 0x8e, + 0xb0, 0xbc, 0x65, 0x00, 0xc2, 0x2a, 0x2b, 0xe4, 0x44, 0x06, 0xac, 0xdb, 0x2e, 0xd2, 0xcb, 0x56, + 0xd8, 0x1e, 0xb3, 0x4c, 0x5d, 0x3b, 0xac, 0xc6, 0xbb, 0x01, 0x85, 0xa3, 0xce, 0xe9, 0x46, 0xb8, + 0xaa, 0xb4, 0xbe, 0x29, 0x14, 0x94, 0xfe, 0x64, 0xb4, 0xa9, 0x92, 0x7c, 0x75, 0x88, 0x08, 0x3b, + 0x2c, 0xa3, 0x93, 0xd3, 0x54, 0x68, 0xec, 0xa6, 0x4a, 0x36, 0x30, 0xfb, 0x15, 0x34, 0xe3, 0xd4, + 0xeb, 0x91, 0xcb, 0x7c, 0x3d, 0x0a, 0x2a, 0x98, 0xeb, 0xc1, 0x24, 0xe3, 0x7a, 0x1e, 0xc0, 0x30, + 0x39, 0x82, 0xf0, 0x05, 0x04, 0xc3, 0xf4, 0xf3, 0x4b, 0x4f, 0xa7, 0xd7, 0xe4, 0xb9, 0xf4, 0x8b, + 0x77, 0x09, 0xd7, 0x6a, 0x06, 0x21, 0x06, 0xb6, 0xe4, 0x18, 0xa3, 0xff, 0xdb, 0x2c, 0x20, 0xfc, + 0x90, 0x03, 0xe7, 0xb3, 0x79, 0xc2, 0x88, 0x56, 0xc0, 0xb0, 0x13, 0x0c, 0xd4, 0x63, 0xc5, 0x6b, + 0x5e, 0xa2, 0xfd, 0x65, 0x37, 0xff, 0x45, 0xd5, 0x70, 0xb7, 0xeb, 0x5b, 0xa2, 0x86, 0x6b, 0x6c, + 0xc4, 0x67, 0x7f, 0x2e, 0x10, 0xfd, 0xb1, 0xe4, 0x36, 0x6d, 0x44, 0xc4, 0x12, 0xd2, 0xfe, 0xf4, + 0xdb, 0x0b, 0x80, 0x29, 0x80, 0x12, 0xd2, 0x64, 0x8a, 0x24, 0xcc, 0x83, 0x69, 0xea, 0xc1, 0xba, + 0xa9, 0x23, 0xe2, 0xde, 0xb7, 0x34, 0x6c, 0x3d, 0x32, 0x9c, 0x1a, 0xd2, 0x37, 0x89, 0x96, 0x21, + 0x29, 0x7f, 0x1a, 0x8c, 0x1c, 0xe9, 0xe7, 0x99, 0xdb, 0x06, 0x80, 0x0d, 0xa2, 0x29, 0x04, 0x59, + 0xba, 0x12, 0x8a, 0x29, 0x56, 0x5a, 0x5f, 0x66, 0x2a, 0xad, 0x4d, 0xa2, 0xdd, 0x43, 0x96, 0x1e, + 0xdd, 0xa0, 0x7e, 0x91, 0x1d, 0x6f, 0xb4, 0xac, 0x17, 0x7e, 0x7f, 0x1a, 0x1c, 0xa1, 0x0e, 0xc1, + 0x3d, 0x0e, 0x9c, 0x4c, 0x93, 0x29, 0xf0, 0x46, 0x26, 0x8b, 0x1d, 0xb4, 0x11, 0xbf, 0x78, 0x00, + 0x04, 0x3f, 0x24, 0xc2, 0xf2, 0x8f, 0xde, 0xfd, 0xfd, 0xe7, 0x83, 0x0b, 0x70, 0xbe, 0xbb, 0xee, + 0x0d, 0x53, 0x9b, 0xe9, 0x20, 0xe9, 0x59, 0xf0, 0x36, 0x9e, 0xc3, 0x77, 0x1c, 0x6b, 0x60, 0xc9, + 0x7a, 0x81, 0x0b, 0xbd, 0x7b, 0x98, 0x10, 0x52, 0xfc, 0x8d, 0xfe, 0x01, 0x18, 0xc3, 0xcb, 0x94, + 0xe1, 0x45, 0x38, 0xd7, 0x03, 0x43, 0x5f, 0x62, 0xc1, 0x17, 0x83, 0x60, 0x62, 0x1f, 0xdd, 0x44, + 0xe0, 0xad, 0x3e, 0x3d, 0x4b, 0x95, 0x68, 0xfc, 0xed, 0x43, 0x42, 0x63, 0xa4, 0x6f, 0x52, 0xd2, + 0x45, 0x78, 0xa3, 0x57, 0xd2, 0x9e, 0x52, 0x76, 0x5c, 0x25, 0x54, 0x3f, 0xf0, 0xbf, 0x1c, 0xf8, + 0x34, 0x5d, 0x86, 0x11, 0xb8, 0xd6, 0xb7, 0xd3, 0xed, 0x7a, 0x8f, 0xbf, 0x75, 0x38, 0x60, 0x2c, + 0x00, 0xab, 0x34, 0x00, 0x8b, 0x70, 0xa1, 0x8f, 0x00, 0x60, 0x3b, 0xc6, 0xff, 0x5f, 0xc1, 0x50, + 0x9f, 0x2a, 0x8f, 0xe0, 0x4a, 0x76, 0xaf, 0x3b, 0x09, 0x3d, 0x7e, 0xf5, 0xc0, 0x38, 0x8c, 0xf8, + 0x22, 0x25, 0x7e, 0x15, 0x5e, 0xce, 0xf0, 0x21, 0x2b, 0x00, 0x52, 0x12, 0x83, 0x4f, 0x0a, 0xe5, + 0xf8, 0x95, 0xdc, 0x17, 0xe5, 0x14, 0x01, 0xd8, 0x17, 0xe5, 0x34, 0xfd, 0xd6, 0x1f, 0xe5, 0xc4, + 0x7d, 0x09, 0xff, 0xc0, 0xb1, 0xb1, 0x2c, 0x21, 0xdd, 0xe0, 0xf5, 0xec, 0x2e, 0xa6, 0x29, 0x42, + 0x7e, 0xa1, 0xef, 0xf3, 0x8c, 0xda, 0x25, 0x4a, 0xad, 0x00, 0x67, 0xbb, 0x53, 0x73, 0x19, 0x80, + 0xff, 0xad, 0x0b, 0xfe, 0x72, 0x10, 0x7c, 0x9e, 0x41, 0x8b, 0xc1, 0xf5, 0xec, 0x2e, 0x66, 0xd2, + 0x80, 0x7c, 0xe5, 0xf0, 0x00, 0x59, 0x10, 0xd6, 0x68, 0x10, 0x96, 0xe1, 0x52, 0xf7, 0x20, 0x38, + 0x21, 0x62, 0x94, 0xd3, 0x0e, 0xc5, 0x54, 0x7c, 0x6d, 0x09, 0xff, 0xd9, 0xa6, 0x1d, 0x93, 0x92, + 0x88, 0xc0, 0x1e, 0x6e, 0xd5, 0x7d, 0x04, 0x2a, 0x5f, 0x3c, 0x08, 0x04, 0x63, 0x5d, 0xa4, 0xac, + 0xaf, 0xc1, 0x2b, 0xdd, 0x59, 0x07, 0xd2, 0x54, 0x69, 0xbd, 0xc0, 0x7e, 0x31, 0xc8, 0x3e, 0xfc, + 0x65, 0xd0, 0x82, 0x70, 0x23, 0xbb, 0xd3, 0xd9, 0x95, 0x2a, 0x7f, 0xff, 0x90, 0x51, 0x59, 0x74, + 0xae, 0xd2, 0xe8, 0x7c, 0x09, 0x2f, 0xf6, 0xdc, 0xdf, 0x0d, 0x1d, 0xfe, 0x86, 0x03, 0xe3, 0x31, + 0xb9, 0x05, 0xbf, 0xdd, 0xc3, 0xeb, 0x8a, 0xcb, 0x36, 0xfe, 0x52, 0xef, 0x07, 0x99, 0xff, 0xb3, + 0xd4, 0xff, 0xb3, 0x70, 0x26, 0xc3, 0xdb, 0xf5, 0x9d, 0xfc, 0x59, 0x50, 0xd0, 0x9d, 0x85, 0x57, + 0x2f, 0x05, 0x9d, 0x49, 0x0b, 0xf6, 0x52, 0xd0, 0xd9, 0x34, 0x61, 0x2f, 0xd3, 0x09, 0xf6, 0x40, + 0x14, 0xc3, 0x52, 0x22, 0x7d, 0x18, 0x9f, 0x3b, 0x7f, 0x37, 0x08, 0xce, 0x64, 0xd6, 0x69, 0xf0, + 0x7e, 0xbf, 0xc3, 0x64, 0x47, 0xa9, 0xc9, 0x6f, 0x1e, 0x36, 0x2c, 0x0b, 0xd3, 0x03, 0x1a, 0xa6, + 0x0d, 0x28, 0xf7, 0x3c, 0xb9, 0x2a, 0x36, 0x72, 0xa2, 0x88, 0x49, 0xcf, 0x5a, 0xc5, 0xe1, 0x73, + 0xf8, 0xeb, 0x41, 0xf0, 0xf5, 0x2c, 0x92, 0x0f, 0x56, 0x0e, 0x30, 0x98, 0xa4, 0xea, 0x58, 0xfe, + 0xee, 0x21, 0x22, 0xb2, 0x48, 0x3d, 0xa4, 0x91, 0x7a, 0x00, 0xbf, 0xdb, 0x4b, 0xa4, 0x42, 0x28, + 0xc5, 0x53, 0xa0, 0xb1, 0xac, 0x4a, 0x8b, 0xd7, 0x7f, 0x38, 0xf6, 0xe5, 0x37, 0x4d, 0x60, 0xc2, + 0xe5, 0xec, 0x94, 0x3a, 0x08, 0x5c, 0x7e, 0xe5, 0xa0, 0x30, 0xbd, 0x5f, 0x98, 0x98, 0xe2, 0x28, + 0xf5, 0x08, 0x48, 0x69, 0x10, 0x2d, 0x16, 0x8c, 0xe2, 0x77, 0xde, 0xec, 0xe5, 0xb8, 0xb7, 0x7b, + 0x39, 0xee, 0x6f, 0x7b, 0x39, 0xee, 0xd5, 0xfb, 0xdc, 0xc0, 0xdb, 0xf7, 0xb9, 0x81, 0x3f, 0xbf, + 0xcf, 0x0d, 0x3c, 0x98, 0x6f, 0xd7, 0xfb, 0x91, 0xbd, 0x0b, 0xa1, 0xbd, 0xc6, 0xb7, 0xa4, 0xa7, + 0x2d, 0xa3, 0x4a, 0xd3, 0x46, 0x64, 0x6b, 0x84, 0x7e, 0x90, 0xbe, 0xf8, 0xbf, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x21, 0x1e, 0x15, 0x5a, 0x72, 0x1d, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/x/ccv/provider/types/query.pb.gw.go b/x/ccv/provider/types/query.pb.gw.go index e44ddd00f5..2be0974fbf 100644 --- a/x/ccv/provider/types/query.pb.gw.go +++ b/x/ccv/provider/types/query.pb.gw.go @@ -321,19 +321,26 @@ func local_request_Query_QueryParams_0(ctx context.Context, marshaler runtime.Ma } -var ( - filter_Query_QueryConsumerChainOptedInValidators_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} -) - func request_Query_QueryConsumerChainOptedInValidators_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq QueryConsumerChainOptedInValidatorsRequest var metadata runtime.ServerMetadata - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["chain_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "chain_id") } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_QueryConsumerChainOptedInValidators_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + + protoReq.ChainId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "chain_id", err) } msg, err := client.QueryConsumerChainOptedInValidators(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) @@ -345,11 +352,22 @@ func local_request_Query_QueryConsumerChainOptedInValidators_0(ctx context.Conte var protoReq QueryConsumerChainOptedInValidatorsRequest var metadata runtime.ServerMetadata - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["chain_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "chain_id") } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_QueryConsumerChainOptedInValidators_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + + protoReq.ChainId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "chain_id", err) } msg, err := server.QueryConsumerChainOptedInValidators(ctx, &protoReq) @@ -357,19 +375,26 @@ func local_request_Query_QueryConsumerChainOptedInValidators_0(ctx context.Conte } -var ( - filter_Query_QueryConsumerChainsValidatorHasToValidate_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} -) - func request_Query_QueryConsumerChainsValidatorHasToValidate_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq QueryConsumerChainsValidatorHasToValidateRequest var metadata runtime.ServerMetadata - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["provider_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "provider_address") } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_QueryConsumerChainsValidatorHasToValidate_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + + protoReq.ProviderAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "provider_address", err) } msg, err := client.QueryConsumerChainsValidatorHasToValidate(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) @@ -381,11 +406,22 @@ func local_request_Query_QueryConsumerChainsValidatorHasToValidate_0(ctx context var protoReq QueryConsumerChainsValidatorHasToValidateRequest var metadata runtime.ServerMetadata - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["provider_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "provider_address") } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_QueryConsumerChainsValidatorHasToValidate_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + + protoReq.ProviderAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "provider_address", err) } msg, err := server.QueryConsumerChainsValidatorHasToValidate(ctx, &protoReq) @@ -393,19 +429,37 @@ func local_request_Query_QueryConsumerChainsValidatorHasToValidate_0(ctx context } -var ( - filter_Query_QueryValidatorConsumerCommissionRate_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} -) - func request_Query_QueryValidatorConsumerCommissionRate_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq QueryValidatorConsumerCommissionRateRequest var metadata runtime.ServerMetadata - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["chain_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "chain_id") } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_QueryValidatorConsumerCommissionRate_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + + protoReq.ChainId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "chain_id", err) + } + + val, ok = pathParams["provider_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "provider_address") + } + + protoReq.ProviderAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "provider_address", err) } msg, err := client.QueryValidatorConsumerCommissionRate(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) @@ -417,11 +471,33 @@ func local_request_Query_QueryValidatorConsumerCommissionRate_0(ctx context.Cont var protoReq QueryValidatorConsumerCommissionRateRequest var metadata runtime.ServerMetadata - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["chain_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "chain_id") } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_QueryValidatorConsumerCommissionRate_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + + protoReq.ChainId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "chain_id", err) + } + + val, ok = pathParams["provider_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "provider_address") + } + + protoReq.ProviderAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "provider_address", err) } msg, err := server.QueryValidatorConsumerCommissionRate(ctx, &protoReq) @@ -1201,11 +1277,11 @@ var ( pattern_Query_QueryParams_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"interchain_security", "ccv", "provider", "params"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_QueryConsumerChainOptedInValidators_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"interchain_security", "ccv", "provider", "opted_in_validators"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_QueryConsumerChainOptedInValidators_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"interchain_security", "ccv", "provider", "opted_in_validators", "chain_id"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_QueryConsumerChainsValidatorHasToValidate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"interchain_security", "ccv", "provider", "consumer_chains_per_validator"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_QueryConsumerChainsValidatorHasToValidate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"interchain_security", "ccv", "provider", "consumer_chains_per_validator", "provider_address"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_QueryValidatorConsumerCommissionRate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"interchain_security", "ccv", "provider", "consumer_commission_rate"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_QueryValidatorConsumerCommissionRate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"interchain_security", "ccv", "provider", "consumer_commission_rate", "chain_id", "provider_address"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_QueryOldestUnconfirmedVsc_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"interchain_security", "ccv", "provider", "oldest_unconfirmed_vsc", "chain_id"}, "", runtime.AssumeColonVerbOpt(false))) ) diff --git a/x/ccv/provider/types/tx.pb.go b/x/ccv/provider/types/tx.pb.go index 7330433f5b..1fd4869548 100644 --- a/x/ccv/provider/types/tx.pb.go +++ b/x/ccv/provider/types/tx.pb.go @@ -276,9 +276,10 @@ type MsgOptIn struct { ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` // the validator address on the provider ProviderAddr string `protobuf:"bytes,2,opt,name=provider_addr,json=providerAddr,proto3" json:"provider_addr,omitempty" yaml:"address"` - // (optional) the consensus public key to use on the consumer in json string format corresponding to proto-any, - // for example `{"@type":"/cosmos.crypto.ed25519.PubKey","key":"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is="}` - // we can set `consumer_key = ""` if we do not consider the `consumer_key` + // (optional) The consensus public key to use on the consumer in json string format corresponding to proto-any, + // for example `{"@type":"/cosmos.crypto.ed25519.PubKey","key":"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is="}`. + // This field is optional and can remain empty (i.e., `consumer_key = ""`). A validator can always change the + // consumer public key at a later stage by issuing a `MsgAssignConsumerKey` message. ConsumerKey string `protobuf:"bytes,3,opt,name=consumer_key,json=consumerKey,proto3" json:"consumer_key,omitempty"` } From 74479ea251c47d448969cce6f327b7123e264744 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Wed, 1 May 2024 16:25:55 +0200 Subject: [PATCH 107/110] Update v4 to v5 in package version --- .../ante/forbidden_proposals_ante_test.go | 4 +-- app/consumer-democracy/ante_handler.go | 6 ++-- app/consumer-democracy/app.go | 16 +++++----- .../proposals_whitelisting_test.go | 6 ++-- .../ante/disabled_modules_ante_test.go | 4 +-- app/consumer/ante/msg_filter_ante_test.go | 4 +-- app/consumer/ante_handler.go | 4 +-- app/consumer/app.go | 10 +++---- app/consumer/genesis.go | 4 +-- app/consumer/genesis_test.go | 6 ++-- app/provider/app.go | 14 ++++----- app/sovereign/app.go | 5 ++-- cmd/interchain-security-cd/cmd/root.go | 4 +-- cmd/interchain-security-cd/main.go | 6 ++-- cmd/interchain-security-cdd/cmd/root.go | 4 +-- cmd/interchain-security-cdd/main.go | 6 ++-- cmd/interchain-security-pd/cmd/root.go | 4 +-- cmd/interchain-security-pd/main.go | 6 ++-- cmd/interchain-security-sd/cmd/root.go | 4 +-- cmd/interchain-security-sd/main.go | 6 ++-- go.mod | 2 +- .../ccv/consumer/v1/consumer.proto | 2 +- .../ccv/consumer/v1/genesis.proto | 2 +- .../ccv/consumer/v1/query.proto | 2 +- .../ccv/provider/v1/genesis.proto | 2 +- .../ccv/provider/v1/provider.proto | 2 +- .../ccv/provider/v1/query.proto | 2 +- .../ccv/provider/v1/tx.proto | 2 +- .../ccv/v1/shared_consumer.proto | 2 +- proto/interchain_security/ccv/v1/wire.proto | 2 +- scripts/protocgen.sh | 2 +- tests/e2e/actions.go | 6 ++-- tests/integration/common.go | 8 ++--- tests/integration/democracy.go | 6 ++-- tests/integration/distribution.go | 12 ++++---- tests/integration/double_vote.go | 4 +-- tests/integration/expired_client.go | 2 +- tests/integration/instance_test.go | 10 +++---- tests/integration/key_assignment.go | 4 +-- tests/integration/misbehaviour.go | 4 +-- tests/integration/normal_operations.go | 4 +-- tests/integration/setup.go | 12 ++++---- tests/integration/slashing.go | 6 ++-- tests/integration/soft_opt_out.go | 4 +-- tests/integration/stop_consumer.go | 2 +- tests/integration/throttle.go | 8 ++--- tests/integration/throttle_retry.go | 2 +- tests/integration/unbonding.go | 4 +-- tests/integration/valset_update.go | 2 +- tests/mbt/driver/core.go | 16 +++++----- tests/mbt/driver/mbt_test.go | 6 ++-- tests/mbt/driver/setup.go | 12 ++++---- testutil/crypto/crypto.go | 2 +- testutil/ibc_testing/generic_setup.go | 8 ++--- testutil/ibc_testing/specific_setup.go | 10 +++---- testutil/integration/debug_test.go | 10 +++---- testutil/integration/interfaces.go | 6 ++-- testutil/keeper/expectations.go | 4 +-- testutil/keeper/unit_test_helpers.go | 10 +++---- x/ccv/consumer/client/cli/query.go | 2 +- x/ccv/consumer/ibc_module.go | 6 ++-- x/ccv/consumer/ibc_module_test.go | 8 ++--- x/ccv/consumer/keeper/changeover_test.go | 4 +-- x/ccv/consumer/keeper/distribution.go | 4 +-- x/ccv/consumer/keeper/distribution_test.go | 6 ++-- x/ccv/consumer/keeper/genesis.go | 4 +-- x/ccv/consumer/keeper/genesis_test.go | 10 +++---- x/ccv/consumer/keeper/grpc_query.go | 4 +-- x/ccv/consumer/keeper/hooks.go | 2 +- x/ccv/consumer/keeper/keeper.go | 4 +-- x/ccv/consumer/keeper/keeper_test.go | 8 ++--- x/ccv/consumer/keeper/migrations.go | 2 +- x/ccv/consumer/keeper/params.go | 2 +- x/ccv/consumer/keeper/params_test.go | 4 +-- x/ccv/consumer/keeper/provider_info.go | 4 +-- x/ccv/consumer/keeper/relay.go | 4 +-- x/ccv/consumer/keeper/relay_test.go | 10 +++---- x/ccv/consumer/keeper/soft_opt_out.go | 2 +- x/ccv/consumer/keeper/soft_opt_out_test.go | 6 ++-- x/ccv/consumer/keeper/throttle_retry.go | 2 +- x/ccv/consumer/keeper/throttle_retry_test.go | 6 ++-- x/ccv/consumer/keeper/validators.go | 2 +- x/ccv/consumer/keeper/validators_test.go | 8 ++--- x/ccv/consumer/migrations/v2/migration.go | 4 +-- .../consumer/migrations/v2/migration_test.go | 8 ++--- x/ccv/consumer/module.go | 8 ++--- x/ccv/consumer/types/genesis.go | 2 +- x/ccv/consumer/types/genesis.pb.go | 2 +- x/ccv/consumer/types/genesis_test.go | 6 ++-- x/ccv/consumer/types/keys.go | 2 +- x/ccv/consumer/types/params_test.go | 2 +- x/ccv/consumer/types/query.pb.go | 2 +- x/ccv/democracy/distribution/module.go | 2 +- x/ccv/provider/client/cli/query.go | 2 +- x/ccv/provider/client/cli/tx.go | 2 +- x/ccv/provider/client/proposal_handler.go | 2 +- x/ccv/provider/handler.go | 4 +-- x/ccv/provider/handler_test.go | 10 +++---- x/ccv/provider/ibc_middleware.go | 4 +-- x/ccv/provider/ibc_middleware_test.go | 2 +- x/ccv/provider/ibc_module.go | 6 ++-- x/ccv/provider/ibc_module_test.go | 10 +++---- .../provider/keeper/consumer_equivocation.go | 4 +-- .../keeper/consumer_equivocation_test.go | 6 ++-- x/ccv/provider/keeper/distribution.go | 2 +- x/ccv/provider/keeper/distribution_test.go | 6 ++-- x/ccv/provider/keeper/genesis.go | 4 +-- x/ccv/provider/keeper/genesis_test.go | 10 +++---- x/ccv/provider/keeper/grpc_query.go | 4 +-- x/ccv/provider/keeper/grpc_query_test.go | 8 ++--- x/ccv/provider/keeper/hooks.go | 6 ++-- x/ccv/provider/keeper/hooks_test.go | 6 ++-- x/ccv/provider/keeper/keeper.go | 6 ++-- x/ccv/provider/keeper/keeper_test.go | 8 ++--- x/ccv/provider/keeper/key_assignment.go | 4 +-- x/ccv/provider/keeper/key_assignment_test.go | 10 +++---- x/ccv/provider/keeper/msg_server.go | 4 +-- x/ccv/provider/keeper/params.go | 4 +-- x/ccv/provider/keeper/params_test.go | 4 +-- x/ccv/provider/keeper/partial_set_security.go | 2 +- .../keeper/partial_set_security_test.go | 8 ++--- x/ccv/provider/keeper/proposal.go | 4 +-- x/ccv/provider/keeper/proposal_test.go | 10 +++---- x/ccv/provider/keeper/relay.go | 4 +-- x/ccv/provider/keeper/relay_test.go | 14 ++++----- x/ccv/provider/keeper/throttle.go | 2 +- x/ccv/provider/keeper/throttle_legacy.go | 4 +-- x/ccv/provider/keeper/throttle_test.go | 4 +-- x/ccv/provider/keeper/validator_set_update.go | 2 +- .../keeper/validator_set_update_test.go | 8 ++--- x/ccv/provider/migrations/migrator.go | 10 +++---- .../provider/migrations/v3/migration_test.go | 2 +- x/ccv/provider/migrations/v3/migrations.go | 2 +- .../provider/migrations/v4/migration_test.go | 4 +-- x/ccv/provider/migrations/v4/migrations.go | 2 +- .../migrations/vPSS/migration_test.go | 30 ------------------- x/ccv/provider/migrations/vPSS/migrations.go | 24 --------------- x/ccv/provider/module.go | 8 ++--- x/ccv/provider/module_test.go | 8 ++--- x/ccv/provider/proposal_handler.go | 4 +-- x/ccv/provider/proposal_handler_test.go | 6 ++-- x/ccv/provider/types/consumer.go | 2 +- x/ccv/provider/types/genesis.go | 2 +- x/ccv/provider/types/genesis.pb.go | 2 +- x/ccv/provider/types/genesis_test.go | 6 ++-- x/ccv/provider/types/key_assignment.go | 2 +- x/ccv/provider/types/keys.go | 2 +- x/ccv/provider/types/keys_test.go | 4 +-- x/ccv/provider/types/msg.go | 2 +- x/ccv/provider/types/params.go | 2 +- x/ccv/provider/types/params_test.go | 2 +- x/ccv/provider/types/proposal.go | 2 +- x/ccv/provider/types/proposal_test.go | 2 +- x/ccv/provider/types/provider.pb.go | 2 +- x/ccv/provider/types/query.pb.go | 2 +- x/ccv/types/utils_test.go | 2 +- x/ccv/types/wire_test.go | 4 +-- 157 files changed, 384 insertions(+), 437 deletions(-) delete mode 100644 x/ccv/provider/migrations/vPSS/migration_test.go delete mode 100644 x/ccv/provider/migrations/vPSS/migrations.go diff --git a/app/consumer-democracy/ante/forbidden_proposals_ante_test.go b/app/consumer-democracy/ante/forbidden_proposals_ante_test.go index 8fd7fe3824..c4c7123290 100644 --- a/app/consumer-democracy/ante/forbidden_proposals_ante_test.go +++ b/app/consumer-democracy/ante/forbidden_proposals_ante_test.go @@ -14,8 +14,8 @@ import ( minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" "github.com/cosmos/cosmos-sdk/x/params/types/proposal" - app "github.com/cosmos/interchain-security/v4/app/consumer-democracy" - "github.com/cosmos/interchain-security/v4/app/consumer-democracy/ante" + app "github.com/cosmos/interchain-security/v5/app/consumer-democracy" + "github.com/cosmos/interchain-security/v5/app/consumer-democracy/ante" ) // in SDKv47 parameter updates full params object is required diff --git a/app/consumer-democracy/ante_handler.go b/app/consumer-democracy/ante_handler.go index 7e652ebb0c..b0f7432fb6 100644 --- a/app/consumer-democracy/ante_handler.go +++ b/app/consumer-democracy/ante_handler.go @@ -10,9 +10,9 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth/ante" - democracyante "github.com/cosmos/interchain-security/v4/app/consumer-democracy/ante" - consumerante "github.com/cosmos/interchain-security/v4/app/consumer/ante" - ibcconsumerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/consumer/keeper" + democracyante "github.com/cosmos/interchain-security/v5/app/consumer-democracy/ante" + consumerante "github.com/cosmos/interchain-security/v5/app/consumer/ante" + ibcconsumerkeeper "github.com/cosmos/interchain-security/v5/x/ccv/consumer/keeper" ) // HandlerOptions extend the SDK's AnteHandler options by requiring the IBC diff --git a/app/consumer-democracy/app.go b/app/consumer-democracy/app.go index e90d35760e..190e6680d8 100644 --- a/app/consumer-democracy/app.go +++ b/app/consumer-democracy/app.go @@ -103,14 +103,14 @@ import ( "github.com/cometbft/cometbft/libs/log" tmos "github.com/cometbft/cometbft/libs/os" - appencoding "github.com/cosmos/interchain-security/v4/app/encoding" - testutil "github.com/cosmos/interchain-security/v4/testutil/integration" - consumer "github.com/cosmos/interchain-security/v4/x/ccv/consumer" - consumerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/consumer/keeper" - consumertypes "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" - ccvdistr "github.com/cosmos/interchain-security/v4/x/ccv/democracy/distribution" - ccvgov "github.com/cosmos/interchain-security/v4/x/ccv/democracy/governance" - ccvstaking "github.com/cosmos/interchain-security/v4/x/ccv/democracy/staking" + appencoding "github.com/cosmos/interchain-security/v5/app/encoding" + testutil "github.com/cosmos/interchain-security/v5/testutil/integration" + consumer "github.com/cosmos/interchain-security/v5/x/ccv/consumer" + consumerkeeper "github.com/cosmos/interchain-security/v5/x/ccv/consumer/keeper" + consumertypes "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" + ccvdistr "github.com/cosmos/interchain-security/v5/x/ccv/democracy/distribution" + ccvgov "github.com/cosmos/interchain-security/v5/x/ccv/democracy/governance" + ccvstaking "github.com/cosmos/interchain-security/v5/x/ccv/democracy/staking" ) const ( diff --git a/app/consumer-democracy/proposals_whitelisting_test.go b/app/consumer-democracy/proposals_whitelisting_test.go index 47dd42317a..c4209bf3b9 100644 --- a/app/consumer-democracy/proposals_whitelisting_test.go +++ b/app/consumer-democracy/proposals_whitelisting_test.go @@ -6,9 +6,9 @@ import ( ibctesting "github.com/cosmos/ibc-go/v7/testing" "github.com/stretchr/testify/require" - appConsumer "github.com/cosmos/interchain-security/v4/app/consumer-democracy" - icstestingutils "github.com/cosmos/interchain-security/v4/testutil/ibc_testing" - testutil "github.com/cosmos/interchain-security/v4/testutil/integration" + appConsumer "github.com/cosmos/interchain-security/v5/app/consumer-democracy" + icstestingutils "github.com/cosmos/interchain-security/v5/testutil/ibc_testing" + testutil "github.com/cosmos/interchain-security/v5/testutil/integration" ) func TestDemocracyGovernanceWhitelistingKeys(t *testing.T) { diff --git a/app/consumer/ante/disabled_modules_ante_test.go b/app/consumer/ante/disabled_modules_ante_test.go index 7fa95f37c6..d06c3ad595 100644 --- a/app/consumer/ante/disabled_modules_ante_test.go +++ b/app/consumer/ante/disabled_modules_ante_test.go @@ -12,8 +12,8 @@ import ( evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" - "github.com/cosmos/interchain-security/v4/app/consumer/ante" - appencoding "github.com/cosmos/interchain-security/v4/app/encoding" + "github.com/cosmos/interchain-security/v5/app/consumer/ante" + appencoding "github.com/cosmos/interchain-security/v5/app/encoding" ) func TestDisabledModulesDecorator(t *testing.T) { diff --git a/app/consumer/ante/msg_filter_ante_test.go b/app/consumer/ante/msg_filter_ante_test.go index bfc1bb0a50..9dd5f47ef3 100644 --- a/app/consumer/ante/msg_filter_ante_test.go +++ b/app/consumer/ante/msg_filter_ante_test.go @@ -9,8 +9,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/cosmos/interchain-security/v4/app/consumer/ante" - appencoding "github.com/cosmos/interchain-security/v4/app/encoding" + "github.com/cosmos/interchain-security/v5/app/consumer/ante" + appencoding "github.com/cosmos/interchain-security/v5/app/encoding" ) type consumerKeeper struct { diff --git a/app/consumer/ante_handler.go b/app/consumer/ante_handler.go index fa28a52caf..f9cd986dad 100644 --- a/app/consumer/ante_handler.go +++ b/app/consumer/ante_handler.go @@ -10,8 +10,8 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth/ante" - consumerante "github.com/cosmos/interchain-security/v4/app/consumer/ante" - ibcconsumerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/consumer/keeper" + consumerante "github.com/cosmos/interchain-security/v5/app/consumer/ante" + ibcconsumerkeeper "github.com/cosmos/interchain-security/v5/x/ccv/consumer/keeper" ) // HandlerOptions extend the SDK's AnteHandler options by requiring the IBC diff --git a/app/consumer/app.go b/app/consumer/app.go index 9853145117..207939adcb 100644 --- a/app/consumer/app.go +++ b/app/consumer/app.go @@ -87,11 +87,11 @@ import ( "github.com/cometbft/cometbft/libs/log" tmos "github.com/cometbft/cometbft/libs/os" - appencoding "github.com/cosmos/interchain-security/v4/app/encoding" - testutil "github.com/cosmos/interchain-security/v4/testutil/integration" - ibcconsumer "github.com/cosmos/interchain-security/v4/x/ccv/consumer" - ibcconsumerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/consumer/keeper" - ibcconsumertypes "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" + appencoding "github.com/cosmos/interchain-security/v5/app/encoding" + testutil "github.com/cosmos/interchain-security/v5/testutil/integration" + ibcconsumer "github.com/cosmos/interchain-security/v5/x/ccv/consumer" + ibcconsumerkeeper "github.com/cosmos/interchain-security/v5/x/ccv/consumer/keeper" + ibcconsumertypes "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" ) const ( diff --git a/app/consumer/genesis.go b/app/consumer/genesis.go index f6c8e47905..da55a0334e 100644 --- a/app/consumer/genesis.go +++ b/app/consumer/genesis.go @@ -16,8 +16,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" - consumerTypes "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" - "github.com/cosmos/interchain-security/v4/x/ccv/types" + consumerTypes "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" + "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // The genesis state of the blockchain is represented here as a map of raw json diff --git a/app/consumer/genesis_test.go b/app/consumer/genesis_test.go index 5827651959..2dd29e1b71 100644 --- a/app/consumer/genesis_test.go +++ b/app/consumer/genesis_test.go @@ -16,9 +16,9 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/x/auth/types" - app "github.com/cosmos/interchain-security/v4/app/consumer" - consumerTypes "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + app "github.com/cosmos/interchain-security/v5/app/consumer" + consumerTypes "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) const ( diff --git a/app/provider/app.go b/app/provider/app.go index 9cf45fe7e3..e5baa31270 100644 --- a/app/provider/app.go +++ b/app/provider/app.go @@ -100,13 +100,13 @@ import ( "github.com/cometbft/cometbft/libs/log" tmos "github.com/cometbft/cometbft/libs/os" - appencoding "github.com/cosmos/interchain-security/v4/app/encoding" - testutil "github.com/cosmos/interchain-security/v4/testutil/integration" - "github.com/cosmos/interchain-security/v4/x/ccv/provider" - ibcprovider "github.com/cosmos/interchain-security/v4/x/ccv/provider" - ibcproviderclient "github.com/cosmos/interchain-security/v4/x/ccv/provider/client" - ibcproviderkeeper "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" - providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + appencoding "github.com/cosmos/interchain-security/v5/app/encoding" + testutil "github.com/cosmos/interchain-security/v5/testutil/integration" + "github.com/cosmos/interchain-security/v5/x/ccv/provider" + ibcprovider "github.com/cosmos/interchain-security/v5/x/ccv/provider" + ibcproviderclient "github.com/cosmos/interchain-security/v5/x/ccv/provider/client" + ibcproviderkeeper "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper" + providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ) const ( diff --git a/app/sovereign/app.go b/app/sovereign/app.go index 3d1a981e83..6dd9774f3b 100644 --- a/app/sovereign/app.go +++ b/app/sovereign/app.go @@ -79,6 +79,7 @@ import ( govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + // add mint mint "github.com/cosmos/cosmos-sdk/x/mint" mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper" @@ -105,8 +106,8 @@ import ( "github.com/cometbft/cometbft/libs/log" tmos "github.com/cometbft/cometbft/libs/os" - appencoding "github.com/cosmos/interchain-security/v4/app/encoding" - testutil "github.com/cosmos/interchain-security/v4/testutil/integration" + appencoding "github.com/cosmos/interchain-security/v5/app/encoding" + testutil "github.com/cosmos/interchain-security/v5/testutil/integration" ) const ( diff --git a/cmd/interchain-security-cd/cmd/root.go b/cmd/interchain-security-cd/cmd/root.go index 215b45317a..3d844d9c7c 100644 --- a/cmd/interchain-security-cd/cmd/root.go +++ b/cmd/interchain-security-cd/cmd/root.go @@ -31,8 +31,8 @@ import ( tmcfg "github.com/cometbft/cometbft/config" "github.com/cometbft/cometbft/libs/log" - consumer "github.com/cosmos/interchain-security/v4/app/consumer" - appencoding "github.com/cosmos/interchain-security/v4/app/encoding" + consumer "github.com/cosmos/interchain-security/v5/app/consumer" + appencoding "github.com/cosmos/interchain-security/v5/app/encoding" ) // NewRootCmd creates a new root command for simd. It is called once in the diff --git a/cmd/interchain-security-cd/main.go b/cmd/interchain-security-cd/main.go index a64a2a8645..7cbe0a898a 100644 --- a/cmd/interchain-security-cd/main.go +++ b/cmd/interchain-security-cd/main.go @@ -6,9 +6,9 @@ import ( "github.com/cosmos/cosmos-sdk/server" svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" - app "github.com/cosmos/interchain-security/v4/app/consumer" - appparams "github.com/cosmos/interchain-security/v4/app/params" - "github.com/cosmos/interchain-security/v4/cmd/interchain-security-cd/cmd" + app "github.com/cosmos/interchain-security/v5/app/consumer" + appparams "github.com/cosmos/interchain-security/v5/app/params" + "github.com/cosmos/interchain-security/v5/cmd/interchain-security-cd/cmd" ) func main() { diff --git a/cmd/interchain-security-cdd/cmd/root.go b/cmd/interchain-security-cdd/cmd/root.go index 6b2e6cc726..cb5140ade6 100644 --- a/cmd/interchain-security-cdd/cmd/root.go +++ b/cmd/interchain-security-cdd/cmd/root.go @@ -31,8 +31,8 @@ import ( tmcfg "github.com/cometbft/cometbft/config" "github.com/cometbft/cometbft/libs/log" - cdd "github.com/cosmos/interchain-security/v4/app/consumer-democracy" - appencoding "github.com/cosmos/interchain-security/v4/app/encoding" + cdd "github.com/cosmos/interchain-security/v5/app/consumer-democracy" + appencoding "github.com/cosmos/interchain-security/v5/app/encoding" ) // NewRootCmd creates a new root command for simd. It is called once in the diff --git a/cmd/interchain-security-cdd/main.go b/cmd/interchain-security-cdd/main.go index 9b6aacd759..9fbd09df75 100644 --- a/cmd/interchain-security-cdd/main.go +++ b/cmd/interchain-security-cdd/main.go @@ -6,9 +6,9 @@ import ( "github.com/cosmos/cosmos-sdk/server" svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" - app "github.com/cosmos/interchain-security/v4/app/consumer-democracy" - appparams "github.com/cosmos/interchain-security/v4/app/params" - "github.com/cosmos/interchain-security/v4/cmd/interchain-security-cdd/cmd" + app "github.com/cosmos/interchain-security/v5/app/consumer-democracy" + appparams "github.com/cosmos/interchain-security/v5/app/params" + "github.com/cosmos/interchain-security/v5/cmd/interchain-security-cdd/cmd" ) func main() { diff --git a/cmd/interchain-security-pd/cmd/root.go b/cmd/interchain-security-pd/cmd/root.go index 8a8f5fec32..7f1b0a6b9a 100644 --- a/cmd/interchain-security-pd/cmd/root.go +++ b/cmd/interchain-security-pd/cmd/root.go @@ -31,8 +31,8 @@ import ( tmcfg "github.com/cometbft/cometbft/config" "github.com/cometbft/cometbft/libs/log" - appencoding "github.com/cosmos/interchain-security/v4/app/encoding" - providerApp "github.com/cosmos/interchain-security/v4/app/provider" + appencoding "github.com/cosmos/interchain-security/v5/app/encoding" + providerApp "github.com/cosmos/interchain-security/v5/app/provider" ) // NewRootCmd creates a new root command for simd. It is called once in the diff --git a/cmd/interchain-security-pd/main.go b/cmd/interchain-security-pd/main.go index 7788f06bff..dab89c91fc 100644 --- a/cmd/interchain-security-pd/main.go +++ b/cmd/interchain-security-pd/main.go @@ -6,9 +6,9 @@ import ( "github.com/cosmos/cosmos-sdk/server" svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" - appparams "github.com/cosmos/interchain-security/v4/app/params" - app "github.com/cosmos/interchain-security/v4/app/provider" - "github.com/cosmos/interchain-security/v4/cmd/interchain-security-pd/cmd" + appparams "github.com/cosmos/interchain-security/v5/app/params" + app "github.com/cosmos/interchain-security/v5/app/provider" + "github.com/cosmos/interchain-security/v5/cmd/interchain-security-pd/cmd" ) func main() { diff --git a/cmd/interchain-security-sd/cmd/root.go b/cmd/interchain-security-sd/cmd/root.go index 28520ef1a4..10a79a251a 100644 --- a/cmd/interchain-security-sd/cmd/root.go +++ b/cmd/interchain-security-sd/cmd/root.go @@ -31,8 +31,8 @@ import ( tmcfg "github.com/cometbft/cometbft/config" "github.com/cometbft/cometbft/libs/log" - appencoding "github.com/cosmos/interchain-security/v4/app/encoding" - sovereignApp "github.com/cosmos/interchain-security/v4/app/sovereign" + appencoding "github.com/cosmos/interchain-security/v5/app/encoding" + sovereignApp "github.com/cosmos/interchain-security/v5/app/sovereign" ) // NewRootCmd creates a new root command for simd. It is called once in the diff --git a/cmd/interchain-security-sd/main.go b/cmd/interchain-security-sd/main.go index 2265afad90..e719eb48f3 100644 --- a/cmd/interchain-security-sd/main.go +++ b/cmd/interchain-security-sd/main.go @@ -6,9 +6,9 @@ import ( "github.com/cosmos/cosmos-sdk/server" svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" - appparams "github.com/cosmos/interchain-security/v4/app/params" - app "github.com/cosmos/interchain-security/v4/app/sovereign" - "github.com/cosmos/interchain-security/v4/cmd/interchain-security-sd/cmd" + appparams "github.com/cosmos/interchain-security/v5/app/params" + app "github.com/cosmos/interchain-security/v5/app/sovereign" + "github.com/cosmos/interchain-security/v5/cmd/interchain-security-sd/cmd" ) func main() { diff --git a/go.mod b/go.mod index 046e92170a..b534b87380 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/cosmos/interchain-security/v4 +module github.com/cosmos/interchain-security/v5 go 1.21.1 diff --git a/proto/interchain_security/ccv/consumer/v1/consumer.proto b/proto/interchain_security/ccv/consumer/v1/consumer.proto index 749eedc7ac..959d06c087 100644 --- a/proto/interchain_security/ccv/consumer/v1/consumer.proto +++ b/proto/interchain_security/ccv/consumer/v1/consumer.proto @@ -1,7 +1,7 @@ syntax = "proto3"; package interchain_security.ccv.consumer.v1; -option go_package = "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types"; +option go_package = "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types"; import "google/protobuf/any.proto"; import "gogoproto/gogo.proto"; diff --git a/proto/interchain_security/ccv/consumer/v1/genesis.proto b/proto/interchain_security/ccv/consumer/v1/genesis.proto index a2ceb0f9f6..642b78451d 100644 --- a/proto/interchain_security/ccv/consumer/v1/genesis.proto +++ b/proto/interchain_security/ccv/consumer/v1/genesis.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package interchain_security.ccv.consumer.v1; -option go_package = "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types"; +option go_package = "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types"; import "interchain_security/ccv/v1/shared_consumer.proto"; import "ibc/lightclients/tendermint/v1/tendermint.proto"; diff --git a/proto/interchain_security/ccv/consumer/v1/query.proto b/proto/interchain_security/ccv/consumer/v1/query.proto index eb8eb29a3d..0e9b088e1d 100644 --- a/proto/interchain_security/ccv/consumer/v1/query.proto +++ b/proto/interchain_security/ccv/consumer/v1/query.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package interchain_security.ccv.consumer.v1; import "interchain_security/ccv/v1/shared_consumer.proto"; -option go_package = "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types"; +option go_package = "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types"; import "gogoproto/gogo.proto"; import "google/api/annotations.proto"; diff --git a/proto/interchain_security/ccv/provider/v1/genesis.proto b/proto/interchain_security/ccv/provider/v1/genesis.proto index 443ea26b32..269743721e 100644 --- a/proto/interchain_security/ccv/provider/v1/genesis.proto +++ b/proto/interchain_security/ccv/provider/v1/genesis.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package interchain_security.ccv.provider.v1; -option go_package = "github.com/cosmos/interchain-security/v4/x/ccv/provider/types"; +option go_package = "github.com/cosmos/interchain-security/v5/x/ccv/provider/types"; import "gogoproto/gogo.proto"; import "interchain_security/ccv/v1/shared_consumer.proto"; diff --git a/proto/interchain_security/ccv/provider/v1/provider.proto b/proto/interchain_security/ccv/provider/v1/provider.proto index 139cc9d25f..068cdc0f06 100644 --- a/proto/interchain_security/ccv/provider/v1/provider.proto +++ b/proto/interchain_security/ccv/provider/v1/provider.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package interchain_security.ccv.provider.v1; -option go_package = "github.com/cosmos/interchain-security/v4/x/ccv/provider/types"; +option go_package = "github.com/cosmos/interchain-security/v5/x/ccv/provider/types"; import "interchain_security/ccv/v1/wire.proto"; import "gogoproto/gogo.proto"; diff --git a/proto/interchain_security/ccv/provider/v1/query.proto b/proto/interchain_security/ccv/provider/v1/query.proto index 139a7386de..f6d5d5a379 100644 --- a/proto/interchain_security/ccv/provider/v1/query.proto +++ b/proto/interchain_security/ccv/provider/v1/query.proto @@ -1,7 +1,7 @@ syntax = "proto3"; package interchain_security.ccv.provider.v1; -option go_package = "github.com/cosmos/interchain-security/v4/x/ccv/provider/types"; +option go_package = "github.com/cosmos/interchain-security/v5/x/ccv/provider/types"; import "google/api/annotations.proto"; import "gogoproto/gogo.proto"; diff --git a/proto/interchain_security/ccv/provider/v1/tx.proto b/proto/interchain_security/ccv/provider/v1/tx.proto index 8e8aab5408..02a69d25f9 100644 --- a/proto/interchain_security/ccv/provider/v1/tx.proto +++ b/proto/interchain_security/ccv/provider/v1/tx.proto @@ -1,7 +1,7 @@ syntax = "proto3"; package interchain_security.ccv.provider.v1; -option go_package = "github.com/cosmos/interchain-security/v4/x/ccv/provider/types"; +option go_package = "github.com/cosmos/interchain-security/v5/x/ccv/provider/types"; import "gogoproto/gogo.proto"; import "cosmos_proto/cosmos.proto"; diff --git a/proto/interchain_security/ccv/v1/shared_consumer.proto b/proto/interchain_security/ccv/v1/shared_consumer.proto index d1f0a5d5a3..ce65df04a6 100644 --- a/proto/interchain_security/ccv/v1/shared_consumer.proto +++ b/proto/interchain_security/ccv/v1/shared_consumer.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package interchain_security.ccv.v1; -option go_package = "github.com/cosmos/interchain-security/v4/x/ccv/types"; +option go_package = "github.com/cosmos/interchain-security/v5/x/ccv/types"; import "tendermint/abci/types.proto"; import "ibc/lightclients/tendermint/v1/tendermint.proto"; diff --git a/proto/interchain_security/ccv/v1/wire.proto b/proto/interchain_security/ccv/v1/wire.proto index 7382b9d0da..f0ba6ab41a 100644 --- a/proto/interchain_security/ccv/v1/wire.proto +++ b/proto/interchain_security/ccv/v1/wire.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package interchain_security.ccv.v1; -option go_package = "github.com/cosmos/interchain-security/v4/x/ccv/types"; +option go_package = "github.com/cosmos/interchain-security/v5/x/ccv/types"; import "cosmos/staking/v1beta1/staking.proto"; diff --git a/scripts/protocgen.sh b/scripts/protocgen.sh index 67ae158143..fdf6a894c1 100644 --- a/scripts/protocgen.sh +++ b/scripts/protocgen.sh @@ -16,6 +16,6 @@ done cd .. # move proto files to the right places -cp -r github.com/cosmos/interchain-security/v4/* ./ +cp -r github.com/cosmos/interchain-security/v5/* ./ rm -rf github.com diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index 1587608177..31813efd27 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -19,9 +19,9 @@ import ( "github.com/tidwall/gjson" "golang.org/x/mod/semver" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/client" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/client" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) const ( diff --git a/tests/integration/common.go b/tests/integration/common.go index 18b657ae56..7c4e88c344 100644 --- a/tests/integration/common.go +++ b/tests/integration/common.go @@ -22,10 +22,10 @@ import ( abci "github.com/cometbft/cometbft/abci/types" tmtypes "github.com/cometbft/cometbft/types" - icstestingutils "github.com/cosmos/interchain-security/v4/testutil/ibc_testing" - testutil "github.com/cosmos/interchain-security/v4/testutil/integration" - providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + icstestingutils "github.com/cosmos/interchain-security/v5/testutil/ibc_testing" + testutil "github.com/cosmos/interchain-security/v5/testutil/integration" + providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // ChainType defines the type of chain (either provider or consumer) diff --git a/tests/integration/democracy.go b/tests/integration/democracy.go index bbada900a8..53333aba0e 100644 --- a/tests/integration/democracy.go +++ b/tests/integration/democracy.go @@ -14,9 +14,9 @@ import ( govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" - icstestingutils "github.com/cosmos/interchain-security/v4/testutil/ibc_testing" - testutil "github.com/cosmos/interchain-security/v4/testutil/integration" - consumertypes "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" + icstestingutils "github.com/cosmos/interchain-security/v5/testutil/ibc_testing" + testutil "github.com/cosmos/interchain-security/v5/testutil/integration" + consumertypes "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" ) type ConsumerDemocracyTestSuite struct { diff --git a/tests/integration/distribution.go b/tests/integration/distribution.go index 5d62b2ee35..edd7e3e0e1 100644 --- a/tests/integration/distribution.go +++ b/tests/integration/distribution.go @@ -15,12 +15,12 @@ import ( abci "github.com/cometbft/cometbft/abci/types" - icstestingutils "github.com/cosmos/interchain-security/v4/testutil/integration" - consumerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/consumer/keeper" - consumertypes "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" - providerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" - providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + icstestingutils "github.com/cosmos/interchain-security/v5/testutil/integration" + consumerkeeper "github.com/cosmos/interchain-security/v5/x/ccv/consumer/keeper" + consumertypes "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" + providerkeeper "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper" + providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // This test is valid for minimal viable consumer chain diff --git a/tests/integration/double_vote.go b/tests/integration/double_vote.go index c22ba3b063..c23d3feb06 100644 --- a/tests/integration/double_vote.go +++ b/tests/integration/double_vote.go @@ -7,8 +7,8 @@ import ( tmcrypto "github.com/cometbft/cometbft/crypto" tmtypes "github.com/cometbft/cometbft/types" - testutil "github.com/cosmos/interchain-security/v4/testutil/crypto" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + testutil "github.com/cosmos/interchain-security/v5/testutil/crypto" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ) // TestHandleConsumerDoubleVoting verifies that handling a double voting evidence diff --git a/tests/integration/expired_client.go b/tests/integration/expired_client.go index a46df32d8e..d5405df1c2 100644 --- a/tests/integration/expired_client.go +++ b/tests/integration/expired_client.go @@ -14,7 +14,7 @@ import ( abci "github.com/cometbft/cometbft/abci/types" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // TestVSCPacketSendWithExpiredClient tests queueing of VSCPackets when the consumer client is expired. diff --git a/tests/integration/instance_test.go b/tests/integration/instance_test.go index d2896ad964..424c6c85f5 100644 --- a/tests/integration/instance_test.go +++ b/tests/integration/instance_test.go @@ -5,11 +5,11 @@ import ( "github.com/stretchr/testify/suite" - appConsumer "github.com/cosmos/interchain-security/v4/app/consumer" - appConsumerDemocracy "github.com/cosmos/interchain-security/v4/app/consumer-democracy" - appProvider "github.com/cosmos/interchain-security/v4/app/provider" - intg "github.com/cosmos/interchain-security/v4/tests/integration" - icstestingutils "github.com/cosmos/interchain-security/v4/testutil/ibc_testing" + appConsumer "github.com/cosmos/interchain-security/v5/app/consumer" + appConsumerDemocracy "github.com/cosmos/interchain-security/v5/app/consumer-democracy" + appProvider "github.com/cosmos/interchain-security/v5/app/provider" + intg "github.com/cosmos/interchain-security/v5/tests/integration" + icstestingutils "github.com/cosmos/interchain-security/v5/testutil/ibc_testing" ) // This file can be used as an example integration testing instance for any provider/consumer applications. diff --git a/tests/integration/key_assignment.go b/tests/integration/key_assignment.go index 799109c0d4..ad7a1a142e 100644 --- a/tests/integration/key_assignment.go +++ b/tests/integration/key_assignment.go @@ -9,8 +9,8 @@ import ( tmencoding "github.com/cometbft/cometbft/crypto/encoding" tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" - providerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + providerkeeper "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) func (s *CCVTestSuite) TestKeyAssignment() { diff --git a/tests/integration/misbehaviour.go b/tests/integration/misbehaviour.go index acdcd0071c..cea0d15e5f 100644 --- a/tests/integration/misbehaviour.go +++ b/tests/integration/misbehaviour.go @@ -9,8 +9,8 @@ import ( tmtypes "github.com/cometbft/cometbft/types" - testutil "github.com/cosmos/interchain-security/v4/testutil/crypto" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + testutil "github.com/cosmos/interchain-security/v5/testutil/crypto" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ) // TestHandleConsumerMisbehaviour tests that handling a valid misbehaviour, diff --git a/tests/integration/normal_operations.go b/tests/integration/normal_operations.go index 81c742eeed..61f7507793 100644 --- a/tests/integration/normal_operations.go +++ b/tests/integration/normal_operations.go @@ -5,8 +5,8 @@ import ( tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - consumertypes "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + consumertypes "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // Tests the tracking of historical info in the context of new blocks being committed diff --git a/tests/integration/setup.go b/tests/integration/setup.go index cb7c78a3be..a70dab3dec 100644 --- a/tests/integration/setup.go +++ b/tests/integration/setup.go @@ -20,12 +20,12 @@ import ( abci "github.com/cometbft/cometbft/abci/types" tmencoding "github.com/cometbft/cometbft/crypto/encoding" - icstestingutils "github.com/cosmos/interchain-security/v4/testutil/ibc_testing" - testutil "github.com/cosmos/interchain-security/v4/testutil/integration" - "github.com/cosmos/interchain-security/v4/testutil/simibc" - consumertypes "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + icstestingutils "github.com/cosmos/interchain-security/v5/testutil/ibc_testing" + testutil "github.com/cosmos/interchain-security/v5/testutil/integration" + "github.com/cosmos/interchain-security/v5/testutil/simibc" + consumertypes "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // Callback for instantiating a new coordinator with a provider test chains diff --git a/tests/integration/slashing.go b/tests/integration/slashing.go index 19805a49ad..a9dcf223f2 100644 --- a/tests/integration/slashing.go +++ b/tests/integration/slashing.go @@ -18,9 +18,9 @@ import ( "github.com/cometbft/cometbft/crypto/ed25519" tmtypes "github.com/cometbft/cometbft/types" - keepertestutil "github.com/cosmos/interchain-security/v4/testutil/keeper" - providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + keepertestutil "github.com/cosmos/interchain-security/v5/testutil/keeper" + providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // TestRelayAndApplyDowntimePacket tests that downtime slash packets can be properly relayed diff --git a/tests/integration/soft_opt_out.go b/tests/integration/soft_opt_out.go index bce2e1d77c..3799de79fc 100644 --- a/tests/integration/soft_opt_out.go +++ b/tests/integration/soft_opt_out.go @@ -10,8 +10,8 @@ import ( abci "github.com/cometbft/cometbft/abci/types" - consumerKeeper "github.com/cosmos/interchain-security/v4/x/ccv/consumer/keeper" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + consumerKeeper "github.com/cosmos/interchain-security/v5/x/ccv/consumer/keeper" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // TestSoftOptOut tests the soft opt-out feature diff --git a/tests/integration/stop_consumer.go b/tests/integration/stop_consumer.go index 6e72679ccd..33f36fa186 100644 --- a/tests/integration/stop_consumer.go +++ b/tests/integration/stop_consumer.go @@ -6,7 +6,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // Tests the functionality of stopping a consumer chain at a higher level than unit tests diff --git a/tests/integration/throttle.go b/tests/integration/throttle.go index ff2d32dade..e9e013575c 100644 --- a/tests/integration/throttle.go +++ b/tests/integration/throttle.go @@ -10,10 +10,10 @@ import ( tmtypes "github.com/cometbft/cometbft/types" - icstestingutils "github.com/cosmos/interchain-security/v4/testutil/ibc_testing" - "github.com/cosmos/interchain-security/v4/x/ccv/provider" - providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + icstestingutils "github.com/cosmos/interchain-security/v5/testutil/ibc_testing" + "github.com/cosmos/interchain-security/v5/x/ccv/provider" + providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) const fullSlashMeterString = "1.0" diff --git a/tests/integration/throttle_retry.go b/tests/integration/throttle_retry.go index 36acad3602..3d26847136 100644 --- a/tests/integration/throttle_retry.go +++ b/tests/integration/throttle_retry.go @@ -7,7 +7,7 @@ import ( stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // TestSlashRetries tests the throttling v2 retry logic at an integration level. diff --git a/tests/integration/unbonding.go b/tests/integration/unbonding.go index 7f87516444..ca94fd3679 100644 --- a/tests/integration/unbonding.go +++ b/tests/integration/unbonding.go @@ -7,8 +7,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - providerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + providerkeeper "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // TestUndelegationNormalOperation tests that undelegations complete after diff --git a/tests/integration/valset_update.go b/tests/integration/valset_update.go index eb0560a35e..113dcc01f4 100644 --- a/tests/integration/valset_update.go +++ b/tests/integration/valset_update.go @@ -10,7 +10,7 @@ import ( abci "github.com/cometbft/cometbft/abci/types" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // TestPacketRoundtrip tests a CCV packet roundtrip when tokens are bonded on provider diff --git a/tests/mbt/driver/core.go b/tests/mbt/driver/core.go index 3c985cb6fa..9235071d3e 100644 --- a/tests/mbt/driver/core.go +++ b/tests/mbt/driver/core.go @@ -24,14 +24,14 @@ import ( "github.com/cometbft/cometbft/proto/tendermint/crypto" cmttypes "github.com/cometbft/cometbft/types" - appConsumer "github.com/cosmos/interchain-security/v4/app/consumer" - appProvider "github.com/cosmos/interchain-security/v4/app/provider" - simibc "github.com/cosmos/interchain-security/v4/testutil/simibc" - consumerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/consumer/keeper" - consumertypes "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" - providerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" - providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - "github.com/cosmos/interchain-security/v4/x/ccv/types" + appConsumer "github.com/cosmos/interchain-security/v5/app/consumer" + appProvider "github.com/cosmos/interchain-security/v5/app/provider" + simibc "github.com/cosmos/interchain-security/v5/testutil/simibc" + consumerkeeper "github.com/cosmos/interchain-security/v5/x/ccv/consumer/keeper" + consumertypes "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" + providerkeeper "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper" + providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // Define a new type for ChainIds to be more explicit diff --git a/tests/mbt/driver/mbt_test.go b/tests/mbt/driver/mbt_test.go index 9a82bd7b9b..e9a50f5c52 100644 --- a/tests/mbt/driver/mbt_test.go +++ b/tests/mbt/driver/mbt_test.go @@ -21,9 +21,9 @@ import ( tmencoding "github.com/cometbft/cometbft/crypto/encoding" cmttypes "github.com/cometbft/cometbft/types" - "github.com/cosmos/interchain-security/v4/testutil/integration" - providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - "github.com/cosmos/interchain-security/v4/x/ccv/types" + "github.com/cosmos/interchain-security/v5/testutil/integration" + providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + "github.com/cosmos/interchain-security/v5/x/ccv/types" ) const verbose = false diff --git a/tests/mbt/driver/setup.go b/tests/mbt/driver/setup.go index a49a1ac000..d30b85bf30 100644 --- a/tests/mbt/driver/setup.go +++ b/tests/mbt/driver/setup.go @@ -30,12 +30,12 @@ import ( cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" cmttypes "github.com/cometbft/cometbft/types" - icstestingutils "github.com/cosmos/interchain-security/v4/testutil/ibc_testing" - "github.com/cosmos/interchain-security/v4/testutil/integration" - simibc "github.com/cosmos/interchain-security/v4/testutil/simibc" - consumertypes "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + icstestingutils "github.com/cosmos/interchain-security/v5/testutil/ibc_testing" + "github.com/cosmos/interchain-security/v5/testutil/integration" + simibc "github.com/cosmos/interchain-security/v5/testutil/simibc" + consumertypes "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) const ( diff --git a/testutil/crypto/crypto.go b/testutil/crypto/crypto.go index a9c5341947..df37e99eb5 100644 --- a/testutil/crypto/crypto.go +++ b/testutil/crypto/crypto.go @@ -15,7 +15,7 @@ import ( tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" tmtypes "github.com/cometbft/cometbft/types" - providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ) // CryptoIdentity is a test helper for generating keys and addresses of diff --git a/testutil/ibc_testing/generic_setup.go b/testutil/ibc_testing/generic_setup.go index 09dfa62140..9d5ec02a71 100644 --- a/testutil/ibc_testing/generic_setup.go +++ b/testutil/ibc_testing/generic_setup.go @@ -16,10 +16,10 @@ import ( tmencoding "github.com/cometbft/cometbft/crypto/encoding" tmtypes "github.com/cometbft/cometbft/types" - testutil "github.com/cosmos/interchain-security/v4/testutil/integration" - testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" - consumerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/consumer/keeper" - providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + testutil "github.com/cosmos/interchain-security/v5/testutil/integration" + testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper" + consumerkeeper "github.com/cosmos/interchain-security/v5/x/ccv/consumer/keeper" + providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ) type ( diff --git a/testutil/ibc_testing/specific_setup.go b/testutil/ibc_testing/specific_setup.go index 2571346ca6..81788e10bc 100644 --- a/testutil/ibc_testing/specific_setup.go +++ b/testutil/ibc_testing/specific_setup.go @@ -17,11 +17,11 @@ import ( "github.com/cometbft/cometbft/abci/types" "github.com/cometbft/cometbft/libs/log" - appConsumer "github.com/cosmos/interchain-security/v4/app/consumer" - appConsumerDemocracy "github.com/cosmos/interchain-security/v4/app/consumer-democracy" - appProvider "github.com/cosmos/interchain-security/v4/app/provider" - consumertypes "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + appConsumer "github.com/cosmos/interchain-security/v5/app/consumer" + appConsumerDemocracy "github.com/cosmos/interchain-security/v5/app/consumer-democracy" + appProvider "github.com/cosmos/interchain-security/v5/app/provider" + consumertypes "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) var ( diff --git a/testutil/integration/debug_test.go b/testutil/integration/debug_test.go index 2481e865ab..ed0ec3d65b 100644 --- a/testutil/integration/debug_test.go +++ b/testutil/integration/debug_test.go @@ -6,11 +6,11 @@ import ( "reflect" "testing" - appConsumer "github.com/cosmos/interchain-security/v4/app/consumer" - appConsumerDemocracy "github.com/cosmos/interchain-security/v4/app/consumer-democracy" - appProvider "github.com/cosmos/interchain-security/v4/app/provider" - integr "github.com/cosmos/interchain-security/v4/tests/integration" - icstestingutils "github.com/cosmos/interchain-security/v4/testutil/ibc_testing" + appConsumer "github.com/cosmos/interchain-security/v5/app/consumer" + appConsumerDemocracy "github.com/cosmos/interchain-security/v5/app/consumer-democracy" + appProvider "github.com/cosmos/interchain-security/v5/app/provider" + integr "github.com/cosmos/interchain-security/v5/tests/integration" + icstestingutils "github.com/cosmos/interchain-security/v5/testutil/ibc_testing" ) // runCCVTestByName runs a single CCV integration test by name, using a CCVTestSuite diff --git a/testutil/integration/interfaces.go b/testutil/integration/interfaces.go index fe3382b524..83d071a037 100644 --- a/testutil/integration/interfaces.go +++ b/testutil/integration/interfaces.go @@ -20,9 +20,9 @@ import ( abci "github.com/cometbft/cometbft/abci/types" - consumerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/consumer/keeper" - providerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + consumerkeeper "github.com/cosmos/interchain-security/v5/x/ccv/consumer/keeper" + providerkeeper "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // The interface that any provider app must implement to be compatible with ccv integration tests. diff --git a/testutil/keeper/expectations.go b/testutil/keeper/expectations.go index 5a37f3a164..c595a5c080 100644 --- a/testutil/keeper/expectations.go +++ b/testutil/keeper/expectations.go @@ -17,8 +17,8 @@ import ( capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - "github.com/cosmos/interchain-security/v4/x/ccv/types" + providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // diff --git a/testutil/keeper/unit_test_helpers.go b/testutil/keeper/unit_test_helpers.go index abba1a23c9..3a80eecce8 100644 --- a/testutil/keeper/unit_test_helpers.go +++ b/testutil/keeper/unit_test_helpers.go @@ -27,11 +27,11 @@ import ( "github.com/cometbft/cometbft/libs/log" tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - consumerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/consumer/keeper" - consumertypes "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" - providerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" - providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - "github.com/cosmos/interchain-security/v4/x/ccv/types" + consumerkeeper "github.com/cosmos/interchain-security/v5/x/ccv/consumer/keeper" + consumertypes "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" + providerkeeper "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper" + providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // Parameters needed to instantiate an in-memory keeper diff --git a/x/ccv/consumer/client/cli/query.go b/x/ccv/consumer/client/cli/query.go index 806b91d2cf..3630b3ed3f 100644 --- a/x/ccv/consumer/client/cli/query.go +++ b/x/ccv/consumer/client/cli/query.go @@ -6,7 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" + "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" ) // NewQueryCmd returns a root CLI command handler for all x/ccv/provider query commands. diff --git a/x/ccv/consumer/ibc_module.go b/x/ccv/consumer/ibc_module.go index 71caa4a082..4780a0bc73 100644 --- a/x/ccv/consumer/ibc_module.go +++ b/x/ccv/consumer/ibc_module.go @@ -17,9 +17,9 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - "github.com/cosmos/interchain-security/v4/x/ccv/consumer/keeper" - consumertypes "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" - "github.com/cosmos/interchain-security/v4/x/ccv/types" + "github.com/cosmos/interchain-security/v5/x/ccv/consumer/keeper" + consumertypes "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" + "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // OnChanOpenInit implements the IBCModule interface diff --git a/x/ccv/consumer/ibc_module_test.go b/x/ccv/consumer/ibc_module_test.go index 51fd910902..b8868038c9 100644 --- a/x/ccv/consumer/ibc_module_test.go +++ b/x/ccv/consumer/ibc_module_test.go @@ -13,10 +13,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" - "github.com/cosmos/interchain-security/v4/x/ccv/consumer" - consumerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/consumer/keeper" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper" + "github.com/cosmos/interchain-security/v5/x/ccv/consumer" + consumerkeeper "github.com/cosmos/interchain-security/v5/x/ccv/consumer/keeper" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // TestOnChanOpenInit validates the consumer's OnChanOpenInit implementation against the spec. diff --git a/x/ccv/consumer/keeper/changeover_test.go b/x/ccv/consumer/keeper/changeover_test.go index c431f43477..89d45534dd 100644 --- a/x/ccv/consumer/keeper/changeover_test.go +++ b/x/ccv/consumer/keeper/changeover_test.go @@ -11,8 +11,8 @@ import ( abci "github.com/cometbft/cometbft/abci/types" - "github.com/cosmos/interchain-security/v4/testutil/crypto" - uthelpers "github.com/cosmos/interchain-security/v4/testutil/keeper" + "github.com/cosmos/interchain-security/v5/testutil/crypto" + uthelpers "github.com/cosmos/interchain-security/v5/testutil/keeper" ) func TestChangeoverToConsumer(t *testing.T) { diff --git a/x/ccv/consumer/keeper/distribution.go b/x/ccv/consumer/keeper/distribution.go index 1b98638498..d6157e50b5 100644 --- a/x/ccv/consumer/keeper/distribution.go +++ b/x/ccv/consumer/keeper/distribution.go @@ -12,8 +12,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // EndBlockRD executes EndBlock logic for the Reward Distribution sub-protocol. diff --git a/x/ccv/consumer/keeper/distribution_test.go b/x/ccv/consumer/keeper/distribution_test.go index 189842a90e..199acae5b0 100644 --- a/x/ccv/consumer/keeper/distribution_test.go +++ b/x/ccv/consumer/keeper/distribution_test.go @@ -10,9 +10,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" authTypes "github.com/cosmos/cosmos-sdk/x/auth/types" - testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" - "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper" + "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // TestGetEstimatedNextFeeDistribution tests next fee distribution parameters. diff --git a/x/ccv/consumer/keeper/genesis.go b/x/ccv/consumer/keeper/genesis.go index 1b9afb2a4e..bdb8e35418 100644 --- a/x/ccv/consumer/keeper/genesis.go +++ b/x/ccv/consumer/keeper/genesis.go @@ -7,8 +7,8 @@ import ( abci "github.com/cometbft/cometbft/abci/types" - "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // InitGenesis initializes the CCV consumer state and binds to PortID. diff --git a/x/ccv/consumer/keeper/genesis_test.go b/x/ccv/consumer/keeper/genesis_test.go index b9fc1b6f3a..77e7e639d3 100644 --- a/x/ccv/consumer/keeper/genesis_test.go +++ b/x/ccv/consumer/keeper/genesis_test.go @@ -18,11 +18,11 @@ import ( abci "github.com/cometbft/cometbft/abci/types" tmtypes "github.com/cometbft/cometbft/types" - "github.com/cosmos/interchain-security/v4/testutil/crypto" - testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" - consumerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/consumer/keeper" - consumertypes "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + "github.com/cosmos/interchain-security/v5/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper" + consumerkeeper "github.com/cosmos/interchain-security/v5/x/ccv/consumer/keeper" + consumertypes "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // TestInitGenesis tests that a consumer chain is correctly initialised from genesis. diff --git a/x/ccv/consumer/keeper/grpc_query.go b/x/ccv/consumer/keeper/grpc_query.go index 5ac5116a28..2f1543071b 100644 --- a/x/ccv/consumer/keeper/grpc_query.go +++ b/x/ccv/consumer/keeper/grpc_query.go @@ -8,8 +8,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) var _ types.QueryServer = Keeper{} //nolint:golint diff --git a/x/ccv/consumer/keeper/hooks.go b/x/ccv/consumer/keeper/hooks.go index c730bf266c..715be50e08 100644 --- a/x/ccv/consumer/keeper/hooks.go +++ b/x/ccv/consumer/keeper/hooks.go @@ -3,7 +3,7 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) var _ ccv.ConsumerHooks = Keeper{} diff --git a/x/ccv/consumer/keeper/keeper.go b/x/ccv/consumer/keeper/keeper.go index b8751344b8..e4f1830333 100644 --- a/x/ccv/consumer/keeper/keeper.go +++ b/x/ccv/consumer/keeper/keeper.go @@ -23,8 +23,8 @@ import ( tmtypes "github.com/cometbft/cometbft/abci/types" "github.com/cometbft/cometbft/libs/log" - "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // Keeper defines the Cross-Chain Validation Consumer Keeper diff --git a/x/ccv/consumer/keeper/keeper_test.go b/x/ccv/consumer/keeper/keeper_test.go index 19856211b5..4ece86571d 100644 --- a/x/ccv/consumer/keeper/keeper_test.go +++ b/x/ccv/consumer/keeper/keeper_test.go @@ -17,10 +17,10 @@ import ( abci "github.com/cometbft/cometbft/abci/types" - "github.com/cosmos/interchain-security/v4/testutil/crypto" - testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" - "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + "github.com/cosmos/interchain-security/v5/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper" + "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // TestProviderClientID tests getter and setter functionality for the client ID stored on consumer keeper diff --git a/x/ccv/consumer/keeper/migrations.go b/x/ccv/consumer/keeper/migrations.go index a1e826e61e..71139fb36c 100644 --- a/x/ccv/consumer/keeper/migrations.go +++ b/x/ccv/consumer/keeper/migrations.go @@ -4,7 +4,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - v2 "github.com/cosmos/interchain-security/v4/x/ccv/consumer/migrations/v2" + v2 "github.com/cosmos/interchain-security/v5/x/ccv/consumer/migrations/v2" ) // Migrator is a struct for handling in-place store migrations. diff --git a/x/ccv/consumer/keeper/params.go b/x/ccv/consumer/keeper/params.go index 4d96ddf604..818b2858bc 100644 --- a/x/ccv/consumer/keeper/params.go +++ b/x/ccv/consumer/keeper/params.go @@ -6,7 +6,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // GetParams returns the params for the consumer ccv module diff --git a/x/ccv/consumer/keeper/params_test.go b/x/ccv/consumer/keeper/params_test.go index e2975a0b31..18d3f5a2b2 100644 --- a/x/ccv/consumer/keeper/params_test.go +++ b/x/ccv/consumer/keeper/params_test.go @@ -6,8 +6,8 @@ import ( "github.com/stretchr/testify/require" - testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // TestParams tests getters/setters for consumer params diff --git a/x/ccv/consumer/keeper/provider_info.go b/x/ccv/consumer/keeper/provider_info.go index e5fbaf6540..aab84e1f85 100644 --- a/x/ccv/consumer/keeper/provider_info.go +++ b/x/ccv/consumer/keeper/provider_info.go @@ -5,8 +5,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) func (k Keeper) GetProviderInfo(ctx sdk.Context) (*types.QueryProviderInfoResponse, error) { //nolint:golint diff --git a/x/ccv/consumer/keeper/relay.go b/x/ccv/consumer/keeper/relay.go index 2d4e16510a..cf431fc054 100644 --- a/x/ccv/consumer/keeper/relay.go +++ b/x/ccv/consumer/keeper/relay.go @@ -14,8 +14,8 @@ import ( abci "github.com/cometbft/cometbft/abci/types" - "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // OnRecvVSCPacket sets the pending validator set changes that will be flushed to ABCI on Endblock diff --git a/x/ccv/consumer/keeper/relay_test.go b/x/ccv/consumer/keeper/relay_test.go index 46a805a85a..b1042de5d0 100644 --- a/x/ccv/consumer/keeper/relay_test.go +++ b/x/ccv/consumer/keeper/relay_test.go @@ -21,11 +21,11 @@ import ( abci "github.com/cometbft/cometbft/abci/types" "github.com/cometbft/cometbft/libs/bytes" - "github.com/cosmos/interchain-security/v4/testutil/crypto" - testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" - consumerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/consumer/keeper" - consumertypes "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" - "github.com/cosmos/interchain-security/v4/x/ccv/types" + "github.com/cosmos/interchain-security/v5/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper" + consumerkeeper "github.com/cosmos/interchain-security/v5/x/ccv/consumer/keeper" + consumertypes "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" + "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // TestOnRecvVSCPacket tests the behavior of OnRecvVSCPacket over various packet scenarios diff --git a/x/ccv/consumer/keeper/soft_opt_out.go b/x/ccv/consumer/keeper/soft_opt_out.go index e5990ff65d..120d3d46d1 100644 --- a/x/ccv/consumer/keeper/soft_opt_out.go +++ b/x/ccv/consumer/keeper/soft_opt_out.go @@ -6,7 +6,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" + "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" ) // BeginBlockSoftOptOut executes BeginBlock logic for the Soft Opt-Out sub-protocol diff --git a/x/ccv/consumer/keeper/soft_opt_out_test.go b/x/ccv/consumer/keeper/soft_opt_out_test.go index 1a726d1767..5c21133832 100644 --- a/x/ccv/consumer/keeper/soft_opt_out_test.go +++ b/x/ccv/consumer/keeper/soft_opt_out_test.go @@ -7,9 +7,9 @@ import ( tmtypes "github.com/cometbft/cometbft/types" - "github.com/cosmos/interchain-security/v4/testutil/crypto" - testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + "github.com/cosmos/interchain-security/v5/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // Tests that UpdateSmallestNonOptOutPower updates the smallest validator power that cannot soft opt out. diff --git a/x/ccv/consumer/keeper/throttle_retry.go b/x/ccv/consumer/keeper/throttle_retry.go index 22e48f9175..4b6df3cc04 100644 --- a/x/ccv/consumer/keeper/throttle_retry.go +++ b/x/ccv/consumer/keeper/throttle_retry.go @@ -5,7 +5,7 @@ import ( sdktypes "github.com/cosmos/cosmos-sdk/types" - consumertypes "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" + consumertypes "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" ) // diff --git a/x/ccv/consumer/keeper/throttle_retry_test.go b/x/ccv/consumer/keeper/throttle_retry_test.go index 4a222fde90..b979ebb51d 100644 --- a/x/ccv/consumer/keeper/throttle_retry_test.go +++ b/x/ccv/consumer/keeper/throttle_retry_test.go @@ -6,9 +6,9 @@ import ( "github.com/stretchr/testify/require" - testutil "github.com/cosmos/interchain-security/v4/testutil/keeper" - consumertypes "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + testutil "github.com/cosmos/interchain-security/v5/testutil/keeper" + consumertypes "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) func TestPacketSendingPermitted(t *testing.T) { diff --git a/x/ccv/consumer/keeper/validators.go b/x/ccv/consumer/keeper/validators.go index 24a1c5a57c..fa1c8991db 100644 --- a/x/ccv/consumer/keeper/validators.go +++ b/x/ccv/consumer/keeper/validators.go @@ -11,7 +11,7 @@ import ( abci "github.com/cometbft/cometbft/abci/types" - "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" + "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" ) // diff --git a/x/ccv/consumer/keeper/validators_test.go b/x/ccv/consumer/keeper/validators_test.go index 1d4dcb2c86..f1c3dbd3f3 100644 --- a/x/ccv/consumer/keeper/validators_test.go +++ b/x/ccv/consumer/keeper/validators_test.go @@ -15,10 +15,10 @@ import ( tmrand "github.com/cometbft/cometbft/libs/rand" tmtypes "github.com/cometbft/cometbft/types" - "github.com/cosmos/interchain-security/v4/testutil/crypto" - testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" - "github.com/cosmos/interchain-security/v4/x/ccv/consumer/keeper" - "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" + "github.com/cosmos/interchain-security/v5/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper" + "github.com/cosmos/interchain-security/v5/x/ccv/consumer/keeper" + "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" ) // TestApplyCCValidatorChanges tests the ApplyCCValidatorChanges method for a consumer keeper diff --git a/x/ccv/consumer/migrations/v2/migration.go b/x/ccv/consumer/migrations/v2/migration.go index 80f06d4d71..ed54512172 100644 --- a/x/ccv/consumer/migrations/v2/migration.go +++ b/x/ccv/consumer/migrations/v2/migration.go @@ -6,8 +6,8 @@ import ( storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" - consumertypes "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + consumertypes "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // MigrateConsumerPacketData migrates consumer packet data according to diff --git a/x/ccv/consumer/migrations/v2/migration_test.go b/x/ccv/consumer/migrations/v2/migration_test.go index a99a2be0fb..8ef05bcbcf 100644 --- a/x/ccv/consumer/migrations/v2/migration_test.go +++ b/x/ccv/consumer/migrations/v2/migration_test.go @@ -9,10 +9,10 @@ import ( storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" - testutil "github.com/cosmos/interchain-security/v4/testutil/keeper" - v2 "github.com/cosmos/interchain-security/v4/x/ccv/consumer/migrations/v2" - consumertypes "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + testutil "github.com/cosmos/interchain-security/v5/testutil/keeper" + v2 "github.com/cosmos/interchain-security/v5/x/ccv/consumer/migrations/v2" + consumertypes "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) func TestMigrateConsumerPacketData(t *testing.T) { diff --git a/x/ccv/consumer/module.go b/x/ccv/consumer/module.go index 4b5d9c053b..f522a34fb8 100644 --- a/x/ccv/consumer/module.go +++ b/x/ccv/consumer/module.go @@ -19,10 +19,10 @@ import ( abci "github.com/cometbft/cometbft/abci/types" - "github.com/cosmos/interchain-security/v4/x/ccv/consumer/client/cli" - "github.com/cosmos/interchain-security/v4/x/ccv/consumer/keeper" - consumertypes "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + "github.com/cosmos/interchain-security/v5/x/ccv/consumer/client/cli" + "github.com/cosmos/interchain-security/v5/x/ccv/consumer/keeper" + consumertypes "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) var ( diff --git a/x/ccv/consumer/types/genesis.go b/x/ccv/consumer/types/genesis.go index cb9cb61f40..9c3fab9c15 100644 --- a/x/ccv/consumer/types/genesis.go +++ b/x/ccv/consumer/types/genesis.go @@ -7,7 +7,7 @@ import ( abci "github.com/cometbft/cometbft/abci/types" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // NewRestartGenesisState returns a consumer GenesisState that has already been established. diff --git a/x/ccv/consumer/types/genesis.pb.go b/x/ccv/consumer/types/genesis.pb.go index dbb7c51981..b51d09efac 100644 --- a/x/ccv/consumer/types/genesis.pb.go +++ b/x/ccv/consumer/types/genesis.pb.go @@ -10,7 +10,7 @@ import ( proto "github.com/cosmos/gogoproto/proto" github_com_cosmos_gogoproto_types "github.com/cosmos/gogoproto/types" _07_tendermint "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - types "github.com/cosmos/interchain-security/v4/x/ccv/types" + types "github.com/cosmos/interchain-security/v5/x/ccv/types" _ "google.golang.org/protobuf/types/known/timestamppb" io "io" math "math" diff --git a/x/ccv/consumer/types/genesis_test.go b/x/ccv/consumer/types/genesis_test.go index dcd30b642c..befd935ba4 100644 --- a/x/ccv/consumer/types/genesis_test.go +++ b/x/ccv/consumer/types/genesis_test.go @@ -15,9 +15,9 @@ import ( abci "github.com/cometbft/cometbft/abci/types" tmtypes "github.com/cometbft/cometbft/types" - "github.com/cosmos/interchain-security/v4/testutil/crypto" - "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + "github.com/cosmos/interchain-security/v5/testutil/crypto" + "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) const ( diff --git a/x/ccv/consumer/types/keys.go b/x/ccv/consumer/types/keys.go index 20163f5ed9..f6400266e8 100644 --- a/x/ccv/consumer/types/keys.go +++ b/x/ccv/consumer/types/keys.go @@ -6,7 +6,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) const ( diff --git a/x/ccv/consumer/types/params_test.go b/x/ccv/consumer/types/params_test.go index 5b11b52d43..caff4db0b1 100644 --- a/x/ccv/consumer/types/params_test.go +++ b/x/ccv/consumer/types/params_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/require" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // Tests the validation of consumer params that happens at genesis diff --git a/x/ccv/consumer/types/query.pb.go b/x/ccv/consumer/types/query.pb.go index fe62a4217f..29f7d33971 100644 --- a/x/ccv/consumer/types/query.pb.go +++ b/x/ccv/consumer/types/query.pb.go @@ -9,7 +9,7 @@ import ( _ "github.com/cosmos/gogoproto/gogoproto" grpc1 "github.com/cosmos/gogoproto/grpc" proto "github.com/cosmos/gogoproto/proto" - types "github.com/cosmos/interchain-security/v4/x/ccv/types" + types "github.com/cosmos/interchain-security/v5/x/ccv/types" _ "google.golang.org/genproto/googleapis/api/annotations" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" diff --git a/x/ccv/democracy/distribution/module.go b/x/ccv/democracy/distribution/module.go index af35c86846..b30893402b 100644 --- a/x/ccv/democracy/distribution/module.go +++ b/x/ccv/democracy/distribution/module.go @@ -16,7 +16,7 @@ import ( abci "github.com/cometbft/cometbft/abci/types" - consumertypes "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" + consumertypes "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" ) var ( diff --git a/x/ccv/provider/client/cli/query.go b/x/ccv/provider/client/cli/query.go index cf68d24681..575470c6f3 100644 --- a/x/ccv/provider/client/cli/query.go +++ b/x/ccv/provider/client/cli/query.go @@ -11,7 +11,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ) // NewQueryCmd returns a root CLI command handler for all x/ccv/provider query commands. diff --git a/x/ccv/provider/client/cli/tx.go b/x/ccv/provider/client/cli/tx.go index 876aaa9b8b..ef65abc28e 100644 --- a/x/ccv/provider/client/cli/tx.go +++ b/x/ccv/provider/client/cli/tx.go @@ -18,7 +18,7 @@ import ( tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ) // GetTxCmd returns the transaction commands for this module diff --git a/x/ccv/provider/client/proposal_handler.go b/x/ccv/provider/client/proposal_handler.go index bb88276393..9942a6d431 100644 --- a/x/ccv/provider/client/proposal_handler.go +++ b/x/ccv/provider/client/proposal_handler.go @@ -20,7 +20,7 @@ import ( govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ) var ( diff --git a/x/ccv/provider/handler.go b/x/ccv/provider/handler.go index 8232ef3b6c..72abf10c1c 100644 --- a/x/ccv/provider/handler.go +++ b/x/ccv/provider/handler.go @@ -6,8 +6,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ) func NewHandler(k *keeper.Keeper) sdk.Handler { diff --git a/x/ccv/provider/handler_test.go b/x/ccv/provider/handler_test.go index 6e13511e3b..2351b6c61c 100644 --- a/x/ccv/provider/handler_test.go +++ b/x/ccv/provider/handler_test.go @@ -14,11 +14,11 @@ import ( tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - testcrypto "github.com/cosmos/interchain-security/v4/testutil/crypto" - testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" - "github.com/cosmos/interchain-security/v4/x/ccv/provider" - keeper "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" - providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + testcrypto "github.com/cosmos/interchain-security/v5/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper" + "github.com/cosmos/interchain-security/v5/x/ccv/provider" + keeper "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper" + providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ) func TestInvalidMsg(t *testing.T) { diff --git a/x/ccv/provider/ibc_middleware.go b/x/ccv/provider/ibc_middleware.go index fb4d96890f..a1ef6e0db8 100644 --- a/x/ccv/provider/ibc_middleware.go +++ b/x/ccv/provider/ibc_middleware.go @@ -12,8 +12,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ) var _ porttypes.Middleware = &IBCMiddleware{} diff --git a/x/ccv/provider/ibc_middleware_test.go b/x/ccv/provider/ibc_middleware_test.go index 347cdc66cb..e2be5a649d 100644 --- a/x/ccv/provider/ibc_middleware_test.go +++ b/x/ccv/provider/ibc_middleware_test.go @@ -7,7 +7,7 @@ import ( channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" "github.com/stretchr/testify/require" - "github.com/cosmos/interchain-security/v4/x/ccv/provider" + "github.com/cosmos/interchain-security/v5/x/ccv/provider" ) func TestGetProviderDenom(t *testing.T) { diff --git a/x/ccv/provider/ibc_module.go b/x/ccv/provider/ibc_module.go index f6ad43d60b..f4b1eace4d 100644 --- a/x/ccv/provider/ibc_module.go +++ b/x/ccv/provider/ibc_module.go @@ -15,9 +15,9 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" - providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper" + providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // OnChanOpenInit implements the IBCModule interface diff --git a/x/ccv/provider/ibc_module_test.go b/x/ccv/provider/ibc_module_test.go index df12ed4cb8..9d41a4d9e1 100644 --- a/x/ccv/provider/ibc_module_test.go +++ b/x/ccv/provider/ibc_module_test.go @@ -15,11 +15,11 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" - "github.com/cosmos/interchain-security/v4/x/ccv/provider" - providerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" - providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper" + "github.com/cosmos/interchain-security/v5/x/ccv/provider" + providerkeeper "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper" + providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // TestOnChanOpenInit tests the provider's OnChanOpenInit method against spec. diff --git a/x/ccv/provider/keeper/consumer_equivocation.go b/x/ccv/provider/keeper/consumer_equivocation.go index 8fc9808304..6324dfa5c0 100644 --- a/x/ccv/provider/keeper/consumer_equivocation.go +++ b/x/ccv/provider/keeper/consumer_equivocation.go @@ -19,8 +19,8 @@ import ( tmtypes "github.com/cometbft/cometbft/types" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // diff --git a/x/ccv/provider/keeper/consumer_equivocation_test.go b/x/ccv/provider/keeper/consumer_equivocation_test.go index d92caf69a3..13b56fc04a 100644 --- a/x/ccv/provider/keeper/consumer_equivocation_test.go +++ b/x/ccv/provider/keeper/consumer_equivocation_test.go @@ -18,9 +18,9 @@ import ( tmtypes "github.com/cometbft/cometbft/types" - cryptotestutil "github.com/cosmos/interchain-security/v4/testutil/crypto" - testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + cryptotestutil "github.com/cosmos/interchain-security/v5/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ) func TestVerifyDoubleVotingEvidence(t *testing.T) { diff --git a/x/ccv/provider/keeper/distribution.go b/x/ccv/provider/keeper/distribution.go index 67e6193e5d..49137936eb 100644 --- a/x/ccv/provider/keeper/distribution.go +++ b/x/ccv/provider/keeper/distribution.go @@ -12,7 +12,7 @@ import ( abci "github.com/cometbft/cometbft/abci/types" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ) // BeginBlockRD executes BeginBlock logic for the Reward Distribution sub-protocol. diff --git a/x/ccv/provider/keeper/distribution_test.go b/x/ccv/provider/keeper/distribution_test.go index d95ae598c0..4a5cd750fc 100644 --- a/x/ccv/provider/keeper/distribution_test.go +++ b/x/ccv/provider/keeper/distribution_test.go @@ -14,9 +14,9 @@ import ( tmtypes "github.com/cometbft/cometbft/types" - testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ) func TestComputeConsumerTotalVotingPower(t *testing.T) { diff --git a/x/ccv/provider/keeper/genesis.go b/x/ccv/provider/keeper/genesis.go index 2075ff48ae..66895233a7 100644 --- a/x/ccv/provider/keeper/genesis.go +++ b/x/ccv/provider/keeper/genesis.go @@ -5,8 +5,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // InitGenesis initializes the CCV provider state and binds to PortID. diff --git a/x/ccv/provider/keeper/genesis_test.go b/x/ccv/provider/keeper/genesis_test.go index 81b0a90bd8..e75241eb58 100644 --- a/x/ccv/provider/keeper/genesis_test.go +++ b/x/ccv/provider/keeper/genesis_test.go @@ -11,11 +11,11 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/interchain-security/v4/testutil/crypto" - testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" - providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + "github.com/cosmos/interchain-security/v5/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper" + providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // TestInitAndExportGenesis tests the export and the initialisation of a provider chain genesis diff --git a/x/ccv/provider/keeper/grpc_query.go b/x/ccv/provider/keeper/grpc_query.go index 84c5928fea..2baed949b7 100644 --- a/x/ccv/provider/keeper/grpc_query.go +++ b/x/ccv/provider/keeper/grpc_query.go @@ -11,8 +11,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) var _ types.QueryServer = Keeper{} diff --git a/x/ccv/provider/keeper/grpc_query_test.go b/x/ccv/provider/keeper/grpc_query_test.go index 14e6e675e1..8283f11235 100644 --- a/x/ccv/provider/keeper/grpc_query_test.go +++ b/x/ccv/provider/keeper/grpc_query_test.go @@ -8,10 +8,10 @@ import ( sdktypes "github.com/cosmos/cosmos-sdk/types" - cryptotestutil "github.com/cosmos/interchain-security/v4/testutil/crypto" - testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + cryptotestutil "github.com/cosmos/interchain-security/v5/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) func TestQueryAllPairsValConAddrByConsumerChainID(t *testing.T) { diff --git a/x/ccv/provider/keeper/hooks.go b/x/ccv/provider/keeper/hooks.go index ed926f16c7..763804868e 100644 --- a/x/ccv/provider/keeper/hooks.go +++ b/x/ccv/provider/keeper/hooks.go @@ -8,9 +8,9 @@ import ( v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // Wrapper struct diff --git a/x/ccv/provider/keeper/hooks_test.go b/x/ccv/provider/keeper/hooks_test.go index 931667fac4..5372fc37cd 100644 --- a/x/ccv/provider/keeper/hooks_test.go +++ b/x/ccv/provider/keeper/hooks_test.go @@ -15,9 +15,9 @@ import ( v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" - cryptotestutil "github.com/cosmos/interchain-security/v4/testutil/crypto" - testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" - providerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" + cryptotestutil "github.com/cosmos/interchain-security/v5/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper" + providerkeeper "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper" ) func TestValidatorConsensusKeyInUse(t *testing.T) { diff --git a/x/ccv/provider/keeper/keeper.go b/x/ccv/provider/keeper/keeper.go index bc3664bfd7..e602c16e5e 100644 --- a/x/ccv/provider/keeper/keeper.go +++ b/x/ccv/provider/keeper/keeper.go @@ -23,9 +23,9 @@ import ( "github.com/cometbft/cometbft/libs/log" - consumertypes "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + consumertypes "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // Keeper defines the Cross-Chain Validation Provider Keeper diff --git a/x/ccv/provider/keeper/keeper_test.go b/x/ccv/provider/keeper/keeper_test.go index d172a96dba..a66b7e3826 100644 --- a/x/ccv/provider/keeper/keeper_test.go +++ b/x/ccv/provider/keeper/keeper_test.go @@ -16,10 +16,10 @@ import ( abci "github.com/cometbft/cometbft/abci/types" tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" - cryptotestutil "github.com/cosmos/interchain-security/v4/testutil/crypto" - testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + cryptotestutil "github.com/cosmos/interchain-security/v5/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) const consumer = "consumer" diff --git a/x/ccv/provider/keeper/key_assignment.go b/x/ccv/provider/keeper/key_assignment.go index 67f4d89fdd..cb359620b9 100644 --- a/x/ccv/provider/keeper/key_assignment.go +++ b/x/ccv/provider/keeper/key_assignment.go @@ -11,8 +11,8 @@ import ( tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // ParseConsumerKey parses the ED25519 PubKey`consumerKey` from a JSON string diff --git a/x/ccv/provider/keeper/key_assignment_test.go b/x/ccv/provider/keeper/key_assignment_test.go index abf7858d40..e721b39c33 100644 --- a/x/ccv/provider/keeper/key_assignment_test.go +++ b/x/ccv/provider/keeper/key_assignment_test.go @@ -17,11 +17,11 @@ import ( abci "github.com/cometbft/cometbft/abci/types" tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" - cryptotestutil "github.com/cosmos/interchain-security/v4/testutil/crypto" - testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" - providerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + cryptotestutil "github.com/cosmos/interchain-security/v5/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper" + providerkeeper "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) const ChainID = "chainID" diff --git a/x/ccv/provider/keeper/msg_server.go b/x/ccv/provider/keeper/msg_server.go index 1f7f51b589..ee17fd8228 100644 --- a/x/ccv/provider/keeper/msg_server.go +++ b/x/ccv/provider/keeper/msg_server.go @@ -11,8 +11,8 @@ import ( tmtypes "github.com/cometbft/cometbft/types" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) type msgServer struct { diff --git a/x/ccv/provider/keeper/params.go b/x/ccv/provider/keeper/params.go index f74baf656e..3834358b0b 100644 --- a/x/ccv/provider/keeper/params.go +++ b/x/ccv/provider/keeper/params.go @@ -7,8 +7,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // GetTemplateClient returns the template client for provider proposals diff --git a/x/ccv/provider/keeper/params_test.go b/x/ccv/provider/keeper/params_test.go index 88175431c0..ccbd8629d6 100644 --- a/x/ccv/provider/keeper/params_test.go +++ b/x/ccv/provider/keeper/params_test.go @@ -11,8 +11,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" - providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper" + providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ) // TestParams tests the getting/setting of provider ccv module params. diff --git a/x/ccv/provider/keeper/partial_set_security.go b/x/ccv/provider/keeper/partial_set_security.go index 0d5177089a..9020a3db82 100644 --- a/x/ccv/provider/keeper/partial_set_security.go +++ b/x/ccv/provider/keeper/partial_set_security.go @@ -9,7 +9,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ) // HandleOptIn prepares validator `providerAddr` to opt in to `chainID` with an optional `consumerKey` consumer public key. diff --git a/x/ccv/provider/keeper/partial_set_security_test.go b/x/ccv/provider/keeper/partial_set_security_test.go index afbd420e7f..42ff7a14ab 100644 --- a/x/ccv/provider/keeper/partial_set_security_test.go +++ b/x/ccv/provider/keeper/partial_set_security_test.go @@ -17,10 +17,10 @@ import ( "github.com/cometbft/cometbft/proto/tendermint/crypto" - testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) func TestHandleOptIn(t *testing.T) { diff --git a/x/ccv/provider/keeper/proposal.go b/x/ccv/provider/keeper/proposal.go index 1d2bf19a4f..67d3c91bca 100644 --- a/x/ccv/provider/keeper/proposal.go +++ b/x/ccv/provider/keeper/proposal.go @@ -18,8 +18,8 @@ import ( tmtypes "github.com/cometbft/cometbft/types" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // HandleConsumerAdditionProposal will receive the consumer chain's client state from the proposal. diff --git a/x/ccv/provider/keeper/proposal_test.go b/x/ccv/provider/keeper/proposal_test.go index 9b769d2f94..67b0f93778 100644 --- a/x/ccv/provider/keeper/proposal_test.go +++ b/x/ccv/provider/keeper/proposal_test.go @@ -17,11 +17,11 @@ import ( abci "github.com/cometbft/cometbft/abci/types" - cryptotestutil "github.com/cosmos/interchain-security/v4/testutil/crypto" - testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" - providerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" - providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + cryptotestutil "github.com/cosmos/interchain-security/v5/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper" + providerkeeper "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper" + providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // diff --git a/x/ccv/provider/keeper/relay.go b/x/ccv/provider/keeper/relay.go index 230ed0a96a..f785d5d6b5 100644 --- a/x/ccv/provider/keeper/relay.go +++ b/x/ccv/provider/keeper/relay.go @@ -12,8 +12,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // OnRecvVSCMaturedPacket handles a VSCMatured packet and returns a no-op result ack. diff --git a/x/ccv/provider/keeper/relay_test.go b/x/ccv/provider/keeper/relay_test.go index 5f74d93424..2b50c695bc 100644 --- a/x/ccv/provider/keeper/relay_test.go +++ b/x/ccv/provider/keeper/relay_test.go @@ -20,13 +20,13 @@ import ( abci "github.com/cometbft/cometbft/abci/types" - "github.com/cosmos/interchain-security/v4/testutil/crypto" - cryptotestutil "github.com/cosmos/interchain-security/v4/testutil/crypto" - testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + "github.com/cosmos/interchain-security/v5/testutil/crypto" + cryptotestutil "github.com/cosmos/interchain-security/v5/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // TestQueueVSCPackets tests queueing validator set updates. diff --git a/x/ccv/provider/keeper/throttle.go b/x/ccv/provider/keeper/throttle.go index b7e7fd5941..b1da78db0f 100644 --- a/x/ccv/provider/keeper/throttle.go +++ b/x/ccv/provider/keeper/throttle.go @@ -10,7 +10,7 @@ import ( tmtypes "github.com/cometbft/cometbft/types" - providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ) // Obtains the effective validator power relevant to a validator consensus address. diff --git a/x/ccv/provider/keeper/throttle_legacy.go b/x/ccv/provider/keeper/throttle_legacy.go index 6f347b8f60..c14c994e84 100644 --- a/x/ccv/provider/keeper/throttle_legacy.go +++ b/x/ccv/provider/keeper/throttle_legacy.go @@ -5,8 +5,8 @@ import ( sdktypes "github.com/cosmos/cosmos-sdk/types" - providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // Pending packet data type enum, used to encode the type of packet data stored at each entry in the mutual queue. diff --git a/x/ccv/provider/keeper/throttle_test.go b/x/ccv/provider/keeper/throttle_test.go index 478ec0f235..5a315e5ec9 100644 --- a/x/ccv/provider/keeper/throttle_test.go +++ b/x/ccv/provider/keeper/throttle_test.go @@ -13,8 +13,8 @@ import ( tmtypes "github.com/cometbft/cometbft/types" - testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" - providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper" + providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ) // TestSlashMeterReplenishment tests the CheckForSlashMeterReplenishment, ReplenishSlashMeter, diff --git a/x/ccv/provider/keeper/validator_set_update.go b/x/ccv/provider/keeper/validator_set_update.go index 264fdd67f2..42016708a5 100644 --- a/x/ccv/provider/keeper/validator_set_update.go +++ b/x/ccv/provider/keeper/validator_set_update.go @@ -8,7 +8,7 @@ import ( abci "github.com/cometbft/cometbft/abci/types" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ) // SetConsumerValidator sets provided consumer `validator` on the consumer chain with `chainID` diff --git a/x/ccv/provider/keeper/validator_set_update_test.go b/x/ccv/provider/keeper/validator_set_update_test.go index 396a74fb1f..9da3039b14 100644 --- a/x/ccv/provider/keeper/validator_set_update_test.go +++ b/x/ccv/provider/keeper/validator_set_update_test.go @@ -16,10 +16,10 @@ import ( "github.com/cometbft/cometbft/crypto/ed25519" "github.com/cometbft/cometbft/proto/tendermint/crypto" - cryptotestutil "github.com/cosmos/interchain-security/v4/testutil/crypto" - testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + cryptotestutil "github.com/cosmos/interchain-security/v5/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ) // TestConsumerValidator tests the `SetConsumerValidator`, `IsConsumerValidator`, and `DeleteConsumerValidator` methods diff --git a/x/ccv/provider/migrations/migrator.go b/x/ccv/provider/migrations/migrator.go index 29fed46851..ea6e9e00d5 100644 --- a/x/ccv/provider/migrations/migrator.go +++ b/x/ccv/provider/migrations/migrator.go @@ -4,10 +4,10 @@ import ( sdktypes "github.com/cosmos/cosmos-sdk/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - providerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" - v3 "github.com/cosmos/interchain-security/v4/x/ccv/provider/migrations/v3" - v4 "github.com/cosmos/interchain-security/v4/x/ccv/provider/migrations/v4" - vPSS "github.com/cosmos/interchain-security/v4/x/ccv/provider/migrations/vPSS" + providerkeeper "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper" + v3 "github.com/cosmos/interchain-security/v5/x/ccv/provider/migrations/v3" + v4 "github.com/cosmos/interchain-security/v5/x/ccv/provider/migrations/v4" + v5 "github.com/cosmos/interchain-security/v5/x/ccv/provider/migrations/v5" ) // Migrator is a struct for handling in-place store migrations. @@ -44,6 +44,6 @@ func (m Migrator) Migrate3to4(ctx sdktypes.Context) error { // MigrateXtoY migrates x/ccvprovider state from consensus version X to Y. // The migration consists of setting a top N of 95 for all registered consumer chains. func (m Migrator) MigrateXtoY(ctx sdktypes.Context) error { - vPSS.MigrateTopNForRegisteredChains(ctx, m.providerKeeper) + v5.MigrateTopNForRegisteredChains(ctx, m.providerKeeper) return nil } diff --git a/x/ccv/provider/migrations/v3/migration_test.go b/x/ccv/provider/migrations/v3/migration_test.go index 630b8fd7dd..56d6b617d9 100644 --- a/x/ccv/provider/migrations/v3/migration_test.go +++ b/x/ccv/provider/migrations/v3/migration_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/require" - testutil "github.com/cosmos/interchain-security/v4/testutil/keeper" + testutil "github.com/cosmos/interchain-security/v5/testutil/keeper" ) func TestMigrate2To3(t *testing.T) { diff --git a/x/ccv/provider/migrations/v3/migrations.go b/x/ccv/provider/migrations/v3/migrations.go index d308316761..2ffd1e6f25 100644 --- a/x/ccv/provider/migrations/v3/migrations.go +++ b/x/ccv/provider/migrations/v3/migrations.go @@ -5,7 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - providerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" + providerkeeper "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper" ) // MigrateQueuedPackets processes all queued packet data for all consumer chains that were stored diff --git a/x/ccv/provider/migrations/v4/migration_test.go b/x/ccv/provider/migrations/v4/migration_test.go index 5ab5faf87a..4423842149 100644 --- a/x/ccv/provider/migrations/v4/migration_test.go +++ b/x/ccv/provider/migrations/v4/migration_test.go @@ -5,8 +5,8 @@ import ( "github.com/stretchr/testify/require" - testutil "github.com/cosmos/interchain-security/v4/testutil/keeper" - providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + testutil "github.com/cosmos/interchain-security/v5/testutil/keeper" + providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ) func TestMigrateParams(t *testing.T) { diff --git a/x/ccv/provider/migrations/v4/migrations.go b/x/ccv/provider/migrations/v4/migrations.go index 825d01e25d..e60c98700e 100644 --- a/x/ccv/provider/migrations/v4/migrations.go +++ b/x/ccv/provider/migrations/v4/migrations.go @@ -4,7 +4,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ) // MigrateParams adds missing provider chain params to the param store. diff --git a/x/ccv/provider/migrations/vPSS/migration_test.go b/x/ccv/provider/migrations/vPSS/migration_test.go deleted file mode 100644 index c8760f4979..0000000000 --- a/x/ccv/provider/migrations/vPSS/migration_test.go +++ /dev/null @@ -1,30 +0,0 @@ -package vPSS - -import ( - "testing" - - "github.com/stretchr/testify/require" - - testutil "github.com/cosmos/interchain-security/v4/testutil/keeper" -) - -func TestMigrateParams(t *testing.T) { - inMemParams := testutil.NewInMemKeeperParams(t) - provKeeper, ctx, ctrl, _ := testutil.GetProviderKeeperAndCtx(t, inMemParams) - defer ctrl.Finish() - - provKeeper.SetConsumerClientId(ctx, "chainID", "clientID") - - // initially top N should not exist - topN, found := provKeeper.GetTopN(ctx, "chainID") - require.False(t, found) - require.Zero(t, topN) - - // migrate - MigrateTopNForRegisteredChains(ctx, provKeeper) - - // after migration, top N should be 95 - topN, found = provKeeper.GetTopN(ctx, "chainID") - require.True(t, found) - require.Equal(t, uint32(95), topN) -} diff --git a/x/ccv/provider/migrations/vPSS/migrations.go b/x/ccv/provider/migrations/vPSS/migrations.go deleted file mode 100644 index 905d59c8e6..0000000000 --- a/x/ccv/provider/migrations/vPSS/migrations.go +++ /dev/null @@ -1,24 +0,0 @@ -package vPSS - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - - providerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" -) - -// This migration only takes already registered chains into account. -// If a chain is in voting while the upgrade happens, this is not sufficient, -// and a migration to rewrite the proposal is needed. -func MigrateTopNForRegisteredChains(ctx sdk.Context, providerKeeper providerkeeper.Keeper) { - // get all consumer chains - registeredConsumerChains := providerKeeper.GetAllConsumerChains(ctx) - - // Set the topN of each chain to 95 - for _, chain := range registeredConsumerChains { - providerKeeper.SetTopN(ctx, chain.ChainId, 95) - } -} - -// // If there are consumer addition proposals in the voting period at the upgrade time, they may need the topN value updated. -// func MigrateTopNForVotingPeriodChains(ctx sdk.Context, govKeeper govkeeper.Keeper, providerKeeper providerkeeper.Keeper) { -// } diff --git a/x/ccv/provider/module.go b/x/ccv/provider/module.go index e29b7a6385..e2203ba4ca 100644 --- a/x/ccv/provider/module.go +++ b/x/ccv/provider/module.go @@ -19,10 +19,10 @@ import ( abci "github.com/cometbft/cometbft/abci/types" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/client/cli" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/migrations" - providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/client/cli" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/migrations" + providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ) var ( diff --git a/x/ccv/provider/module_test.go b/x/ccv/provider/module_test.go index 869c24253f..2dfdfc1598 100644 --- a/x/ccv/provider/module_test.go +++ b/x/ccv/provider/module_test.go @@ -11,10 +11,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" - "github.com/cosmos/interchain-security/v4/x/ccv/provider" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper" + "github.com/cosmos/interchain-security/v5/x/ccv/provider" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // Tests the provider's InitGenesis implementation against the spec. diff --git a/x/ccv/provider/proposal_handler.go b/x/ccv/provider/proposal_handler.go index 50089a8ab5..2a4342ea20 100644 --- a/x/ccv/provider/proposal_handler.go +++ b/x/ccv/provider/proposal_handler.go @@ -7,8 +7,8 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ) // NewProviderProposalHandler defines the handler for consumer addition, diff --git a/x/ccv/provider/proposal_handler_test.go b/x/ccv/provider/proposal_handler_test.go index 185db25b07..e15036f565 100644 --- a/x/ccv/provider/proposal_handler_test.go +++ b/x/ccv/provider/proposal_handler_test.go @@ -12,9 +12,9 @@ import ( distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" - testkeeper "github.com/cosmos/interchain-security/v4/testutil/keeper" - "github.com/cosmos/interchain-security/v4/x/ccv/provider" - providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper" + "github.com/cosmos/interchain-security/v5/x/ccv/provider" + providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ) // TestProviderProposalHandler tests the highest level handler for proposals diff --git a/x/ccv/provider/types/consumer.go b/x/ccv/provider/types/consumer.go index 4c43bd58e7..02651ac03e 100644 --- a/x/ccv/provider/types/consumer.go +++ b/x/ccv/provider/types/consumer.go @@ -1,7 +1,7 @@ package types import ( - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) func NewConsumerStates( diff --git a/x/ccv/provider/types/genesis.go b/x/ccv/provider/types/genesis.go index ae929ba541..00802558c5 100644 --- a/x/ccv/provider/types/genesis.go +++ b/x/ccv/provider/types/genesis.go @@ -9,7 +9,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) func NewGenesisState( diff --git a/x/ccv/provider/types/genesis.pb.go b/x/ccv/provider/types/genesis.pb.go index d5041f1b10..d7d225b762 100644 --- a/x/ccv/provider/types/genesis.pb.go +++ b/x/ccv/provider/types/genesis.pb.go @@ -7,7 +7,7 @@ import ( fmt "fmt" _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/cosmos/gogoproto/proto" - types "github.com/cosmos/interchain-security/v4/x/ccv/types" + types "github.com/cosmos/interchain-security/v5/x/ccv/types" io "io" math "math" math_bits "math/bits" diff --git a/x/ccv/provider/types/genesis_test.go b/x/ccv/provider/types/genesis_test.go index 41a716757f..d682e93897 100644 --- a/x/ccv/provider/types/genesis_test.go +++ b/x/ccv/provider/types/genesis_test.go @@ -14,9 +14,9 @@ import ( abci "github.com/cometbft/cometbft/abci/types" tmtypes "github.com/cometbft/cometbft/types" - "github.com/cosmos/interchain-security/v4/testutil/crypto" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v4/x/ccv/types" + "github.com/cosmos/interchain-security/v5/testutil/crypto" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // Tests validation of consumer states and params within a provider genesis state diff --git a/x/ccv/provider/types/key_assignment.go b/x/ccv/provider/types/key_assignment.go index 04192ae53a..ee403e1e49 100644 --- a/x/ccv/provider/types/key_assignment.go +++ b/x/ccv/provider/types/key_assignment.go @@ -8,7 +8,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // A validator's consensus address on the provider chain. diff --git a/x/ccv/provider/types/keys.go b/x/ccv/provider/types/keys.go index 14521b9289..4126a58cb7 100644 --- a/x/ccv/provider/types/keys.go +++ b/x/ccv/provider/types/keys.go @@ -8,7 +8,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) type Status int diff --git a/x/ccv/provider/types/keys_test.go b/x/ccv/provider/types/keys_test.go index eac11a0993..78d8b4f806 100644 --- a/x/ccv/provider/types/keys_test.go +++ b/x/ccv/provider/types/keys_test.go @@ -8,8 +8,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - cryptoutil "github.com/cosmos/interchain-security/v4/testutil/crypto" - providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + cryptoutil "github.com/cosmos/interchain-security/v5/testutil/crypto" + providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ) // Tests that all singular keys, or prefixes to fully resolves keys are non duplicate byte values. diff --git a/x/ccv/provider/types/msg.go b/x/ccv/provider/types/msg.go index b80e608785..b6546506fd 100644 --- a/x/ccv/provider/types/msg.go +++ b/x/ccv/provider/types/msg.go @@ -14,7 +14,7 @@ import ( tmtypes "github.com/cometbft/cometbft/proto/tendermint/types" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // provider message types diff --git a/x/ccv/provider/types/params.go b/x/ccv/provider/types/params.go index a0a7a5ed7a..c398188c98 100644 --- a/x/ccv/provider/types/params.go +++ b/x/ccv/provider/types/params.go @@ -11,7 +11,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) const ( diff --git a/x/ccv/provider/types/params_test.go b/x/ccv/provider/types/params_test.go index 4e72c233af..b86dd0cddf 100644 --- a/x/ccv/provider/types/params_test.go +++ b/x/ccv/provider/types/params_test.go @@ -11,7 +11,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ) func TestValidateParams(t *testing.T) { diff --git a/x/ccv/provider/types/proposal.go b/x/ccv/provider/types/proposal.go index fa6483acd1..d2cfa7ed3f 100644 --- a/x/ccv/provider/types/proposal.go +++ b/x/ccv/provider/types/proposal.go @@ -14,7 +14,7 @@ import ( evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" - ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types" + ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" ) const ( diff --git a/x/ccv/provider/types/proposal_test.go b/x/ccv/provider/types/proposal_test.go index 465a376b47..a2f8f574ee 100644 --- a/x/ccv/provider/types/proposal_test.go +++ b/x/ccv/provider/types/proposal_test.go @@ -15,7 +15,7 @@ import ( govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" - "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ) func TestConsumerAdditionProposalValidateBasic(t *testing.T) { diff --git a/x/ccv/provider/types/provider.pb.go b/x/ccv/provider/types/provider.pb.go index 4f0a2fd605..07e511669c 100644 --- a/x/ccv/provider/types/provider.pb.go +++ b/x/ccv/provider/types/provider.pb.go @@ -15,7 +15,7 @@ import ( github_com_cosmos_gogoproto_types "github.com/cosmos/gogoproto/types" types "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" _07_tendermint "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - types3 "github.com/cosmos/interchain-security/v4/x/ccv/types" + types3 "github.com/cosmos/interchain-security/v5/x/ccv/types" _ "google.golang.org/protobuf/types/known/durationpb" _ "google.golang.org/protobuf/types/known/timestamppb" io "io" diff --git a/x/ccv/provider/types/query.pb.go b/x/ccv/provider/types/query.pb.go index dbca4d229d..099c2be2db 100644 --- a/x/ccv/provider/types/query.pb.go +++ b/x/ccv/provider/types/query.pb.go @@ -13,7 +13,7 @@ import ( grpc1 "github.com/cosmos/gogoproto/grpc" proto "github.com/cosmos/gogoproto/proto" github_com_cosmos_gogoproto_types "github.com/cosmos/gogoproto/types" - types "github.com/cosmos/interchain-security/v4/x/ccv/types" + types "github.com/cosmos/interchain-security/v5/x/ccv/types" _ "google.golang.org/genproto/googleapis/api/annotations" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" diff --git a/x/ccv/types/utils_test.go b/x/ccv/types/utils_test.go index f7ecd83197..44f4ff6d27 100644 --- a/x/ccv/types/utils_test.go +++ b/x/ccv/types/utils_test.go @@ -10,7 +10,7 @@ import ( abci "github.com/cometbft/cometbft/abci/types" - "github.com/cosmos/interchain-security/v4/x/ccv/types" + "github.com/cosmos/interchain-security/v5/x/ccv/types" ) func TestAccumulateChanges(t *testing.T) { diff --git a/x/ccv/types/wire_test.go b/x/ccv/types/wire_test.go index ab6692912e..93512a5218 100644 --- a/x/ccv/types/wire_test.go +++ b/x/ccv/types/wire_test.go @@ -12,8 +12,8 @@ import ( abci "github.com/cometbft/cometbft/abci/types" - "github.com/cosmos/interchain-security/v4/testutil/crypto" - "github.com/cosmos/interchain-security/v4/x/ccv/types" + "github.com/cosmos/interchain-security/v5/testutil/crypto" + "github.com/cosmos/interchain-security/v5/x/ccv/types" ) func TestPacketDataValidateBasic(t *testing.T) { From 967737b1836371762056c9f129dd586902a5d8d1 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Wed, 1 May 2024 16:27:26 +0200 Subject: [PATCH 108/110] Bump consensus version --- x/ccv/provider/module.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/ccv/provider/module.go b/x/ccv/provider/module.go index e2203ba4ca..85555af2c2 100644 --- a/x/ccv/provider/module.go +++ b/x/ccv/provider/module.go @@ -137,7 +137,7 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.Raw } // ConsensusVersion implements AppModule/ConsensusVersion. -func (AppModule) ConsensusVersion() uint64 { return 4 } +func (AppModule) ConsensusVersion() uint64 { return 5 } // BeginBlock implements the AppModule interface func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) { From 8a14a78cbb3b4a0670eda9e116fc7c9c50d0afa2 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Wed, 1 May 2024 16:39:43 +0200 Subject: [PATCH 109/110] Add migration in correct folder --- .../provider/migrations/v5/migration_test.go | 30 +++++++++++++++++++ x/ccv/provider/migrations/v5/migrations.go | 24 +++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 x/ccv/provider/migrations/v5/migration_test.go create mode 100644 x/ccv/provider/migrations/v5/migrations.go diff --git a/x/ccv/provider/migrations/v5/migration_test.go b/x/ccv/provider/migrations/v5/migration_test.go new file mode 100644 index 0000000000..c8760f4979 --- /dev/null +++ b/x/ccv/provider/migrations/v5/migration_test.go @@ -0,0 +1,30 @@ +package vPSS + +import ( + "testing" + + "github.com/stretchr/testify/require" + + testutil "github.com/cosmos/interchain-security/v4/testutil/keeper" +) + +func TestMigrateParams(t *testing.T) { + inMemParams := testutil.NewInMemKeeperParams(t) + provKeeper, ctx, ctrl, _ := testutil.GetProviderKeeperAndCtx(t, inMemParams) + defer ctrl.Finish() + + provKeeper.SetConsumerClientId(ctx, "chainID", "clientID") + + // initially top N should not exist + topN, found := provKeeper.GetTopN(ctx, "chainID") + require.False(t, found) + require.Zero(t, topN) + + // migrate + MigrateTopNForRegisteredChains(ctx, provKeeper) + + // after migration, top N should be 95 + topN, found = provKeeper.GetTopN(ctx, "chainID") + require.True(t, found) + require.Equal(t, uint32(95), topN) +} diff --git a/x/ccv/provider/migrations/v5/migrations.go b/x/ccv/provider/migrations/v5/migrations.go new file mode 100644 index 0000000000..905d59c8e6 --- /dev/null +++ b/x/ccv/provider/migrations/v5/migrations.go @@ -0,0 +1,24 @@ +package vPSS + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + providerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" +) + +// This migration only takes already registered chains into account. +// If a chain is in voting while the upgrade happens, this is not sufficient, +// and a migration to rewrite the proposal is needed. +func MigrateTopNForRegisteredChains(ctx sdk.Context, providerKeeper providerkeeper.Keeper) { + // get all consumer chains + registeredConsumerChains := providerKeeper.GetAllConsumerChains(ctx) + + // Set the topN of each chain to 95 + for _, chain := range registeredConsumerChains { + providerKeeper.SetTopN(ctx, chain.ChainId, 95) + } +} + +// // If there are consumer addition proposals in the voting period at the upgrade time, they may need the topN value updated. +// func MigrateTopNForVotingPeriodChains(ctx sdk.Context, govKeeper govkeeper.Keeper, providerKeeper providerkeeper.Keeper) { +// } From 940d60ab2fd98f8e77d6c895d528d919657d57d5 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Wed, 1 May 2024 16:42:11 +0200 Subject: [PATCH 110/110] Update version from v4 to v5 in migration --- x/ccv/provider/migrations/v5/migration_test.go | 4 ++-- x/ccv/provider/migrations/v5/migrations.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/x/ccv/provider/migrations/v5/migration_test.go b/x/ccv/provider/migrations/v5/migration_test.go index c8760f4979..907aa1b019 100644 --- a/x/ccv/provider/migrations/v5/migration_test.go +++ b/x/ccv/provider/migrations/v5/migration_test.go @@ -1,11 +1,11 @@ -package vPSS +package v5 import ( "testing" "github.com/stretchr/testify/require" - testutil "github.com/cosmos/interchain-security/v4/testutil/keeper" + testutil "github.com/cosmos/interchain-security/v5/testutil/keeper" ) func TestMigrateParams(t *testing.T) { diff --git a/x/ccv/provider/migrations/v5/migrations.go b/x/ccv/provider/migrations/v5/migrations.go index 905d59c8e6..aa228b6a09 100644 --- a/x/ccv/provider/migrations/v5/migrations.go +++ b/x/ccv/provider/migrations/v5/migrations.go @@ -1,9 +1,9 @@ -package vPSS +package v5 import ( sdk "github.com/cosmos/cosmos-sdk/types" - providerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" + providerkeeper "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper" ) // This migration only takes already registered chains into account.