From 1ec81485bad165674334a51bcdc24eed06e28d1f Mon Sep 17 00:00:00 2001 From: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Thu, 1 Jun 2023 15:30:00 -0700 Subject: [PATCH 001/134] docs: cleanup changelog for v2.0.0 on main (#988) cleans --- CHANGELOG.md | 10 +++++++--- x/ccv/provider/keeper/migration.go | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 526d82baae..5f946901f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,13 @@ Add an entry to the unreleased section whenever merging a PR to main that is not ## v.2.0.0 -Date: May 12th, 2023 +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. +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](./x/ccv/provider/keeper/migration.go). See the provider module's `ConsensusVersion` in [module](./x/ccv/provider/module.go) + +Upgrading a consumer from `v1.2.0-multiden` to `v2.0.0` will NOT require state migrations. See the consumer module's `ConsensusVersion` in [module](./x/ccv/consumer/module.go) 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. @@ -19,7 +23,7 @@ Some PRs from v2.0.0 may reappear from other releases below. This is due to the * Various fixes, critical and non-critical * Docs updates which should not affect production code -## PRs included in v2.0.0 +## Notable PRs included in v2.0.0 * (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) * (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) diff --git a/x/ccv/provider/keeper/migration.go b/x/ccv/provider/keeper/migration.go index 1254faf463..4e899bcce2 100644 --- a/x/ccv/provider/keeper/migration.go +++ b/x/ccv/provider/keeper/migration.go @@ -22,7 +22,7 @@ func NewMigrator(ccvProviderKeeper Keeper, ccvProviderParamSpace paramtypes.Subs return Migrator{ccvProviderKeeper: ccvProviderKeeper, ccvProviderParamSpace: ccvProviderParamSpace} } -// Migratev1Tov2 migrates a provider from v1.0.0 to v2.0.0. +// Migratev1Tov2 migrates a provider from v1.0.0 to v2.0.0, and/or consensus version 1 -> 2. func (m Migrator) Migratev1Tov2(ctx sdk.Context) error { // Migrate params MigrateParamsv1Tov2(ctx, From 9920121274605ee5bf79984a687d7b4586fdec71 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Date: Fri, 2 Jun 2023 17:55:13 +0200 Subject: [PATCH 002/134] chore: Hardcode golangci-lint version (#990) * Hardcode golangci-lint version * Hardcode version in CI config --- .github/workflows/golangci-lint.yml | 2 +- Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 7dcf88c9c0..28eba10b41 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -25,7 +25,7 @@ jobs: uses: golangci/golangci-lint-action@v3 with: # Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version - version: latest + version: v1.52.2 # Optional: working directory, useful for monorepos # working-directory: somedir diff --git a/Makefile b/Makefile index 600c617d70..b84eca6524 100644 --- a/Makefile +++ b/Makefile @@ -71,7 +71,7 @@ test-no-cache: ### Linting ### ############################################################################### -golangci_version=latest +golangci_version=v1.52.2 lint: @echo "--> Running linter" From 957ddf4bdbaba784f0800312c689df00ae11f66d Mon Sep 17 00:00:00 2001 From: Milan Mulji <98309852+mmulji-ic@users.noreply.github.com> Date: Thu, 8 Jun 2023 19:10:57 +0200 Subject: [PATCH 003/134] docs: Increase the validator set of cosmos hub to 180 from 175 (#999) Updated number of validators to 180 --- docs/docs/validators/overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/validators/overview.md b/docs/docs/validators/overview.md index 5a670f0780..35ce56cdb3 100644 --- a/docs/docs/validators/overview.md +++ b/docs/docs/validators/overview.md @@ -14,7 +14,7 @@ Once a `ConsumerAdditionProposal` passes, validators need to prepare to run the Provider chain and consumer chains represent standalone chains that only share the validator set ie. the same validator operators are tasked with running all chains. :::info -To validate a consumer chain and be eligible for rewards validators are required to be in the active set of the provider chain (first 175 validators for Cosmos Hub). +To validate a consumer chain and be eligible for rewards validators are required to be in the active set of the provider chain (first 180 validators for Cosmos Hub). ::: ## Startup sequence overview From a1e18d0cfe4cfc105e6bbb0730471075ee1edc28 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Thu, 8 Jun 2023 10:56:41 -0700 Subject: [PATCH 004/134] fix: proper consumer key prefix ordering (#991) * Update keys.go * tests * fix another bug * fix comments --- x/ccv/consumer/types/keys.go | 39 +++++++++++++++++-------------- x/ccv/consumer/types/keys_test.go | 20 +++++++++------- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/x/ccv/consumer/types/keys.go b/x/ccv/consumer/types/keys.go index d52c9c551e..093f78b450 100644 --- a/x/ccv/consumer/types/keys.go +++ b/x/ccv/consumer/types/keys.go @@ -49,6 +49,23 @@ const ( // received over CCV channel but not yet flushed over ABCI PendingChangesByteKey + // NOTE: This prefix is depreciated, but left in place to avoid consumer state migrations + // [DEPRECATED] + PendingDataPacketsByteKey + + // PreCCVByteKey is the byte to store the consumer is running on democracy staking module without consumer + PreCCVByteKey + + // InitialValSetByteKey is the byte to store the initial validator set for a consumer + InitialValSetByteKey + + // NOTE: This prefix is depreciated, but left in place to avoid consumer state migrations + // [DEPRECATED] + LastStandaloneHeightByteKey + + // SmallestNonOptOutPowerByteKey is the byte that will store the smallest val power that cannot opt out + SmallestNonOptOutPowerByteKey + // HistoricalInfoKey is the byte prefix that will store the historical info for a given height HistoricalInfoBytePrefix @@ -61,30 +78,18 @@ const ( // OutstandingDowntimePrefix is the byte prefix that will store the validators outstanding downtime by consensus address OutstandingDowntimeBytePrefix - // NOTE: This prefix is depreciated, but left in place to avoid consumer state migrations - PendingDataPacketsBytePrefix - - // CrossChainValidatorPrefix is the byte prefix that will store cross-chain validators by consensus address - CrossChainValidatorBytePrefix - - // PendingDataPacketsByteKey is the byte key for storing + // PendingDataPacketsBytePrefix is the byte prefix for storing // a list of data packets that cannot be sent yet to the provider // chain either because the CCV channel is not established or // because the client is expired - PendingDataPacketsByteKey - - // PreCCVByteKey is the byte to store the consumer is running on democracy staking module without consumer - PreCCVByteKey + PendingDataPacketsBytePrefix - // InitialValSetByteKey is the byte to store the initial validator set for a consumer - InitialValSetByteKey + // CrossChainValidatorPrefix is the byte prefix that will store cross-chain validators by consensus address + CrossChainValidatorBytePrefix // InitGenesisHeightByteKey is the byte that will store the init genesis height InitGenesisHeightByteKey - // SmallestNonOptOutPowerByteKey is the byte that will store the smallest val power that cannot opt out - SmallestNonOptOutPowerByteKey - // StandaloneTransferChannelIDByteKey is the byte storing the channelID of transfer channel // that existed from a standalone chain changing over to a consumer StandaloneTransferChannelIDByteKey @@ -170,7 +175,7 @@ func CrossChainValidatorKey(addr []byte) []byte { // that cannot be sent yet to the provider chain either because the CCV channel // is not established or because the client is expired. func PendingDataPacketsKey() []byte { - return []byte{PendingDataPacketsByteKey} + return []byte{PendingDataPacketsBytePrefix} } func PreCCVKey() []byte { diff --git a/x/ccv/consumer/types/keys_test.go b/x/ccv/consumer/types/keys_test.go index c0ab13391a..a63da6f326 100644 --- a/x/ccv/consumer/types/keys_test.go +++ b/x/ccv/consumer/types/keys_test.go @@ -27,16 +27,18 @@ func getAllKeyPrefixes() []byte { ProviderClientByteKey, ProviderChannelByteKey, PendingChangesByteKey, + PendingDataPacketsByteKey, + PreCCVByteKey, + InitialValSetByteKey, + LastStandaloneHeightByteKey, + SmallestNonOptOutPowerByteKey, HistoricalInfoBytePrefix, PacketMaturityTimeBytePrefix, HeightValsetUpdateIDBytePrefix, OutstandingDowntimeBytePrefix, + PendingDataPacketsBytePrefix, CrossChainValidatorBytePrefix, - PendingDataPacketsByteKey, - PreCCVByteKey, - InitialValSetByteKey, InitGenesisHeightByteKey, - SmallestNonOptOutPowerByteKey, StandaloneTransferChannelIDByteKey, PrevStandaloneChainByteKey, } @@ -61,16 +63,18 @@ func getAllFullyDefinedKeys() [][]byte { ProviderClientIDKey(), ProviderChannelKey(), PendingChangesKey(), + // PendingDataPacketsKey() does not use duplicated prefix with value of 0x06 + PreCCVKey(), + InitialValSetKey(), + // LastStandaloneHeightKey() is depreciated + SmallestNonOptOutPowerKey(), HistoricalInfoKey(0), PacketMaturityTimeKey(0, time.Time{}), HeightValsetUpdateIDKey(0), OutstandingDowntimeKey([]byte{}), - CrossChainValidatorKey([]byte{}), PendingDataPacketsKey(), - PreCCVKey(), - InitialValSetKey(), + CrossChainValidatorKey([]byte{}), InitGenesisHeightKey(), - SmallestNonOptOutPowerKey(), StandaloneTransferChannelIDKey(), PrevStandaloneChainKey(), } From e2ac9743e9a309b29e6e92ab64be2e4e79503f75 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Thu, 8 Jun 2023 11:46:35 -0700 Subject: [PATCH 005/134] feat: Remove consumer genesis migration on provider (#997) * Update keys.go * tests * fix another bug * remove consumer genesis deletion, link to test * remove unused bond denom method * Revert "remove unused bond denom method" This reverts commit f930eca428bade49a05368fe5dae2d96842659cc. * remove test too * update changelog --- CHANGELOG.md | 4 ++-- x/ccv/provider/keeper/migration.go | 14 ++++---------- x/ccv/provider/keeper/migration_test.go | 19 ------------------- 3 files changed, 6 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f946901f2..d2b0b754e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,11 +25,11 @@ Some PRs from v2.0.0 may reappear from other releases below. This is due to the ## Notable PRs included in v2.0.0 -* (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) +* (fix) cosumer 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) consumer key prefix order to avoid complex migrations [#963](https://github.com/cosmos/interchain-security/pull/963) * (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) diff --git a/x/ccv/provider/keeper/migration.go b/x/ccv/provider/keeper/migration.go index 4e899bcce2..d33fcb7968 100644 --- a/x/ccv/provider/keeper/migration.go +++ b/x/ccv/provider/keeper/migration.go @@ -33,8 +33,10 @@ func (m Migrator) Migratev1Tov2(ctx sdk.Context) error { sdk.NewCoin(m.ccvProviderKeeper.BondDenom(ctx), sdk.NewInt(10000000)), ) - // Delete select consumer genesis states for consumers that're launched - MigrateConsumerGenesisStatesv1Tov2(ctx, m.ccvProviderKeeper) + // Consumer genesis states persisted on the provider do not need to be migrated, + // as protobuf serialization is able to gracefully handle unpopulated fields when deserializing. + // See https://github.com/smarshall-spitzbart/ics-migration-tests/commit/b589e3982c26783ed66e954051f7da1ead16de68 + // which passes, proving the addition of preCCV will not break things. // Migrate keys to accommodate fix from https://github.com/cosmos/interchain-security/pull/786 MigrateKeysv1Tov2(ctx, m.ccvProviderKeeper) @@ -80,14 +82,6 @@ func MigrateParamsv1Tov2(ctx sdk.Context, paramsSubspace paramtypes.Subspace, co paramsSubspace.SetParamSet(ctx, &newParams) } -func MigrateConsumerGenesisStatesv1Tov2(ctx sdk.Context, providerKeeper Keeper) { - // We could try to migrate existing ConsumerGenesisStates, but they're not needed after consumer launch. - // Hence we delete them strategically. - providerKeeper.DeleteConsumerGenesis(ctx, "neutron-1") // See https://github.com/neutron-org/mainnet-assets#parameters - - // TODO: determine if any other ConsumerGenesisStates need to be deleted, or actually migrated! -} - // Due to https://github.com/cosmos/interchain-security/pull/786, // validators' slash logs are stored under the key prefix for slash acks. // This method will extract "slash logs" from the slash acks part of the store, and put the slash logs diff --git a/x/ccv/provider/keeper/migration_test.go b/x/ccv/provider/keeper/migration_test.go index 858aa193e6..e488dd2d36 100644 --- a/x/ccv/provider/keeper/migration_test.go +++ b/x/ccv/provider/keeper/migration_test.go @@ -13,7 +13,6 @@ import ( types2 "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" "github.com/cosmos/interchain-security/v2/testutil/crypto" testutil "github.com/cosmos/interchain-security/v2/testutil/keeper" - consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" providerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/provider/keeper" providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" @@ -124,24 +123,6 @@ type v1Params struct { MaxThrottledPackets int64 `protobuf:"varint,8,opt,name=max_throttled_packets,json=maxThrottledPackets,proto3" json:"max_throttled_packets,omitempty"` } -func TestMigrateConsumerGenesisv1Tov2(t *testing.T) { - providerKeeper, ctx, ctrl, _ := testutil.GetProviderKeeperAndCtx(t, testutil.NewInMemKeeperParams(t)) - defer ctrl.Finish() - - _, found := providerKeeper.GetConsumerGenesis(ctx, "neutron-1") - require.False(t, found) - - providerKeeper.SetConsumerGenesis(ctx, "neutron-1", consumertypes.GenesisState{}) - - _, found = providerKeeper.GetConsumerGenesis(ctx, "neutron-1") - require.True(t, found) - - providerkeeper.MigrateConsumerGenesisStatesv1Tov2(ctx, providerKeeper) - - _, found = providerKeeper.GetConsumerGenesis(ctx, "neutron-1") - require.False(t, found) -} - func TestMigrateKeysv1Tov2(t *testing.T) { providerKeeper, ctx, ctrl, _ := testutil.GetProviderKeeperAndCtx(t, testutil.NewInMemKeeperParams(t)) defer ctrl.Finish() From 67b93a4834cc756230f29fbcef11e2dfc0b61228 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Fri, 9 Jun 2023 10:52:59 -0700 Subject: [PATCH 006/134] docs: Update reward-distribution.md (#994) * Update reward-distribution.md * docs: add instructions for registering denoms * Update docs/docs/features/reward-distribution.md Co-authored-by: Marius Poke * Update reward-distribution.md * Update docs/docs/features/reward-distribution.md Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> --------- Co-authored-by: MSalopek Co-authored-by: Marius Poke --- docs/docs/features/reward-distribution.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/docs/docs/features/reward-distribution.md b/docs/docs/features/reward-distribution.md index 122eab5ad9..31b3f9e54e 100644 --- a/docs/docs/features/reward-distribution.md +++ b/docs/docs/features/reward-distribution.md @@ -12,6 +12,21 @@ The distributed reward tokens are IBC tokens and therefore cannot be staked on t Sending and distributing rewards from consumer chains to provider chain is handled by the `Reward Distribution` sub-protocol. +## Note +The ICS distribution system works by allowing consumer chains to send rewards to a module address on the provider called the `ConsumerRewardsPool`. +There is a new transaction type called `RegisterConsumerRewardDenom`. This transaction allows consumer chains to register denoms to be used as consumer chain rewards on the provider. +The cost to register a denom is configurable (`ConsumerRewardDenomRegistrationFee` chain param) and the full amount of this fee is transferred to the community pool of the provider chain. Only denoms registered through this transaction are then transferred from the `ConsumerRewardsPool` to the `FeePoolAddress`, to be distributed out to delegators and validators. + +### Instructions for adding a denom +The transaction must be carried out on the provider chain. Please use the `ibc/*` denom trace format. + +:::tip +``` +# reward denoms must be registered on the provider chain (gaia in this example) +gaiad tx provider register-consumer-reward-denom ibc/3C3D7B3BE4ECC85A0E5B52A3AEC3B7DFC2AA9CA47C37821E57020D6807043BE9 --from mykey +``` +::: + ## Parameters :::tip The following chain parameters dictate consumer chain distribution amount and frequency. @@ -21,12 +36,12 @@ They are set at consumer genesis and `blocks_per_distribution_transmission`, `co ### `consumer_redistribution_fraction` -The fraction of tokens sent from consumer to provider during distribution events. The fraction is a string representing a decimal number. For example "0.75" would represent 75%. +The fraction of tokens allocated to the consumer redistribution address during distribution events. The fraction is a string representing a decimal number. For example "0.75" would represent 75%. :::tip Example: -With `consumer_redistribution_fraction` set to `0.75` the consumer chain would send 75% of its block rewards and accumulated fees to the consumer chain and the remaining 25% to the provider chain every `n` blocks where `n == blocks_per_distribution_transmission`. +With `consumer_redistribution_fraction` set to `0.75` the consumer chain would send 75% of its block rewards and accumulated fees to the consumer redistribution address, and the remaining 25% to the provider chain every `n` blocks where `n == blocks_per_distribution_transmission`. ::: ### `blocks_per_distribution_transmission` From 274eea0705fb52e3c7b613b01eee34c7d63e4ee2 Mon Sep 17 00:00:00 2001 From: Marius Poke Date: Mon, 12 Jun 2023 10:15:32 +0200 Subject: [PATCH 007/134] chore: update workflow re. issues and PRs (#1002) * update PR workflow * update issue workflow * rename other.md to others.md * fix typo --------- Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> --- .github/ISSUE_TEMPLATE/epic-template.md | 8 +-- .github/ISSUE_TEMPLATE/feature-request.md | 16 +++++- .github/ISSUE_TEMPLATE/issue-template.md | 6 +-- .github/PULL_REQUEST_TEMPLATE.md | 54 ++----------------- .../{other.md => others.md} | 0 .github/PULL_REQUEST_TEMPLATE/production.md | 48 +++++++++++++++++ CONTRIBUTING.md | 7 +-- 7 files changed, 78 insertions(+), 61 deletions(-) rename .github/PULL_REQUEST_TEMPLATE/{other.md => others.md} (100%) create mode 100644 .github/PULL_REQUEST_TEMPLATE/production.md diff --git a/.github/ISSUE_TEMPLATE/epic-template.md b/.github/ISSUE_TEMPLATE/epic-template.md index ff49d57323..6738bb12d1 100644 --- a/.github/ISSUE_TEMPLATE/epic-template.md +++ b/.github/ISSUE_TEMPLATE/epic-template.md @@ -4,20 +4,20 @@ about: Basic template for EPICs (used by the team) labels: epic, needs-triage --- -# Problem +## Problem -# Closing criteria +## Closing criteria -# Problem details +## Problem details -# Task list +## Task list ```[tasklist] ### Must have diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md index e16a421183..44f19495cd 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.md +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -1,7 +1,7 @@ --- name: Feature Request about: Create a proposal to request a feature -labels: enhancement, needs-triage +labels: enhancement, epic, needs-triage --- +## Task list + +```[tasklist] +### Must have +- [ ] discuss proposal (if proposal rejected, close EPIC) +- [ ] create ADR (if ADR rejected, close EPIC) +- [ ] add sub-tasks needed to implement the proposed feature +``` + +```[tasklist] +### Nice to have +- [ ] add sub-tasks that are nice to have for the proposed feature +``` + ____ #### For Admin Use diff --git a/.github/ISSUE_TEMPLATE/issue-template.md b/.github/ISSUE_TEMPLATE/issue-template.md index 2ce98fd81b..bef74bd4bb 100644 --- a/.github/ISSUE_TEMPLATE/issue-template.md +++ b/.github/ISSUE_TEMPLATE/issue-template.md @@ -10,15 +10,15 @@ v Before smashing the submit button please review the template. v Please also ensure that this is not a duplicate issue :) ☺ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > --> -# Problem +## Problem -# Closing criteria +## Closing criteria -# Problem details +## Problem details diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 979c1d1c42..1036e0b387 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,51 +1,5 @@ - +Please go the the `Preview` tab and select the appropriate sub-template: -## Description - -Closes: #XXXX - - - ---- - -### Author Checklist - -*All items are required. Please add a note to the item if the item is not applicable and -please add links to any relevant follow up issues.* - -I have... - -* [ ] Included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title -* [ ] Added `!` to the type prefix if API or client breaking change -* [ ] Confirmed this PR does not introduce changes requiring state migrations, OR migration code has been added to consumer and/or provider modules -* [ ] Targeted the correct branch (see [PR Targeting](https://github.com/cosmos/interchain-security/blob/main/CONTRIBUTING.md#pr-targeting)) -* [ ] Provided a link to the relevant issue or specification -* [ ] Followed the guidelines for [building SDK modules](https://github.com/cosmos/cosmos-sdk/blob/main/docs/docs/building-modules) -* [ ] Included the necessary unit and integration [tests](https://github.com/cosmos/interchain-security/blob/main/CONTRIBUTING.md#testing) -* [ ] Added a changelog entry to `CHANGELOG.md` -* [ ] Included comments for [documenting Go code](https://blog.golang.org/godoc) -* [ ] Updated the relevant documentation or specification -* [ ] Reviewed "Files changed" and left comments if necessary -* [ ] Confirmed all CI checks have passed - -### Reviewers Checklist - -*All items are required. Please add a note if the item is not applicable and please add -your handle next to the items reviewed if you only reviewed selected items.* - -I have... - -* [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title -* [ ] confirmed `!` in the type prefix if API or client breaking change -* [ ] confirmed this PR does not introduce changes requiring state migrations, OR confirmed migration code has been added to consumer and/or provider modules -* [ ] confirmed all author checklist items have been addressed -* [ ] reviewed state machine logic -* [ ] reviewed API design and naming -* [ ] reviewed documentation is accurate -* [ ] reviewed tests and test coverage +* [Production code](?expand=1&template=production.md) - for types `fix`, `feat`, and `refactor`. +* [Docs](?expand=1&template=docs.md) - for documentation changes. +* [Others](?expand=1&template=others.md) - for changes that do not affect production code. \ No newline at end of file diff --git a/.github/PULL_REQUEST_TEMPLATE/other.md b/.github/PULL_REQUEST_TEMPLATE/others.md similarity index 100% rename from .github/PULL_REQUEST_TEMPLATE/other.md rename to .github/PULL_REQUEST_TEMPLATE/others.md diff --git a/.github/PULL_REQUEST_TEMPLATE/production.md b/.github/PULL_REQUEST_TEMPLATE/production.md new file mode 100644 index 0000000000..0d197d890c --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/production.md @@ -0,0 +1,48 @@ + + +## Description + +Closes: #XXXX + + + +--- + +### Author Checklist + +*All items are required. Please add a note to the item if the item is not applicable and +please add links to any relevant follow up issues.* + +I have... + +* [ ] Included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title +* [ ] Added `!` to the type prefix if API or client breaking change +* [ ] Confirmed this PR does not introduce changes requiring state migrations, OR migration code has been added to consumer and/or provider modules +* [ ] Targeted the correct branch (see [PR Targeting](https://github.com/cosmos/interchain-security/blob/main/CONTRIBUTING.md#pr-targeting)) +* [ ] Provided a link to the relevant issue or specification +* [ ] Followed the guidelines for [building SDK modules](https://github.com/cosmos/cosmos-sdk/blob/main/docs/docs/building-modules) +* [ ] Included the necessary unit and integration [tests](https://github.com/cosmos/interchain-security/blob/main/CONTRIBUTING.md#testing) +* [ ] Added a changelog entry to `CHANGELOG.md` +* [ ] Included comments for [documenting Go code](https://blog.golang.org/godoc) +* [ ] Updated the relevant documentation or specification +* [ ] Reviewed "Files changed" and left comments if necessary +* [ ] Confirmed all CI checks have passed + +### Reviewers Checklist + +*All items are required. Please add a note if the item is not applicable and please add +your handle next to the items reviewed if you only reviewed selected items.* + +I have... + +* [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title +* [ ] confirmed `!` in the type prefix if API or client breaking change +* [ ] confirmed this PR does not introduce changes requiring state migrations, OR confirmed migration code has been added to consumer and/or provider modules +* [ ] confirmed all author checklist items have been addressed +* [ ] reviewed state machine logic +* [ ] reviewed API design and naming +* [ ] reviewed documentation is accurate +* [ ] reviewed tests and test coverage diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 21fc360d3f..dca2431585 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -179,10 +179,11 @@ Additionally, **each PR should only address a single issue**. ### Pull Request Templates -There are three PR templates. The [default template](./.github/PULL_REQUEST_TEMPLATE.md) is for types `fix`, `feat`, and `refactor`. We also have a [docs template](./.github/PULL_REQUEST_TEMPLATE/docs.md) for documentation changes and an [other template](./.github/PULL_REQUEST_TEMPLATE/other.md) for changes that do not affect production code. When previewing a PR before it has been opened, you can change the template by adding one of the following parameters to the url: +There are three PR templates. The [default template](./.github/PULL_REQUEST_TEMPLATE.md) contains links to the three templates. Please go the the `Preview` tab and select the appropriate sub-template: -* `template=docs.md` -* `template=other.md` +- The [production template](./.github/PULL_REQUEST_TEMPLATE/production.md) is for types `fix`, `feat`, and `refactor`. +- The [docs template](./.github/PULL_REQUEST_TEMPLATE/docs.md) is for documentation changes. +- The [other template](./.github/PULL_REQUEST_TEMPLATE/other.md) is for changes that do not affect production code. ### Requesting Reviews From 1113ba40df1fe833a98f5c578e3db02705e12e62 Mon Sep 17 00:00:00 2001 From: Thomas Bruyelle Date: Mon, 12 Jun 2023 11:09:34 +0200 Subject: [PATCH 008/134] docs(adr): ADR-007 pause unbonding period during equivocation proposal (#964) * docs(adr): pause unbonding period during equivocation proposal Co-authored-by: Albert Le Batteux Co-authored-by: Giuseppe Natale * fix voting period duration * remove issue reference * docs: filter out unbonding operations before pause/unpause Co-authored-by: Albert Le Batteux Co-authored-by: Giuseppe Natale --------- Co-authored-by: Albert Le Batteux Co-authored-by: Giuseppe Natale --- .../adr-007-pause-unbonding-on-eqv-prop.md | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 docs/docs/adrs/adr-007-pause-unbonding-on-eqv-prop.md diff --git a/docs/docs/adrs/adr-007-pause-unbonding-on-eqv-prop.md b/docs/docs/adrs/adr-007-pause-unbonding-on-eqv-prop.md new file mode 100644 index 0000000000..bf3a761704 --- /dev/null +++ b/docs/docs/adrs/adr-007-pause-unbonding-on-eqv-prop.md @@ -0,0 +1,93 @@ +--- +sidebar_position: 2 +title: ADR Template +--- +# ADR 007: Pause validator unbonding during equivocation proposal + +## Changelog +* 2023-05-16: Initial Draft + +## Status + +Proposed + +## Context + +Currently, if an equivocation slashing proposal is created after more than one +week has passed since the equivocation, it is possible that the validator in +question could unbond and get away without being slashed, since the unbonding +period is 3 weeks, and the voting period is 2 weeks. For this reason, it might +be good to pause unbondings for validators named in an equivocation slashing +proposal until the proposal's voting period is over. + +## Decision + +### How + +Pausing the unbonding period is already possible thanks to the changes in the +`staking` module of the cosmos-sdk: +- `stakingKeeper.PutUnbondingOnHold` pauses an unbonding period +- `stakingKeeper.UnbondingCanComplete` unpauses an unbonding period + +These methods use a reference counter under the hood, that gets incremented +every time `PutUnbondingOnHold` is called, and decreased when +`UnbondingCanComplete` is called instead. A specific unbonding is considered +fully unpaused when its underlying reference counter reaches 0. Therefore, as +long as we safeguard consistency - i.e. we make sure we eventually decrement +the reference counter for each time we have incremented it - we can safely use +this existing mechanism without conflicts with the *Completion of Unbonding +Operations* system. + +### When pause + +The unbonding period (if there is any unbonding) should be paused once an +equivocation proposal enters the voting period. For that, the `gov` module's +hook `AfterProposalDeposit` can be used. + +If the hook is triggered with a an equivocation proposal in voting period, then +for each equivocation of the proposal, the unbonding operations of the related +validator that were initiated after the equivocation block time must be paused +- i.e. the underlying reference counter has to be increased. + +Note that even after the voting period has started, a proposal can receive +additional deposits. The hook is triggered however at arrival of a deposit, so +a check to verify that the proposal is not already in voting period is +required. + +### When unpause + +We can use a `gov` module's hook also here and it is +`AfterProposalVotingPeriodEnded`. + +If the hook is triggered with an equivocation proposal, then for each +associated equivocation, the unbonding operations of the related validator that +were initiated between the equivocation block time and the start of the +proposal voting period must be unpaused - i.e. decrease the underlying +reference counter - regardless of the proposal outcome. + +## Consequences + +### Positive + +- Validators subject to an equivocation proposal cannot finish unbonding + their tokens before the end of the voting period. + +### Negative + +- A malicious consumer chain could forge slash packets enabling submission of + an equivocation proposal on the provider chain, resulting in the freezing of + validator's unbondings for an undeterminated amount of time. +- Misbehavior on a consumer chain can potentially go unpunished, if no one + submits an equivocation proposal in time, or if the proposal doesn't pass. + +### Neutral + +- This feature can't be used for social slashing, because an equivocation + proposal is only accepted if there's a slash log for the related + validator(s), meaning the consumer chain has reported the equivocation to + the provider chain. + +## References + +* https://github.com/cosmos/interchain-security/issues/747 +* https://github.com/cosmos/interchain-security/pull/791 From 2b18b5e56896afe057cc41f04ad6f1ab86c81590 Mon Sep 17 00:00:00 2001 From: Marius Poke Date: Mon, 12 Jun 2023 21:28:10 +0200 Subject: [PATCH 009/134] docs: Add type prefix link to CONTRIBUTING.md (#1007) Update CONTRIBUTING.md --- CONTRIBUTING.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dca2431585..61dd6a3102 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -170,8 +170,9 @@ Then: 4. Be sure to include a relevant changelog entry in the `Unreleased` section of `CHANGELOG.md` (see file for log format). The entry should be on top of all others changes in the section. PRs must have a category prefix that is based on the type of changes being made (for example, `fix`, `feat`, -`refactor`, `docs`, and so on). The *type* must be included in the PR title as a prefix (for example, -`fix: `). This convention ensures that all changes that are committed to the base branch follow the +`refactor`, `docs`, and so on). The [type](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) +must be included in the PR title as a prefix (for example, `fix: `). +This convention ensures that all changes that are committed to the base branch follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification. Additionally, **each PR should only address a single issue**. From 93e45a5133600d8bb5cd7a179173a2e61720faa7 Mon Sep 17 00:00:00 2001 From: Marius Poke Date: Tue, 13 Jun 2023 12:48:09 +0200 Subject: [PATCH 010/134] chore: enable mergify (#1009) * add config for mergify * enable security dependecies for v2.0.x --- .github/dependabot.yml | 10 ++++++++++ .mergify.yml | 20 ++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 .mergify.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 029e4e2a7d..42241f2b1d 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -15,5 +15,15 @@ updates: interval: weekly target-branch: "main" open-pull-requests-limit: 10 + labels: + - dependencies + + - package-ecosystem: gomod + directory: "/" + schedule: + interval: daily + target-branch: "release/v2.0.x" + # Only allow automated security-related dependency updates on release branches. + open-pull-requests-limit: 0 labels: - dependencies \ No newline at end of file diff --git a/.mergify.yml b/.mergify.yml new file mode 100644 index 0000000000..7eae0395e1 --- /dev/null +++ b/.mergify.yml @@ -0,0 +1,20 @@ +defaults: + actions: + backport: + assignees: + - "{{ author }}" + +queue_rules: + - name: default + conditions: + - "#approved-reviews-by>1" + +pull_request_rules: + - name: Backport patches to the release/v2.0.x branch + conditions: + - base=main + - label=A:backport/v2.0.x + actions: + backport: + branches: + - release/v2.0.x From 281a7ca146a3e5180c6b558c6c643cf2707dbbd2 Mon Sep 17 00:00:00 2001 From: Ruslan Akhtariev <46343690+pysel@users.noreply.github.com> Date: Tue, 13 Jun 2023 22:19:02 +0700 Subject: [PATCH 011/134] Markdownlint (#907) markdownlint Co-authored-by: Jacob Gadikian --- .markdownlint.json | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .markdownlint.json diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 0000000000..a74b230946 --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,4 @@ +{ + "MD036": false, + "MD013": false +} \ No newline at end of file From 8c2fc562dedecee7799ac69bd72734c37a356638 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Tue, 13 Jun 2023 15:52:11 -0700 Subject: [PATCH 012/134] fix: limit vsc matured packets handled per endblocker (#1004) * initial implementation, still need tests * UTs * integration test * linter * Update CHANGELOG.md * make vsc matured handled this block a var * comment --- CHANGELOG.md | 1 + tests/integration/throttle.go | 85 ++++++++++++++++++++++++-- testutil/integration/debug_test.go | 4 ++ x/ccv/provider/keeper/relay.go | 22 +++++-- x/ccv/provider/keeper/throttle.go | 30 +++++++-- x/ccv/provider/keeper/throttle_test.go | 2 +- x/ccv/provider/types/keys.go | 8 +++ x/ccv/provider/types/keys_test.go | 2 + 8 files changed, 140 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2b0b754e8..208c4ec2c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ Some PRs from v2.0.0 may reappear from other releases below. This is due to the ## Notable PRs included in v2.0.0 +* (feat/fix) limit vsc matured packets handled per endblocker [#1004](https://github.com/cosmos/interchain-security/pull/1004) * (fix) cosumer 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) diff --git a/tests/integration/throttle.go b/tests/integration/throttle.go index c2ef98a4ae..b2dc390ea1 100644 --- a/tests/integration/throttle.go +++ b/tests/integration/throttle.go @@ -12,6 +12,8 @@ import ( tmtypes "github.com/tendermint/tendermint/types" ) +const fullSlashMeterString = "1.0" + // TestBasicSlashPacketThrottling tests slash packet throttling with a single consumer, // two slash packets, and no VSC matured packets. The most basic scenario. func (s *CCVTestSuite) TestBasicSlashPacketThrottling() { @@ -651,7 +653,7 @@ func (s *CCVTestSuite) TestSlashSameValidator() { // Set replenish fraction to 1.0 so that all sent packets should handled immediately (no throttling) params := providerKeeper.GetParams(s.providerCtx()) - params.SlashMeterReplenishFraction = "1.0" + params.SlashMeterReplenishFraction = fullSlashMeterString // needs to be const for linter providerKeeper.SetParams(s.providerCtx(), params) providerKeeper.InitializeSlashMeter(s.providerCtx()) @@ -706,7 +708,7 @@ func (s CCVTestSuite) TestSlashAllValidators() { //nolint:govet // this is a tes // Set replenish fraction to 1.0 so that all sent packets should be handled immediately (no throttling) params := providerKeeper.GetParams(s.providerCtx()) - params.SlashMeterReplenishFraction = "1.0" + params.SlashMeterReplenishFraction = fullSlashMeterString // needs to be const for linter providerKeeper.SetParams(s.providerCtx(), params) providerKeeper.InitializeSlashMeter(s.providerCtx()) @@ -779,7 +781,7 @@ func (s *CCVTestSuite) TestLeadingVSCMaturedAreDequeued() { // Queue up 50 slash packets for each consumer for _, bundle := range s.consumerBundles { - for i := 0; i < 50; i++ { + for i := 50; i < 100; i++ { ibcSeqNum := uint64(i) packet := s.constructSlashPacketFromConsumer(*bundle, *s.providerChain.Vals.Validators[0], stakingtypes.Downtime, ibcSeqNum) @@ -792,7 +794,7 @@ func (s *CCVTestSuite) TestLeadingVSCMaturedAreDequeued() { // Queue up another 50 vsc matured packets for each consumer for _, bundle := range s.consumerBundles { - for i := 0; i < 50; i++ { + for i := 100; i < 150; i++ { ibcSeqNum := uint64(i) packet := s.constructVSCMaturedPacketFromConsumer(*bundle, ibcSeqNum) packetData := ccvtypes.ConsumerPacketData{} @@ -818,6 +820,10 @@ func (s *CCVTestSuite) TestLeadingVSCMaturedAreDequeued() { providerKeeper.SetSlashMeterReplenishTimeCandidate(s.providerCtx()) // Execute end blocker to dequeue only the leading vsc matured packets. + // Note we must call the end blocker three times, since only 100 vsc matured packets can be handled + // each block, and we have 5*50=250 total. + s.providerChain.NextBlock() + s.providerChain.NextBlock() s.providerChain.NextBlock() // Confirm queue size is 100 for each consumer-specific queue (50 leading vsc matured are dequeued). @@ -827,9 +833,80 @@ func (s *CCVTestSuite) TestLeadingVSCMaturedAreDequeued() { } // No slash packets handled, global slash queue is same size as last block. + globalEntries = providerKeeper.GetAllGlobalSlashEntries(s.providerCtx()) + s.Require().Equal(len(globalEntries), 50*5) + + // No slash packets handled even if we call end blocker a couple more times. + s.providerChain.NextBlock() + s.providerChain.NextBlock() + globalEntries = providerKeeper.GetAllGlobalSlashEntries(s.providerCtx()) s.Require().Equal(len(globalEntries), 50*5) } +// TestVscMaturedHandledPerBlockLimit tests that only 100 vsc matured packets are handled per block, +// specifically from HandleThrottleQueues(). +// +// Note the vsc matured per block limit is also tested in, TestLeadingVSCMaturedAreDequeued, +// specifically in the context of HandleLeadingVSCMaturedPackets(). +func (s *CCVTestSuite) TestVscMaturedHandledPerBlockLimit() { + s.SetupAllCCVChannels() + providerKeeper := s.providerApp.GetProviderKeeper() + + // Set replenish fraction to 1.0 so that all sent packets should be handled immediately (no jail throttling) + params := providerKeeper.GetParams(s.providerCtx()) + params.SlashMeterReplenishFraction = fullSlashMeterString // needs to be const for linter + providerKeeper.SetParams(s.providerCtx(), params) + providerKeeper.InitializeSlashMeter(s.providerCtx()) + + // Queue up 100 vsc matured packets for each consumer + for _, bundle := range s.consumerBundles { + for i := 0; i < 100; i++ { + ibcSeqNum := uint64(i) + packet := s.constructVSCMaturedPacketFromConsumer(*bundle, ibcSeqNum) + packetData := ccvtypes.ConsumerPacketData{} + ccvtypes.ModuleCdc.MustUnmarshalJSON(packet.GetData(), &packetData) + providerKeeper.OnRecvVSCMaturedPacket(s.providerCtx(), + packet, *packetData.GetVscMaturedPacketData()) + } + } + + // Queue up 50 slash packets for each consumer, with new IBC sequence numbers + for _, bundle := range s.consumerBundles { + for i := 100; i < 150; i++ { + ibcSeqNum := uint64(i) + packet := s.constructSlashPacketFromConsumer(*bundle, + *s.providerChain.Vals.Validators[0], stakingtypes.Downtime, ibcSeqNum) + packetData := ccvtypes.ConsumerPacketData{} + ccvtypes.ModuleCdc.MustUnmarshalJSON(packet.GetData(), &packetData) + providerKeeper.OnRecvSlashPacket(s.providerCtx(), + packet, *packetData.GetSlashPacketData()) + } + } + + // Confirm queue size is 150 for each consumer-specific queue. + for _, bundle := range s.consumerBundles { + s.Require().Equal(uint64(150), + providerKeeper.GetThrottledPacketDataSize(s.providerCtx(), bundle.Chain.ChainID)) + } + // Confirm global queue size is 50 * 5 (50 slash packets for each of 5 consumers) + globalEntries := providerKeeper.GetAllGlobalSlashEntries(s.providerCtx()) + s.Require().Equal(len(globalEntries), 50*5) + + // Note even though there is no jail throttling active, slash packets will not be handled until + // all of the leading vsc matured packets are handled first. This should take 5 blocks. + for i := 0; i < 5; i++ { + s.providerChain.NextBlock() + s.Require().Len(providerKeeper.GetAllGlobalSlashEntries(s.providerCtx()), 250) // global entries remain same size + } + + // Set signing info for val to be jailed, preventing panic + s.setDefaultValSigningInfo(*s.providerChain.Vals.Validators[0]) + + // Now we execute one more block and all 250 of the slash packets should be handled. + s.providerChain.NextBlock() + s.Require().Empty(providerKeeper.GetAllGlobalSlashEntries(s.providerCtx())) // empty global entries = all slash packets handled +} + func (s *CCVTestSuite) confirmValidatorJailed(tmVal tmtypes.Validator, checkPower bool) { sdkVal, found := s.providerApp.GetTestStakingKeeper().GetValidator( s.providerCtx(), sdk.ValAddress(tmVal.Address)) diff --git a/testutil/integration/debug_test.go b/testutil/integration/debug_test.go index 95190ba8a0..b6456663a9 100644 --- a/testutil/integration/debug_test.go +++ b/testutil/integration/debug_test.go @@ -205,6 +205,10 @@ func TestLeadingVSCMaturedAreDequeued(t *testing.T) { runCCVTestByName(t, "TestLeadingVSCMaturedAreDequeued") } +func TestVscMaturedHandledPerBlockLimit(t *testing.T) { + runCCVTestByName(t, "TestVscMaturedHandledPerBlockLimit") +} + // // Unbonding tests // diff --git a/x/ccv/provider/keeper/relay.go b/x/ccv/provider/keeper/relay.go index 1d93b2fdd9..ea07e0e9af 100644 --- a/x/ccv/provider/keeper/relay.go +++ b/x/ccv/provider/keeper/relay.go @@ -53,14 +53,25 @@ func (k Keeper) OnRecvVSCMaturedPacket( // the "VSC Maturity and Slashing Order" CCV property. If VSC matured packet data DOES NOT // trail slash packet data for that consumer, it will be handled in this method, // bypassing HandleThrottleQueues. -func (k Keeper) HandleLeadingVSCMaturedPackets(ctx sdk.Context) { +func (k Keeper) HandleLeadingVSCMaturedPackets(ctx sdk.Context) (vscMaturedHandledThisBlock int) { + vscMaturedHandledThisBlock = 0 for _, chain := range k.GetAllConsumerChains(ctx) { + // Note: it's assumed the order of the vsc matured slice matches the order of the ibc seq nums slice, + // in that a vsc matured packet data at index i is associated with the ibc seq num at index i. leadingVscMatured, ibcSeqNums := k.GetLeadingVSCMaturedData(ctx, chain.ChainId) - for _, data := range leadingVscMatured { + ibcSeqNumsHandled := []uint64{} + for idx, data := range leadingVscMatured { + if vscMaturedHandledThisBlock >= vscMaturedHandledPerBlockLimit { + // Break from inner for-loop, DeleteThrottledPacketData will still be called for this consumer + break + } k.HandleVSCMaturedPacket(ctx, chain.ChainId, data) + vscMaturedHandledThisBlock++ + ibcSeqNumsHandled = append(ibcSeqNumsHandled, ibcSeqNums[idx]) } - k.DeleteThrottledPacketData(ctx, chain.ChainId, ibcSeqNums...) + k.DeleteThrottledPacketData(ctx, chain.ChainId, ibcSeqNumsHandled...) } + return vscMaturedHandledThisBlock } // HandleVSCMaturedPacket handles a VSCMatured packet. @@ -267,13 +278,14 @@ func (k Keeper) EndBlockCIS(ctx sdk.Context) { // - Marshaling and/or store corruption errors. // - Setting invalid slash meter values (see SetSlashMeter). k.CheckForSlashMeterReplenishment(ctx) + // Handle leading vsc matured packets before throttling logic. // // Note: HandleLeadingVSCMaturedPackets contains panics for the following scenarios, any of which should never occur // if the protocol is correct and external data is properly validated: // // - Marshaling and/or store corruption errors. - k.HandleLeadingVSCMaturedPackets(ctx) + vscMaturedHandledThisBlock := k.HandleLeadingVSCMaturedPackets(ctx) // Handle queue entries considering throttling logic. // // Note: HandleThrottleQueues contains panics for the following scenarios, any of which should never occur @@ -282,7 +294,7 @@ func (k Keeper) EndBlockCIS(ctx sdk.Context) { // - SlashMeter has not been set (which should be set in InitGenesis, see InitializeSlashMeter). // - Marshaling and/or store corruption errors. // - Setting invalid slash meter values (see SetSlashMeter). - k.HandleThrottleQueues(ctx) + k.HandleThrottleQueues(ctx, vscMaturedHandledThisBlock) } // OnRecvSlashPacket delivers a received slash packet, validates it and diff --git a/x/ccv/provider/keeper/throttle.go b/x/ccv/provider/keeper/throttle.go index 704a2f6d19..d832125bfb 100644 --- a/x/ccv/provider/keeper/throttle.go +++ b/x/ccv/provider/keeper/throttle.go @@ -12,16 +12,25 @@ import ( // This file contains functionality relevant to the throttling of slash and vsc matured packets, aka circuit breaker logic. +const vscMaturedHandledPerBlockLimit = 100 + // HandleThrottleQueues iterates over the global slash entry queue, and // handles all or some portion of throttled (slash and/or VSC matured) packet data received from // consumer chains. The slash meter is decremented appropriately in this method. -func (k Keeper) HandleThrottleQueues(ctx sdktypes.Context) { +func (k Keeper) HandleThrottleQueues(ctx sdktypes.Context, vscMaturedHandledThisBlock int) { meter := k.GetSlashMeter(ctx) // Return if meter is negative in value if meter.IsNegative() { return } + // Return if vsc matured handle limit was already reached this block, during HandleLeadingVSCMaturedPackets. + // It makes no practical difference for throttling logic to execute next block. + // By doing this, we assure that all leading vsc matured packets were handled before any slash packets. + if vscMaturedHandledThisBlock >= vscMaturedHandledPerBlockLimit { + return + } + // Obtain all global slash entries, where only some of them may be handled in this method, // depending on the value of the slash meter. allEntries := k.GetAllGlobalSlashEntries(ctx) @@ -35,7 +44,7 @@ func (k Keeper) HandleThrottleQueues(ctx sdktypes.Context) { // Handle one slash and any trailing vsc matured packet data instances by passing in // chainID and appropriate callbacks, relevant packet data is deleted in this method. - k.HandlePacketDataForChain(ctx, globalEntry.ConsumerChainID, k.HandleSlashPacket, k.HandleVSCMaturedPacket) + k.HandlePacketDataForChain(ctx, globalEntry.ConsumerChainID, k.HandleSlashPacket, k.HandleVSCMaturedPacket, vscMaturedHandledThisBlock) handledEntries = append(handledEntries, globalEntry) // don't handle any more global entries if meter becomes negative in value @@ -82,18 +91,31 @@ func (k Keeper) GetEffectiveValPower(ctx sdktypes.Context, func (k Keeper) HandlePacketDataForChain(ctx sdktypes.Context, consumerChainID string, slashPacketHandler func(sdktypes.Context, string, ccvtypes.SlashPacketData), vscMaturedPacketHandler func(sdktypes.Context, string, ccvtypes.VSCMaturedPacketData), + vscMaturedHandledThisBlock int, ) { // Get slash packet data and trailing vsc matured packet data, handle it all. slashFound, slashData, vscMaturedData, seqNums := k.GetSlashAndTrailingData(ctx, consumerChainID) + seqNumsHandled := []uint64{} if slashFound { slashPacketHandler(ctx, consumerChainID, slashData) + // Due to HandleLeadingVSCMaturedPackets() running before HandleThrottleQueues(), and the fact that + // HandleThrottleQueues() will return until all leading vsc matured have been handled, a slash packet + // should always be the first packet in the queue. So we can safely append the first seqNum here. + seqNumsHandled = append(seqNumsHandled, seqNums[0]) } - for _, vscMData := range vscMaturedData { + for idx, vscMData := range vscMaturedData { + if vscMaturedHandledThisBlock >= vscMaturedHandledPerBlockLimit { + // Break from for-loop, DeleteThrottledPacketData will still be called for this consumer + break + } vscMaturedPacketHandler(ctx, consumerChainID, vscMData) + vscMaturedHandledThisBlock++ + // Append seq num for this vsc matured packet + seqNumsHandled = append(seqNumsHandled, seqNums[idx+1]) // Note idx+1, since slash packet is at index 0 } // Delete handled data after it has all been handled. - k.DeleteThrottledPacketData(ctx, consumerChainID, seqNums...) + k.DeleteThrottledPacketData(ctx, consumerChainID, seqNumsHandled...) } // InitializeSlashMeter initializes the slash meter to it's max value (also its allowance), diff --git a/x/ccv/provider/keeper/throttle_test.go b/x/ccv/provider/keeper/throttle_test.go index 3be597e28a..3b93523d4b 100644 --- a/x/ccv/provider/keeper/throttle_test.go +++ b/x/ccv/provider/keeper/throttle_test.go @@ -134,7 +134,7 @@ func TestHandlePacketDataForChain(t *testing.T) { handledData = append(handledData, data) } - providerKeeper.HandlePacketDataForChain(ctx, tc.chainID, slashHandleCounter, vscMaturedHandleCounter) + providerKeeper.HandlePacketDataForChain(ctx, tc.chainID, slashHandleCounter, vscMaturedHandleCounter, 0) // Assert number of handled data instances matches expected number require.Equal(t, len(tc.expectedHandledIndexes), len(handledData)) diff --git a/x/ccv/provider/types/keys.go b/x/ccv/provider/types/keys.go index bb2ffcc881..4e15f566ef 100644 --- a/x/ccv/provider/types/keys.go +++ b/x/ccv/provider/types/keys.go @@ -134,6 +134,10 @@ const ( // ConsumerRewardDenomsBytePrefix is the byte prefix that will store a list of consumer reward denoms ConsumerRewardDenomsBytePrefix + // VSCMaturedHandledThisBlockBytePrefix is the byte prefix storing the number of vsc matured packets + // handled in the current block + VSCMaturedHandledThisBlockBytePrefix + // NOTE: DO NOT ADD NEW BYTE PREFIXES HERE WITHOUT ADDING THEM TO getAllKeyPrefixes() IN keys_test.go ) @@ -476,6 +480,10 @@ func ParseChainIdAndConsAddrKey(prefix byte, bz []byte) (string, sdk.ConsAddress return chainID, addr, nil } +func VSCMaturedHandledThisBlockKey() []byte { + return []byte{VSCMaturedHandledThisBlockBytePrefix} +} + // // End of generic helpers section // diff --git a/x/ccv/provider/types/keys_test.go b/x/ccv/provider/types/keys_test.go index d28232c6a2..03493c1138 100644 --- a/x/ccv/provider/types/keys_test.go +++ b/x/ccv/provider/types/keys_test.go @@ -51,6 +51,7 @@ func getAllKeyPrefixes() []byte { providertypes.KeyAssignmentReplacementsBytePrefix, providertypes.ConsumerAddrsToPruneBytePrefix, providertypes.SlashLogBytePrefix, + providertypes.VSCMaturedHandledThisBlockBytePrefix, } } @@ -94,6 +95,7 @@ func getAllFullyDefinedKeys() [][]byte { providertypes.KeyAssignmentReplacementsKey("chainID", providertypes.NewProviderConsAddress([]byte{0x05})), providertypes.ConsumerAddrsToPruneKey("chainID", 88), providertypes.SlashLogKey(providertypes.NewProviderConsAddress([]byte{0x05})), + providertypes.VSCMaturedHandledThisBlockKey(), } } From 07be71aa678a0ad204c62a6eb6033a526c0bef27 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Date: Wed, 14 Jun 2023 10:51:38 +0200 Subject: [PATCH 013/134] feat: integrate cometmock (#989) * Add gorelayer and CometMock to Dockerfile * Add option to start with cometmock in start-chain script * Start adding support for rly * Adjust relayer start action * Add entrypoint for short happy path steps * Add . nosec G204 and waiting for blocks * Adjust rly config: Gas is free * Remove optout steps from short happy path * Use separate redelegate step for short happy path * Wait for blocks after unbonding * Make naming more descriptive and add comments * Add comment to chain name sorting and improve comments * Update start-chain.sh Address comments form joint review session with @MSalopek * Fix typo --- Dockerfile | 8 + tests/e2e/actions.go | 286 +++++++++++++++++- tests/e2e/config.go | 10 + tests/e2e/main.go | 24 +- tests/e2e/state.go | 5 + tests/e2e/step_delegation.go | 65 +++- tests/e2e/steps.go | 12 +- tests/e2e/steps_democracy.go | 9 +- tests/e2e/steps_double_sign.go | 9 +- tests/e2e/steps_downtime.go | 24 +- tests/e2e/steps_multi_consumer_delegation.go | 18 +- tests/e2e/steps_multi_consumer_double_sign.go | 15 +- tests/e2e/steps_multi_consumer_downtime.go | 27 +- tests/e2e/steps_reward_denom.go | 9 +- tests/e2e/steps_start_chains.go | 3 +- tests/e2e/steps_stop_chain.go | 6 +- .../e2e/steps_submit_equivocation_proposal.go | 3 +- tests/e2e/testnet-scripts/start-chain.sh | 65 +++- 18 files changed, 534 insertions(+), 64 deletions(-) diff --git a/Dockerfile b/Dockerfile index 0da9141620..ac528fa8fb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -30,12 +30,20 @@ RUN make install # Get Hermes build FROM ghcr.io/informalsystems/hermes:1.4.1 AS hermes-builder +# Get CometMock +FROM informalofftermatt/cometmock:latest as cometmock-builder + +# Get GoRelayer +FROM informalofftermatt/gorelayer:nogas AS gorelayer-builder + FROM --platform=linux/amd64 fedora:36 RUN dnf update -y RUN dnf install -y which iproute iputils procps-ng vim-minimal tmux net-tools htop jq USER root COPY --from=hermes-builder /usr/bin/hermes /usr/local/bin/ +COPY --from=cometmock-builder /usr/local/bin/cometmock /usr/local/bin/cometmock +COPY --from=gorelayer-builder /bin/rly /usr/local/bin/ COPY --from=is-builder /go/bin/interchain-security-pd /usr/local/bin/interchain-security-pd COPY --from=is-builder /go/bin/interchain-security-cd /usr/local/bin/interchain-security-cd diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index 4a4c471f79..b1e6863b7a 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -122,6 +122,13 @@ func (tr TestRun) startChain( genesisChanges = chainConfig.genesisChanges } + var cometmockArg string + if tr.useCometmock { + cometmockArg = "true" + } else { + cometmockArg = "false" + } + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, "/bin/bash", "/testnet-scripts/start-chain.sh", chainConfig.binaryName, string(vals), @@ -132,6 +139,7 @@ func (tr TestRun) startChain( // lower timeout_commit means the blocks are produced faster making the test run shorter // with short timeout_commit (eg. timeout_commit = 1s) some nodes may miss blocks causing the test run to fail tr.tendermintConfigOverride, + cometmockArg, ) cmdReader, err := cmd.StdoutPipe() @@ -587,9 +595,80 @@ websocket_addr = "%s" numerator = "1" ` +// Set up the config for a new chain for gorelayer. +// This config is added to the container as a file. +// We then add the chain to the relayer, using this config as the chain config with `rly chains add --file` +// This is functionally similar to the config used by Hermes for chains, e.g. gas is free. +const gorelayerChainConfigTemplate = ` +{ + "type": "cosmos", + "value": { + "key": "default", + "chain-id": "%s", + "rpc-addr": "%s", + "account-prefix": "cosmos", + "keyring-backend": "test", + "gas-adjustment": 1.2, + "gas-prices": "0.00stake", + "debug": true, + "timeout": "20s", + "output-format": "json", + "sign-mode": "direct" + } +}` + func (tr TestRun) addChainToRelayer( action addChainToRelayerAction, verbose bool, +) { + if !tr.useGorelayer { + tr.addChainToHermes(action, verbose) + } else { + tr.addChainToGorelayer(action, verbose) + } +} + +func (tr TestRun) addChainToGorelayer( + action addChainToRelayerAction, + verbose bool, +) { + queryNodeIP := tr.getQueryNodeIP(action.chain) + chainId := tr.chainConfigs[action.chain].chainId + rpcAddr := "http://" + queryNodeIP + ":26658" + + chainConfig := fmt.Sprintf(gorelayerChainConfigTemplate, + chainId, + rpcAddr, + ) + + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + bz, err := exec.Command("docker", "exec", tr.containerConfig.instanceName, "rly", "config", "init").CombinedOutput() + if err != nil && !strings.Contains(string(bz), "config already exists") { + log.Fatal(err, "\n", string(bz)) + } + + chainConfigFileName := fmt.Sprintf("/root/%s_config.json", chainId) + + bashCommand := fmt.Sprintf(`echo '%s' >> %s`, chainConfig, chainConfigFileName) + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + bz, err = exec.Command("docker", "exec", tr.containerConfig.instanceName, "bash", "-c", + bashCommand).CombinedOutput() + if err != nil { + log.Fatal(err, "\n", string(bz)) + } + + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + addChainCommand := exec.Command("docker", "exec", tr.containerConfig.instanceName, "rly", "chains", "add", "--file", chainConfigFileName, string(chainId)) + executeCommand(addChainCommand, "add chain") + + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + keyRestoreCommand := exec.Command("docker", "exec", tr.containerConfig.instanceName, "rly", "keys", "restore", string(chainId), "default", tr.validatorConfigs[action.validator].mnemonic) + executeCommand(keyRestoreCommand, "restore keys") +} + +func (tr TestRun) addChainToHermes( + action addChainToRelayerAction, + verbose bool, ) { queryNodeIP := tr.getQueryNodeIP(action.chain) chainId := tr.chainConfigs[action.chain].chainId @@ -638,6 +717,26 @@ func (tr TestRun) addChainToRelayer( } } +// This config file is used by gorelayer to create a path between chains. +// Since the tests assume we use a certain client-id for certain paths, +// in the config we specify the client id, e.g. 07-tendermint-5. +// The src-channel-filter is empty because we want to relay all channels. +const gorelayerPathConfigTemplate = `{ + "src": { + "chain-id": "%s", + "client-id": "07-tendermint-%v" + }, + "dst": { + "chain-id": "%s", + "client-id": "07-tendermint-%v" + }, + "src-channel-filter": { + "rule": "", + "channel-list": [] + } +} +` + type addIbcConnectionAction struct { chainA chainID chainB chainID @@ -648,6 +747,67 @@ type addIbcConnectionAction struct { func (tr TestRun) addIbcConnection( action addIbcConnectionAction, verbose bool, +) { + if !tr.useGorelayer { + tr.addIbcConnectionHermes(action, verbose) + } else { + tr.addIbcConnectionGorelayer(action, verbose) + } +} + +func (tr TestRun) addIbcConnectionGorelayer( + action addIbcConnectionAction, + verbose bool, +) { + pathName := tr.GetPathNameForGorelayer(action.chainA, action.chainB) + + pathConfig := fmt.Sprintf(gorelayerPathConfigTemplate, action.chainA, action.clientA, action.chainB, action.clientB) + + pathConfigFileName := fmt.Sprintf("/root/%s_config.json", pathName) + + bashCommand := fmt.Sprintf(`echo '%s' >> %s`, pathConfig, pathConfigFileName) + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + pathConfigCommand := exec.Command("docker", "exec", tr.containerConfig.instanceName, "bash", "-c", + bashCommand) + executeCommand(pathConfigCommand, "add path config") + + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + newPathCommand := exec.Command("docker", "exec", tr.containerConfig.instanceName, "rly", + "paths", "add", + string(tr.chainConfigs[action.chainA].chainId), + string(tr.chainConfigs[action.chainB].chainId), + pathName, + "--file", pathConfigFileName, + ) + + executeCommand(newPathCommand, "new path") + + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + newClientsCommand := exec.Command("docker", "exec", tr.containerConfig.instanceName, "rly", + "transact", "clients", + pathName, + ) + + executeCommand(newClientsCommand, "new clients") + + tr.waitBlocks(action.chainA, 1, 10*time.Second) + tr.waitBlocks(action.chainB, 1, 10*time.Second) + + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + newConnectionCommand := exec.Command("docker", "exec", tr.containerConfig.instanceName, "rly", + "transact", "connection", + pathName, + ) + + executeCommand(newConnectionCommand, "new connection") + + tr.waitBlocks(action.chainA, 1, 10*time.Second) + tr.waitBlocks(action.chainB, 1, 10*time.Second) +} + +func (tr TestRun) addIbcConnectionHermes( + action addIbcConnectionAction, + verbose bool, ) { //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, "hermes", @@ -692,10 +852,40 @@ type addIbcChannelAction struct { order string } -type startHermesAction struct{} +type startRelayerAction struct{} + +func (tr TestRun) startRelayer( + action startRelayerAction, + verbose bool, +) { + if tr.useGorelayer { + tr.startGorelayer(action, verbose) + } else { + tr.startHermes(action, verbose) + } +} + +func (tr TestRun) startGorelayer( + action startRelayerAction, + verbose bool, +) { + // gorelayer start is running in detached mode + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + cmd := exec.Command("docker", "exec", "-d", tr.containerConfig.instanceName, "rly", + "start", + ) + + if err := cmd.Start(); err != nil { + log.Fatal(err) + } + + if verbose { + fmt.Println("started gorelayer") + } +} func (tr TestRun) startHermes( - action startHermesAction, + action startRelayerAction, verbose bool, ) { // hermes start is running in detached mode @@ -716,6 +906,35 @@ func (tr TestRun) startHermes( func (tr TestRun) addIbcChannel( action addIbcChannelAction, verbose bool, +) { + if tr.useGorelayer { + tr.addIbcChannelGorelayer(action, verbose) + } else { + tr.addIbcChannelHermes(action, verbose) + } +} + +func (tr TestRun) addIbcChannelGorelayer( + action addIbcChannelAction, + verbose bool, +) { + pathName := tr.GetPathNameForGorelayer(action.chainA, action.chainB) + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, "rly", + "transact", "channel", + pathName, + "--src-port", action.portA, + "--dst-port", action.portB, + "--version", tr.containerConfig.ccvVersion, + "--order", action.order, + "--debug", + ) + executeCommand(cmd, "addChannel") +} + +func (tr TestRun) addIbcChannelHermes( + action addIbcChannelAction, + verbose bool, ) { //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, "hermes", @@ -773,6 +992,10 @@ func (tr TestRun) transferChannelComplete( action transferChannelCompleteAction, verbose bool, ) { + if tr.useGorelayer { + log.Fatal("transferChannelComplete is not implemented for rly") + } + //#nosec G204 -- Bypass linter warning for spawning subprocess with chanOpenTryCmd arguments. chanOpenTryCmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, "hermes", "tx", "chan-open-try", @@ -841,7 +1064,8 @@ func executeCommand(cmd *exec.Cmd, cmdName string) { } type relayPacketsAction struct { - chain chainID + chainA chainID + chainB chainID port string channel uint } @@ -849,11 +1073,43 @@ type relayPacketsAction struct { func (tr TestRun) relayPackets( action relayPacketsAction, verbose bool, +) { + if tr.useGorelayer { + tr.relayPacketsGorelayer(action, verbose) + } else { + tr.relayPacketsHermes(action, verbose) + } +} + +func (tr TestRun) relayPacketsGorelayer( + action relayPacketsAction, + verbose bool, +) { + pathName := tr.GetPathNameForGorelayer(action.chainA, action.chainB) + + // rly transact relay-packets [path-name] --channel [channel-id] + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, "rly", "transact", "flush", + pathName, + "channel-"+fmt.Sprint(action.channel), + ) + if verbose { + log.Println("relayPackets cmd:", cmd.String()) + } + bz, err := cmd.CombinedOutput() + if err != nil { + log.Fatal(err, "\n", string(bz)) + } +} + +func (tr TestRun) relayPacketsHermes( + action relayPacketsAction, + verbose bool, ) { // hermes clear packets ibc0 transfer channel-13 //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, "hermes", "clear", "packets", - "--chain", string(tr.chainConfigs[action.chain].chainId), + "--chain", string(tr.chainConfigs[action.chainA].chainId), "--port", action.port, "--channel", "channel-"+fmt.Sprint(action.channel), ) @@ -866,7 +1122,7 @@ func (tr TestRun) relayPackets( log.Fatal(err, "\n", string(bz)) } - tr.waitBlocks(action.chain, 1, 30*time.Second) + tr.waitBlocks(action.chainA, 1, 30*time.Second) } type relayRewardPacketsToProviderAction struct { @@ -886,7 +1142,7 @@ func (tr TestRun) relayRewardPacketsToProvider( tr.waitBlocks(action.consumerChain, uint(blockPerDistribution-currentBlock+1), 60*time.Second) } - tr.relayPackets(relayPacketsAction{chain: action.consumerChain, port: action.port, channel: action.channel}, verbose) + tr.relayPackets(relayPacketsAction{chainA: action.consumerChain, chainB: action.providerChain, port: action.port, channel: action.channel}, verbose) tr.waitBlocks(action.providerChain, 1, 10*time.Second) } @@ -929,6 +1185,8 @@ func (tr TestRun) delegateTokens( if err != nil { log.Fatal(err, "\n", string(bz)) } + + tr.waitBlocks(action.chain, 1, 10*time.Second) } type unbondTokensAction struct { @@ -971,6 +1229,8 @@ func (tr TestRun) unbondTokens( if err != nil { log.Fatal(err, "\n", string(bz)) } + + tr.waitBlocks(action.chain, 1, 10*time.Second) } type redelegateTokensAction struct { @@ -1370,3 +1630,17 @@ func (tr TestRun) waitForSlashThrottleDequeue( func uintPointer(i uint) *uint { return &i } + +// GetPathNameForGorelayer returns the name of the path between two given chains used by Gorelayer. +// Since paths are bidirectional, we need either chain to be able to be provided as first or second argument +// and still return the same name, so we sort the chain names alphabetically. +func (tr TestRun) GetPathNameForGorelayer(chainA, chainB chainID) string { + var pathName string + if string(chainA) < string(chainB) { + pathName = string(chainA) + "-" + string(chainB) + } else { + pathName = string(chainB) + "-" + string(chainA) + } + + return pathName +} diff --git a/tests/e2e/config.go b/tests/e2e/config.go index 6d7e36d637..cc755cb97a 100644 --- a/tests/e2e/config.go +++ b/tests/e2e/config.go @@ -70,6 +70,8 @@ type TestRun struct { tendermintConfigOverride string localSdkPath string useGaia bool + useCometmock bool // if false, nodes run CometBFT + useGorelayer bool // if false, Hermes is used as the relayer gaiaTag string name string @@ -339,6 +341,14 @@ func (s *TestRun) SetDockerConfig(localSdkPath string, useGaia bool, gaiaTag str s.localSdkPath = localSdkPath } +func (s *TestRun) SetCometMockConfig(useCometmock bool) { + s.useCometmock = useCometmock +} + +func (s *TestRun) SetRelayerConfig(useRly bool) { + s.useGorelayer = useRly +} + // validateStringLiterals enforces that configs follow the constraints // necessary to to execute the tests // diff --git a/tests/e2e/main.go b/tests/e2e/main.go index 8ef9d93b7a..141f8a8cd8 100644 --- a/tests/e2e/main.go +++ b/tests/e2e/main.go @@ -16,12 +16,19 @@ import ( ) var ( - verbose = flag.Bool("verbose", false, "turn verbose logging on/off") - happyPathOnly = flag.Bool("happy-path-only", false, "run happy path tests only") + verbose = flag.Bool("verbose", false, "turn verbose logging on/off") + happyPathOnly = flag.Bool("happy-path-only", false, "run happy path tests only") + shortHappyPathOnly = flag.Bool("short-happy-path", false, `run abridged happy path tests only. +This is like the happy path, but skips steps +that involve starting or stopping nodes for the same chain outside of the chain setup or teardown. +In particular, this skips steps related to downtime and double signing. +This is suited for CometMock+Gorelayer testing`) includeMultiConsumer = flag.Bool("include-multi-consumer", false, "include multiconsumer tests in run") parallel = flag.Bool("parallel", false, "run all tests in parallel") localSdkPath = flag.String("local-sdk-path", "", "path of a local sdk version to build and reference in integration tests") + useCometmock = flag.Bool("use-cometmock", false, "use cometmock instead of CometBFT") + useGorelayer = flag.Bool("use-gorelayer", false, "use go relayer instead of Hermes") ) var ( @@ -35,6 +42,13 @@ var ( func main() { flag.Parse() + if shortHappyPathOnly != nil && *shortHappyPathOnly { + fmt.Println("=============== running short happy path only ===============") + tr := DefaultTestRun() + tr.Run(shortHappyPathSteps, *localSdkPath, *useGaia, *gaiaTag) + return + } + if happyPathOnly != nil && *happyPathOnly { fmt.Println("=============== running happy path only ===============") tr := DefaultTestRun() @@ -80,6 +94,8 @@ func main() { // Docker containers are torn down after the test run is complete. func (tr *TestRun) Run(steps []Step, localSdkPath string, useGaia bool, gaiaTag string) { tr.SetDockerConfig(localSdkPath, useGaia, gaiaTag) + tr.SetCometMockConfig(*useCometmock) + tr.SetRelayerConfig(*useGorelayer) tr.validateStringLiterals() tr.startDocker() @@ -142,8 +158,8 @@ func (tr *TestRun) runStep(step Step, verbose bool) { tr.assignConsumerPubKey(action, verbose) case slashThrottleDequeue: tr.waitForSlashThrottleDequeue(action, verbose) - case startHermesAction: - tr.startHermes(action, verbose) + case startRelayerAction: + tr.startRelayer(action, verbose) case registerConsumerRewardDenomAction: tr.registerConsumerRewardDenom(action, verbose) default: diff --git a/tests/e2e/state.go b/tests/e2e/state.go index 98483ffb7e..9127c65df8 100644 --- a/tests/e2e/state.go +++ b/tests/e2e/state.go @@ -669,6 +669,11 @@ func (tr TestRun) getRegisteredConsumerRewardDenoms(chain chainID) []string { } func (tr TestRun) getValidatorNode(chain chainID, validator validatorID) string { + // for CometMock, validatorNodes are all the same address as the query node (which is CometMocks address) + if tr.useCometmock { + return tr.getQueryNode(chain) + } + return "tcp://" + tr.getValidatorIP(chain, validator) + ":26658" } diff --git a/tests/e2e/step_delegation.go b/tests/e2e/step_delegation.go index 8e9f090736..f33fc136d4 100644 --- a/tests/e2e/step_delegation.go +++ b/tests/e2e/step_delegation.go @@ -46,7 +46,8 @@ func stepsDelegate(consumerName string) []Step { }, { action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumerName), port: "provider", channel: 0, }, @@ -110,7 +111,8 @@ func stepsUnbond(consumerName string) []Step { }, { action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumerName), port: "provider", channel: 0, }, @@ -160,7 +162,8 @@ func stepsRedelegateForOptOut(consumerName string) []Step { }, { action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumerName), port: "provider", channel: 0, }, @@ -212,7 +215,61 @@ func stepsRedelegate(consumerName string) []Step { }, { action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumerName), + port: "provider", + channel: 0, + }, + state: State{ + chainID(consumerName): ChainState{ + ValPowers: &map[validatorID]uint{ + // Now power changes are seen by consumer + validatorID("alice"): 509, + validatorID("bob"): 500, + validatorID("carol"): 501, + }, + }, + }, + }, + } +} + +// stepsRedelegate tests redelegation and resulting validator power changes. +func stepsRedelegateShort(consumerName string) []Step { + return []Step{ + { + action: redelegateTokensAction{ + chain: chainID("provi"), + src: validatorID("alice"), + dst: validatorID("carol"), + txSender: validatorID("alice"), + // Leave alice with majority stake so non-faulty validators maintain more than + // 2/3 voting power during downtime tests below, avoiding chain halt + amount: 1000000, + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 500, + // carol always uses a consumer assigned key + validatorID("carol"): 501, + }, + }, + chainID(consumerName): ChainState{ + ValPowers: &map[validatorID]uint{ + // Voting power changes not seen by consumer yet + validatorID("alice"): 510, + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + }, + }, + { + action: relayPacketsAction{ + chainA: chainID("provi"), + chainB: chainID(consumerName), port: "provider", channel: 0, }, diff --git a/tests/e2e/steps.go b/tests/e2e/steps.go index 234672546b..8c0b4b2661 100644 --- a/tests/e2e/steps.go +++ b/tests/e2e/steps.go @@ -25,11 +25,21 @@ var happyPathSteps = concatSteps( stepsRejectEquivocationProposal("consu", 2), // prop to tombstone bob is rejected stepsDoubleSignOnProviderAndConsumer("consu"), // carol double signs on provider, bob double signs on consumer stepsSubmitEquivocationProposal("consu", 2), // now prop to tombstone bob is submitted and accepted - stepsStartHermes(), + stepsStartRelayer(), stepsConsumerRemovalPropNotPassing("consu", 3), // submit removal prop but vote no on it - chain should stay stepsStopChain("consu", 4), // stop chain ) +var shortHappyPathSteps = concatSteps( + stepsStartChains([]string{"consu"}, false), + stepsDelegate("consu"), + stepsUnbond("consu"), + stepsRedelegateShort("consu"), + stepsStartRelayer(), + stepsConsumerRemovalPropNotPassing("consu", 2), // submit removal prop but vote no on it - chain should stay + stepsStopChain("consu", 3), // stop chain +) + var slashThrottleSteps = concatSteps( stepsStartChains([]string{"consu"}, false), stepsDelegate("consu"), diff --git a/tests/e2e/steps_democracy.go b/tests/e2e/steps_democracy.go index 9f5915f71d..686fbf1c49 100644 --- a/tests/e2e/steps_democracy.go +++ b/tests/e2e/steps_democracy.go @@ -195,7 +195,8 @@ func stepsDemocracy(consumerName string) []Step { }, { action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumerName), port: "provider", channel: 0, }, @@ -221,7 +222,8 @@ func stepsDemocracy(consumerName string) []Step { // and can now be relayed as packet to consumer { action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumerName), port: "provider", channel: 0, }, @@ -260,7 +262,8 @@ func stepsDemocracy(consumerName string) []Step { }, { action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumerName), port: "provider", channel: 0, }, diff --git a/tests/e2e/steps_double_sign.go b/tests/e2e/steps_double_sign.go index e4efca4bb5..c007fa5c1c 100644 --- a/tests/e2e/steps_double_sign.go +++ b/tests/e2e/steps_double_sign.go @@ -30,7 +30,8 @@ func stepsDoubleSignOnProviderAndConsumer(consumerName string) []Step { { // relay power change to consumerName action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumerName), port: "provider", channel: 0, // consumerName channel }, @@ -78,7 +79,8 @@ func stepsDoubleSignOnProviderAndConsumer(consumerName string) []Step { }, { action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumerName), port: "provider", channel: 0, }, @@ -102,7 +104,8 @@ func stepsDoubleSignOnProviderAndConsumer(consumerName string) []Step { { // consumer learns about the double sign action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumerName), port: "provider", channel: 0, }, diff --git a/tests/e2e/steps_downtime.go b/tests/e2e/steps_downtime.go index af2d2f237e..74cb349000 100644 --- a/tests/e2e/steps_downtime.go +++ b/tests/e2e/steps_downtime.go @@ -39,7 +39,8 @@ func stepsDowntime(consumerName string) []Step { }, { action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumerName), port: "provider", channel: 0, }, @@ -65,7 +66,8 @@ func stepsDowntime(consumerName string) []Step { // and can now be relayed as packet to consumer { action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumerName), port: "provider", channel: 0, }, @@ -106,7 +108,8 @@ func stepsDowntime(consumerName string) []Step { }, { action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumerName), port: "provider", channel: 0, }, @@ -150,7 +153,8 @@ func stepsDowntime(consumerName string) []Step { }, { action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumerName), port: "provider", channel: 0, }, @@ -188,7 +192,8 @@ func stepsDowntime(consumerName string) []Step { }, { action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumerName), port: "provider", channel: 0, }, @@ -236,7 +241,8 @@ func stepsDowntimeWithOptOut(consumerName string) []Step { }, { action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumerName), port: "provider", channel: 0, }, @@ -314,7 +320,8 @@ func stepsThrottledDowntime(consumerName string) []Step { }, { action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumerName), port: "provider", channel: 0, }, @@ -376,7 +383,8 @@ func stepsThrottledDowntime(consumerName string) []Step { // and can now be relayed as packet to consumer { action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumerName), port: "provider", channel: 0, }, diff --git a/tests/e2e/steps_multi_consumer_delegation.go b/tests/e2e/steps_multi_consumer_delegation.go index 106307629d..45536c0679 100644 --- a/tests/e2e/steps_multi_consumer_delegation.go +++ b/tests/e2e/steps_multi_consumer_delegation.go @@ -38,7 +38,8 @@ func stepsMultiConsumerDelegate(consumer1, consumer2 string) []Step { { // relay changes to consumer1 action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumer1), port: "provider", channel: 0, // consumer1 channel }, @@ -69,7 +70,8 @@ func stepsMultiConsumerDelegate(consumer1, consumer2 string) []Step { { // relay changes to consumer2 action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumer2), port: "provider", channel: 1, // consumer2 channel }, @@ -138,7 +140,8 @@ func stepsMultiConsumerUnbond(consumer1, consumer2 string) []Step { { // relay to consumer1 action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumer1), port: "provider", channel: 0, // consumer1 channel }, @@ -169,7 +172,8 @@ func stepsMultiConsumerUnbond(consumer1, consumer2 string) []Step { { // relay to consumer2 action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumer2), port: "provider", channel: 1, // consumer2 channel }, @@ -242,7 +246,8 @@ func stepsMultiConsumerRedelegate(consumer1, consumer2 string) []Step { { // relay to consumer1 action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumer1), port: "provider", channel: 0, // consumer1 channel }, @@ -273,7 +278,8 @@ func stepsMultiConsumerRedelegate(consumer1, consumer2 string) []Step { { // relay to consumer2 action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumer2), port: "provider", channel: 1, // consumer1 channel }, diff --git a/tests/e2e/steps_multi_consumer_double_sign.go b/tests/e2e/steps_multi_consumer_double_sign.go index a50f21e11f..d12eb37eff 100644 --- a/tests/e2e/steps_multi_consumer_double_sign.go +++ b/tests/e2e/steps_multi_consumer_double_sign.go @@ -45,7 +45,8 @@ func stepsMultiConsumerDoubleSign(consumer1, consumer2 string) []Step { { // relay power change to consumer1 action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumer1), port: "provider", channel: 0, // consumer1 channel }, @@ -76,7 +77,8 @@ func stepsMultiConsumerDoubleSign(consumer1, consumer2 string) []Step { { // relay power change to consumer2 action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumer2), port: "provider", channel: 1, // consumer2 channel }, @@ -137,7 +139,8 @@ func stepsMultiConsumerDoubleSign(consumer1, consumer2 string) []Step { }, { action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumer1), port: "provider", channel: 0, // consumer1 channel }, @@ -168,7 +171,8 @@ func stepsMultiConsumerDoubleSign(consumer1, consumer2 string) []Step { { // consumer1 learns about the double sign action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumer1), port: "provider", channel: 0, // consumer1 channel }, @@ -199,7 +203,8 @@ func stepsMultiConsumerDoubleSign(consumer1, consumer2 string) []Step { { // consumer2 learns about the double sign action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumer2), port: "provider", channel: 1, // consumer2 channel }, diff --git a/tests/e2e/steps_multi_consumer_downtime.go b/tests/e2e/steps_multi_consumer_downtime.go index 181ced029f..ce6cbdff59 100644 --- a/tests/e2e/steps_multi_consumer_downtime.go +++ b/tests/e2e/steps_multi_consumer_downtime.go @@ -40,7 +40,8 @@ func stepsMultiConsumerDowntimeFromConsumer(consumer1, consumer2 string) []Step // Downtime jailing and corresponding voting power change are processed by provider // Validator powers are unchanged on consumer chains action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumer1), port: "provider", channel: 0, }, @@ -73,7 +74,8 @@ func stepsMultiConsumerDowntimeFromConsumer(consumer1, consumer2 string) []Step // and can now be relayed as packet to consumer // consumer1 will now see the validator power changes - consumer2 will not (had not been relayed) action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumer1), port: "provider", channel: 0, // consumer1 chan }, @@ -100,7 +102,8 @@ func stepsMultiConsumerDowntimeFromConsumer(consumer1, consumer2 string) []Step { // both consumer1 and consumer will now see the validator power changes action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumer2), port: "provider", channel: 1, // consumer2 chan }, @@ -156,7 +159,8 @@ func stepsMultiConsumerDowntimeFromConsumer(consumer1, consumer2 string) []Step { // relay to consumer 1 action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumer1), port: "provider", channel: 0, }, @@ -187,7 +191,8 @@ func stepsMultiConsumerDowntimeFromConsumer(consumer1, consumer2 string) []Step { // relay to consumer2 action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumer2), port: "provider", channel: 1, // consumer2 chan }, @@ -255,7 +260,8 @@ func stepsMultiConsumerDowntimeFromProvider(consumer1, consumer2 string) []Step }, { action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumer1), port: "provider", channel: 0, // consumer 1 channel }, @@ -288,7 +294,8 @@ func stepsMultiConsumerDowntimeFromProvider(consumer1, consumer2 string) []Step }, { action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumer2), port: "provider", channel: 1, // consumer2 channel }, @@ -349,7 +356,8 @@ func stepsMultiConsumerDowntimeFromProvider(consumer1, consumer2 string) []Step }, { action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumer1), port: "provider", channel: 0, // consumer1 channel }, @@ -380,7 +388,8 @@ func stepsMultiConsumerDowntimeFromProvider(consumer1, consumer2 string) []Step }, { action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumer2), port: "provider", channel: 1, // consumer2 channel }, diff --git a/tests/e2e/steps_reward_denom.go b/tests/e2e/steps_reward_denom.go index bc26f38d27..dc10ccb7c6 100644 --- a/tests/e2e/steps_reward_denom.go +++ b/tests/e2e/steps_reward_denom.go @@ -193,7 +193,8 @@ func stepsRewardDenomConsumer(consumerName string) []Step { }, { action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumerName), port: "provider", channel: 0, }, @@ -219,7 +220,8 @@ func stepsRewardDenomConsumer(consumerName string) []Step { // and can now be relayed as packet to consumer { action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumerName), port: "provider", channel: 0, }, @@ -258,7 +260,8 @@ func stepsRewardDenomConsumer(consumerName string) []Step { }, { action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumerName), port: "provider", channel: 0, }, diff --git a/tests/e2e/steps_start_chains.go b/tests/e2e/steps_start_chains.go index e3ba9d9ad8..c51042e8c8 100644 --- a/tests/e2e/steps_start_chains.go +++ b/tests/e2e/steps_start_chains.go @@ -265,7 +265,8 @@ func stepsAssignConsumerKeyOnStartedChain(consumerName, validator string) []Step }, { action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumerName), port: "provider", channel: 0, }, diff --git a/tests/e2e/steps_stop_chain.go b/tests/e2e/steps_stop_chain.go index 229b40b215..9cef49a9ea 100644 --- a/tests/e2e/steps_stop_chain.go +++ b/tests/e2e/steps_stop_chain.go @@ -2,11 +2,11 @@ package main import "time" -// start hermes so that all messages are relayed -func stepsStartHermes() []Step { +// start relayer so that all messages are relayed +func stepsStartRelayer() []Step { return []Step{ { - action: startHermesAction{}, + action: startRelayerAction{}, state: State{}, }, } diff --git a/tests/e2e/steps_submit_equivocation_proposal.go b/tests/e2e/steps_submit_equivocation_proposal.go index f8a91d5362..8af1d2464d 100644 --- a/tests/e2e/steps_submit_equivocation_proposal.go +++ b/tests/e2e/steps_submit_equivocation_proposal.go @@ -122,7 +122,8 @@ func stepsSubmitEquivocationProposal(consumerName string, propNumber uint) []Ste { // relay power change to consumer1 action: relayPacketsAction{ - chain: chainID("provi"), + chainA: chainID("provi"), + chainB: chainID(consumerName), port: "provider", channel: 0, }, diff --git a/tests/e2e/testnet-scripts/start-chain.sh b/tests/e2e/testnet-scripts/start-chain.sh index b4d139ec27..9d6e73fdbb 100644 --- a/tests/e2e/testnet-scripts/start-chain.sh +++ b/tests/e2e/testnet-scripts/start-chain.sh @@ -33,6 +33,18 @@ SKIP_GENTX=$6 # A sed string modifying the tendermint config TENDERMINT_CONFIG_TRANSFORM=$7 +# whether to use CometMock +USE_COMETMOCK=$8 + +# stores a comma separated list of nodes addresses +# needed for CometMock - these are the addresses that the ABCI servers of the apps are listening on +NODE_LISTEN_ADDR_STR="" # example value: 7.7.8.6:26655,7.7.8.4:26655,7.7.8.5:26655 + +# stores a comma separated list of nodes home folders +# needed for CometMock - validator nodes have their private keys in their home directories, and CometMock +# reads the keys to sign with from there +NODE_HOMES="" # example value: /consu/validatorcarol,/consu/validatoralice,/consu/validatorbob + # CREATE VALIDATORS AND DO GENESIS CEREMONY @@ -219,10 +231,13 @@ do VAL_IP_SUFFIX=$(echo "$VALIDATORS" | jq -r ".[$i].ip_suffix") NET_NAMESPACE_NAME="$CHAIN_ID-$VAL_ID" - GAIA_HOME="--home /$CHAIN_ID/validator$VAL_ID" + NODE_HOME="/$CHAIN_ID/validator$VAL_ID" + GAIA_HOME="--home $NODE_HOME" + NODE_HOMES="$NODE_HOME,$NODE_HOMES" RPC_ADDRESS="--rpc.laddr tcp://$CHAIN_IP_PREFIX.$VAL_IP_SUFFIX:26658" GRPC_ADDRESS="--grpc.address $CHAIN_IP_PREFIX.$VAL_IP_SUFFIX:9091" LISTEN_ADDRESS="--address tcp://$CHAIN_IP_PREFIX.$VAL_IP_SUFFIX:26655" + NODE_LISTEN_ADDR_STR="$CHAIN_IP_PREFIX.$VAL_IP_SUFFIX:26655,$NODE_LISTEN_ADDR_STR" P2P_ADDRESS="--p2p.laddr tcp://$CHAIN_IP_PREFIX.$VAL_IP_SUFFIX:26656" # LOG_LEVEL="--log_level trace" # switch to trace to see panic messages and rich and all debug msgs LOG_LEVEL="--log_level info" @@ -246,7 +261,13 @@ do PERSISTENT_PEERS="--p2p.persistent_peers ${PERSISTENT_PEERS:1}" ARGS="$GAIA_HOME $LISTEN_ADDRESS $RPC_ADDRESS $GRPC_ADDRESS $LOG_LEVEL $P2P_ADDRESS $ENABLE_WEBGRPC $PERSISTENT_PEERS" - ip netns exec $NET_NAMESPACE_NAME $BIN $ARGS start &> /$CHAIN_ID/validator$VAL_ID/logs & + if [[ "$USE_COMETMOCK" == "true" ]]; then + # to start with CometMock, ensure ABCI server uses grpc (--transport=grpc) and the app is started without in-process CometBFT (--with-tendermint=false) + ip netns exec $NET_NAMESPACE_NAME $BIN $ARGS start --transport=grpc --with-tendermint=false &> /$CHAIN_ID/validator$VAL_ID/logs & + else + ip netns exec $NET_NAMESPACE_NAME $BIN $ARGS start &> /$CHAIN_ID/validator$VAL_ID/logs & + fi + done ## SETUP DOUBLE SIGNING NODE NETWORK NAMESPACE @@ -321,16 +342,46 @@ QUERY_PERSISTENT_PEERS="--p2p.persistent_peers ${QUERY_PERSISTENT_PEERS:1}" ## START NODE ARGS="$QUERY_GAIA_HOME $QUERY_LISTEN_ADDRESS $QUERY_RPC_ADDRESS $QUERY_GRPC_ADDRESS $QUERY_LOG_LEVEL $QUERY_P2P_ADDRESS $QUERY_ENABLE_WEBGRPC $QUERY_PERSISTENT_PEERS" -ip netns exec $QUERY_NET_NAMESPACE_NAME $BIN $ARGS start &> /$CHAIN_ID/$QUERY_NODE_ID/logs & + +# Query node is only started if CometMock is not used - with CometMock, it takes the role of the query node +if [[ "$USE_COMETMOCK" != "true" ]]; then + ip netns exec $QUERY_NET_NAMESPACE_NAME $BIN $ARGS start &> /$CHAIN_ID/$QUERY_NODE_ID/logs & +fi ## DONE START NODE +echo "Node addresses:" +echo $NODE_LISTEN_ADDR_STR + +echo "Node homes:" +echo $NODE_HOMES + +NODE_LISTEN_ADDR_STR=${NODE_LISTEN_ADDR_STR%?} +NODE_HOMES=${NODE_HOMES%?} + + +# CometMock takes the role of the query node +if [[ "$USE_COMETMOCK" == "true" ]]; then + sleep 2 + ip netns exec $QUERY_NET_NAMESPACE_NAME cometmock $NODE_LISTEN_ADDR_STR /$CHAIN_ID/genesis.json tcp://$CHAIN_IP_PREFIX.$QUERY_IP_SUFFIX:26658 $NODE_HOMES &> cometmock_${CHAIN_ID}_out.log & + sleep 3 +fi + +# exit + # poll for chain start -set +e -until $BIN query block --node "tcp://$CHAIN_IP_PREFIX.$QUERY_IP_SUFFIX:26658" | grep -q -v '{"block_id":{"hash":"","parts":{"total":0,"hash":""}},"block":null}'; do sleep 0.3 ; done -set -e +if [[ "$USE_COMETMOCK" == "true" ]]; then + set +e + until $BIN query block --node "tcp://$CHAIN_IP_PREFIX.$QUERY_IP_SUFFIX:26658"; do sleep 0.3 ; done + set -e +else + set +e + until $BIN query block --node "tcp://$CHAIN_IP_PREFIX.$QUERY_IP_SUFFIX:26658" | grep -q -v '{"block_id":{"hash":"","parts":{"total":0,"hash": + ""}},"block":null}'; do sleep 0.3 ; done + set -e +fi echo "done!!!!!!!!" -read -p "Press Return to Close..." \ No newline at end of file +read -p "Press Return to Close..." From 669a33a9b7d627658b8a9c11db4e90979d443476 Mon Sep 17 00:00:00 2001 From: Jehan Date: Thu, 15 Jun 2023 10:11:47 -0700 Subject: [PATCH 014/134] docs: Create adr-004-denom-dos-fixes.md (#934) * Create adr-006-denom-dos-fixes * Update docs/docs/adrs/adr-006-denom-dos-fixes Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> * Update docs/docs/adrs/adr-006-denom-dos-fixes Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> * Update docs/docs/adrs/adr-006-denom-dos-fixes Co-authored-by: Marius Poke * Update docs/docs/adrs/adr-006-denom-dos-fixes * Update docs/docs/adrs/adr-006-denom-dos-fixes * rename to adr 004 * remove extra file * add entry to Table of Contents * add ADR 7 to ToC --------- Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Co-authored-by: Marius Poke --- docs/docs/adrs/adr-004-denom-dos-fixes | 53 ++++++++++++++++++++++++++ docs/docs/adrs/intro.md | 4 +- 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 docs/docs/adrs/adr-004-denom-dos-fixes diff --git a/docs/docs/adrs/adr-004-denom-dos-fixes b/docs/docs/adrs/adr-004-denom-dos-fixes new file mode 100644 index 0000000000..7ca260f4f6 --- /dev/null +++ b/docs/docs/adrs/adr-004-denom-dos-fixes @@ -0,0 +1,53 @@ +--- +sidebar_position: 2 +title: ADR Template +--- +# ADR 004: Denom DOS fixes + +## Changelog +* 5/9/2023: ADR created + +## Status + +Accepted + +## Context + +The provider and consumer modules are vulnerable to similar issues involving an attacker sending millions of denoms to certain addresses and causing the chain to halt. This ADR outlines both fixes since they are similar. Both fixes involve processing only denoms that are on a whitelist to avoid iterating over millions of junk denoms but have different requirements and are implemented in different ways. + +## Decision + +### Provider + +- Put the distribution module's FeePoolAddress back on the blocklist so that it cannot receive funds from users. +- Create a new address called ConsumerRewardPool and unblock it, allowing funds to be sent to it. +- Create a set of strings in the store for allowed ConsumerRewardDenoms. +- Create an endpoint called RegisterConsumerRewardDenom which deducts a fee from the sender's account, sends it to the community pool and adds a string to the ConsumerRewardDenoms set. +- Create a parameter called ConsumerRewardDenomRegistrationFee which determines the fee which is charged to register a consumer reward denom in the step above. +- Create a function called TransferRewardsToFeeCollector which gets the entire ConsumerRewardDenoms set from the store, iterates over it, and for each entry: + - Gets the balance of this denom for the ConsumerRewardPool account + - Sends the entire balance out to the FeePoolAddress using SendCoinsFromModuleToModule which is not affected by the blocklist. +- Run TransferRewardsToFeeCollector in the endblock + +Now, nobody can send millions of junk denoms to the FeePoolAddress because it is on the block list. If they send millions of junk denoms to the ConsumerRewardPool, this does not matter because all balances are not iterated over, only those which are in the ConsumerRewardDenoms set. + +We also add a new tx: register-consumer-reward-denom, and a new query: registered-consumer-reward-denoms + +### Consumer + +- Create a new param RewardDenoms with a list of strings +- Create a new param ProviderRewardDenoms with a list of strings +- Create a function AllowedRewardDenoms which iterates over ProviderRewardDenoms and converts each denom to its ibc-prefixed denom using the provider chain's ibc channel information, then concatenates the RewardDenoms list and returns the combined list of allowed denoms. +- In SendRewardsToProvider, instead of iterating over the balances of all denoms in the ToSendToProvider address, iterate over AllowedRewardDenoms + +Now, if somebody sends millions of junk denoms to ToSendToProvider, they will not be iterated over. Only the RewardDenoms and ProviderRewardDenoms will be iterated over. Since we do not require this feature to be permissionless on the consumer, the registration fee process is not needed. + +## Consequences + +### Positive + +- Denom DOS is no longer possible on either provider or consumer. + +### Negative + +- Consumer chain teams must pay a fee to register a denom for distribution on the provider, and add some extra parameters in their genesis file. diff --git a/docs/docs/adrs/intro.md b/docs/docs/adrs/intro.md index aa6b7781c9..528b4799ae 100644 --- a/docs/docs/adrs/intro.md +++ b/docs/docs/adrs/intro.md @@ -34,4 +34,6 @@ To suggest an ADR, please make use of the [ADR template](./adr-template.md) prov | ------ | ----------- | ------ | | [001](./adr-001-key-assignment.md) | Consumer chain key assignment | Accepted, Implemented | | [002](./adr-002-throttle.md) | Jail Throttling | Accepted, Implemented | -| [003](./adr-003-equivocation-gov-proposal.md) | Equivocation governance proposal | Accepted, Implemented +| [003](./adr-003-equivocation-gov-proposal.md) | Equivocation governance proposal | Accepted, Implemented | +| [004](./adr-004-denom-dos-fixes) | Denom DOS fixes | Accepted, Implemented | +| [007](./adr-007-pause-unbonding-on-eqv-prop.md) | Pause validator unbonding during equivocation proposal | Proposed | \ No newline at end of file From 6ee8315dd9014a217d20896999a62d40f171c7cd Mon Sep 17 00:00:00 2001 From: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Date: Fri, 16 Jun 2023 16:34:18 +0200 Subject: [PATCH 015/134] docs: Fix link to template (#1027) Fix link to template Fixes typo in contributing.md --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 61dd6a3102..e9a3c092ae 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -184,7 +184,7 @@ There are three PR templates. The [default template](./.github/PULL_REQUEST_TEMP - The [production template](./.github/PULL_REQUEST_TEMPLATE/production.md) is for types `fix`, `feat`, and `refactor`. - The [docs template](./.github/PULL_REQUEST_TEMPLATE/docs.md) is for documentation changes. -- The [other template](./.github/PULL_REQUEST_TEMPLATE/other.md) is for changes that do not affect production code. +- The [others template](./.github/PULL_REQUEST_TEMPLATE/others.md) is for changes that do not affect production code. ### Requesting Reviews @@ -197,7 +197,7 @@ that you would like early feedback and tagging whoever you would like to receive Codeowners are marked automatically as the reviewers. All PRs require at least two review approvals before they can be merged (one review might be acceptable in -the case of minor changes to [docs](./.github/PULL_REQUEST_TEMPLATE/docs.md) or [other](./.github/PULL_REQUEST_TEMPLATE/other.md) changes that do not affect production code). Each PR template has a reviewers checklist that must be completed before the PR can be merged. Each reviewer is responsible +the case of minor changes to [docs](./.github/PULL_REQUEST_TEMPLATE/docs.md) or [others](./.github/PULL_REQUEST_TEMPLATE/others.md) changes that do not affect production code). Each PR template has a reviewers checklist that must be completed before the PR can be merged. Each reviewer is responsible for all checked items unless they have indicated otherwise by leaving their handle next to specific items. In addition, use the following review explanations: From 0b636da0b98abac18297492602a43afae95dabd9 Mon Sep 17 00:00:00 2001 From: Marius Poke Date: Fri, 16 Jun 2023 20:17:49 +0200 Subject: [PATCH 016/134] feat!: Add DistributionTransmissionChannel to ConsumerAdditionProposal (#965) * update proto * remove transfer_channel_id from consumer genesis * ConsumerAdditionProposal: transfer_channel_id -> distribution_transmission_channel * send updated ConsumerAdditionProposal * validate consumer genesis param * remove StandaloneTransferChannelID from store * fix TestOnChanOpenAck * remove state breaking change * finalize merge and fix issues * chore: update docs and changelog * chore: regenerate protos * re-add integrationt tests around changeover * mv entry in changelog * test: add sovereign to consumer changeover e2e (#1025) * tests: add sovereign to consumer e2e test * rm unused bash scripts * partially address review comments * apply remaining review comments * chore: apply formatting rules --------- Co-authored-by: MSalopek --- CHANGELOG.md | 1 + Dockerfile | 2 +- Dockerfile.gaia | 2 +- Makefile | 1 + app/consumer-democracy/app.go | 8 +- app/sovereign/ante_handler.go | 55 ++ app/sovereign/app.go | 838 ++++++++++++++++++ app/sovereign/export.go | 187 ++++ app/sovereign/genesis.go | 21 + cmd/interchain-security-sd/cmd/genaccounts.go | 180 ++++ cmd/interchain-security-sd/cmd/root.go | 305 +++++++ cmd/interchain-security-sd/main.go | 24 + docs/docs/consumer-development/onboarding.md | 7 + docs/docs/features/proposals.md | 3 + .../ccv/consumer/v1/genesis.proto | 8 +- .../ccv/provider/v1/provider.proto | 7 + tests/e2e/actions.go | 198 ++++- tests/e2e/actions_sovereign_chain.go | 166 ++++ tests/e2e/config.go | 48 + tests/e2e/main.go | 11 + tests/e2e/state.go | 44 +- tests/e2e/steps.go | 15 + tests/e2e/steps_sovereign_changeover.go | 367 ++++++++ .../testnet-scripts/sovereign-genesis.json | 279 ++++++ tests/e2e/testnet-scripts/start-changeover.sh | 187 ++++ tests/e2e/testnet-scripts/start-sovereign.sh | 133 +++ tests/integration/changeover.go | 2 +- testutil/keeper/unit_test_helpers.go | 1 + x/ccv/consumer/ibc_module.go | 13 +- x/ccv/consumer/ibc_module_test.go | 7 +- x/ccv/consumer/keeper/changeover.go | 1 + x/ccv/consumer/keeper/keeper.go | 14 - x/ccv/consumer/keeper/keeper_test.go | 13 - x/ccv/consumer/keeper/migration_test.go | 2 +- x/ccv/consumer/types/genesis_test.go | 21 +- x/ccv/consumer/types/params.go | 13 +- x/ccv/provider/client/proposal_handler.go | 9 +- x/ccv/provider/keeper/proposal.go | 2 +- x/ccv/provider/keeper/proposal_test.go | 6 + x/ccv/provider/proposal_handler_test.go | 5 +- x/ccv/provider/types/proposal.go | 10 +- x/ccv/provider/types/proposal_test.go | 30 + x/ccv/provider/types/provider.pb.go | 251 +++--- x/ccv/types/shared_params.go | 10 + 44 files changed, 3329 insertions(+), 178 deletions(-) create mode 100644 app/sovereign/ante_handler.go create mode 100644 app/sovereign/app.go create mode 100644 app/sovereign/export.go create mode 100644 app/sovereign/genesis.go create mode 100644 cmd/interchain-security-sd/cmd/genaccounts.go create mode 100644 cmd/interchain-security-sd/cmd/root.go create mode 100644 cmd/interchain-security-sd/main.go create mode 100644 tests/e2e/actions_sovereign_chain.go create mode 100644 tests/e2e/steps_sovereign_changeover.go create mode 100644 tests/e2e/testnet-scripts/sovereign-genesis.json create mode 100644 tests/e2e/testnet-scripts/start-changeover.sh create mode 100644 tests/e2e/testnet-scripts/start-sovereign.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index 208c4ec2c9..5960c76238 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ Some PRs from v2.0.0 may reappear from other releases below. This is due to the ## 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) cosumer 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) diff --git a/Dockerfile b/Dockerfile index ac528fa8fb..4d81392316 100644 --- a/Dockerfile +++ b/Dockerfile @@ -48,7 +48,7 @@ COPY --from=gorelayer-builder /bin/rly /usr/local/bin/ COPY --from=is-builder /go/bin/interchain-security-pd /usr/local/bin/interchain-security-pd COPY --from=is-builder /go/bin/interchain-security-cd /usr/local/bin/interchain-security-cd COPY --from=is-builder /go/bin/interchain-security-cdd /usr/local/bin/interchain-security-cdd - +COPY --from=is-builder /go/bin/interchain-security-sd /usr/local/bin/interchain-security-sd # Copy in the shell scripts that run the testnet ADD ./tests/e2e/testnet-scripts /testnet-scripts diff --git a/Dockerfile.gaia b/Dockerfile.gaia index 196f7dfa74..87448a1d63 100644 --- a/Dockerfile.gaia +++ b/Dockerfile.gaia @@ -74,7 +74,7 @@ COPY --from=hermes-builder /usr/bin/hermes /usr/local/bin/ COPY --from=gaia-builder /go/gaia/build/gaiad /usr/local/bin/interchain-security-pd COPY --from=is-builder /go/bin/interchain-security-cd /usr/local/bin/interchain-security-cd COPY --from=is-builder /go/bin/interchain-security-cdd /usr/local/bin/interchain-security-cdd - +COPY --from=is-builder /go/bin/interchain-security-sd /usr/local/bin/interchain-security-sd # Copy in the shell scripts that run the testnet ADD ./tests/e2e/testnet-scripts /testnet-scripts diff --git a/Makefile b/Makefile index b84eca6524..351852cd21 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,7 @@ install: go.sum go install $(BUILD_FLAGS) ./cmd/interchain-security-pd go install $(BUILD_FLAGS) ./cmd/interchain-security-cd go install $(BUILD_FLAGS) ./cmd/interchain-security-cdd + go install $(BUILD_FLAGS) ./cmd/interchain-security-sd # run all tests: unit, integration, diff, and E2E test: diff --git a/app/consumer-democracy/app.go b/app/consumer-democracy/app.go index ee299d6221..e9406cfecd 100644 --- a/app/consumer-democracy/app.go +++ b/app/consumer-democracy/app.go @@ -117,7 +117,7 @@ import ( const ( AppName = "interchain-security-cd" - upgradeName = "ics-v1-to-v2" // arbitrary name, define your own appropriately named upgrade + upgradeName = "sovereign-changeover" // arbitrary name, define your own appropriately named upgrade AccountAddressPrefix = "cosmos" ) @@ -645,12 +645,6 @@ func New( // upgrade handler code is application specific. However, as an example, standalone to consumer // changeover chains should utilize customized upgrade handler code similar to below. - // Setting the standalone transfer channel ID is only needed for standalone to consumer changeover chains - // who wish to preserve existing IBC transfer denoms. Here's an example. - // - // Note: This setter needs to execute before the ccv channel handshake is initiated. - app.ConsumerKeeper.SetStandaloneTransferChannelID(ctx, "hardcoded-existing-channel-id") - // TODO: should have a way to read from current node home userHomeDir, err := os.UserHomeDir() if err != nil { diff --git a/app/sovereign/ante_handler.go b/app/sovereign/ante_handler.go new file mode 100644 index 0000000000..3b1a3b7d38 --- /dev/null +++ b/app/sovereign/ante_handler.go @@ -0,0 +1,55 @@ +package app + +import ( + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/auth/ante" + ibcante "github.com/cosmos/ibc-go/v4/modules/core/ante" + ibckeeper "github.com/cosmos/ibc-go/v4/modules/core/keeper" +) + +// HandlerOptions extend the SDK's AnteHandler options by requiring the IBC +// channel keeper. +type HandlerOptions struct { + ante.HandlerOptions + + IBCKeeper *ibckeeper.Keeper +} + +func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { + if options.AccountKeeper == nil { + return nil, errorsmod.Wrap(sdkerrors.ErrLogic, "account keeper is required for AnteHandler") + } + if options.BankKeeper == nil { + return nil, errorsmod.Wrap(sdkerrors.ErrLogic, "bank keeper is required for AnteHandler") + } + if options.SignModeHandler == nil { + return nil, errorsmod.Wrap(sdkerrors.ErrLogic, "sign mode handler is required for ante builder") + } + + sigGasConsumer := options.SigGasConsumer + if sigGasConsumer == nil { + sigGasConsumer = ante.DefaultSigVerificationGasConsumer + } + + anteDecorators := []sdk.AnteDecorator{ + ante.NewSetUpContextDecorator(), + ante.NewRejectExtensionOptionsDecorator(), + ante.NewMempoolFeeDecorator(), + ante.NewValidateBasicDecorator(), + ante.NewTxTimeoutHeightDecorator(), + ante.NewValidateMemoDecorator(options.AccountKeeper), + ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), + ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper), + // SetPubKeyDecorator must be called before all signature verification decorators + ante.NewSetPubKeyDecorator(options.AccountKeeper), + ante.NewValidateSigCountDecorator(options.AccountKeeper), + ante.NewSigGasConsumeDecorator(options.AccountKeeper, sigGasConsumer), + ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler), + ante.NewIncrementSequenceDecorator(options.AccountKeeper), + ibcante.NewAnteDecorator(options.IBCKeeper), + } + + return sdk.ChainAnteDecorators(anteDecorators...), nil +} diff --git a/app/sovereign/app.go b/app/sovereign/app.go new file mode 100644 index 0000000000..43d732884b --- /dev/null +++ b/app/sovereign/app.go @@ -0,0 +1,838 @@ +package app + +import ( + "fmt" + "io" + stdlog "log" + "net/http" + "os" + "path/filepath" + + appparams "github.com/cosmos/interchain-security/v2/app/params" + + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/grpc/tmservice" + "github.com/cosmos/cosmos-sdk/client/rpc" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/server/api" + "github.com/cosmos/cosmos-sdk/server/config" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/std" + store "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/version" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/auth/ante" + authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/x/auth/vesting" + vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" + "github.com/cosmos/cosmos-sdk/x/authz" + authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper" + authzmodule "github.com/cosmos/cosmos-sdk/x/authz/module" + "github.com/cosmos/cosmos-sdk/x/bank" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/cosmos-sdk/x/capability" + capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + "github.com/cosmos/cosmos-sdk/x/crisis" + crisiskeeper "github.com/cosmos/cosmos-sdk/x/crisis/keeper" + crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types" + "github.com/cosmos/cosmos-sdk/x/evidence" + evidencekeeper "github.com/cosmos/cosmos-sdk/x/evidence/keeper" + evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" + "github.com/cosmos/cosmos-sdk/x/feegrant" + feegrantkeeper "github.com/cosmos/cosmos-sdk/x/feegrant/keeper" + feegrantmodule "github.com/cosmos/cosmos-sdk/x/feegrant/module" + "github.com/cosmos/cosmos-sdk/x/params" + paramsclient "github.com/cosmos/cosmos-sdk/x/params/client" + paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" + paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" + upgradeclient "github.com/cosmos/cosmos-sdk/x/upgrade/client" + + "github.com/cosmos/cosmos-sdk/x/slashing" + slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + "github.com/cosmos/cosmos-sdk/x/upgrade" + upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer" + ibctransferkeeper "github.com/cosmos/ibc-go/v4/modules/apps/transfer/keeper" + ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + ibc "github.com/cosmos/ibc-go/v4/modules/core" + ibcconnectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" + ibchost "github.com/cosmos/ibc-go/v4/modules/core/24-host" + ibckeeper "github.com/cosmos/ibc-go/v4/modules/core/keeper" + ibctestingcore "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/core" + ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" + "github.com/gorilla/mux" + "github.com/rakyll/statik/fs" + "github.com/spf13/cast" + abci "github.com/tendermint/tendermint/abci/types" + tmjson "github.com/tendermint/tendermint/libs/json" + "github.com/tendermint/tendermint/libs/log" + tmos "github.com/tendermint/tendermint/libs/os" + dbm "github.com/tendermint/tm-db" + + sdkdistr "github.com/cosmos/cosmos-sdk/x/distribution" + distrclient "github.com/cosmos/cosmos-sdk/x/distribution/client" + distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + testutil "github.com/cosmos/interchain-security/v2/testutil/integration" + + sdkstaking "github.com/cosmos/cosmos-sdk/x/staking" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + "github.com/cosmos/cosmos-sdk/x/genutil" + genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" + + sdkgov "github.com/cosmos/cosmos-sdk/x/gov" + govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + + // add mint + mint "github.com/cosmos/cosmos-sdk/x/mint" + mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + + paramproposal "github.com/cosmos/cosmos-sdk/x/params/types/proposal" +) + +const ( + AppName = "interchain-security-s" + upgradeName = "v07-Theta" // arbitrary name, define your own appropriately named upgrade + AccountAddressPrefix = "cosmos" +) + +var ( + // DefaultNodeHome default home directories for the application daemon + DefaultNodeHome string + + // ModuleBasics defines the module BasicManager is in charge of setting up basic, + // non-dependant module elements, such as codec registration + // and genesis verification. + ModuleBasics = module.NewBasicManager( + auth.AppModuleBasic{}, + genutil.AppModuleBasic{}, + bank.AppModuleBasic{}, + capability.AppModuleBasic{}, + sdkstaking.AppModuleBasic{}, + mint.AppModuleBasic{}, + sdkdistr.AppModuleBasic{}, + sdkgov.NewAppModuleBasic( + // TODO: eventually remove upgrade proposal handler and cancel proposal handler + paramsclient.ProposalHandler, distrclient.ProposalHandler, upgradeclient.ProposalHandler, upgradeclient.CancelProposalHandler, + ), + params.AppModuleBasic{}, + crisis.AppModuleBasic{}, + slashing.AppModuleBasic{}, + feegrantmodule.AppModuleBasic{}, + authzmodule.AppModuleBasic{}, + ibc.AppModuleBasic{}, + upgrade.AppModuleBasic{}, + evidence.AppModuleBasic{}, + transfer.AppModuleBasic{}, + vesting.AppModuleBasic{}, + ) + + // module account permissions + maccPerms = map[string][]string{ + authtypes.FeeCollectorName: nil, + stakingtypes.BondedPoolName: {authtypes.Burner, authtypes.Staking}, + stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking}, + distrtypes.ModuleName: nil, + minttypes.ModuleName: {authtypes.Minter}, + ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner}, + govtypes.ModuleName: {authtypes.Burner}, + } +) + +var ( + _ simapp.App = (*App)(nil) + _ servertypes.Application = (*App)(nil) + _ ibctesting.TestingApp = (*App)(nil) +) + +// App extends an ABCI application, but with most of its parameters exported. +// They are exported for convenience in creating helper functions, as object +// capabilities aren't needed for testing. +type App struct { // nolint: golint + *baseapp.BaseApp + legacyAmino *codec.LegacyAmino + appCodec codec.Codec + interfaceRegistry types.InterfaceRegistry + + invCheckPeriod uint + + // keys to access the substores + keys map[string]*sdk.KVStoreKey + tkeys map[string]*sdk.TransientStoreKey + memKeys map[string]*sdk.MemoryStoreKey + + // keepers + AccountKeeper authkeeper.AccountKeeper + BankKeeper bankkeeper.Keeper + CapabilityKeeper *capabilitykeeper.Keeper + StakingKeeper stakingkeeper.Keeper + SlashingKeeper slashingkeeper.Keeper + MintKeeper mintkeeper.Keeper + + DistrKeeper distrkeeper.Keeper + + GovKeeper govkeeper.Keeper + CrisisKeeper crisiskeeper.Keeper + UpgradeKeeper upgradekeeper.Keeper + ParamsKeeper paramskeeper.Keeper + IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly + EvidenceKeeper evidencekeeper.Keeper + TransferKeeper ibctransferkeeper.Keeper + FeeGrantKeeper feegrantkeeper.Keeper + AuthzKeeper authzkeeper.Keeper + + // make scoped keepers public for test purposes + ScopedIBCKeeper capabilitykeeper.ScopedKeeper + ScopedTransferKeeper capabilitykeeper.ScopedKeeper + + // the module manager + MM *module.Manager + + // simulation manager + sm *module.SimulationManager + configurator module.Configurator +} + +func init() { + userHomeDir, err := os.UserHomeDir() + if err != nil { + stdlog.Println("Failed to get home dir %2", err) + } + + DefaultNodeHome = filepath.Join(userHomeDir, "."+AppName) +} + +// New returns a reference to an initialized App. +func New( + logger log.Logger, + db dbm.DB, + traceStore io.Writer, + loadLatest bool, + skipUpgradeHeights map[int64]bool, + homePath string, + invCheckPeriod uint, + encodingConfig appparams.EncodingConfig, + appOpts servertypes.AppOptions, + baseAppOptions ...func(*baseapp.BaseApp), +) *App { + appCodec := encodingConfig.Marshaler + legacyAmino := encodingConfig.Amino + interfaceRegistry := encodingConfig.InterfaceRegistry + + bApp := baseapp.NewBaseApp(AppName, logger, db, encodingConfig.TxConfig.TxDecoder(), baseAppOptions...) + bApp.SetCommitMultiStoreTracer(traceStore) + bApp.SetVersion(version.Version) + bApp.SetInterfaceRegistry(interfaceRegistry) + + keys := sdk.NewKVStoreKeys( + authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, + minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey, + govtypes.StoreKey, paramstypes.StoreKey, ibchost.StoreKey, upgradetypes.StoreKey, feegrant.StoreKey, + evidencetypes.StoreKey, ibctransfertypes.StoreKey, + capabilitytypes.StoreKey, authzkeeper.StoreKey, + ) + tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey) + memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey) + + app := &App{ + BaseApp: bApp, + legacyAmino: legacyAmino, + appCodec: appCodec, + interfaceRegistry: interfaceRegistry, + invCheckPeriod: invCheckPeriod, + keys: keys, + tkeys: tkeys, + memKeys: memKeys, + } + + app.ParamsKeeper = initParamsKeeper( + appCodec, + legacyAmino, + keys[paramstypes.StoreKey], + tkeys[paramstypes.TStoreKey], + ) + + // set the BaseApp's parameter store + bApp.SetParamStore( + app.ParamsKeeper.Subspace(baseapp.Paramspace).WithKeyTable( + paramskeeper.ConsensusParamsKeyTable()), + ) + + // add capability keeper and ScopeToModule for ibc module + app.CapabilityKeeper = capabilitykeeper.NewKeeper( + appCodec, + keys[capabilitytypes.StoreKey], + memKeys[capabilitytypes.MemStoreKey], + ) + scopedIBCKeeper := app.CapabilityKeeper.ScopeToModule(ibchost.ModuleName) + scopedTransferKeeper := app.CapabilityKeeper.ScopeToModule(ibctransfertypes.ModuleName) + app.CapabilityKeeper.Seal() + + // add keepers + app.AccountKeeper = authkeeper.NewAccountKeeper( + appCodec, + keys[authtypes.StoreKey], + app.GetSubspace(authtypes.ModuleName), + authtypes.ProtoBaseAccount, + maccPerms, + ) + + bankBlockedAddrs := app.ModuleAccountAddrs() + + app.BankKeeper = bankkeeper.NewBaseKeeper( + appCodec, + keys[banktypes.StoreKey], + app.AccountKeeper, + app.GetSubspace(banktypes.ModuleName), + bankBlockedAddrs, + ) + app.AuthzKeeper = authzkeeper.NewKeeper( + keys[authzkeeper.StoreKey], + appCodec, + app.BaseApp.MsgServiceRouter(), + ) + app.FeeGrantKeeper = feegrantkeeper.NewKeeper( + appCodec, + keys[feegrant.StoreKey], + app.AccountKeeper, + ) + + stakingKeeper := stakingkeeper.NewKeeper( + appCodec, + keys[stakingtypes.StoreKey], + app.AccountKeeper, + app.BankKeeper, + app.GetSubspace(stakingtypes.ModuleName), + ) + + app.MintKeeper = mintkeeper.NewKeeper( + appCodec, keys[minttypes.StoreKey], app.GetSubspace(minttypes.ModuleName), &stakingKeeper, + app.AccountKeeper, app.BankKeeper, authtypes.FeeCollectorName, + ) + + app.SlashingKeeper = slashingkeeper.NewKeeper( + appCodec, + keys[slashingtypes.StoreKey], + &app.StakingKeeper, + app.GetSubspace(slashingtypes.ModuleName), + ) + app.DistrKeeper = distrkeeper.NewKeeper( + appCodec, + keys[distrtypes.StoreKey], + app.GetSubspace(distrtypes.ModuleName), + app.AccountKeeper, + app.BankKeeper, + &stakingKeeper, + authtypes.FeeCollectorName, + app.ModuleAccountAddrs(), + ) + app.CrisisKeeper = crisiskeeper.NewKeeper( + app.GetSubspace(crisistypes.ModuleName), + invCheckPeriod, + app.BankKeeper, + authtypes.FeeCollectorName, + ) + app.UpgradeKeeper = upgradekeeper.NewKeeper( + skipUpgradeHeights, + keys[upgradetypes.StoreKey], + appCodec, + homePath, + app.BaseApp, + ) + + // register the staking hooks + // NOTE: stakingKeeper above is passed by reference, so that it will contain these hooks + app.StakingKeeper = *stakingKeeper.SetHooks( + stakingtypes.NewMultiStakingHooks( + app.DistrKeeper.Hooks(), + app.SlashingKeeper.Hooks(), + ), + ) + + // register the proposal types + sdkgovRouter := govtypes.NewRouter() + sdkgovRouter.AddRoute(govtypes.RouterKey, govtypes.ProposalHandler). + AddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(app.ParamsKeeper)). + AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper)) + govKeeper := govkeeper.NewKeeper( + appCodec, + keys[govtypes.StoreKey], + app.GetSubspace(govtypes.ModuleName), + app.AccountKeeper, + app.BankKeeper, + &stakingKeeper, + sdkgovRouter, + ) + + app.GovKeeper = *govKeeper.SetHooks( + govtypes.NewMultiGovHooks( + // register the governance hooks + ), + ) + + app.IBCKeeper = ibckeeper.NewKeeper( + appCodec, + keys[ibchost.StoreKey], + app.GetSubspace(ibchost.ModuleName), + &app.StakingKeeper, + app.UpgradeKeeper, + scopedIBCKeeper, + ) + + app.SlashingKeeper = slashingkeeper.NewKeeper( + appCodec, + keys[slashingtypes.StoreKey], + &app.StakingKeeper, + app.GetSubspace(slashingtypes.ModuleName), + ) + + app.TransferKeeper = ibctransferkeeper.NewKeeper( + appCodec, + keys[ibctransfertypes.StoreKey], + app.GetSubspace(ibctransfertypes.ModuleName), + app.IBCKeeper.ChannelKeeper, + app.IBCKeeper.ChannelKeeper, + &app.IBCKeeper.PortKeeper, + app.AccountKeeper, + app.BankKeeper, + scopedTransferKeeper, + ) + transferModule := transfer.NewAppModule(app.TransferKeeper) + ibcmodule := transfer.NewIBCModule(app.TransferKeeper) + + // create static IBC router, add transfer route, then set and seal it + ibcRouter := porttypes.NewRouter() + ibcRouter.AddRoute(ibctransfertypes.ModuleName, ibcmodule) + app.IBCKeeper.SetRouter(ibcRouter) + + // create evidence keeper with router + evidenceKeeper := evidencekeeper.NewKeeper( + appCodec, + keys[evidencetypes.StoreKey], + &app.StakingKeeper, + app.SlashingKeeper, + ) + + app.EvidenceKeeper = *evidenceKeeper + + skipGenesisInvariants := cast.ToBool(appOpts.Get(crisis.FlagSkipGenesisInvariants)) + + // NOTE: Any module instantiated in the module manager that is later modified + // must be passed by reference here. + app.MM = module.NewManager( + genutil.NewAppModule( + app.AccountKeeper, + app.StakingKeeper, + app.BaseApp.DeliverTx, + encodingConfig.TxConfig, + ), + auth.NewAppModule(appCodec, app.AccountKeeper, nil), + vesting.NewAppModule(app.AccountKeeper, app.BankKeeper), + bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper), + capability.NewAppModule(appCodec, *app.CapabilityKeeper), + crisis.NewAppModule(&app.CrisisKeeper, skipGenesisInvariants), + feegrantmodule.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry), + sdkgov.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper), + mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper), + slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper), + sdkdistr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper), + sdkstaking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper), + upgrade.NewAppModule(app.UpgradeKeeper), + evidence.NewAppModule(app.EvidenceKeeper), + params.NewAppModule(app.ParamsKeeper), + authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), + ibc.NewAppModule(app.IBCKeeper), + transferModule, + ) + + app.MM.SetOrderBeginBlockers( + upgradetypes.ModuleName, + capabilitytypes.ModuleName, + minttypes.ModuleName, + distrtypes.ModuleName, + slashingtypes.ModuleName, + evidencetypes.ModuleName, + stakingtypes.ModuleName, + authtypes.ModuleName, + banktypes.ModuleName, + govtypes.ModuleName, + crisistypes.ModuleName, + authz.ModuleName, + feegrant.ModuleName, + paramstypes.ModuleName, + genutiltypes.ModuleName, + vestingtypes.ModuleName, + ibctransfertypes.ModuleName, + ibchost.ModuleName, + ) + app.MM.SetOrderEndBlockers( + crisistypes.ModuleName, + govtypes.ModuleName, + stakingtypes.ModuleName, + capabilitytypes.ModuleName, + authtypes.ModuleName, + banktypes.ModuleName, + distrtypes.ModuleName, + slashingtypes.ModuleName, + minttypes.ModuleName, + evidencetypes.ModuleName, + authz.ModuleName, + feegrant.ModuleName, + paramstypes.ModuleName, + genutiltypes.ModuleName, + upgradetypes.ModuleName, + vestingtypes.ModuleName, + ibctransfertypes.ModuleName, + ibchost.ModuleName, + ) + + // NOTE: The genutils module must occur after staking so that pools are + // properly initialized with tokens from genesis accounts. + // NOTE: The genutils module must also occur after auth so that it can access the params from auth. + // NOTE: Capability module must occur first so that it can initialize any capabilities + // so that other modules that want to create or claim capabilities afterwards in InitChain + // can do so safely. + app.MM.SetOrderInitGenesis( + capabilitytypes.ModuleName, + authtypes.ModuleName, + banktypes.ModuleName, + distrtypes.ModuleName, + stakingtypes.ModuleName, + slashingtypes.ModuleName, + govtypes.ModuleName, + minttypes.ModuleName, + crisistypes.ModuleName, + evidencetypes.ModuleName, + authz.ModuleName, + feegrant.ModuleName, + paramstypes.ModuleName, + upgradetypes.ModuleName, + vestingtypes.ModuleName, + genutiltypes.ModuleName, + ibchost.ModuleName, + ibctransfertypes.ModuleName, + ) + + app.MM.RegisterInvariants(&app.CrisisKeeper) + app.MM.RegisterRoutes(app.Router(), app.QueryRouter(), encodingConfig.Amino) + + app.configurator = module.NewConfigurator(app.appCodec, app.MsgServiceRouter(), app.GRPCQueryRouter()) + app.MM.RegisterServices(app.configurator) + + // initialize stores + app.MountKVStores(keys) + app.MountTransientStores(tkeys) + app.MountMemoryStores(memKeys) + + anteHandler, err := NewAnteHandler( + HandlerOptions{ + HandlerOptions: ante.HandlerOptions{ + AccountKeeper: app.AccountKeeper, + BankKeeper: app.BankKeeper, + FeegrantKeeper: app.FeeGrantKeeper, + SignModeHandler: encodingConfig.TxConfig.SignModeHandler(), + SigGasConsumer: ante.DefaultSigVerificationGasConsumer, + }, + IBCKeeper: app.IBCKeeper, + }, + ) + if err != nil { + panic(fmt.Errorf("failed to create AnteHandler: %s", err)) + } + app.SetAnteHandler(anteHandler) + + app.SetInitChainer(app.InitChainer) + app.SetBeginBlocker(app.BeginBlocker) + app.SetEndBlocker(app.EndBlocker) + + app.UpgradeKeeper.SetUpgradeHandler( + upgradeName, + func(ctx sdk.Context, _ upgradetypes.Plan, _ module.VersionMap) (module.VersionMap, error) { + app.IBCKeeper.ConnectionKeeper.SetParams(ctx, ibcconnectiontypes.DefaultParams()) + + fromVM := make(map[string]uint64) + + for moduleName, eachModule := range app.MM.Modules { + fromVM[moduleName] = eachModule.ConsensusVersion() + } + + ctx.Logger().Info("start to run module migrations...") + + return app.MM.RunMigrations(ctx, app.configurator, fromVM) + }, + ) + + upgradeInfo, err := app.UpgradeKeeper.ReadUpgradeInfoFromDisk() + if err != nil { + panic(fmt.Sprintf("failed to read upgrade info from disk %s", err)) + } + + if upgradeInfo.Name == upgradeName && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { + storeUpgrades := store.StoreUpgrades{} + app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades)) + } + + if loadLatest { + if err := app.LoadLatestVersion(); err != nil { + tmos.Exit(fmt.Sprintf("failed to load latest version: %s", err)) + } + } + + app.ScopedIBCKeeper = scopedIBCKeeper + app.ScopedTransferKeeper = scopedTransferKeeper + + return app +} + +// Name returns the name of the App +func (app *App) Name() string { return app.BaseApp.Name() } + +// BeginBlocker application updates every begin block +func (app *App) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock { + return app.MM.BeginBlock(ctx, req) +} + +// EndBlocker application updates every end block +func (app *App) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock { + return app.MM.EndBlock(ctx, req) +} + +// InitChainer application update at chain initialization +func (app *App) InitChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { + var genesisState GenesisState + if err := tmjson.Unmarshal(req.AppStateBytes, &genesisState); err != nil { + panic(err) + } + + app.UpgradeKeeper.SetModuleVersionMap(ctx, app.MM.GetVersionMap()) + return app.MM.InitGenesis(ctx, app.appCodec, genesisState) +} + +// LoadHeight loads a particular height +func (app *App) LoadHeight(height int64) error { + return app.LoadVersion(height) +} + +// ModuleAccountAddrs returns all the app's module account addresses. +func (app *App) ModuleAccountAddrs() map[string]bool { + modAccAddrs := make(map[string]bool) + for acc := range maccPerms { + modAccAddrs[authtypes.NewModuleAddress(acc).String()] = true + } + + return modAccAddrs +} + +// LegacyAmino returns App's amino codec. +// +// NOTE: This is solely to be used for testing purposes as it may be desirable +// for modules to register their own custom testing types. +func (app *App) LegacyAmino() *codec.LegacyAmino { + return app.legacyAmino +} + +// AppCodec returns the app codec. +// +// NOTE: This is solely to be used for testing purposes as it may be desirable +// for modules to register their own custom testing types. +func (app *App) AppCodec() codec.Codec { + return app.appCodec +} + +// InterfaceRegistry returns the InterfaceRegistry +func (app *App) InterfaceRegistry() types.InterfaceRegistry { + return app.interfaceRegistry +} + +// GetKey returns the KVStoreKey for the provided store key. +// +// NOTE: This is solely to be used for testing purposes. +func (app *App) GetKey(storeKey string) *sdk.KVStoreKey { + return app.keys[storeKey] +} + +// GetTKey returns the TransientStoreKey for the provided store key. +// +// NOTE: This is solely to be used for testing purposes. +func (app *App) GetTKey(storeKey string) *sdk.TransientStoreKey { + return app.tkeys[storeKey] +} + +// GetMemKey returns the MemStoreKey for the provided mem key. +// +// NOTE: This is solely used for testing purposes. +func (app *App) GetMemKey(storeKey string) *sdk.MemoryStoreKey { + return app.memKeys[storeKey] +} + +// GetSubspace returns a param subspace for a given module name. +// +// NOTE: This is solely to be used for testing purposes. +func (app *App) GetSubspace(moduleName string) paramstypes.Subspace { + subspace, _ := app.ParamsKeeper.GetSubspace(moduleName) + return subspace +} + +// SimulationManager implements the SimulationApp interface +func (app *App) SimulationManager() *module.SimulationManager { + return app.sm +} + +func (app *App) GetTestBankKeeper() testutil.TestBankKeeper { + return app.BankKeeper +} + +func (app *App) GetTestAccountKeeper() testutil.TestAccountKeeper { + return app.AccountKeeper +} + +func (app *App) GetTestSlashingKeeper() testutil.TestSlashingKeeper { + return app.SlashingKeeper +} + +func (app *App) GetTestEvidenceKeeper() testutil.TestEvidenceKeeper { + return app.EvidenceKeeper +} + +func (app *App) GetTestStakingKeeper() testutil.TestStakingKeeper { + return app.StakingKeeper +} + +func (app *App) GetTestDistributionKeeper() testutil.TestDistributionKeeper { + return app.DistrKeeper +} + +func (app *App) GetTestMintKeeper() testutil.TestMintKeeper { + return app.MintKeeper +} + +func (app *App) GetTestGovKeeper() testutil.TestGovKeeper { + return app.GovKeeper +} + +// TestingApp functions + +// GetBaseApp implements the TestingApp interface. +func (app *App) GetBaseApp() *baseapp.BaseApp { + return app.BaseApp +} + +// GetStakingKeeper implements the TestingApp interface. +func (app *App) GetStakingKeeper() ibctestingcore.StakingKeeper { + return app.StakingKeeper +} + +// GetIBCKeeper implements the TestingApp interface. +func (app *App) GetIBCKeeper() *ibckeeper.Keeper { + return app.IBCKeeper +} + +// GetScopedIBCKeeper implements the TestingApp interface. +func (app *App) GetScopedIBCKeeper() capabilitykeeper.ScopedKeeper { + return app.ScopedIBCKeeper +} + +// GetTxConfig implements the TestingApp interface. +func (app *App) GetTxConfig() client.TxConfig { + return MakeTestEncodingConfig().TxConfig +} + +// RegisterAPIRoutes registers all application module routes with the provided +// API server. +func (app *App) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig) { + clientCtx := apiSvr.ClientCtx + rpc.RegisterRoutes(clientCtx, apiSvr.Router) + // Register legacy tx routes. + authrest.RegisterTxRoutes(clientCtx, apiSvr.Router) + // Register new tx routes from grpc-gateway. + authtx.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) + // Register new tendermint queries routes from grpc-gateway. + tmservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) + + // Register legacy and grpc-gateway routes for all modules. + ModuleBasics.RegisterRESTRoutes(clientCtx, apiSvr.Router) + ModuleBasics.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) + + // register swagger API from root so that other applications can override easily + if apiConfig.Swagger { + RegisterSwaggerAPI(apiSvr.Router) + } +} + +// RegisterTxService implements the Application.RegisterTxService method. +func (app *App) RegisterTxService(clientCtx client.Context) { + authtx.RegisterTxService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.BaseApp.Simulate, app.interfaceRegistry) +} + +// RegisterTendermintService implements the Application.RegisterTendermintService method. +func (app *App) RegisterTendermintService(clientCtx client.Context) { + tmservice.RegisterTendermintService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.interfaceRegistry) +} + +// RegisterSwaggerAPI registers swagger route with API Server +func RegisterSwaggerAPI(rtr *mux.Router) { + statikFS, err := fs.New() + if err != nil { + panic(err) + } + + staticServer := http.FileServer(statikFS) + rtr.PathPrefix("/swagger/").Handler(http.StripPrefix("/swagger/", staticServer)) +} + +// GetMaccPerms returns a copy of the module account permissions +func GetMaccPerms() map[string][]string { + dupMaccPerms := make(map[string][]string) + for k, v := range maccPerms { + dupMaccPerms[k] = v + } + return dupMaccPerms +} + +// initParamsKeeper init params keeper and its subspaces +func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey sdk.StoreKey) paramskeeper.Keeper { + paramsKeeper := paramskeeper.NewKeeper(appCodec, legacyAmino, key, tkey) + + paramsKeeper.Subspace(authtypes.ModuleName) + paramsKeeper.Subspace(banktypes.ModuleName) + paramsKeeper.Subspace(stakingtypes.ModuleName) + paramsKeeper.Subspace(minttypes.ModuleName) + paramsKeeper.Subspace(distrtypes.ModuleName) + paramsKeeper.Subspace(slashingtypes.ModuleName) + paramsKeeper.Subspace(govtypes.ModuleName).WithKeyTable(govtypes.ParamKeyTable()) + paramsKeeper.Subspace(crisistypes.ModuleName) + paramsKeeper.Subspace(ibctransfertypes.ModuleName) + paramsKeeper.Subspace(ibchost.ModuleName) + + return paramsKeeper +} + +// MakeTestEncodingConfig creates an EncodingConfig for testing. This function +// should be used only in tests or when creating a new app instance (NewApp*()). +// App user shouldn't create new codecs - use the app.AppCodec instead. +// [DEPRECATED] +func MakeTestEncodingConfig() appparams.EncodingConfig { + encodingConfig := appparams.MakeTestEncodingConfig() + std.RegisterLegacyAminoCodec(encodingConfig.Amino) + std.RegisterInterfaces(encodingConfig.InterfaceRegistry) + ModuleBasics.RegisterLegacyAminoCodec(encodingConfig.Amino) + ModuleBasics.RegisterInterfaces(encodingConfig.InterfaceRegistry) + return encodingConfig +} diff --git a/app/sovereign/export.go b/app/sovereign/export.go new file mode 100644 index 0000000000..f0b3e3ed76 --- /dev/null +++ b/app/sovereign/export.go @@ -0,0 +1,187 @@ +package app + +import ( + "encoding/json" + "log" + + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + + servertypes "github.com/cosmos/cosmos-sdk/server/types" + sdk "github.com/cosmos/cosmos-sdk/types" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + "github.com/cosmos/cosmos-sdk/x/staking" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +// ExportAppStateAndValidators exports the state of the application for a genesis +// file. +func (app *App) ExportAppStateAndValidators( + forZeroHeight bool, jailAllowedAddrs []string, +) (servertypes.ExportedApp, error) { + // as if they could withdraw from the start of the next block + ctx := app.NewContext(true, tmproto.Header{Height: app.LastBlockHeight()}) + + // We export at last height + 1, because that's the height at which + // Tendermint will start InitChain. + height := app.LastBlockHeight() + 1 + if forZeroHeight { + height = 0 + app.prepForZeroHeightGenesis(ctx, jailAllowedAddrs) + } + + genState := app.MM.ExportGenesis(ctx, app.appCodec) + appState, err := json.MarshalIndent(genState, "", " ") + if err != nil { + return servertypes.ExportedApp{}, err + } + + validators, err := staking.WriteValidators(ctx, app.StakingKeeper) + if err != nil { + return servertypes.ExportedApp{}, err + } + return servertypes.ExportedApp{ + AppState: appState, + Validators: validators, + Height: height, + ConsensusParams: app.BaseApp.GetConsensusParams(ctx), + }, nil +} + +// prepare for fresh start at zero height +// NOTE zero height genesis is a temporary feature which will be deprecated +// +// in favour of export at a block height +func (app *App) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs []string) { + applyAllowedAddrs := false + + // check if there is a allowed address list + if len(jailAllowedAddrs) > 0 { + applyAllowedAddrs = true + } + + allowedAddrsMap := make(map[string]bool) + + for _, addr := range jailAllowedAddrs { + _, err := sdk.ValAddressFromBech32(addr) + if err != nil { + log.Fatal(err) + } + allowedAddrsMap[addr] = true + } + + /* Just to be safe, assert the invariants on current state. */ + app.CrisisKeeper.AssertInvariants(ctx) + + /* Handle fee distribution state. */ + + // withdraw all validator commission + app.StakingKeeper.IterateValidators(ctx, func(_ int64, val stakingtypes.ValidatorI) (stop bool) { + _, err := app.DistrKeeper.WithdrawValidatorCommission(ctx, val.GetOperator()) + if err != nil { + panic(err) + } + return false + }) + + // withdraw all delegator rewards + dels := app.StakingKeeper.GetAllDelegations(ctx) + for _, delegation := range dels { + _, err := app.DistrKeeper.WithdrawDelegationRewards(ctx, delegation.GetDelegatorAddr(), delegation.GetValidatorAddr()) + if err != nil { + panic(err) + } + } + + // clear validator slash events + app.DistrKeeper.DeleteAllValidatorSlashEvents(ctx) + + // clear validator historical rewards + app.DistrKeeper.DeleteAllValidatorHistoricalRewards(ctx) + + // set context height to zero + height := ctx.BlockHeight() + ctx = ctx.WithBlockHeight(0) + + // reinitialize all validators + app.StakingKeeper.IterateValidators(ctx, func(_ int64, val stakingtypes.ValidatorI) (stop bool) { + // donate any unwithdrawn outstanding reward fraction tokens to the community pool + scraps := app.DistrKeeper.GetValidatorOutstandingRewardsCoins(ctx, val.GetOperator()) + feePool := app.DistrKeeper.GetFeePool(ctx) + feePool.CommunityPool = feePool.CommunityPool.Add(scraps...) + app.DistrKeeper.SetFeePool(ctx, feePool) + + app.DistrKeeper.Hooks().AfterValidatorCreated(ctx, val.GetOperator()) + return false + }) + + // reinitialize all delegations + for _, del := range dels { + app.DistrKeeper.Hooks().BeforeDelegationCreated(ctx, del.GetDelegatorAddr(), del.GetValidatorAddr()) + app.DistrKeeper.Hooks().AfterDelegationModified(ctx, del.GetDelegatorAddr(), del.GetValidatorAddr()) + } + + // reset context height + ctx = ctx.WithBlockHeight(height) + + /* Handle staking state. */ + + // iterate through redelegations, reset creation height + app.StakingKeeper.IterateRedelegations(ctx, func(_ int64, red stakingtypes.Redelegation) (stop bool) { + for i := range red.Entries { + red.Entries[i].CreationHeight = 0 + } + app.StakingKeeper.SetRedelegation(ctx, red) + return false + }) + + // iterate through unbonding delegations, reset creation height + app.StakingKeeper.IterateUnbondingDelegations(ctx, func(_ int64, ubd stakingtypes.UnbondingDelegation) (stop bool) { + for i := range ubd.Entries { + ubd.Entries[i].CreationHeight = 0 + } + app.StakingKeeper.SetUnbondingDelegation(ctx, ubd) + return false + }) + + // Iterate through validators by power descending, reset bond heights, and + // update bond intra-tx counters. + store := ctx.KVStore(app.keys[stakingtypes.StoreKey]) + iter := sdk.KVStoreReversePrefixIterator(store, stakingtypes.ValidatorsKey) + counter := int16(0) + + for ; iter.Valid(); iter.Next() { + addr := sdk.ValAddress(iter.Key()[1:]) + validator, found := app.StakingKeeper.GetValidator(ctx, addr) + if !found { + panic("expected validator, not found") + } + + validator.UnbondingHeight = 0 + if applyAllowedAddrs && !allowedAddrsMap[addr.String()] { + validator.Jailed = true + } + + app.StakingKeeper.SetValidator(ctx, validator) + counter++ + } + + if err := iter.Close(); err != nil { + panic(err) + } + + if _, err := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx); err != nil { + panic(err) + } + + /* Handle slashing state. */ + + // reset start height on signing infos + app.SlashingKeeper.IterateValidatorSigningInfos( + ctx, + func(addr sdk.ConsAddress, info slashingtypes.ValidatorSigningInfo) (stop bool) { + info.StartHeight = 0 + app.SlashingKeeper.SetValidatorSigningInfo(ctx, addr, info) + return false + }, + ) +} diff --git a/app/sovereign/genesis.go b/app/sovereign/genesis.go new file mode 100644 index 0000000000..5bf0c1da80 --- /dev/null +++ b/app/sovereign/genesis.go @@ -0,0 +1,21 @@ +package app + +import ( + "encoding/json" + + "github.com/cosmos/cosmos-sdk/codec" +) + +// The genesis state of the blockchain is represented here as a map of raw json +// messages key'd by a identifier string. +// The identifier is used to determine which module genesis information belongs +// to so it may be appropriately routed during init chain. +// Within this application default genesis information is retrieved from +// the ModuleBasicManager which populates json from each BasicModule +// object provided to it during init. +type GenesisState map[string]json.RawMessage + +// NewDefaultGenesisState generates the default state for the application. +func NewDefaultGenesisState(cdc codec.JSONCodec) GenesisState { + return ModuleBasics.DefaultGenesis(cdc) +} diff --git a/cmd/interchain-security-sd/cmd/genaccounts.go b/cmd/interchain-security-sd/cmd/genaccounts.go new file mode 100644 index 0000000000..c3340dccad --- /dev/null +++ b/cmd/interchain-security-sd/cmd/genaccounts.go @@ -0,0 +1,180 @@ +package cmd + +import ( + "bufio" + "encoding/json" + "errors" + "fmt" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + "github.com/cosmos/cosmos-sdk/server" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + authvesting "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/cosmos-sdk/x/genutil" + genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" +) + +const ( + flagVestingStart = "vesting-start-time" + flagVestingEnd = "vesting-end-time" + flagVestingAmt = "vesting-amount" +) + +// AddGenesisAccountCmd returns add-genesis-account cobra Command. +func AddGenesisAccountCmd(defaultNodeHome string) *cobra.Command { + cmd := &cobra.Command{ + Use: "add-genesis-account [address_or_key_name] [coin][,[coin]]", + Short: "Add a genesis account to genesis.json", + Long: `Add a genesis account to genesis.json. The provided account must specify +the account address or key name and a list of initial coins. If a key name is given, +the address will be looked up in the local Keybase. The list of initial tokens must +contain valid denominations. Accounts may optionally be supplied with vesting parameters. +`, + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx := client.GetClientContextFromCmd(cmd) + serverCtx := server.GetServerContextFromCmd(cmd) + config := serverCtx.Config + + config.SetRoot(clientCtx.HomeDir) + + var kr keyring.Keyring + addr, err := sdk.AccAddressFromBech32(args[0]) + if err != nil { + inBuf := bufio.NewReader(cmd.InOrStdin()) + keyringBackend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend) + if keyringBackend != "" && clientCtx.Keyring == nil { + var err error + kr, err = keyring.New(sdk.KeyringServiceName(), keyringBackend, clientCtx.HomeDir, inBuf) + if err != nil { + return err + } + } else { + kr = clientCtx.Keyring + } + + info, err := kr.Key(args[0]) + if err != nil { + return fmt.Errorf("failed to get address from Keyring: %w", err) + } + addr = info.GetAddress() + } + + coins, err := sdk.ParseCoinsNormalized(args[1]) + if err != nil { + return fmt.Errorf("failed to parse coins: %w", err) + } + + vestingStart, _ := cmd.Flags().GetInt64(flagVestingStart) + vestingEnd, _ := cmd.Flags().GetInt64(flagVestingEnd) + vestingAmtStr, _ := cmd.Flags().GetString(flagVestingAmt) + + vestingAmt, err := sdk.ParseCoinsNormalized(vestingAmtStr) + if err != nil { + return fmt.Errorf("failed to parse vesting amount: %w", err) + } + + // create concrete account type based on input parameters + var genAccount authtypes.GenesisAccount + + balances := banktypes.Balance{Address: addr.String(), Coins: coins.Sort()} + baseAccount := authtypes.NewBaseAccount(addr, nil, 0, 0) + + if !vestingAmt.IsZero() { + baseVestingAccount := authvesting.NewBaseVestingAccount(baseAccount, vestingAmt.Sort(), vestingEnd) + + if (balances.Coins.IsZero() && !baseVestingAccount.OriginalVesting.IsZero()) || + baseVestingAccount.OriginalVesting.IsAnyGT(balances.Coins) { + return errors.New("vesting amount cannot be greater than total amount") + } + + switch { + case vestingStart != 0 && vestingEnd != 0: + genAccount = authvesting.NewContinuousVestingAccountRaw(baseVestingAccount, vestingStart) + + case vestingEnd != 0: + genAccount = authvesting.NewDelayedVestingAccountRaw(baseVestingAccount) + + default: + return errors.New("invalid vesting parameters; must supply start and end time or end time") + } + } else { + genAccount = baseAccount + } + + if err := genAccount.Validate(); err != nil { + return fmt.Errorf("failed to validate new genesis account: %w", err) + } + + genFile := config.GenesisFile() + appState, genDoc, err := genutiltypes.GenesisStateFromGenFile(genFile) + if err != nil { + return fmt.Errorf("failed to unmarshal genesis state: %w", err) + } + + authGenState := authtypes.GetGenesisStateFromAppState(clientCtx.Codec, appState) + + accs, err := authtypes.UnpackAccounts(authGenState.Accounts) + if err != nil { + return fmt.Errorf("failed to get accounts from any: %w", err) + } + + if accs.Contains(addr) { + return fmt.Errorf("cannot add account at existing address %s", addr) + } + + // Add the new account to the set of genesis accounts and sanitize the + // accounts afterwards. + accs = append(accs, genAccount) + accs = authtypes.SanitizeGenesisAccounts(accs) + + genAccs, err := authtypes.PackAccounts(accs) + if err != nil { + return fmt.Errorf("failed to convert accounts into any's: %w", err) + } + authGenState.Accounts = genAccs + + authGenStateBz, err := clientCtx.Codec.MarshalJSON(&authGenState) + if err != nil { + return fmt.Errorf("failed to marshal auth genesis state: %w", err) + } + + appState[authtypes.ModuleName] = authGenStateBz + + bankGenState := banktypes.GetGenesisStateFromAppState(clientCtx.Codec, appState) + bankGenState.Balances = append(bankGenState.Balances, balances) + bankGenState.Balances = banktypes.SanitizeGenesisBalances(bankGenState.Balances) + bankGenState.Supply = bankGenState.Supply.Add(balances.Coins...) + + bankGenStateBz, err := clientCtx.Codec.MarshalJSON(bankGenState) + if err != nil { + return fmt.Errorf("failed to marshal bank genesis state: %w", err) + } + + appState[banktypes.ModuleName] = bankGenStateBz + + appStateJSON, err := json.Marshal(appState) + if err != nil { + return fmt.Errorf("failed to marshal application genesis state: %w", err) + } + + genDoc.AppState = appStateJSON + return genutil.ExportGenesisFile(genDoc, genFile) + }, + } + + cmd.Flags().String(flags.FlagHome, defaultNodeHome, "The application home directory") + cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|kwallet|pass|test)") + cmd.Flags().String(flagVestingAmt, "", "amount of coins for vesting accounts") + cmd.Flags().Int64(flagVestingStart, 0, "schedule start time (unix epoch) for vesting accounts") + cmd.Flags().Int64(flagVestingEnd, 0, "schedule end time (unix epoch) for vesting accounts") + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/cmd/interchain-security-sd/cmd/root.go b/cmd/interchain-security-sd/cmd/root.go new file mode 100644 index 0000000000..56f9ad667b --- /dev/null +++ b/cmd/interchain-security-sd/cmd/root.go @@ -0,0 +1,305 @@ +package cmd + +import ( + "errors" + "io" + "os" + "path/filepath" + + serverconfig "github.com/cosmos/cosmos-sdk/server/config" + "github.com/spf13/cast" + "github.com/spf13/cobra" + tmcli "github.com/tendermint/tendermint/libs/cli" + "github.com/tendermint/tendermint/libs/log" + dbm "github.com/tendermint/tm-db" + + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/config" + "github.com/cosmos/cosmos-sdk/client/debug" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/keys" + "github.com/cosmos/cosmos-sdk/client/pruning" + "github.com/cosmos/cosmos-sdk/client/rpc" + "github.com/cosmos/cosmos-sdk/server" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + "github.com/cosmos/cosmos-sdk/snapshots" + "github.com/cosmos/cosmos-sdk/store" + sdk "github.com/cosmos/cosmos-sdk/types" + authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" + "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/cosmos-sdk/x/crisis" + genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" + "github.com/cosmos/interchain-security/v2/app/params" + simapp "github.com/cosmos/interchain-security/v2/app/sovereign" +) + +// NewRootCmd creates a new root command for simd. It is called once in the +// main function. +func NewRootCmd() (*cobra.Command, params.EncodingConfig) { + encodingConfig := simapp.MakeTestEncodingConfig() + initClientCtx := client.Context{}. + WithCodec(encodingConfig.Marshaler). + WithInterfaceRegistry(encodingConfig.InterfaceRegistry). + WithTxConfig(encodingConfig.TxConfig). + WithLegacyAmino(encodingConfig.Amino). + WithInput(os.Stdin). + WithAccountRetriever(types.AccountRetriever{}). + WithHomeDir(simapp.DefaultNodeHome). + WithViper("") // In simapp, we don't use any prefix for env variables. + + rootCmd := &cobra.Command{ + Use: "interchain-security-sd", + Short: "simulation app", + PersistentPreRunE: func(cmd *cobra.Command, _ []string) error { + // set the default command outputs + cmd.SetOut(cmd.OutOrStdout()) + cmd.SetErr(cmd.ErrOrStderr()) + + initClientCtx, err := client.ReadPersistentCommandFlags(initClientCtx, cmd.Flags()) + if err != nil { + return err + } + + initClientCtx, err = config.ReadFromClientConfig(initClientCtx) + if err != nil { + return err + } + + if err := client.SetCmdClientContextHandler(initClientCtx, cmd); err != nil { + return err + } + + customAppTemplate, customAppConfig := initAppConfig() + + return server.InterceptConfigsPreRunHandler(cmd, customAppTemplate, customAppConfig) + }, + } + + initRootCmd(rootCmd, encodingConfig) + + return rootCmd, encodingConfig +} + +// initAppConfig helps to override default appConfig template and configs. +// return "", nil if no custom configuration is required for the application. +func initAppConfig() (string, interface{}) { + // The following code snippet is just for reference. + + // WASMConfig defines configuration for the wasm module. + type WASMConfig struct { + // This is the maximum sdk gas (wasm and storage) that we allow for any x/wasm "smart" queries + QueryGasLimit uint64 `mapstructure:"query_gas_limit"` + + // Address defines the gRPC-web server to listen on + LruSize uint64 `mapstructure:"lru_size"` + } + + type CustomAppConfig struct { + serverconfig.Config + + WASM WASMConfig `mapstructure:"wasm"` + } + + // Optionally allow the chain developer to overwrite the SDK's default + // server config. + srvCfg := serverconfig.DefaultConfig() + // The SDK's default minimum gas price is set to "" (empty value) inside + // app.toml. If left empty by validators, the node will halt on startup. + // However, the chain developer can set a default app.toml value for their + // validators here. + // + // In summary: + // - if you leave srvCfg.MinGasPrices = "", all validators MUST tweak their + // own app.toml config, + // - if you set srvCfg.MinGasPrices non-empty, validators CAN tweak their + // own app.toml to override, or use this default value. + // + // In simapp, we set the min gas prices to 0. + srvCfg.MinGasPrices = "0stake" + // srvCfg.BaseConfig.IAVLDisableFastNode = true // disable fastnode by default + + customAppConfig := CustomAppConfig{ + Config: *srvCfg, + WASM: WASMConfig{ + LruSize: 1, + QueryGasLimit: 300000, + }, + } + + customAppTemplate := serverconfig.DefaultConfigTemplate + ` +[wasm] +# This is the maximum sdk gas (wasm and storage) that we allow for any x/wasm "smart" queries +query_gas_limit = 300000 +# This is the number of wasm vm instances we keep cached in memory for speed-up +# Warning: this is currently unstable and may lead to crashes, best to keep for 0 unless testing locally +lru_size = 0` + + return customAppTemplate, customAppConfig +} + +func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) { + cfg := sdk.GetConfig() + cfg.Seal() + + a := appCreator{encodingConfig} + rootCmd.AddCommand( + genutilcli.InitCmd(simapp.ModuleBasics, simapp.DefaultNodeHome), + genutilcli.CollectGenTxsCmd(banktypes.GenesisBalancesIterator{}, simapp.DefaultNodeHome), + genutilcli.MigrateGenesisCmd(), + genutilcli.GenTxCmd(simapp.ModuleBasics, encodingConfig.TxConfig, banktypes.GenesisBalancesIterator{}, simapp.DefaultNodeHome), + genutilcli.ValidateGenesisCmd(simapp.ModuleBasics), + AddGenesisAccountCmd(simapp.DefaultNodeHome), + tmcli.NewCompletionCmd(rootCmd, true), + debug.Cmd(), + config.Cmd(), + pruning.PruningCmd(a.newApp), + ) + + server.AddCommands(rootCmd, simapp.DefaultNodeHome, a.newApp, a.appExport, addModuleInitFlags) + + // add keybase, auxiliary RPC, query, and tx child commands + rootCmd.AddCommand( + rpc.StatusCommand(), + queryCommand(), + txCommand(), + keys.Commands(simapp.DefaultNodeHome), + ) + + // add rosetta + rootCmd.AddCommand(server.RosettaCommand(encodingConfig.InterfaceRegistry, encodingConfig.Marshaler)) +} + +func addModuleInitFlags(startCmd *cobra.Command) { + crisis.AddModuleInitFlags(startCmd) +} + +func queryCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "query", + Aliases: []string{"q"}, + Short: "Querying subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand( + authcmd.GetAccountCmd(), + rpc.ValidatorCommand(), + rpc.BlockCommand(), + authcmd.QueryTxsByEventsCmd(), + authcmd.QueryTxCmd(), + ) + + simapp.ModuleBasics.AddQueryCommands(cmd) + cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID") + + return cmd +} + +func txCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "tx", + Short: "Transactions subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand( + authcmd.GetSignCommand(), + authcmd.GetSignBatchCommand(), + authcmd.GetMultiSignCommand(), + authcmd.GetMultiSignBatchCmd(), + authcmd.GetValidateSignaturesCommand(), + authcmd.GetBroadcastCommand(), + authcmd.GetEncodeCommand(), + authcmd.GetDecodeCommand(), + ) + + simapp.ModuleBasics.AddTxCommands(cmd) + cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID") + + return cmd +} + +type appCreator struct { + encCfg params.EncodingConfig +} + +// newApp is an appCreator +func (a appCreator) newApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts servertypes.AppOptions) servertypes.Application { + var cache sdk.MultiStorePersistentCache + + if cast.ToBool(appOpts.Get(server.FlagInterBlockCache)) { + cache = store.NewCommitKVStoreCacheManager() + } + + skipUpgradeHeights := make(map[int64]bool) + for _, h := range cast.ToIntSlice(appOpts.Get(server.FlagUnsafeSkipUpgrades)) { + skipUpgradeHeights[int64(h)] = true + } + + pruningOpts, err := server.GetPruningOptionsFromFlags(appOpts) + if err != nil { + panic(err) + } + + snapshotDir := filepath.Join(cast.ToString(appOpts.Get(flags.FlagHome)), "data", "snapshots") + snapshotDB, err := sdk.NewLevelDB("metadata", snapshotDir) + if err != nil { + panic(err) + } + snapshotStore, err := snapshots.NewStore(snapshotDB, snapshotDir) + if err != nil { + panic(err) + } + + return simapp.New( + logger, db, traceStore, true, skipUpgradeHeights, + cast.ToString(appOpts.Get(flags.FlagHome)), + cast.ToUint(appOpts.Get(server.FlagInvCheckPeriod)), + a.encCfg, + appOpts, + baseapp.SetPruning(pruningOpts), + baseapp.SetMinGasPrices(cast.ToString(appOpts.Get(server.FlagMinGasPrices))), + baseapp.SetHaltHeight(cast.ToUint64(appOpts.Get(server.FlagHaltHeight))), + baseapp.SetHaltTime(cast.ToUint64(appOpts.Get(server.FlagHaltTime))), + baseapp.SetMinRetainBlocks(cast.ToUint64(appOpts.Get(server.FlagMinRetainBlocks))), + baseapp.SetInterBlockCache(cache), + baseapp.SetTrace(cast.ToBool(appOpts.Get(server.FlagTrace))), + baseapp.SetIndexEvents(cast.ToStringSlice(appOpts.Get(server.FlagIndexEvents))), + baseapp.SetSnapshotStore(snapshotStore), + baseapp.SetSnapshotInterval(cast.ToUint64(appOpts.Get(server.FlagStateSyncSnapshotInterval))), + baseapp.SetSnapshotKeepRecent(cast.ToUint32(appOpts.Get(server.FlagStateSyncSnapshotKeepRecent))), + baseapp.SetIAVLCacheSize(cast.ToInt(appOpts.Get(server.FlagIAVLCacheSize))), + baseapp.SetIAVLDisableFastNode(cast.ToBool(appOpts.Get(server.FlagDisableIAVLFastNode))), + ) +} + +// appExport creates a new simapp (optionally at a given height) +// and exports state. +func (a appCreator) appExport( + logger log.Logger, db dbm.DB, traceStore io.Writer, height int64, forZeroHeight bool, jailAllowedAddrs []string, + appOpts servertypes.AppOptions, +) (servertypes.ExportedApp, error) { + var simApp *simapp.App + homePath, ok := appOpts.Get(flags.FlagHome).(string) + if !ok || homePath == "" { + return servertypes.ExportedApp{}, errors.New("application home not set") + } + + if height != -1 { + simApp = simapp.New(logger, db, traceStore, false, map[int64]bool{}, homePath, uint(1), a.encCfg, appOpts) + + if err := simApp.LoadHeight(height); err != nil { + return servertypes.ExportedApp{}, err + } + } else { + simApp = simapp.New(logger, db, traceStore, true, map[int64]bool{}, homePath, uint(1), a.encCfg, appOpts) + } + + return simApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs) +} diff --git a/cmd/interchain-security-sd/main.go b/cmd/interchain-security-sd/main.go new file mode 100644 index 0000000000..6b43e7b396 --- /dev/null +++ b/cmd/interchain-security-sd/main.go @@ -0,0 +1,24 @@ +package main + +import ( + "os" + + "github.com/cosmos/cosmos-sdk/server" + svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" + app "github.com/cosmos/interchain-security/v2/app/sovereign" + "github.com/cosmos/interchain-security/v2/cmd/interchain-security-sd/cmd" +) + +func main() { + rootCmd, _ := cmd.NewRootCmd() + + if err := svrcmd.Execute(rootCmd, app.DefaultNodeHome); err != nil { + switch e := err.(type) { + case server.ErrorCode: + os.Exit(e.Code) + + default: + os.Exit(1) + } + } +} diff --git a/docs/docs/consumer-development/onboarding.md b/docs/docs/consumer-development/onboarding.md index faa2969e63..89c5f32dc5 100644 --- a/docs/docs/consumer-development/onboarding.md +++ b/docs/docs/consumer-development/onboarding.md @@ -91,6 +91,13 @@ Example of a consumer chain addition proposal. // This param is a part of the cosmos sdk staking module. In the case of // a ccv enabled consumer chain, the ccv module acts as the staking module. "historical_entries": 10000, + // The ID of a token transfer channel used for the Reward Distribution + // sub-protocol. If DistributionTransmissionChannel == "", a new transfer + // channel is created on top of the same connection as the CCV channel. + // Note that transfer_channel_id is the ID of the channel end on the consumer chain. + // it is most relevant for chains performing a sovereign to consumer changeover + // in order to maintan the existing ibc transfer channel + "distribution_transmission_channel": "channel-123" } ``` diff --git a/docs/docs/features/proposals.md b/docs/docs/features/proposals.md index 9285baa62b..a34160ecf4 100644 --- a/docs/docs/features/proposals.md +++ b/docs/docs/features/proposals.md @@ -43,6 +43,9 @@ Minimal example: "historical_entries": 10000, "genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0", "binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1" + // relevant for chains performing a sovereign to consumer changeover + // in order to maintan the existing ibc transfer channel + "distribution_transmission_channel": "channel-123" } ``` More examples can be found in the replicated security testnet repository [here](https://github.com/cosmos/testnets/blob/master/replicated-security/baryon-1/proposal-baryon-1.json) and [here](https://github.com/cosmos/testnets/blob/master/replicated-security/noble-1/start-proposal-noble-1.json). diff --git a/proto/interchain_security/ccv/consumer/v1/genesis.proto b/proto/interchain_security/ccv/consumer/v1/genesis.proto index bf019879ac..578518086c 100644 --- a/proto/interchain_security/ccv/consumer/v1/genesis.proto +++ b/proto/interchain_security/ccv/consumer/v1/genesis.proto @@ -34,12 +34,12 @@ message GenesisState { // OutstandingDowntimes nil on new chain, filled in on restart. repeated OutstandingDowntime outstanding_downtime_slashing = 10 [ (gogoproto.nullable) = false ]; - // PendingConsumerPackets nil on new chain, filled in on restart. - interchain_security.ccv.v1.ConsumerPacketDataList pending_consumer_packets = 11 - [ (gogoproto.nullable) = false ]; + // PendingConsumerPackets nil on new chain, filled in on restart. + interchain_security.ccv.v1.ConsumerPacketDataList pending_consumer_packets = 11 + [ (gogoproto.nullable) = false ]; // LastTransmissionBlockHeight nil on new chain, filled in on restart. interchain_security.ccv.consumer.v1.LastTransmissionBlockHeight last_transmission_block_height = 12 - [ (gogoproto.nullable) = false ]; + [ (gogoproto.nullable) = false ]; bool preCCV = 13; // flag indicating whether the consumer CCV module starts in pre-CCV state } diff --git a/proto/interchain_security/ccv/provider/v1/provider.proto b/proto/interchain_security/ccv/provider/v1/provider.proto index 743d2c9c33..d190b3a6ca 100644 --- a/proto/interchain_security/ccv/provider/v1/provider.proto +++ b/proto/interchain_security/ccv/provider/v1/provider.proto @@ -62,6 +62,13 @@ message ConsumerAdditionProposal { // This param is a part of the cosmos sdk staking module. In the case of // a ccv enabled consumer chain, the ccv module acts as the staking module. int64 historical_entries = 13; + // The ID of a token transfer channel used for the Reward Distribution + // sub-protocol. If DistributionTransmissionChannel == "", a new transfer + // channel is created on top of the same connection as the CCV channel. + // Note that transfer_channel_id is the ID of the channel end on the consumer chain. + // it is most relevant for chains performing a sovereign to consumer changeover + // in order to maintan the existing ibc transfer channel + string distribution_transmission_channel = 14; } // ConsumerRemovalProposal is a governance proposal on the provider chain to remove (and stop) a consumer chain. diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index b1e6863b7a..06bcb7f5f7 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -209,12 +209,14 @@ func (tr TestRun) submitTextProposal( } type submitConsumerAdditionProposalAction struct { - chain chainID - from validatorID - deposit uint - consumerChain chainID - spawnTime uint - initialHeight clienttypes.Height + preCCV bool + chain chainID + from validatorID + deposit uint + consumerChain chainID + spawnTime uint + initialHeight clienttypes.Height + distributionChannel string } func (tr TestRun) submitConsumerAdditionProposal( @@ -238,6 +240,7 @@ func (tr TestRun) submitConsumerAdditionProposal( TransferTimeoutPeriod: params.TransferTimeoutPeriod, UnbondingPeriod: params.UnbondingPeriod, Deposit: fmt.Sprint(action.deposit) + `stake`, + DistributionTransmissionChannel: action.distributionChannel, } bz, err := json.Marshal(prop) @@ -565,6 +568,133 @@ func (tr TestRun) startConsumerChain( }, verbose) } +type ChangeoverChainAction struct { + sovereignChain chainID + providerChain chainID + validators []StartChainValidator + genesisChanges string +} + +func (tr TestRun) changeoverChain( + action ChangeoverChainAction, + verbose bool, +) { + // sleep until the consumer chain genesis is ready on consumer + time.Sleep(5 * time.Second) + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[action.providerChain].binaryName, + + "query", "provider", "consumer-genesis", + string(tr.chainConfigs[action.sovereignChain].chainId), + + `--node`, tr.getQueryNode(action.providerChain), + `-o`, `json`, + ) + + if verbose { + log.Println("changeoverChain cmd: ", cmd.String()) + } + + bz, err := cmd.CombinedOutput() + if err != nil { + log.Fatal(err, "\n", string(bz)) + } + + consumerGenesis := ".app_state.ccvconsumer = " + string(bz) + consumerGenesisChanges := tr.chainConfigs[action.sovereignChain].genesisChanges + if consumerGenesisChanges != "" { + consumerGenesis = consumerGenesis + " | " + consumerGenesisChanges + " | " + action.genesisChanges + } + + tr.startChangeover(ChangeoverChainAction{ + validators: action.validators, + genesisChanges: consumerGenesis, + }, verbose) +} + +func (tr TestRun) startChangeover( + action ChangeoverChainAction, + verbose bool, +) { + chainConfig := tr.chainConfigs[chainID("sover")] + type jsonValAttrs struct { + Mnemonic string `json:"mnemonic"` + Allocation string `json:"allocation"` + Stake string `json:"stake"` + ValId string `json:"val_id"` + PrivValidatorKey string `json:"priv_validator_key"` + NodeKey string `json:"node_key"` + IpSuffix string `json:"ip_suffix"` + + ConsumerMnemonic string `json:"consumer_mnemonic"` + ConsumerPrivValidatorKey string `json:"consumer_priv_validator_key"` + StartWithConsumerKey bool `json:"start_with_consumer_key"` + } + + var validators []jsonValAttrs + for _, val := range action.validators { + validators = append(validators, jsonValAttrs{ + Mnemonic: tr.validatorConfigs[val.id].mnemonic, + NodeKey: tr.validatorConfigs[val.id].nodeKey, + ValId: fmt.Sprint(val.id), + PrivValidatorKey: tr.validatorConfigs[val.id].privValidatorKey, + Allocation: fmt.Sprint(val.allocation) + "stake", + Stake: fmt.Sprint(val.stake) + "stake", + IpSuffix: tr.validatorConfigs[val.id].ipSuffix, + + ConsumerMnemonic: tr.validatorConfigs[val.id].consumerMnemonic, + ConsumerPrivValidatorKey: tr.validatorConfigs[val.id].consumerPrivValidatorKey, + // if true node will be started with consumer key for each consumer chain + StartWithConsumerKey: tr.validatorConfigs[val.id].useConsumerKey, + }) + } + + vals, err := json.Marshal(validators) + if err != nil { + log.Fatal(err) + } + + // Concat genesis changes defined in chain config, with any custom genesis changes for this chain instantiation + var genesisChanges string + if action.genesisChanges != "" { + genesisChanges = chainConfig.genesisChanges + " | " + action.genesisChanges + } else { + genesisChanges = chainConfig.genesisChanges + } + + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, "/bin/bash", + "/testnet-scripts/start-changeover.sh", chainConfig.upgradeBinary, string(vals), + "sover", chainConfig.ipPrefix, genesisChanges, + tr.tendermintConfigOverride, + ) + + cmdReader, err := cmd.StdoutPipe() + if err != nil { + log.Fatal(err) + } + cmd.Stderr = cmd.Stdout + + if err := cmd.Start(); err != nil { + log.Fatal(err) + } + + scanner := bufio.NewScanner(cmdReader) + + for scanner.Scan() { + out := scanner.Text() + if verbose { + fmt.Println("startChangeover: " + out) + } + if out == done { + break + } + } + if err := scanner.Err(); err != nil { + log.Fatal("startChangeover died", err) + } +} + type addChainToRelayerAction struct { chain chainID validator validatorID @@ -683,6 +813,7 @@ func (tr TestRun) addChainToHermes( keyName, rpcAddr, wsAddr, + // action.consumer, ) bashCommand := fmt.Sprintf(`echo '%s' >> %s`, chainConfig, "/root/.hermes/config.toml") @@ -805,6 +936,51 @@ func (tr TestRun) addIbcConnectionGorelayer( tr.waitBlocks(action.chainB, 1, 10*time.Second) } +type createIbcClientsAction struct { + chainA chainID + chainB chainID +} + +// if clients are not provided hermes will first +// create new clients and then a new connection +// otherwise, it would use client provided as CLI argument (-a-client) +func (tr TestRun) createIbcClientsHermes( + action createIbcClientsAction, + verbose bool, +) { + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, "hermes", + "create", "connection", + "--a-chain", string(tr.chainConfigs[action.chainA].chainId), + "--b-chain", string(tr.chainConfigs[action.chainB].chainId), + ) + + cmdReader, err := cmd.StdoutPipe() + if err != nil { + log.Fatal(err) + } + cmd.Stderr = cmd.Stdout + + if err := cmd.Start(); err != nil { + log.Fatal(err) + } + + scanner := bufio.NewScanner(cmdReader) + + for scanner.Scan() { + out := scanner.Text() + if verbose { + fmt.Println("createIbcClientsHermes: " + out) + } + if out == done { + break + } + } + if err := scanner.Err(); err != nil { + log.Fatal(err) + } +} + func (tr TestRun) addIbcConnectionHermes( action addIbcConnectionAction, verbose bool, @@ -850,6 +1026,7 @@ type addIbcChannelAction struct { portA string portB string order string + version string } type startRelayerAction struct{} @@ -936,6 +1113,13 @@ func (tr TestRun) addIbcChannelHermes( action addIbcChannelAction, verbose bool, ) { + // if version is not specified, use the default version when creating ccv connections + // otherwise, use the provided version schema (usually it is ICS20-1 for IBC transfer) + chanVersion := action.version + if chanVersion == "" { + chanVersion = tr.containerConfig.ccvVersion + } + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, "hermes", "create", "channel", @@ -943,7 +1127,7 @@ func (tr TestRun) addIbcChannelHermes( "--a-connection", "connection-"+fmt.Sprint(action.connectionA), "--a-port", action.portA, "--b-port", action.portB, - "--channel-version", tr.containerConfig.ccvVersion, + "--channel-version", chanVersion, "--order", action.order, ) diff --git a/tests/e2e/actions_sovereign_chain.go b/tests/e2e/actions_sovereign_chain.go new file mode 100644 index 0000000000..c61a2a9a38 --- /dev/null +++ b/tests/e2e/actions_sovereign_chain.go @@ -0,0 +1,166 @@ +package main + +import ( + "bufio" + "encoding/json" + "fmt" + "log" + "os/exec" + "time" +) + +type StartSovereignChainAction struct { + chain chainID + validators []StartChainValidator + // Genesis changes specific to this action, appended to genesis changes defined in chain config + genesisChanges string +} + +// calls a simplified startup script (start-sovereign.sh) and runs a validator node +// upgrades are simpler with a single validator node since only one node needs to be upgraded +func (tr TestRun) startSovereignChain( + action StartSovereignChainAction, + verbose bool, +) { + chainConfig := tr.chainConfigs["sover"] + type jsonValAttrs struct { + Mnemonic string `json:"mnemonic"` + Allocation string `json:"allocation"` + Stake string `json:"stake"` + ValId string `json:"val_id"` + PrivValidatorKey string `json:"priv_validator_key"` + NodeKey string `json:"node_key"` + IpSuffix string `json:"ip_suffix"` + + ConsumerMnemonic string `json:"consumer_mnemonic"` + ConsumerPrivValidatorKey string `json:"consumer_priv_validator_key"` + StartWithConsumerKey bool `json:"start_with_consumer_key"` + } + + var validators []jsonValAttrs + for _, val := range action.validators { + validators = append(validators, jsonValAttrs{ + Mnemonic: tr.validatorConfigs[val.id].mnemonic, + NodeKey: tr.validatorConfigs[val.id].nodeKey, + ValId: fmt.Sprint(val.id), + PrivValidatorKey: tr.validatorConfigs[val.id].privValidatorKey, + Allocation: fmt.Sprint(val.allocation) + "stake", + Stake: fmt.Sprint(val.stake) + "stake", + IpSuffix: tr.validatorConfigs[val.id].ipSuffix, + + ConsumerMnemonic: tr.validatorConfigs[val.id].consumerMnemonic, + ConsumerPrivValidatorKey: tr.validatorConfigs[val.id].consumerPrivValidatorKey, + // if true node will be started with consumer key for each consumer chain + StartWithConsumerKey: tr.validatorConfigs[val.id].useConsumerKey, + }) + } + + vals, err := json.Marshal(validators) + if err != nil { + log.Fatal(err) + } + + // Concat genesis changes defined in chain config, with any custom genesis changes for this chain instantiation + var genesisChanges string + if action.genesisChanges != "" { + genesisChanges = chainConfig.genesisChanges + " | " + action.genesisChanges + } else { + genesisChanges = chainConfig.genesisChanges + } + + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, "/bin/bash", + "/testnet-scripts/start-sovereign.sh", chainConfig.binaryName, string(vals), + string(chainConfig.chainId), chainConfig.ipPrefix, genesisChanges, + tr.tendermintConfigOverride, + ) + + cmdReader, err := cmd.StdoutPipe() + if err != nil { + log.Fatal(err) + } + cmd.Stderr = cmd.Stdout + + if err := cmd.Start(); err != nil { + log.Fatal(err) + } + + scanner := bufio.NewScanner(cmdReader) + + for scanner.Scan() { + out := scanner.Text() + if verbose { + fmt.Println("startSovereignChain: " + out) + } + if out == done { + break + } + } + if err := scanner.Err(); err != nil { + log.Fatal(err) + } + tr.addChainToRelayer(addChainToRelayerAction{ + chain: action.chain, + validator: action.validators[0].id, + }, verbose) +} + +type UpgradeProposalAction struct { + chainID chainID + upgradeTitle string + proposer validatorID + upgradeHeight uint64 +} + +func (tr *TestRun) submitUpgradeProposal(action UpgradeProposalAction, verbose bool) { + submit := fmt.Sprintf( + `%s tx gov submit-proposal software-upgrade %s \ + --title %s \ + --deposit 10000000stake \ + --upgrade-height %s \ + --upgrade-info "perform changeover" \ + --description "perform changeover" \ + --gas 900000 \ + --from validator%s \ + --keyring-backend test \ + --chain-id %s \ + --home %s \ + --node %s \ + -b block \ + -y`, + tr.chainConfigs[chainID("sover")].binaryName, + action.upgradeTitle, + action.upgradeTitle, + fmt.Sprint(action.upgradeHeight), + action.proposer, + tr.chainConfigs[chainID("sover")].chainId, + tr.getValidatorHome(chainID("sover"), action.proposer), + tr.getValidatorNode(chainID("sover"), action.proposer), + ) + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + cmd := exec.Command("docker", "exec", + tr.containerConfig.instanceName, + "/bin/bash", "-c", + submit, + ) + + if verbose { + fmt.Println("submitUpgradeProposal cmd:", cmd.String()) + } + + bz, err := cmd.CombinedOutput() + if err != nil { + log.Fatal(err, "\n", string(bz)) + } +} + +type waitUntilBlockAction struct { + block uint + chain chainID +} + +func (tr *TestRun) waitUntilBlockOnChain(action waitUntilBlockAction) { + fmt.Println("waitUntilBlockOnChain is waiting for block:", action.block) + tr.waitUntilBlock(action.chain, action.block, 120*time.Second) + fmt.Println("waitUntilBlockOnChain done waiting for block:", action.block) +} diff --git a/tests/e2e/config.go b/tests/e2e/config.go index cc755cb97a..3038f69f4e 100644 --- a/tests/e2e/config.go +++ b/tests/e2e/config.go @@ -47,6 +47,9 @@ type ChainConfig struct { // Example: ".app_state.gov.voting_params.voting_period = \"5s\" | .app_state.slashing.params.signed_blocks_window = \"2\" | .app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\"" genesisChanges string binaryName string + + // binary to use after upgrade height + upgradeBinary string } type ContainerConfig struct { @@ -328,6 +331,51 @@ func MultiConsumerTestRun() TestRun { } } +func ChangeoverTestRun() TestRun { + return TestRun{ + name: "changeover", + containerConfig: ContainerConfig{ + containerName: "interchain-security-changeover-container", + instanceName: "interchain-security-changeover-instance", + ccvVersion: "1", + now: time.Now(), + }, + validatorConfigs: getDefaultValidators(), + chainConfigs: map[chainID]ChainConfig{ + chainID("provi"): { + chainId: chainID("provi"), + binaryName: "interchain-security-pd", + ipPrefix: "7.7.7", + votingWaitTime: 20, + genesisChanges: ".app_state.gov.voting_params.voting_period = \"20s\" | " + + // Custom slashing parameters for testing validator downtime functionality + // See https://docs.cosmos.network/main/modules/slashing/04_begin_block.html#uptime-tracking + ".app_state.slashing.params.signed_blocks_window = \"10\" | " + + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + + ".app_state.slashing.params.downtime_jail_duration = \"2s\" | " + + ".app_state.slashing.params.slash_fraction_downtime = \"0.010000000000000000\" | " + + ".app_state.provider.params.slash_meter_replenish_fraction = \"1.0\" | " + // This disables slash packet throttling + ".app_state.provider.params.slash_meter_replenish_period = \"3s\"", + }, + chainID("sover"): { + chainId: chainID("sover"), + binaryName: "interchain-security-sd", + upgradeBinary: "interchain-security-cdd", + ipPrefix: "7.7.8", + votingWaitTime: 20, + genesisChanges: ".app_state.gov.voting_params.voting_period = \"20s\" | " + + ".app_state.slashing.params.signed_blocks_window = \"15\" | " + + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + + ".app_state.slashing.params.downtime_jail_duration = \"2s\" | " + + ".app_state.slashing.params.slash_fraction_downtime = \"0.010000000000000000\" | " + + ".app_state.staking.params.unbonding_time = \"1728000s\"", // making the genesis unbonding time equal to unbonding time in the consumer addition proposal + }, + }, + tendermintConfigOverride: `s/timeout_commit = "5s"/timeout_commit = "1s"/;` + + `s/peer_gossip_sleep_duration = "100ms"/peer_gossip_sleep_duration = "50ms"/;`, + } +} + func (s *TestRun) SetDockerConfig(localSdkPath string, useGaia bool, gaiaTag string) { if localSdkPath != "" { fmt.Println("USING LOCAL SDK", localSdkPath) diff --git a/tests/e2e/main.go b/tests/e2e/main.go index 141f8a8cd8..737a318de2 100644 --- a/tests/e2e/main.go +++ b/tests/e2e/main.go @@ -57,6 +57,7 @@ func main() { } testRuns := []testRunWithSteps{ + {ChangeoverTestRun(), changeoverSteps}, {DefaultTestRun(), happyPathSteps}, {DemocracyTestRun(true), democracySteps}, {DemocracyTestRun(false), rewardDenomConsumerSteps}, @@ -112,6 +113,14 @@ func (tr *TestRun) runStep(step Step, verbose bool) { switch action := step.action.(type) { case StartChainAction: tr.startChain(action, verbose) + case StartSovereignChainAction: + tr.startSovereignChain(action, verbose) + case UpgradeProposalAction: + tr.submitUpgradeProposal(action, verbose) + case waitUntilBlockAction: + tr.waitUntilBlockOnChain(action) + case ChangeoverChainAction: + tr.changeoverChain(action, verbose) case SendTokensAction: tr.sendTokens(action, verbose) case submitTextProposalAction: @@ -130,6 +139,8 @@ func (tr *TestRun) runStep(step Step, verbose bool) { tr.startConsumerChain(action, verbose) case addChainToRelayerAction: tr.addChainToRelayer(action, verbose) + case createIbcClientsAction: + tr.createIbcClientsHermes(action, verbose) case addIbcConnectionAction: tr.addIbcConnection(action, verbose) case addIbcChannelAction: diff --git a/tests/e2e/state.go b/tests/e2e/state.go index 9127c65df8..15500dd01f 100644 --- a/tests/e2e/state.go +++ b/tests/e2e/state.go @@ -50,6 +50,17 @@ type ConsumerAdditionProposal struct { Status string } +type UpgradeProposal struct { + Title string + Description string + UpgradeHeight uint64 + Type string + Deposit uint + Status string +} + +func (p UpgradeProposal) isProposal() {} + func (p ConsumerAdditionProposal) isProposal() {} type ConsumerRemovalProposal struct { @@ -214,6 +225,20 @@ func (tr TestRun) waitBlocks(chain chainID, blocks uint, timeout time.Duration) } } +func (tr TestRun) waitUntilBlock(chain chainID, block uint, timeout time.Duration) { + start := time.Now() + for { + thisBlock := tr.getBlockHeight(chain) + if thisBlock >= block { + return + } + if time.Since(start) > timeout { + panic(fmt.Sprintf("\n\n\nwaitBlocks method has timed out after: %s\n\n", timeout)) + } + time.Sleep(500 * time.Millisecond) + } +} + func (tr TestRun) getBalances(chain chainID, modelState map[validatorID]uint) map[validatorID]uint { actualState := map[validatorID]uint{} for k := range modelState { @@ -390,6 +415,16 @@ func (tr TestRun) getProposal(chain chainID, proposal uint) Proposal { RevisionHeight: gjson.Get(string(bz), `content.initial_height.revision_height`).Uint(), }, } + case "/cosmos.upgrade.v1beta1.SoftwareUpgradeProposal": + height := gjson.Get(string(bz), `content.plan.height`).Uint() + title := gjson.Get(string(bz), `content.plan.name`).String() + return UpgradeProposal{ + Deposit: uint(deposit), + Status: status, + UpgradeHeight: height, + Title: title, + Type: "/cosmos.upgrade.v1beta1.SoftwareUpgradeProposal", + } case "/interchain_security.ccv.provider.v1.ConsumerRemovalProposal": chainId := gjson.Get(string(bz), `content.chain_id`).String() stopTime := gjson.Get(string(bz), `content.stop_time`).Time().Sub(tr.containerConfig.now) @@ -691,7 +726,14 @@ func (tr TestRun) getQueryNode(chain chainID) string { } // getQueryNodeIP returns query node IP for chain, -// ipSuffix is hardcoded to be 253 on all query nodes. +// ipSuffix is hardcoded to be 253 on all query nodes +// except for "sover" chain where there's only one node func (tr TestRun) getQueryNodeIP(chain chainID) string { + if chain == chainID("sover") { + // return address of first and only validator + return fmt.Sprintf("%s.%s", + tr.chainConfigs[chain].ipPrefix, + tr.validatorConfigs[validatorID("alice")].ipSuffix) + } return fmt.Sprintf("%s.253", tr.chainConfigs[chain].ipPrefix) } diff --git a/tests/e2e/steps.go b/tests/e2e/steps.go index 8c0b4b2661..7613b05558 100644 --- a/tests/e2e/steps.go +++ b/tests/e2e/steps.go @@ -72,3 +72,18 @@ var multipleConsumers = concatSteps( stepsMultiConsumerDowntimeFromProvider("consu", "densu"), stepsMultiConsumerDoubleSign("consu", "densu"), // double sign on one of the chains ) + +var changeoverSteps = concatSteps( + // start sovereign chain and test delegation operation + + stepRunSovereignChain(), + stepStartProviderChain(), + stepsSovereignTransferChan(), + + // the chain will halt once upgrade height is reached + // after upgrade height is reached, the chain will become a consumer + stepsUpgradeChain(), + stepsChangeoverToConsumer("sover"), + + stepsPostChangeoverDelegate("sover"), +) diff --git a/tests/e2e/steps_sovereign_changeover.go b/tests/e2e/steps_sovereign_changeover.go new file mode 100644 index 0000000000..e122c1fb2a --- /dev/null +++ b/tests/e2e/steps_sovereign_changeover.go @@ -0,0 +1,367 @@ +package main + +import clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + +// this creates new clients on both chains and a connection (connection-0) between them +// connection-0 is used to create a transfer channel between the chains +// the transfer channel is maintained during the changeover process, meaning that +// the consumer chain will be able to send rewards to the provider chain using the old channel +// as opposed to creating a new transfer channel which happens for new consumers +func stepsSovereignTransferChan() []Step { + return []Step{ + { + action: createIbcClientsAction{ + chainA: chainID("sover"), + chainB: chainID("provi"), + }, + state: State{}, + }, + { + // this will create channel-0 connection end on both chain + action: addIbcChannelAction{ + chainA: chainID("sover"), + chainB: chainID("provi"), + connectionA: 0, + portA: "transfer", + portB: "transfer", + order: "unordered", + version: "ics20-1", + }, + state: State{}, + }, + } +} + +// steps to convert sovereign to consumer chain +func stepsChangeoverToConsumer(consumerName string) []Step { + s := []Step{ + { + action: submitConsumerAdditionProposalAction{ + preCCV: true, + chain: chainID("provi"), + from: validatorID("alice"), + deposit: 10000001, + consumerChain: chainID(consumerName), + // chain-0 is the transfer channelID that gets created in stepsSovereignTransferChan + // the consumer chain will use this channel to send rewards to the provider chain + // there is no need to create a new channel for rewards distribution + distributionChannel: "channel-0", + spawnTime: 0, + initialHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: 111}, // 1 block after upgrade !important + }, + state: State{ + chainID("provi"): ChainState{ + ValBalances: &map[validatorID]uint{ + validatorID("alice"): 9489999999, + validatorID("bob"): 9500000000, + }, + Proposals: &map[uint]Proposal{ + 1: ConsumerAdditionProposal{ + Deposit: 10000001, + Chain: chainID(consumerName), + SpawnTime: 0, + InitialHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: 111}, + Status: "PROPOSAL_STATUS_VOTING_PERIOD", + }, + }, + }, + }, + }, + { + action: voteGovProposalAction{ + chain: chainID("provi"), + from: []validatorID{validatorID("alice"), validatorID("bob"), validatorID("carol")}, + vote: []string{"yes", "yes", "yes"}, + propNumber: 1, + }, + state: State{ + chainID("provi"): ChainState{ + Proposals: &map[uint]Proposal{ + 1: ConsumerAdditionProposal{ + Deposit: 10000001, + Chain: chainID(consumerName), + SpawnTime: 0, + InitialHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: 111}, + Status: "PROPOSAL_STATUS_PASSED", + }, + }, + ValBalances: &map[validatorID]uint{ + validatorID("alice"): 9500000000, + validatorID("bob"): 9500000000, + }, + }, + }, + }, + { + action: ChangeoverChainAction{ + sovereignChain: chainID(consumerName), + providerChain: chainID("provi"), + validators: []StartChainValidator{ + {id: validatorID("alice"), stake: 500000000, allocation: 10000000000}, + {id: validatorID("bob"), stake: 500000000, allocation: 10000000000}, + {id: validatorID("carol"), stake: 500000000, allocation: 10000000000}, + }, + genesisChanges: ".app_state.ccvconsumer.params.soft_opt_out_threshold = \"0.05\"", + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 500, + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + chainID(consumerName): ChainState{ + ValPowers: &map[validatorID]uint{ + // uses val powers from consumer + validatorID("alice"): 500, + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + }, + }, + { + action: addIbcConnectionAction{ + chainA: chainID(consumerName), + chainB: chainID("provi"), + clientA: 1, + clientB: 1, + }, + state: State{}, + }, + { + action: addIbcChannelAction{ + chainA: chainID(consumerName), + chainB: chainID("provi"), + connectionA: 1, + portA: "consumer", + portB: "provider", + order: "ordered", + }, + state: State{}, + }, + } + + return s +} + +// start sovereign chain with a single validator so it is easier to manage +// when the chain is converted to a consumer chain the validators from the +// consumer chain will be used +// validatoralice is the only validator on the sovereign chain that is in both +// sovereign validator set and consumer validator set +func stepRunSovereignChain() []Step { + return []Step{ + { + action: StartSovereignChainAction{ + chain: chainID("sover"), + validators: []StartChainValidator{ + {id: validatorID("alice"), stake: 500000000, allocation: 10000000000}, + }, + }, + state: State{ + chainID("sover"): ChainState{ + ValBalances: &map[validatorID]uint{ + validatorID("alice"): 9500000000, + }, + }, + }, + }, + { + action: delegateTokensAction{ + chain: chainID("sover"), + from: validatorID("alice"), + to: validatorID("alice"), + amount: 11000000, + }, + state: State{ + chainID("sover"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 511, + validatorID("bob"): 0, // does not exist on pre-ccv sover + validatorID("carol"): 0, // does not exist on pre-ccv sover + }, + }, + }, + }, + } +} + +// TODO: use args instead of hardcoding +func stepsUpgradeChain() []Step { + return []Step{ + { + action: UpgradeProposalAction{ + chainID: chainID("sover"), + upgradeTitle: "sovereign-changeover", + proposer: validatorID("alice"), + upgradeHeight: 110, + }, + state: State{ + chainID("sover"): ChainState{ + Proposals: &map[uint]Proposal{ + 1: UpgradeProposal{ + Title: "sovereign-changeover", + UpgradeHeight: 110, + Type: "/cosmos.upgrade.v1beta1.SoftwareUpgradeProposal", + Deposit: 10000000, + Status: "PROPOSAL_STATUS_VOTING_PERIOD", + }, + }, + }, + }, + }, + { + action: voteGovProposalAction{ + chain: chainID("sover"), + from: []validatorID{validatorID("alice")}, + vote: []string{"yes"}, + propNumber: 1, + }, + state: State{ + chainID("sover"): ChainState{ + Proposals: &map[uint]Proposal{ + 1: UpgradeProposal{ + Deposit: 10000000, + UpgradeHeight: 110, + Title: "sovereign-changeover", + Type: "/cosmos.upgrade.v1beta1.SoftwareUpgradeProposal", + Status: "PROPOSAL_STATUS_PASSED", + }, + }, + }, + }, + }, + { + action: waitUntilBlockAction{ + chain: chainID("sover"), + block: 110, + }, + state: State{}, + }, + } +} + +// stepsPostChangeoverDelegate tests basic delegation and resulting validator power changes after changeover +// we cannot use stepsDelegate and stepsUnbond because they make assumptions about which connection to use +// here we need to use connection-1, and in tests with new consumers connection-0 is used because the chain is new (has no IBC states prior to launch) +func stepsPostChangeoverDelegate(consumerName string) []Step { + return []Step{ + { + action: SendTokensAction{ + chain: chainID(consumerName), + from: validatorID("alice"), + to: validatorID("bob"), + amount: 100, + }, + state: State{ + chainID(consumerName): ChainState{ + // Tx should not go through, ICS channel is not setup until first VSC packet has been relayed to consumer + ValBalances: &map[validatorID]uint{ + validatorID("bob"): 0, + }, + }, + }, + }, + { + action: delegateTokensAction{ + chain: chainID("provi"), + from: validatorID("alice"), + to: validatorID("alice"), + amount: 11000000, + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 511, + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + chainID(consumerName): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 500, + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + }, + }, + { + action: relayPacketsAction{ + chainA: chainID("provi"), + chainB: chainID(consumerName), + port: "provider", + channel: 1, + }, + state: State{ + chainID(consumerName): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 511, + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + }, + }, + { + action: SendTokensAction{ + chain: chainID(consumerName), + from: validatorID("alice"), + to: validatorID("bob"), + amount: 100, + }, + state: State{ + chainID(consumerName): ChainState{ + // Tx should go through, ICS channel is setup + ValBalances: &map[validatorID]uint{ + validatorID("bob"): 100, + }, + }, + }, + }, + { + action: unbondTokensAction{ + chain: chainID("provi"), + unbondFrom: validatorID("alice"), + sender: validatorID("alice"), + amount: 1000000, + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 510, + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + chainID(consumerName): ChainState{ + ValPowers: &map[validatorID]uint{ + // Voting power on consumer should not be affected yet + validatorID("alice"): 511, + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + }, + }, + { + action: relayPacketsAction{ + chainA: chainID("provi"), + chainB: chainID(consumerName), + port: "provider", + channel: 1, + }, + state: State{ + chainID(consumerName): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 510, + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + }, + }, + } +} diff --git a/tests/e2e/testnet-scripts/sovereign-genesis.json b/tests/e2e/testnet-scripts/sovereign-genesis.json new file mode 100644 index 0000000000..94a279840e --- /dev/null +++ b/tests/e2e/testnet-scripts/sovereign-genesis.json @@ -0,0 +1,279 @@ +{ + "genesis_time": "2023-06-13T11:19:05.998449459Z", + "chain_id": "sover", + "initial_height": "1", + "consensus_params": { + "block": { + "max_bytes": "22020096", + "max_gas": "-1", + "time_iota_ms": "1000" + }, + "evidence": { + "max_age_num_blocks": "100000", + "max_age_duration": "172800000000000", + "max_bytes": "1048576" + }, + "validator": { + "pub_key_types": [ + "ed25519" + ] + }, + "version": {} + }, + "app_hash": "", + "app_state": { + "auth": { + "params": { + "max_memo_characters": "256", + "tx_sig_limit": "7", + "tx_size_cost_per_byte": "10", + "sig_verify_cost_ed25519": "590", + "sig_verify_cost_secp256k1": "1000" + }, + "accounts": [ + { + "@type": "/cosmos.auth.v1beta1.BaseAccount", + "address": "cosmos19pe9pg5dv9k5fzgzmsrgnw9rl9asf7ddwhu7lm", + "pub_key": null, + "account_number": "0", + "sequence": "0" + } + ] + }, + "authz": { + "authorization": [] + }, + "bank": { + "params": { + "send_enabled": [], + "default_send_enabled": true + }, + "balances": [ + { + "address": "cosmos19pe9pg5dv9k5fzgzmsrgnw9rl9asf7ddwhu7lm", + "coins": [ + { + "denom": "stake", + "amount": "10000000000" + } + ] + } + ], + "supply": [ + { + "denom": "stake", + "amount": "10000000000" + } + ], + "denom_metadata": [] + }, + "capability": { + "index": "1", + "owners": [] + }, + "crisis": { + "constant_fee": { + "denom": "stake", + "amount": "1000" + } + }, + "distribution": { + "params": { + "community_tax": "0.020000000000000000", + "base_proposer_reward": "0.010000000000000000", + "bonus_proposer_reward": "0.040000000000000000", + "withdraw_addr_enabled": true + }, + "fee_pool": { + "community_pool": [] + }, + "delegator_withdraw_infos": [], + "previous_proposer": "", + "outstanding_rewards": [], + "validator_accumulated_commissions": [], + "validator_historical_rewards": [], + "validator_current_rewards": [], + "delegator_starting_infos": [], + "validator_slash_events": [] + }, + "evidence": { + "evidence": [] + }, + "feegrant": { + "allowances": [] + }, + "genutil": { + "gen_txs": [ + { + "body": { + "messages": [ + { + "@type": "/cosmos.staking.v1beta1.MsgCreateValidator", + "description": { + "moniker": "validatoralice", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "commission": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "min_self_delegation": "1", + "delegator_address": "cosmos19pe9pg5dv9k5fzgzmsrgnw9rl9asf7ddwhu7lm", + "validator_address": "cosmosvaloper19pe9pg5dv9k5fzgzmsrgnw9rl9asf7ddtrgtng", + "pubkey": { + "@type": "/cosmos.crypto.ed25519.PubKey", + "key": "RrclQz9bIhkIy/gfL485g3PYMeiIku4qeo495787X10=" + }, + "value": { + "denom": "stake", + "amount": "500000000" + } + } + ], + "memo": "8339e14baab81c2a2350e261962263397a8d7fb0@7.7.8.254:26656", + "timeout_height": "0", + "extension_options": [], + "non_critical_extension_options": [] + }, + "auth_info": { + "signer_infos": [ + { + "public_key": { + "@type": "/cosmos.crypto.secp256k1.PubKey", + "key": "AsFC8tmbGGQSHthsVStbsQ13/+Yza9IT8KCSXXEN7y9f" + }, + "mode_info": { + "single": { + "mode": "SIGN_MODE_DIRECT" + } + }, + "sequence": "0" + } + ], + "fee": { + "amount": [], + "gas_limit": "200000", + "payer": "", + "granter": "" + } + }, + "signatures": [ + "rZuml3RLgrrZkUoNHw90FuHF/Orxzs0uiwflCkUOcvoA4bzohisjdQhkPWCn5aRw30mqZJGj1IxgXS15XleMvQ==" + ] + } + ] + }, + "gov": { + "starting_proposal_id": "1", + "deposits": [], + "votes": [], + "proposals": [], + "deposit_params": { + "min_deposit": [ + { + "denom": "stake", + "amount": "10000000" + } + ], + "max_deposit_period": "172800s" + }, + "voting_params": { + "voting_period": "20s" + }, + "tally_params": { + "quorum": "0.334000000000000000", + "threshold": "0.500000000000000000", + "veto_threshold": "0.334000000000000000" + } + }, + "ibc": { + "client_genesis": { + "clients": [], + "clients_consensus": [], + "clients_metadata": [], + "params": { + "allowed_clients": [ + "06-solomachine", + "07-tendermint" + ] + }, + "create_localhost": false, + "next_client_sequence": "0" + }, + "connection_genesis": { + "connections": [], + "client_connection_paths": [], + "next_connection_sequence": "0", + "params": { + "max_expected_time_per_block": "30000000000" + } + }, + "channel_genesis": { + "channels": [], + "acknowledgements": [], + "commitments": [], + "receipts": [], + "send_sequences": [], + "recv_sequences": [], + "ack_sequences": [], + "next_channel_sequence": "0" + } + }, + "mint": { + "minter": { + "inflation": "0.130000000000000000", + "annual_provisions": "0.000000000000000000" + }, + "params": { + "mint_denom": "stake", + "inflation_rate_change": "0.130000000000000000", + "inflation_max": "0.200000000000000000", + "inflation_min": "0.070000000000000000", + "goal_bonded": "0.670000000000000000", + "blocks_per_year": "6311520" + } + }, + "params": null, + "slashing": { + "params": { + "signed_blocks_window": "15", + "min_signed_per_window": "0.500000000000000000", + "downtime_jail_duration": "2s", + "slash_fraction_double_sign": "0.050000000000000000", + "slash_fraction_downtime": "0.010000000000000000" + }, + "signing_infos": [], + "missed_blocks": [] + }, + "staking": { + "params": { + "unbonding_time": "1814400s", + "max_validators": 100, + "max_entries": 7, + "historical_entries": 10000, + "bond_denom": "stake" + }, + "last_total_power": "0", + "last_validator_powers": [], + "validators": [], + "delegations": [], + "unbonding_delegations": [], + "redelegations": [], + "exported": false + }, + "transfer": { + "port_id": "transfer", + "denom_traces": [], + "params": { + "send_enabled": true, + "receive_enabled": true + } + }, + "upgrade": {}, + "vesting": {} + } + } \ No newline at end of file diff --git a/tests/e2e/testnet-scripts/start-changeover.sh b/tests/e2e/testnet-scripts/start-changeover.sh new file mode 100644 index 0000000000..d28479a8e7 --- /dev/null +++ b/tests/e2e/testnet-scripts/start-changeover.sh @@ -0,0 +1,187 @@ +#!/bin/bash +set -eux + +# The gaiad binary +BIN=$1 + +# JSON array of validator information +# [{ +# mnemonic: "crackle snap pop ... etc", +# allocation: "10000000000stake,10000000000footoken", +# stake: "5000000000stake", +# val_id: "alice", +# ip_suffix: "1", +# priv_validator_key: "{\"address\": \"3566F464673B2F069758DAE86FC25D04017BB147\",\"pub_key\": {\"type\": \"tendermint/PubKeyEd25519\",\"value\": \"XrLjKdc4mB2gfqplvnoySjSJq2E90RynUwaO3WhJutk=\"},\"priv_key\": {\"type\": \"tendermint/PrivKeyEd25519\",\"value\": \"czGSLs/Ocau8aJ5J5zQHMxf3d7NR0xjMECN6YGTIWqtesuMp1ziYHaB+qmW+ejJKNImrYT3RHKdTBo7daEm62Q==\"}}" +# node_key: "{\"priv_key\":{\"type\":\"tendermint/PrivKeyEd25519\",\"value\":\"alIHj6hXnzpLAadgb7+E2eeecwxoNdzuZrfhMX36EaD5/LgzL0ZUoVp7AK3np0K5T35JWLLv0jJKmeRIhG0GjA==\"}}" +# }, ... ] +VALIDATORS=$2 + +# The chain ID +CHAIN_ID=$3 + +# This is the first 3 fields of the IP addresses which will be used internally by the validators of this blockchain +# Recommended to use something starting with 7, since it is squatted by the DoD and is unroutable on the internet +# For example: "7.7.7" +CHAIN_IP_PREFIX=$4 + +# A transformation to apply to the genesis file, as a jq string +GENESIS_TRANSFORM=$5 + +# A sed string modifying the tendermint config +TENDERMINT_CONFIG_TRANSFORM=$6 + + +# CREATE VALIDATORS AND DO GENESIS CEREMONY +# !!!!!!!!!!!!!! IMPORTANT !!!!!!!!!!!!!!!! # +# data dir from the sovereign chain is copied to other nodes (namely bob and carol) +# alice simply performs a chain upgrade +echo "killing nodes" +pkill -f "^"interchain-security-sd &> /dev/null || true + +mkdir -p /root/.sovereign/config + +# apply genesis changes to existing genesis -> this creates the changeover genesis file wih intial validator set +jq "$GENESIS_TRANSFORM" /sover/validatoralice/config/genesis.json > /root/.sovereign/config/genesis.json + + +# Get number of nodes from length of validators array +NODES=$(echo "$VALIDATORS" | jq '. | length') + +# SETUP NETWORK NAMESPACES, see: https://adil.medium.com/container-networking-under-the-hood-network-namespaces-6b2b8fe8dc2a + +# Create virtual bridge device (acts like a switch) +ip link add name virtual-bridge type bridge || true + +for i in $(seq 0 $(($NODES - 1))); +do + # first validator is already setup + if [[ "$i" -ne 0 ]]; then + VAL_ID=$(echo "$VALIDATORS" | jq -r ".[$i].val_id") + VAL_IP_SUFFIX=$(echo "$VALIDATORS" | jq -r ".[$i].ip_suffix") + NET_NAMESPACE_NAME="$CHAIN_ID-$VAL_ID" + IP_ADDR="$CHAIN_IP_PREFIX.$VAL_IP_SUFFIX/24" + + # Create network namespace + ip netns add $NET_NAMESPACE_NAME + # Create virtual ethernet device to connect with bridge + ip link add $NET_NAMESPACE_NAME-in type veth peer name $NET_NAMESPACE_NAME-out + # Connect input end of virtual ethernet device to namespace + ip link set $NET_NAMESPACE_NAME-in netns $NET_NAMESPACE_NAME + # Assign ip address to namespace + ip netns exec $NET_NAMESPACE_NAME ip addr add $IP_ADDR dev $NET_NAMESPACE_NAME-in + # Connect output end of virtual ethernet device to bridge + ip link set $NET_NAMESPACE_NAME-out master virtual-bridge + fi +done + +# Enable bridge interface +ip link set virtual-bridge up + +for i in $(seq 0 $(($NODES - 1))); +do + # first validator is already setup + if [[ "$i" -ne 0 ]]; then + VAL_ID=$(echo "$VALIDATORS" | jq -r ".[$i].val_id") + NET_NAMESPACE_NAME="$CHAIN_ID-$VAL_ID" + + # Enable in/out interfaces for the namespace + ip link set $NET_NAMESPACE_NAME-out up + ip netns exec $NET_NAMESPACE_NAME ip link set dev $NET_NAMESPACE_NAME-in up + # Enable loopback device + ip netns exec $NET_NAMESPACE_NAME ip link set dev lo up + fi +done + +# Assign IP for bridge, to route between default network namespace and bridge +# BRIDGE_IP="$CHAIN_IP_PREFIX.254/24" +# ip addr add $BRIDGE_IP dev virtual-bridge + + +# HANDLE VALIDATOR HOMES, COPY OLD DATA FOLDER +for i in $(seq 0 $(($NODES - 1))); +do + # first validator is already setup + if [[ "$i" -ne 0 ]]; then + VAL_ID=$(echo "$VALIDATORS" | jq -r ".[$i].val_id") + echo "$VALIDATORS" | jq -r ".[$i].mnemonic" | $BIN keys add validator$VAL_ID \ + --home /$CHAIN_ID/validator$VAL_ID \ + --keyring-backend test \ + --recover > /dev/null + + # Copy in the genesis.json + cp /sover/validatoralice/config/genesis.json /$CHAIN_ID/validator$VAL_ID/config/genesis.json + cp -r /sover/validatoralice/data /$CHAIN_ID/validator$VAL_ID/ + + # Copy in validator state file + # echo '{"height": "0","round": 0,"step": 0}' > /$CHAIN_ID/validator$VAL_ID/data/priv_validator_state.json + + + PRIV_VALIDATOR_KEY=$(echo "$VALIDATORS" | jq -r ".[$i].priv_validator_key") + if [[ "$PRIV_VALIDATOR_KEY" ]]; then + echo "$PRIV_VALIDATOR_KEY" > /$CHAIN_ID/validator$VAL_ID/config/priv_validator_key.json + fi + + NODE_KEY=$(echo "$VALIDATORS" | jq -r ".[$i].node_key") + if [[ "$NODE_KEY" ]]; then + echo "$NODE_KEY" > /$CHAIN_ID/validator$VAL_ID/config/node_key.json + fi + + # Modify tendermint configs of validator + if [ "$TENDERMINT_CONFIG_TRANSFORM" != "" ] ; then + #'s/foo/bar/;s/abc/def/' + sed -i "$TENDERMINT_CONFIG_TRANSFORM" $CHAIN_ID/validator$VAL_ID/config/config.toml + fi + fi +done + + +# START VALIDATOR NODES -> this will perform the sovereign upgrade and start the chain +# ALICE is a validator on the sovereign and also the validator on the consumer chain +# BOB, CAROL are not validators on the sovereign, they will become validator once the chain switches to the consumer chain +echo "Starting validator nodes..." +for i in $(seq 0 $(($NODES - 1))); +do + VAL_ID=$(echo "$VALIDATORS" | jq -r ".[$i].val_id") + VAL_IP_SUFFIX=$(echo "$VALIDATORS" | jq -r ".[$i].ip_suffix") + NET_NAMESPACE_NAME="$CHAIN_ID-$VAL_ID" + + GAIA_HOME="--home /$CHAIN_ID/validator$VAL_ID" + RPC_ADDRESS="--rpc.laddr tcp://$CHAIN_IP_PREFIX.$VAL_IP_SUFFIX:26658" + GRPC_ADDRESS="--grpc.address $CHAIN_IP_PREFIX.$VAL_IP_SUFFIX:9091" + LISTEN_ADDRESS="--address tcp://$CHAIN_IP_PREFIX.$VAL_IP_SUFFIX:26655" + P2P_ADDRESS="--p2p.laddr tcp://$CHAIN_IP_PREFIX.$VAL_IP_SUFFIX:26656" + # LOG_LEVEL="--log_level trace" # switch to trace to see panic messages and rich and all debug msgs + LOG_LEVEL="--log_level info" + ENABLE_WEBGRPC="--grpc-web.enable=false" + + PERSISTENT_PEERS="" + + for j in $(seq 0 $(($NODES - 1))); + do + if [ $i -ne $j ]; then + PEER_VAL_ID=$(echo "$VALIDATORS" | jq -r ".[$j].val_id") + PEER_VAL_IP_SUFFIX=$(echo "$VALIDATORS" | jq -r ".[$j].ip_suffix") + NODE_ID=$($BIN tendermint show-node-id --home /$CHAIN_ID/validator$PEER_VAL_ID) + ADDRESS="$NODE_ID@$CHAIN_IP_PREFIX.$PEER_VAL_IP_SUFFIX:26656" + # (jq -r '.body.memo' /$CHAIN_ID/validator$j/config/gentx/*) # Getting the address from the gentx should also work + PERSISTENT_PEERS="$PERSISTENT_PEERS,$ADDRESS" + fi + done + + # Remove leading comma and concat to flag + PERSISTENT_PEERS="--p2p.persistent_peers ${PERSISTENT_PEERS:1}" + + ARGS="$GAIA_HOME $LISTEN_ADDRESS $RPC_ADDRESS $GRPC_ADDRESS $LOG_LEVEL $P2P_ADDRESS $ENABLE_WEBGRPC $PERSISTENT_PEERS" + ip netns exec $NET_NAMESPACE_NAME $BIN $ARGS start &> /$CHAIN_ID/validator$VAL_ID/logs & +done + +QUERY_NODE_SUFFIX=$(echo "$VALIDATORS" | jq -r ".[0].ip_suffix") +echo "NODE SUFFIX: $QUERY_NODE_SUFFIX" +# poll for chain start +set +e +until $BIN query block --node "tcp://$CHAIN_IP_PREFIX.$QUERY_NODE_SUFFIX:26658" | grep -q -v '{"block_id":{"hash":"","parts":{"total":0,"hash":""}},"block":null}'; do sleep 0.3 ; done +set -e + +echo "done!!!!!!!!" + +read -p "Press Return to Close..." \ No newline at end of file diff --git a/tests/e2e/testnet-scripts/start-sovereign.sh b/tests/e2e/testnet-scripts/start-sovereign.sh new file mode 100644 index 0000000000..9daed9a207 --- /dev/null +++ b/tests/e2e/testnet-scripts/start-sovereign.sh @@ -0,0 +1,133 @@ +#!/bin/bash +set -eux + +# The gaiad binary +BIN=$1 + +# JSON array of validator information +# [{ +# mnemonic: "crackle snap pop ... etc", +# allocation: "10000000000stake,10000000000footoken", +# stake: "5000000000stake", +# val_id: "alice", +# ip_suffix: "1", +# priv_validator_key: "{\"address\": \"3566F464673B2F069758DAE86FC25D04017BB147\",\"pub_key\": {\"type\": \"tendermint/PubKeyEd25519\",\"value\": \"XrLjKdc4mB2gfqplvnoySjSJq2E90RynUwaO3WhJutk=\"},\"priv_key\": {\"type\": \"tendermint/PrivKeyEd25519\",\"value\": \"czGSLs/Ocau8aJ5J5zQHMxf3d7NR0xjMECN6YGTIWqtesuMp1ziYHaB+qmW+ejJKNImrYT3RHKdTBo7daEm62Q==\"}}" +# node_key: "{\"priv_key\":{\"type\":\"tendermint/PrivKeyEd25519\",\"value\":\"alIHj6hXnzpLAadgb7+E2eeecwxoNdzuZrfhMX36EaD5/LgzL0ZUoVp7AK3np0K5T35JWLLv0jJKmeRIhG0GjA==\"}}" +# }, ... ] +VALIDATORS=$2 + +# The chain ID +CHAIN_ID=$3 + +# This is the first 3 fields of the IP addresses which will be used internally by the validators of this blockchain +# Recommended to use something starting with 7, since it is squatted by the DoD and is unroutable on the internet +# For example: "7.7.7" +CHAIN_IP_PREFIX=$4 + +# A transformation to apply to the genesis file, as a jq string +GENESIS_TRANSFORM=$5 + +# A sed string modifying the tendermint config +TENDERMINT_CONFIG_TRANSFORM=$6 + +# SETUP NETWORK NAMESPACES, see: https://adil.medium.com/container-networking-under-the-hood-network-namespaces-6b2b8fe8dc2a + +# Create virtual bridge device (acts like a switch) +ip link add name virtual-bridge type bridge || true + +# used globally in the whole script +VAL_ID=$(echo "$VALIDATORS" | jq -r ".[0].val_id") +VAL_IP_SUFFIX=$(echo "$VALIDATORS" | jq -r ".[0].ip_suffix") +NET_NAMESPACE_NAME="$CHAIN_ID-$VAL_ID" +IP_ADDR="$CHAIN_IP_PREFIX.$VAL_IP_SUFFIX/24" + +# Create network namespace +ip netns add $NET_NAMESPACE_NAME +# Create virtual ethernet device to connect with bridge +ip link add $NET_NAMESPACE_NAME-in type veth peer name $NET_NAMESPACE_NAME-out +# Connect input end of virtual ethernet device to namespace +ip link set $NET_NAMESPACE_NAME-in netns $NET_NAMESPACE_NAME +# Assign ip address to namespace +ip netns exec $NET_NAMESPACE_NAME ip addr add $IP_ADDR dev $NET_NAMESPACE_NAME-in +# Connect output end of virtual ethernet device to bridge +ip link set $NET_NAMESPACE_NAME-out master virtual-bridge + +# Enable bridge interface +ip link set virtual-bridge up + +NET_NAMESPACE_NAME="$CHAIN_ID-$VAL_ID" +# Enable in/out interfaces for the namespace +ip link set $NET_NAMESPACE_NAME-out up +ip netns exec $NET_NAMESPACE_NAME ip link set dev $NET_NAMESPACE_NAME-in up +# Enable loopback device +ip netns exec $NET_NAMESPACE_NAME ip link set dev lo up + +# Assign IP for bridge, to route between default network namespace and bridge +BRIDGE_IP="$CHAIN_IP_PREFIX.254/24" +ip addr add $BRIDGE_IP dev virtual-bridge + +# first we start a genesis.json with the first validator +# the first validator will also collect the gentx's once gnerated +echo "$VALIDATORS" | jq -r ".[0].mnemonic" | $BIN init --home /$CHAIN_ID/validator$VAL_ID --chain-id=$CHAIN_ID validator$VAL_ID --recover > /dev/null + +# !!!!!!!!! IMPORTANT !!!!!!!!! # +# move the sovereign genesis to the correct validator home dir +cp /testnet-scripts/sovereign-genesis.json /$CHAIN_ID/validator$VAL_ID/config/genesis.json + +# Apply jq transformations to genesis file +jq "$GENESIS_TRANSFORM" /$CHAIN_ID/validator$VAL_ID/config/genesis.json > /$CHAIN_ID/edited-genesis.json +mv /$CHAIN_ID/edited-genesis.json /$CHAIN_ID/genesis.json +cp /$CHAIN_ID/genesis.json /$CHAIN_ID/validator$VAL_ID/config/genesis.json + + + +# SETUP LOCAL VALIDATOR STATE +echo '{"height": "0","round": 0,"step": 0}' > /$CHAIN_ID/validator$VAL_ID/data/priv_validator_state.json + +PRIV_VALIDATOR_KEY=$(echo "$VALIDATORS" | jq -r ".[0].priv_validator_key") +if [[ "$PRIV_VALIDATOR_KEY" ]]; then + echo "$PRIV_VALIDATOR_KEY" > /$CHAIN_ID/validator$VAL_ID/config/priv_validator_key.json +fi + +NODE_KEY=$(echo "$VALIDATORS" | jq -r ".[0].node_key") +if [[ "$NODE_KEY" ]]; then + echo "$NODE_KEY" > /$CHAIN_ID/validator$VAL_ID/config/node_key.json +fi + +echo "$VALIDATORS" | jq -r ".[0].mnemonic" | $BIN keys add validator$VAL_ID \ +--home /$CHAIN_ID/validator$VAL_ID \ +--keyring-backend test \ +--recover > /dev/null + +# Modify tendermint configs of validator +if [ "$TENDERMINT_CONFIG_TRANSFORM" != "" ] ; then + #'s/foo/bar/;s/abc/def/' + sed -i "$TENDERMINT_CONFIG_TRANSFORM" $CHAIN_ID/validator$VAL_ID/config/config.toml +fi + + +# START VALIDATOR NODE +VAL_IP_SUFFIX=$(echo "$VALIDATORS" | jq -r ".[0].ip_suffix") +NET_NAMESPACE_NAME="$CHAIN_ID-$VAL_ID" + +GAIA_HOME="--home /$CHAIN_ID/validator$VAL_ID" +RPC_ADDRESS="--rpc.laddr tcp://$CHAIN_IP_PREFIX.$VAL_IP_SUFFIX:26658" +GRPC_ADDRESS="--grpc.address $CHAIN_IP_PREFIX.$VAL_IP_SUFFIX:9091" +LISTEN_ADDRESS="--address tcp://$CHAIN_IP_PREFIX.$VAL_IP_SUFFIX:26655" +P2P_ADDRESS="--p2p.laddr tcp://$CHAIN_IP_PREFIX.$VAL_IP_SUFFIX:26656" +# LOG_LEVEL="--log_level trace" # switch to trace to see panic messages and rich and all debug msgs +LOG_LEVEL="--log_level info" +ENABLE_WEBGRPC="--grpc-web.enable=false" + +ARGS="$GAIA_HOME $LISTEN_ADDRESS $RPC_ADDRESS $GRPC_ADDRESS $LOG_LEVEL $P2P_ADDRESS $ENABLE_WEBGRPC" +ip netns exec $NET_NAMESPACE_NAME $BIN $ARGS start &> /$CHAIN_ID/validator$VAL_ID/logs & + + +# poll for chain start +set +e +until $BIN query block --node "tcp://$CHAIN_IP_PREFIX.$VAL_IP_SUFFIX:26658" | grep -q -v '{"block_id":{"hash":"","parts":{"total":0,"hash":""}},"block":null}'; do sleep 0.3 ; done +set -e + +echo "done!!!!!!!!" + +read -p "Press Return to Close..." \ No newline at end of file diff --git a/tests/integration/changeover.go b/tests/integration/changeover.go index 3bf4e11932..13d18a4026 100644 --- a/tests/integration/changeover.go +++ b/tests/integration/changeover.go @@ -34,7 +34,7 @@ func (suite *CCVTestSuite) TestRecycleTransferChannel() { // Setup state s.t. the consumer keeper emulates a consumer that was previously standalone consumerKeeper.MarkAsPrevStandaloneChain(suite.consumerCtx()) suite.Require().True(consumerKeeper.IsPrevStandaloneChain(suite.consumerCtx())) - suite.consumerApp.GetConsumerKeeper().SetStandaloneTransferChannelID(suite.consumerCtx(), resp.ChannelId) + suite.consumerApp.GetConsumerKeeper().SetDistributionTransmissionChannel(suite.consumerCtx(), resp.ChannelId) // Now finish setting up CCV channel suite.ExecuteCCVChannelHandshake(suite.path) diff --git a/testutil/keeper/unit_test_helpers.go b/testutil/keeper/unit_test_helpers.go index 426a94b4b6..77a597c726 100644 --- a/testutil/keeper/unit_test_helpers.go +++ b/testutil/keeper/unit_test_helpers.go @@ -237,6 +237,7 @@ func GetTestConsumerAdditionProp() *providertypes.ConsumerAdditionProposal { time.Now(), consumertypes.DefaultConsumerRedistributeFrac, consumertypes.DefaultBlocksPerDistributionTransmission, + "", consumertypes.DefaultHistoricalEntries, types.DefaultCCVTimeoutPeriod, consumertypes.DefaultTransferTimeoutPeriod, diff --git a/x/ccv/consumer/ibc_module.go b/x/ccv/consumer/ibc_module.go index d7191d0be0..b3dde3d48a 100644 --- a/x/ccv/consumer/ibc_module.go +++ b/x/ccv/consumer/ibc_module.go @@ -140,15 +140,10 @@ func (am AppModule) OnChanOpenAck( /////////////////////////////////////////////////// // Initialize distribution token transfer channel - // First check if an existing transfer channel exists, if this consumer was a previously standalone chain. - if am.keeper.IsPrevStandaloneChain(ctx) { - transChannelID := am.keeper.GetStandaloneTransferChannelID(ctx) - found := am.keeper.TransferChannelExists(ctx, transChannelID) - if found { - // If existing transfer channel is found, persist that channel ID and return - am.keeper.SetDistributionTransmissionChannel(ctx, transChannelID) - return nil - } + // First check if an existing transfer channel already exists. + transChannelID := am.keeper.GetDistributionTransmissionChannel(ctx) + if found := am.keeper.TransferChannelExists(ctx, transChannelID); found { + return nil } // NOTE The handshake for this channel is handled by the ibc-go/transfer diff --git a/x/ccv/consumer/ibc_module_test.go b/x/ccv/consumer/ibc_module_test.go index fc6c3d2200..4c8377a8c8 100644 --- a/x/ccv/consumer/ibc_module_test.go +++ b/x/ccv/consumer/ibc_module_test.go @@ -214,7 +214,7 @@ func TestOnChanOpenAck(t *testing.T) { expPass bool }{ { - "success", + "success - empty transferChannelID", func(keeper *consumerkeeper.Keeper, params *params, mocks testkeeper.MockedKeepers) { // Expected msg distrTransferMsg := channeltypes.NewMsgChannelOpenInit( @@ -226,8 +226,13 @@ func TestOnChanOpenAck(t *testing.T) { "", // signer unused ) + transferChannelID := "" + keeper.SetDistributionTransmissionChannel(params.ctx, transferChannelID) + // Expected mock calls gomock.InOrder( + mocks.MockChannelKeeper.EXPECT().GetChannel( + params.ctx, transfertypes.PortID, transferChannelID).Return(channeltypes.Channel{}, false).Times(1), mocks.MockChannelKeeper.EXPECT().GetChannel( params.ctx, params.portID, params.channelID).Return(channeltypes.Channel{ ConnectionHops: []string{"connectionID"}, diff --git a/x/ccv/consumer/keeper/changeover.go b/x/ccv/consumer/keeper/changeover.go index 50e1a57184..57770a077d 100644 --- a/x/ccv/consumer/keeper/changeover.go +++ b/x/ccv/consumer/keeper/changeover.go @@ -48,5 +48,6 @@ func (k Keeper) ChangeoverToConsumer(ctx sdk.Context) (initialValUpdates []abci. // Therefore we set the PreCCV state to false so the endblocker caller doesn't call this method again. k.DeletePreCCV(ctx) + k.Logger(ctx).Info("ICS changeover complete - you are now a consumer chain!") return initialValUpdates } diff --git a/x/ccv/consumer/keeper/keeper.go b/x/ccv/consumer/keeper/keeper.go index 54c1cd5577..d420bb9bd4 100644 --- a/x/ccv/consumer/keeper/keeper.go +++ b/x/ccv/consumer/keeper/keeper.go @@ -618,17 +618,3 @@ func (k Keeper) IsPrevStandaloneChain(ctx sdk.Context) bool { store := ctx.KVStore(k.storeKey) return store.Has(types.PrevStandaloneChainKey()) } - -// SetStandaloneTransferChannelID sets the channelID of an existing transfer channel, -// for a chain which used to be a standalone chain. -func (k Keeper) SetStandaloneTransferChannelID(ctx sdk.Context, channelID string) { - store := ctx.KVStore(k.storeKey) - store.Set(types.StandaloneTransferChannelIDKey(), []byte(channelID)) -} - -// GetStandaloneTransferChannelID returns the channelID of an existing transfer channel, -// for a chain which used to be a standalone chain. -func (k Keeper) GetStandaloneTransferChannelID(ctx sdk.Context) string { - store := ctx.KVStore(k.storeKey) - return string(store.Get(types.StandaloneTransferChannelIDKey())) -} diff --git a/x/ccv/consumer/keeper/keeper_test.go b/x/ccv/consumer/keeper/keeper_test.go index 4280f1de37..fe523ce7cf 100644 --- a/x/ccv/consumer/keeper/keeper_test.go +++ b/x/ccv/consumer/keeper/keeper_test.go @@ -541,19 +541,6 @@ func TestGetAllOutstandingDowntimes(t *testing.T) { require.Equal(t, result, expectedGetAllOrder) } -// TestStandaloneTransferChannelID tests the getter and setter for the existing transfer channel id -func TestStandaloneTransferChannelID(t *testing.T) { - ck, ctx, ctrl, _ := testkeeper.GetConsumerKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) - defer ctrl.Finish() - - // Test that the default value is empty - require.Equal(t, "", ck.GetStandaloneTransferChannelID(ctx)) - - // Test that the value can be set and retrieved - ck.SetStandaloneTransferChannelID(ctx, "channelID1234") - require.Equal(t, "channelID1234", ck.GetStandaloneTransferChannelID(ctx)) -} - func TestPrevStandaloneChainFlag(t *testing.T) { ck, ctx, ctrl, _ := testkeeper.GetConsumerKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() diff --git a/x/ccv/consumer/keeper/migration_test.go b/x/ccv/consumer/keeper/migration_test.go index ee14d2bcc8..29574a4808 100644 --- a/x/ccv/consumer/keeper/migration_test.go +++ b/x/ccv/consumer/keeper/migration_test.go @@ -116,7 +116,7 @@ func (p *v1Params) ParamSetPairs() paramtypes.ParamSetPairs { paramtypes.NewParamSetPair(consumertypes.KeyBlocksPerDistributionTransmission, p.BlocksPerDistributionTransmission, ccvtypes.ValidatePositiveInt64), paramtypes.NewParamSetPair(consumertypes.KeyDistributionTransmissionChannel, - p.DistributionTransmissionChannel, consumertypes.ValidateDistributionTransmissionChannel), + p.DistributionTransmissionChannel, ccvtypes.ValidateDistributionTransmissionChannel), paramtypes.NewParamSetPair(consumertypes.KeyProviderFeePoolAddrStr, p.ProviderFeePoolAddrStr, consumertypes.ValidateProviderFeePoolAddrStr), paramtypes.NewParamSetPair(ccvtypes.KeyCCVTimeoutPeriod, diff --git a/x/ccv/consumer/types/genesis_test.go b/x/ccv/consumer/types/genesis_test.go index f5e6ce075c..0398b39f54 100644 --- a/x/ccv/consumer/types/genesis_test.go +++ b/x/ccv/consumer/types/genesis_test.go @@ -210,7 +210,7 @@ func TestValidateInitialGenesisState(t *testing.T) { true, }, { - "invalid new consumer genesis state: invalid params", + "invalid new consumer genesis state: invalid params - ccvTimeoutPeriod", types.NewInitialGenesisState(cs, consensusState, valUpdates, types.NewParams( true, @@ -228,6 +228,25 @@ func TestValidateInitialGenesisState(t *testing.T) { )), true, }, + { + "invalid new consumer genesis state: invalid params - distributionTransmissionChannel", + types.NewInitialGenesisState(cs, consensusState, valUpdates, + types.NewParams( + true, + types.DefaultBlocksPerDistributionTransmission, + "badchannel/", + "", + ccv.DefaultCCVTimeoutPeriod, + types.DefaultTransferTimeoutPeriod, + types.DefaultConsumerRedistributeFrac, + types.DefaultHistoricalEntries, + types.DefaultConsumerUnbondingPeriod, + types.DefaultSoftOptOutThreshold, + []string{}, + []string{}, + )), + true, + }, } for _, c := range cases { diff --git a/x/ccv/consumer/types/params.go b/x/ccv/consumer/types/params.go index 509e3725b4..7ab51fbad8 100644 --- a/x/ccv/consumer/types/params.go +++ b/x/ccv/consumer/types/params.go @@ -113,7 +113,7 @@ func (p Params) Validate() error { if err := ccvtypes.ValidatePositiveInt64(p.BlocksPerDistributionTransmission); err != nil { return err } - if err := ValidateDistributionTransmissionChannel(p.DistributionTransmissionChannel); err != nil { + if err := ccvtypes.ValidateDistributionTransmissionChannel(p.DistributionTransmissionChannel); err != nil { return err } if err := ValidateProviderFeePoolAddrStr(p.ProviderFeePoolAddrStr); err != nil { @@ -153,7 +153,7 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { paramtypes.NewParamSetPair(KeyBlocksPerDistributionTransmission, p.BlocksPerDistributionTransmission, ccvtypes.ValidatePositiveInt64), paramtypes.NewParamSetPair(KeyDistributionTransmissionChannel, - p.DistributionTransmissionChannel, ValidateDistributionTransmissionChannel), + p.DistributionTransmissionChannel, ccvtypes.ValidateDistributionTransmissionChannel), paramtypes.NewParamSetPair(KeyProviderFeePoolAddrStr, p.ProviderFeePoolAddrStr, ValidateProviderFeePoolAddrStr), paramtypes.NewParamSetPair(ccvtypes.KeyCCVTimeoutPeriod, @@ -175,15 +175,6 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { } } -func ValidateDistributionTransmissionChannel(i interface{}) error { - // Accept empty string as valid, since this will be the default value on genesis - if i == "" { - return nil - } - // Otherwise validate as usual for a channelID - return ccvtypes.ValidateChannelIdentifier(i) -} - func ValidateProviderFeePoolAddrStr(i interface{}) error { // Accept empty string as valid, since this will be the default value on genesis if i == "" { diff --git a/x/ccv/provider/client/proposal_handler.go b/x/ccv/provider/client/proposal_handler.go index 19848d9282..76491b86d2 100644 --- a/x/ccv/provider/client/proposal_handler.go +++ b/x/ccv/provider/client/proposal_handler.go @@ -58,6 +58,7 @@ Where proposal.json contains: "spawn_time": "2022-01-27T15:59:50.121607-08:00", "blocks_per_distribution_transmission": 1000, "consumer_redistribution_fraction": "0.75", + "distribution_transmission_channel": "", "historical_entries": 10000, "transfer_timeout_period": 3600000000000, "ccv_timeout_period": 2419200000000000, @@ -82,7 +83,8 @@ Where proposal.json contains: content := types.NewConsumerAdditionProposal( proposal.Title, proposal.Description, proposal.ChainId, proposal.InitialHeight, proposal.GenesisHash, proposal.BinaryHash, proposal.SpawnTime, - proposal.ConsumerRedistributionFraction, proposal.BlocksPerDistributionTransmission, proposal.HistoricalEntries, + proposal.ConsumerRedistributionFraction, proposal.BlocksPerDistributionTransmission, + proposal.DistributionTransmissionChannel, proposal.HistoricalEntries, proposal.CcvTimeoutPeriod, proposal.TransferTimeoutPeriod, proposal.UnbondingPeriod) from := clientCtx.GetFromAddress() @@ -224,6 +226,7 @@ type ConsumerAdditionProposalJSON struct { ConsumerRedistributionFraction string `json:"consumer_redistribution_fraction"` BlocksPerDistributionTransmission int64 `json:"blocks_per_distribution_transmission"` + DistributionTransmissionChannel string `json:"distribution_transmission_channel"` HistoricalEntries int64 `json:"historical_entries"` CcvTimeoutPeriod time.Duration `json:"ccv_timeout_period"` TransferTimeoutPeriod time.Duration `json:"transfer_timeout_period"` @@ -246,6 +249,7 @@ type ConsumerAdditionProposalReq struct { ConsumerRedistributionFraction string `json:"consumer_redistribution_fraction"` BlocksPerDistributionTransmission int64 `json:"blocks_per_distribution_transmission"` + DistributionTransmissionChannel string `json:"distribution_transmission_channel"` HistoricalEntries int64 `json:"historical_entries"` CcvTimeoutPeriod time.Duration `json:"ccv_timeout_period"` TransferTimeoutPeriod time.Duration `json:"transfer_timeout_period"` @@ -375,7 +379,8 @@ func postConsumerAdditionProposalHandlerFn(clientCtx client.Context) http.Handle content := types.NewConsumerAdditionProposal( req.Title, req.Description, req.ChainId, req.InitialHeight, req.GenesisHash, req.BinaryHash, req.SpawnTime, - req.ConsumerRedistributionFraction, req.BlocksPerDistributionTransmission, req.HistoricalEntries, + req.ConsumerRedistributionFraction, req.BlocksPerDistributionTransmission, + req.DistributionTransmissionChannel, req.HistoricalEntries, req.CcvTimeoutPeriod, req.TransferTimeoutPeriod, req.UnbondingPeriod) msg, err := govtypes.NewMsgSubmitProposal(content, req.Deposit, req.Proposer) diff --git a/x/ccv/provider/keeper/proposal.go b/x/ccv/provider/keeper/proposal.go index dcff74385b..e50619c066 100644 --- a/x/ccv/provider/keeper/proposal.go +++ b/x/ccv/provider/keeper/proposal.go @@ -303,7 +303,7 @@ func (k Keeper) MakeConsumerGenesis( consumerGenesisParams := consumertypes.NewParams( true, prop.BlocksPerDistributionTransmission, - "", // distributionTransmissionChannel + prop.DistributionTransmissionChannel, "", // providerFeePoolAddrStr, prop.CcvTimeoutPeriod, prop.TransferTimeoutPeriod, diff --git a/x/ccv/provider/keeper/proposal_test.go b/x/ccv/provider/keeper/proposal_test.go index cb18a119b4..68ee7e9663 100644 --- a/x/ccv/provider/keeper/proposal_test.go +++ b/x/ccv/provider/keeper/proposal_test.go @@ -61,6 +61,7 @@ func TestHandleConsumerAdditionProposal(t *testing.T) { now, // Spawn time "0.75", 10, + "", 10000, 100000000000, 100000000000, @@ -85,6 +86,7 @@ func TestHandleConsumerAdditionProposal(t *testing.T) { now, "0.75", 10, + "", 10000, 100000000000, 100000000000, @@ -883,6 +885,7 @@ func TestBeginBlockInit(t *testing.T) { now.Add(-time.Hour*2).UTC(), "0.75", 10, + "", 10000, 100000000000, 100000000000, @@ -893,6 +896,7 @@ func TestBeginBlockInit(t *testing.T) { now.Add(-time.Hour*1).UTC(), "0.75", 10, + "", 10000, 100000000000, 100000000000, @@ -903,6 +907,7 @@ func TestBeginBlockInit(t *testing.T) { now.Add(time.Hour).UTC(), "0.75", 10, + "", 10000, 100000000000, 100000000000, @@ -913,6 +918,7 @@ func TestBeginBlockInit(t *testing.T) { now.UTC(), "0.75", 10, + "", 10000, 100000000000, 100000000000, diff --git a/x/ccv/provider/proposal_handler_test.go b/x/ccv/provider/proposal_handler_test.go index ddf3698b6f..1e8e9b34b5 100644 --- a/x/ccv/provider/proposal_handler_test.go +++ b/x/ccv/provider/proposal_handler_test.go @@ -41,6 +41,7 @@ func TestProviderProposalHandler(t *testing.T) { clienttypes.NewHeight(2, 3), []byte("gen_hash"), []byte("bin_hash"), now, "0.75", 10, + "", 10000, 100000000000, 100000000000, @@ -58,14 +59,14 @@ func TestProviderProposalHandler(t *testing.T) { }, { // no slash log for equivocation - name: "invalid equivocation posal", + name: "invalid equivocation proposal", content: providertypes.NewEquivocationProposal( "title", "description", []*evidencetypes.Equivocation{equivocation}), blockTime: hourFromNow, expValidEquivocation: false, }, { - name: "valid equivocation posal", + name: "valid equivocation proposal", content: providertypes.NewEquivocationProposal( "title", "description", []*evidencetypes.Equivocation{equivocation}), blockTime: hourFromNow, diff --git a/x/ccv/provider/types/proposal.go b/x/ccv/provider/types/proposal.go index 49fe00531f..913152e68c 100644 --- a/x/ccv/provider/types/proposal.go +++ b/x/ccv/provider/types/proposal.go @@ -36,7 +36,8 @@ func NewConsumerAdditionProposal(title, description, chainID string, initialHeight clienttypes.Height, genesisHash, binaryHash []byte, spawnTime time.Time, consumerRedistributionFraction string, - blocksPerDistributionTransmission, + blocksPerDistributionTransmission int64, + distributionTransmissionChannel string, historicalEntries int64, ccvTimeoutPeriod time.Duration, transferTimeoutPeriod time.Duration, @@ -52,6 +53,7 @@ func NewConsumerAdditionProposal(title, description, chainID string, SpawnTime: spawnTime, ConsumerRedistributionFraction: consumerRedistributionFraction, BlocksPerDistributionTransmission: blocksPerDistributionTransmission, + DistributionTransmissionChannel: distributionTransmissionChannel, HistoricalEntries: historicalEntries, CcvTimeoutPeriod: ccvTimeoutPeriod, TransferTimeoutPeriod: transferTimeoutPeriod, @@ -106,6 +108,10 @@ func (cccp *ConsumerAdditionProposal) ValidateBasic() error { return errorsmod.Wrap(ErrInvalidConsumerAdditionProposal, "blocks per distribution transmission cannot be < 1") } + if err := ccvtypes.ValidateDistributionTransmissionChannel(cccp.DistributionTransmissionChannel); err != nil { + return errorsmod.Wrap(ErrInvalidConsumerAdditionProposal, "distribution transmission channel") + } + if err := ccvtypes.ValidatePositiveInt64(cccp.HistoricalEntries); err != nil { return errorsmod.Wrap(ErrInvalidConsumerAdditionProposal, "historical entries cannot be < 1") } @@ -137,6 +143,7 @@ func (cccp *ConsumerAdditionProposal) String() string { SpawnTime: %s ConsumerRedistributionFraction: %s BlocksPerDistributionTransmission: %d + DistributionTransmissionChannel: %s HistoricalEntries: %d CcvTimeoutPeriod: %d TransferTimeoutPeriod: %d @@ -150,6 +157,7 @@ func (cccp *ConsumerAdditionProposal) String() string { cccp.SpawnTime, cccp.ConsumerRedistributionFraction, cccp.BlocksPerDistributionTransmission, + cccp.DistributionTransmissionChannel, cccp.HistoricalEntries, cccp.CcvTimeoutPeriod, cccp.TransferTimeoutPeriod, diff --git a/x/ccv/provider/types/proposal_test.go b/x/ccv/provider/types/proposal_test.go index db765a86ca..d1440eb9a0 100644 --- a/x/ccv/provider/types/proposal_test.go +++ b/x/ccv/provider/types/proposal_test.go @@ -32,6 +32,7 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { types.NewConsumerAdditionProposal("title", "description", "chainID", initialHeight, []byte("gen_hash"), []byte("bin_hash"), time.Now(), "0.75", 10, + "", 10000, 100000000000, 100000000000, @@ -44,6 +45,7 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { types.NewConsumerAdditionProposal("title", "description", "chainID", initialHeight, []byte("gen_hash"), []byte("bin_hash"), time.Now(), "0.0", // fraction can be 0.0 but not empty 10, + "", 10000, 100000000000, 100000000000, @@ -55,6 +57,7 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { types.NewConsumerAdditionProposal(" ", "description", "chainID", initialHeight, []byte("gen_hash"), []byte("bin_hash"), time.Now(), "0.75", 10, + "", 10000, 100000000000, 100000000000, @@ -66,6 +69,7 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { types.NewConsumerAdditionProposal("title", "description", " ", initialHeight, []byte("gen_hash"), []byte("bin_hash"), time.Now(), "0.75", 10, + "", 10000, 100000000000, 100000000000, @@ -86,6 +90,7 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { CcvTimeoutPeriod: 100000000000, TransferTimeoutPeriod: 100000000000, ConsumerRedistributionFraction: "0.75", + DistributionTransmissionChannel: "", HistoricalEntries: 10000, UnbondingPeriod: 100000000000, }, @@ -96,6 +101,7 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { types.NewConsumerAdditionProposal("title", "description", "chainID", initialHeight, []byte(""), []byte("bin_hash"), time.Now(), "0.75", 10, + "", 10000, 100000000000, 100000000000, @@ -107,6 +113,7 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { types.NewConsumerAdditionProposal("title", "description", "chainID", initialHeight, []byte("gen_hash"), []byte(""), time.Now(), "0.75", 10, + "", 10000, 100000000000, 100000000000, @@ -118,6 +125,7 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { types.NewConsumerAdditionProposal("title", "description", "chainID", initialHeight, []byte("gen_hash"), []byte("bin_hash"), time.Time{}, "0.75", 10, + "", 10000, 100000000000, 100000000000, @@ -129,6 +137,7 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { types.NewConsumerAdditionProposal("title", "description", "chainID", initialHeight, []byte("gen_hash"), []byte("bin_hash"), time.Now(), "", // fraction can be 0.0 but not empty 10, + "", 10000, 100000000000, 100000000000, @@ -140,17 +149,31 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { types.NewConsumerAdditionProposal("title", "description", "chainID", initialHeight, []byte("gen_hash"), []byte("bin_hash"), time.Now(), "0.75", 0, + "", 100000000000, 10000, 100000000000, 100000000000), false, }, + { + "distribution transmission channel is invalid", + types.NewConsumerAdditionProposal("title", "description", "chainID", initialHeight, []byte("gen_hash"), []byte("bin_hash"), time.Now(), + "0.75", + 10, + "badchannel/", + 10000, + 100000000000, + 100000000000, + 100000000000), + false, + }, { "historical entries is invalid", types.NewConsumerAdditionProposal("title", "description", "chainID", initialHeight, []byte("gen_hash"), []byte("bin_hash"), time.Now(), "0.75", 10, + "", -2, 100000000000, 100000000000, @@ -162,6 +185,7 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { types.NewConsumerAdditionProposal("title", "description", "chainID", initialHeight, []byte("gen_hash"), []byte("bin_hash"), time.Now(), "0.75", 10, + "", 10000, 0, 100000000000, @@ -173,6 +197,7 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { types.NewConsumerAdditionProposal("title", "description", "chainID", initialHeight, []byte("gen_hash"), []byte("bin_hash"), time.Now(), "0.75", 10, + "", 10000, 100000000000, 0, @@ -184,6 +209,7 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { types.NewConsumerAdditionProposal("title", "description", "chainID", initialHeight, []byte("gen_hash"), []byte("bin_hash"), time.Now(), "0.75", 10, + "", 10000, 100000000000, 100000000000, @@ -207,6 +233,7 @@ func TestMarshalConsumerAdditionProposal(t *testing.T) { content := types.NewConsumerAdditionProposal("title", "description", "chainID", clienttypes.NewHeight(0, 1), []byte("gen_hash"), []byte("bin_hash"), time.Now().UTC(), "0.75", 10, + "", 10000, 100000000000, 100000000000, @@ -248,6 +275,7 @@ func TestConsumerAdditionProposalString(t *testing.T) { spawnTime, "0.75", 10001, + "", 500000, 100000000000, 10000000000, @@ -263,12 +291,14 @@ func TestConsumerAdditionProposalString(t *testing.T) { SpawnTime: %s ConsumerRedistributionFraction: %s BlocksPerDistributionTransmission: %d + DistributionTransmissionChannel: %s HistoricalEntries: %d CcvTimeoutPeriod: %d TransferTimeoutPeriod: %d UnbondingPeriod: %d`, initialHeight, []byte("gen_hash"), []byte("bin_hash"), spawnTime, "0.75", 10001, + "", 500000, 100000000000, 10000000000, diff --git a/x/ccv/provider/types/provider.pb.go b/x/ccv/provider/types/provider.pb.go index 37e175acea..acc95ca9af 100644 --- a/x/ccv/provider/types/provider.pb.go +++ b/x/ccv/provider/types/provider.pb.go @@ -74,6 +74,13 @@ type ConsumerAdditionProposal struct { // This param is a part of the cosmos sdk staking module. In the case of // a ccv enabled consumer chain, the ccv module acts as the staking module. HistoricalEntries int64 `protobuf:"varint,13,opt,name=historical_entries,json=historicalEntries,proto3" json:"historical_entries,omitempty"` + // The ID of a token transfer channel used for the Reward Distribution + // sub-protocol. If DistributionTransmissionChannel == "", a new transfer + // channel is created on top of the same connection as the CCV channel. + // Note that transfer_channel_id is the ID of the channel end on the consumer chain. + // it is most relevant for chains performing a sovereign to consumer changeover + // in order to maintan the existing ibc transfer channel + DistributionTransmissionChannel string `protobuf:"bytes,14,opt,name=distribution_transmission_channel,json=distributionTransmissionChannel,proto3" json:"distribution_transmission_channel,omitempty"` } func (m *ConsumerAdditionProposal) Reset() { *m = ConsumerAdditionProposal{} } @@ -1220,106 +1227,107 @@ func init() { } var fileDescriptor_f22ec409a72b7b72 = []byte{ - // 1579 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0xcd, 0x72, 0xdc, 0xc6, - 0x11, 0x26, 0xb8, 0xfc, 0xdb, 0x59, 0xfe, 0x48, 0x10, 0x65, 0x2d, 0x15, 0x66, 0xb9, 0x86, 0x13, - 0x17, 0x53, 0x2e, 0x63, 0x43, 0xfa, 0x92, 0x52, 0xc5, 0xe5, 0x22, 0x57, 0x96, 0xc5, 0x30, 0xb6, - 0xd6, 0x20, 0x43, 0x55, 0x92, 0x03, 0x6a, 0x30, 0x68, 0xed, 0x4e, 0x11, 0xc0, 0x40, 0x33, 0x03, - 0x48, 0x7b, 0xc9, 0x39, 0x47, 0xa7, 0x72, 0x71, 0x25, 0x17, 0xe7, 0x09, 0xf2, 0x1a, 0x3e, 0xfa, - 0x98, 0x93, 0x93, 0xa2, 0x0e, 0x39, 0xe4, 0x25, 0x52, 0x33, 0xf8, 0x5f, 0x52, 0xca, 0xaa, 0x92, - 0xdc, 0x30, 0x3d, 0xdd, 0x5f, 0xf7, 0x4c, 0x77, 0x7f, 0x3d, 0x40, 0x87, 0x34, 0x92, 0xc0, 0xc9, - 0x04, 0xd3, 0xc8, 0x15, 0x40, 0x12, 0x4e, 0xe5, 0x74, 0x40, 0x48, 0x3a, 0x88, 0x39, 0x4b, 0xa9, - 0x0f, 0x7c, 0x90, 0x1e, 0x94, 0xdf, 0x76, 0xcc, 0x99, 0x64, 0xe6, 0x7b, 0x37, 0xd8, 0xd8, 0x84, - 0xa4, 0x76, 0xa9, 0x97, 0x1e, 0xdc, 0xdf, 0x1e, 0xb3, 0x31, 0xd3, 0xfa, 0x03, 0xf5, 0x95, 0x99, - 0xde, 0xdf, 0x1b, 0x33, 0x36, 0x0e, 0x60, 0xa0, 0x57, 0x5e, 0xf2, 0x6c, 0x20, 0x69, 0x08, 0x42, - 0xe2, 0x30, 0xce, 0x15, 0x7a, 0xb3, 0x0a, 0x7e, 0xc2, 0xb1, 0xa4, 0x2c, 0x2a, 0x00, 0xa8, 0x47, - 0x06, 0x84, 0x71, 0x18, 0x90, 0x80, 0x42, 0x24, 0x55, 0x78, 0xd9, 0x57, 0xae, 0x30, 0x50, 0x0a, - 0x01, 0x1d, 0x4f, 0x64, 0x26, 0x16, 0x03, 0x09, 0x91, 0x0f, 0x3c, 0xa4, 0x99, 0x72, 0xb5, 0xca, - 0x0d, 0x76, 0x6b, 0xfb, 0x84, 0x4f, 0x63, 0xc9, 0x06, 0x97, 0x30, 0x15, 0xf9, 0xee, 0xfb, 0x84, - 0x89, 0x90, 0x89, 0x01, 0xa8, 0x83, 0x45, 0x04, 0x06, 0xe9, 0x81, 0x07, 0x12, 0x1f, 0x94, 0x82, - 0x22, 0xee, 0x5c, 0xcf, 0xc3, 0xa2, 0xd2, 0x21, 0x8c, 0xe6, 0x71, 0x5b, 0x7f, 0x5c, 0x41, 0xdd, - 0x21, 0x8b, 0x44, 0x12, 0x02, 0x3f, 0xf2, 0x7d, 0xaa, 0x8e, 0x34, 0xe2, 0x2c, 0x66, 0x02, 0x07, - 0xe6, 0x36, 0x5a, 0x96, 0x54, 0x06, 0xd0, 0x35, 0xfa, 0xc6, 0x7e, 0xdb, 0xc9, 0x16, 0x66, 0x1f, - 0x75, 0x7c, 0x10, 0x84, 0xd3, 0x58, 0x29, 0x77, 0x17, 0xf5, 0x5e, 0x5d, 0x64, 0xee, 0xa0, 0xb5, - 0x2c, 0x0b, 0xd4, 0xef, 0xb6, 0xf4, 0xf6, 0xaa, 0x5e, 0x9f, 0xf8, 0xe6, 0x67, 0x68, 0x93, 0x46, - 0x54, 0x52, 0x1c, 0xb8, 0x13, 0x50, 0xb7, 0xd1, 0x5d, 0xea, 0x1b, 0xfb, 0x9d, 0xc3, 0xfb, 0x36, - 0xf5, 0x88, 0xad, 0x2e, 0xd0, 0xce, 0xaf, 0x2d, 0x3d, 0xb0, 0x1f, 0x6b, 0x8d, 0xe3, 0xa5, 0x6f, - 0xbf, 0xdf, 0x5b, 0x70, 0x36, 0x72, 0xbb, 0x4c, 0x68, 0xbe, 0x8b, 0xd6, 0xc7, 0x10, 0x81, 0xa0, - 0xc2, 0x9d, 0x60, 0x31, 0xe9, 0x2e, 0xf7, 0x8d, 0xfd, 0x75, 0xa7, 0x93, 0xcb, 0x1e, 0x63, 0x31, - 0x31, 0xf7, 0x50, 0xc7, 0xa3, 0x11, 0xe6, 0xd3, 0x4c, 0x63, 0x45, 0x6b, 0xa0, 0x4c, 0xa4, 0x15, - 0x86, 0x08, 0x89, 0x18, 0xbf, 0x88, 0x5c, 0x95, 0xed, 0xee, 0x6a, 0x1e, 0x48, 0x96, 0x69, 0xbb, - 0xc8, 0xb4, 0x7d, 0x5e, 0x94, 0xc2, 0xf1, 0x9a, 0x0a, 0xe4, 0xab, 0xbf, 0xef, 0x19, 0x4e, 0x5b, - 0xdb, 0xa9, 0x1d, 0xf3, 0x0b, 0x74, 0x2b, 0x89, 0x3c, 0x16, 0xf9, 0x34, 0x1a, 0xbb, 0x31, 0x70, - 0xca, 0xfc, 0xee, 0x9a, 0x86, 0xda, 0xb9, 0x06, 0xf5, 0x30, 0x2f, 0x9a, 0x0c, 0xe9, 0x6b, 0x85, - 0xb4, 0x55, 0x1a, 0x8f, 0xb4, 0xad, 0xf9, 0x25, 0x32, 0x09, 0x49, 0x75, 0x48, 0x2c, 0x91, 0x05, - 0x62, 0x7b, 0x7e, 0xc4, 0x5b, 0x84, 0xa4, 0xe7, 0x99, 0x75, 0x0e, 0xf9, 0x5b, 0x74, 0x4f, 0x72, - 0x1c, 0x89, 0x67, 0xc0, 0x67, 0x71, 0xd1, 0xfc, 0xb8, 0x77, 0x0b, 0x8c, 0x26, 0xf8, 0x63, 0xd4, - 0x27, 0x79, 0x01, 0xb9, 0x1c, 0x7c, 0x2a, 0x24, 0xa7, 0x5e, 0xa2, 0x6c, 0xdd, 0x67, 0x1c, 0x13, - 0x5d, 0x23, 0x1d, 0x5d, 0x04, 0xbd, 0x42, 0xcf, 0x69, 0xa8, 0x3d, 0xca, 0xb5, 0xcc, 0x27, 0xe8, - 0x47, 0x5e, 0xc0, 0xc8, 0xa5, 0x50, 0xc1, 0xb9, 0x0d, 0x24, 0xed, 0x3a, 0xa4, 0x42, 0x28, 0xb4, - 0xf5, 0xbe, 0xb1, 0xdf, 0x72, 0xde, 0xcd, 0x74, 0x47, 0xc0, 0x1f, 0xd6, 0x34, 0xcf, 0x6b, 0x8a, - 0xe6, 0x87, 0xc8, 0x9c, 0x50, 0x21, 0x19, 0xa7, 0x04, 0x07, 0x2e, 0x44, 0x92, 0x53, 0x10, 0xdd, - 0x0d, 0x6d, 0x7e, 0xbb, 0xda, 0xf9, 0x34, 0xdb, 0x78, 0xb0, 0xf6, 0xfb, 0x6f, 0xf6, 0x16, 0xbe, - 0xfe, 0x66, 0x6f, 0xc1, 0xfa, 0xab, 0x81, 0xee, 0x0d, 0xcb, 0x60, 0x43, 0x96, 0xe2, 0xe0, 0xff, - 0xd9, 0x14, 0x47, 0xa8, 0x2d, 0x24, 0x8b, 0xb3, 0x32, 0x5c, 0x7a, 0x8b, 0x32, 0x5c, 0x53, 0x66, - 0x6a, 0xc3, 0xfa, 0xb3, 0x81, 0xb6, 0x3f, 0x7d, 0x9e, 0xd0, 0x94, 0x11, 0xfc, 0x3f, 0xe9, 0xe1, - 0x53, 0xb4, 0x01, 0x35, 0x3c, 0xd1, 0x6d, 0xf5, 0x5b, 0xfb, 0x9d, 0xc3, 0x1f, 0xdb, 0x19, 0xa1, - 0xd8, 0x25, 0xcf, 0xe4, 0xa4, 0x62, 0xd7, 0xbd, 0x3b, 0x4d, 0x5b, 0xeb, 0x5f, 0x06, 0xba, 0xf5, - 0x59, 0xc0, 0x3c, 0x1c, 0x9c, 0x05, 0x58, 0x4c, 0xd4, 0x85, 0x4f, 0xd5, 0xa9, 0x39, 0xe4, 0x95, - 0xae, 0xa3, 0x9b, 0xfb, 0xd4, 0xca, 0x4c, 0xf7, 0xde, 0x27, 0xe8, 0x76, 0x59, 0x7b, 0xe5, 0xe5, - 0xea, 0xc3, 0x1c, 0xdf, 0xb9, 0xfa, 0x7e, 0x6f, 0xab, 0xc8, 0xe1, 0x50, 0x5f, 0xf4, 0x43, 0x67, - 0x8b, 0x34, 0x04, 0xbe, 0xd9, 0x43, 0x1d, 0xea, 0x11, 0x57, 0xc0, 0x73, 0x37, 0x4a, 0x42, 0x9d, - 0x97, 0x25, 0xa7, 0x4d, 0x3d, 0x72, 0x06, 0xcf, 0xbf, 0x48, 0x42, 0xf3, 0x23, 0xf4, 0x4e, 0x31, - 0x3c, 0xdc, 0x14, 0x07, 0xae, 0xb2, 0x77, 0xb1, 0xef, 0x73, 0x9d, 0xa6, 0x75, 0xe7, 0x4e, 0xb1, - 0x7b, 0x81, 0x03, 0xe5, 0xec, 0xc8, 0xf7, 0xb9, 0xf5, 0xcf, 0x65, 0xb4, 0x32, 0xc2, 0x1c, 0x87, - 0xc2, 0x3c, 0x47, 0x5b, 0x12, 0xc2, 0x38, 0xc0, 0x12, 0xdc, 0x8c, 0xd7, 0xf2, 0x93, 0x7e, 0xa0, - 0xf9, 0xae, 0x3e, 0x0f, 0xec, 0xda, 0x04, 0x48, 0x0f, 0xec, 0xa1, 0x96, 0x9e, 0x49, 0x2c, 0xc1, - 0xd9, 0x2c, 0x30, 0x32, 0xa1, 0xf9, 0x33, 0xd4, 0x95, 0x3c, 0x11, 0xb2, 0x62, 0x9c, 0xaa, 0xd5, - 0xb2, 0x54, 0xbe, 0x53, 0xec, 0x67, 0x4d, 0x5a, 0xb6, 0xd8, 0xcd, 0xe4, 0xd2, 0xfa, 0x6f, 0xc8, - 0xe5, 0x0c, 0xdd, 0x51, 0xcc, 0x3c, 0x8b, 0xb9, 0x34, 0x3f, 0xe6, 0x6d, 0x65, 0xdf, 0x04, 0xfd, - 0x12, 0x99, 0xa9, 0x20, 0xb3, 0x98, 0xcb, 0x6f, 0x11, 0x67, 0x2a, 0x48, 0x13, 0xd2, 0x47, 0xbb, - 0x42, 0x15, 0x9f, 0x1b, 0x82, 0xd4, 0x54, 0x15, 0x07, 0x10, 0x51, 0x31, 0x29, 0xc0, 0x57, 0xe6, - 0x07, 0xdf, 0xd1, 0x40, 0x9f, 0x2b, 0x1c, 0xa7, 0x80, 0xc9, 0xbd, 0x0c, 0x51, 0xef, 0x66, 0x2f, - 0x65, 0x82, 0x56, 0x75, 0x82, 0x7e, 0x70, 0x03, 0x44, 0x99, 0xa5, 0x43, 0x74, 0x37, 0xc4, 0x2f, - 0x5d, 0x39, 0xe1, 0x4c, 0xca, 0x00, 0x7c, 0x37, 0xc6, 0xe4, 0x12, 0xa4, 0xd0, 0x73, 0xa5, 0xe5, - 0xdc, 0x09, 0xf1, 0xcb, 0xf3, 0x62, 0x6f, 0x94, 0x6d, 0x99, 0x02, 0xbd, 0x5f, 0xa3, 0xe1, 0x17, - 0x98, 0xfb, 0xae, 0x0f, 0x11, 0x0b, 0x5d, 0x0e, 0x63, 0xc5, 0x8f, 0x38, 0x63, 0x64, 0x80, 0x72, - 0x94, 0xe4, 0x8d, 0xac, 0x5e, 0x06, 0x65, 0x13, 0x0f, 0x19, 0x8d, 0xf2, 0x79, 0x6b, 0x55, 0x6c, - 0xad, 0xd0, 0x1e, 0x2a, 0x30, 0xa7, 0x86, 0xf5, 0x08, 0xc0, 0xf2, 0xd0, 0xed, 0xc7, 0x38, 0xf2, - 0xc5, 0x04, 0x5f, 0xc2, 0xe7, 0x20, 0xb1, 0x8f, 0x25, 0x6e, 0xf4, 0xcc, 0x33, 0x00, 0x37, 0x66, - 0x2c, 0xc8, 0x7a, 0x26, 0xa3, 0xa0, 0xb2, 0x67, 0x1e, 0x01, 0x8c, 0x18, 0x0b, 0x54, 0xcf, 0x98, - 0x5d, 0xb4, 0x9a, 0x02, 0x17, 0x55, 0x05, 0x17, 0x4b, 0xeb, 0x27, 0xa8, 0xad, 0x49, 0xe3, 0x88, - 0x5c, 0x0a, 0x73, 0x17, 0xb5, 0x15, 0x12, 0x08, 0x01, 0xa2, 0x6b, 0xf4, 0x5b, 0xfb, 0x6d, 0xa7, - 0x12, 0x58, 0x12, 0xed, 0xbc, 0xee, 0x2d, 0x23, 0xcc, 0xa7, 0x68, 0x35, 0x06, 0x3d, 0x68, 0xb5, - 0x61, 0xe7, 0xf0, 0x63, 0x7b, 0x8e, 0xf7, 0xa2, 0xfd, 0x3a, 0x40, 0xa7, 0x40, 0xb3, 0x78, 0xf5, - 0x82, 0x9a, 0x99, 0x15, 0xc2, 0xbc, 0x98, 0x75, 0xfa, 0xf3, 0xb7, 0x72, 0x3a, 0x83, 0x57, 0xf9, - 0xfc, 0x00, 0x75, 0x8e, 0xb2, 0x63, 0xff, 0x92, 0x0a, 0x79, 0xfd, 0x5a, 0xd6, 0xeb, 0xd7, 0xf2, - 0x0b, 0xb4, 0x39, 0x9c, 0xe0, 0x28, 0x82, 0xe0, 0x9c, 0x69, 0xe2, 0x33, 0x7f, 0x88, 0x10, 0xc9, - 0x24, 0x8a, 0x30, 0xb3, 0xb4, 0xb4, 0x73, 0xc9, 0x89, 0xdf, 0x18, 0x55, 0x8b, 0x8d, 0x51, 0x65, - 0x39, 0x68, 0xeb, 0x42, 0x90, 0x5f, 0x15, 0x6f, 0x96, 0x27, 0xb1, 0x30, 0xef, 0xa2, 0x15, 0xd5, - 0xab, 0x39, 0xd0, 0x92, 0xb3, 0x9c, 0x0a, 0x72, 0xe2, 0x9b, 0xfb, 0xf5, 0x77, 0x11, 0x8b, 0x5d, - 0xea, 0x8b, 0xee, 0x62, 0xbf, 0xb5, 0xbf, 0xe4, 0x6c, 0x26, 0x95, 0xf9, 0x89, 0x2f, 0xac, 0x5f, - 0xa3, 0x4e, 0x0d, 0xd0, 0xdc, 0x44, 0x8b, 0x25, 0xd6, 0x22, 0xf5, 0xcd, 0x07, 0x68, 0xa7, 0x02, - 0x6a, 0xd2, 0x7d, 0x86, 0xd8, 0x76, 0xee, 0x95, 0x0a, 0x0d, 0xc6, 0x17, 0xd6, 0x13, 0xb4, 0x7d, - 0x52, 0x91, 0x4b, 0x39, 0x4c, 0x1a, 0x27, 0x34, 0x9a, 0xc3, 0x78, 0x17, 0xb5, 0xcb, 0xc7, 0xbf, - 0x3e, 0xfd, 0x92, 0x53, 0x09, 0xac, 0x10, 0xdd, 0xba, 0x10, 0xe4, 0x0c, 0x22, 0xbf, 0x02, 0x7b, - 0xcd, 0x05, 0x1c, 0xcf, 0x02, 0xcd, 0xfd, 0xb8, 0xac, 0xdc, 0xfd, 0xc1, 0x40, 0xdd, 0x53, 0x98, - 0x1e, 0x09, 0x41, 0xc7, 0x51, 0x08, 0x91, 0x54, 0x64, 0x81, 0x09, 0xa8, 0x4f, 0xf3, 0x3d, 0xb4, - 0x51, 0x36, 0x5a, 0xd9, 0x5f, 0xeb, 0xce, 0x7a, 0x21, 0xd4, 0x8d, 0xf5, 0x00, 0xa1, 0x98, 0x43, - 0xea, 0x12, 0xf7, 0x12, 0xa6, 0x79, 0x18, 0xbb, 0xf5, 0x59, 0x93, 0xfd, 0x5b, 0xd8, 0xa3, 0xc4, - 0x0b, 0x28, 0x39, 0x85, 0xa9, 0xb3, 0xa6, 0xf4, 0x87, 0xa7, 0x30, 0x55, 0x6f, 0x87, 0x98, 0xbd, - 0x00, 0xae, 0x07, 0x44, 0xcb, 0xc9, 0x16, 0xd6, 0x9f, 0x0c, 0x74, 0xef, 0x02, 0x07, 0xd4, 0xc7, - 0x92, 0xf1, 0xe2, 0xbe, 0x47, 0x89, 0xa7, 0x2c, 0xde, 0x70, 0xaf, 0xd7, 0xa2, 0x5d, 0xbc, 0x21, - 0xda, 0x4f, 0xd0, 0x7a, 0x99, 0x61, 0x15, 0x6f, 0x6b, 0x8e, 0x78, 0x3b, 0x85, 0xc5, 0x29, 0x4c, - 0xad, 0xdf, 0xd5, 0x62, 0x3b, 0x9e, 0xd6, 0x9a, 0x97, 0xff, 0x87, 0xd8, 0x4a, 0xb7, 0xf5, 0xd8, - 0x48, 0xdd, 0xfe, 0xda, 0x01, 0x5a, 0xd7, 0x0f, 0x60, 0xfd, 0xc5, 0x40, 0xdb, 0x75, 0xaf, 0xe2, - 0x9c, 0x8d, 0x78, 0x12, 0xc1, 0x9b, 0xbc, 0x57, 0xf5, 0xb3, 0x58, 0xaf, 0x9f, 0xa7, 0x68, 0xb3, - 0x11, 0x94, 0xc8, 0x6f, 0xe3, 0xa7, 0x73, 0x51, 0x48, 0x8d, 0x1e, 0x9c, 0x8d, 0xfa, 0x39, 0xc4, - 0xf1, 0xd3, 0x6f, 0xaf, 0x7a, 0xc6, 0x77, 0x57, 0x3d, 0xe3, 0x1f, 0x57, 0x3d, 0xe3, 0xab, 0x57, - 0xbd, 0x85, 0xef, 0x5e, 0xf5, 0x16, 0xfe, 0xf6, 0xaa, 0xb7, 0xf0, 0x9b, 0x8f, 0xc7, 0x54, 0x4e, - 0x12, 0xcf, 0x26, 0x2c, 0x1c, 0xe4, 0x3f, 0x8e, 0x95, 0xaf, 0x0f, 0xcb, 0xff, 0xf0, 0xf4, 0x70, - 0xf0, 0xb2, 0xf9, 0x33, 0x2e, 0xa7, 0x31, 0x08, 0x6f, 0x45, 0x97, 0xf5, 0x47, 0xff, 0x0e, 0x00, - 0x00, 0xff, 0xff, 0x50, 0x7d, 0x10, 0xbd, 0xbd, 0x0f, 0x00, 0x00, + // 1598 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0x4b, 0x73, 0xdc, 0xc6, + 0x11, 0x26, 0xb8, 0x7c, 0xed, 0x2c, 0x1f, 0x12, 0x44, 0x59, 0x4b, 0x85, 0x59, 0xae, 0xe0, 0xc4, + 0xc5, 0x94, 0xcb, 0xd8, 0x90, 0xbe, 0xa4, 0x54, 0x71, 0xb9, 0xc8, 0x95, 0x65, 0xd1, 0x8c, 0xad, + 0x35, 0xc8, 0x50, 0x95, 0xe4, 0x80, 0x1a, 0x0c, 0x5a, 0xbb, 0x53, 0x04, 0x30, 0xd0, 0xcc, 0x00, + 0xd2, 0x5e, 0x72, 0xce, 0xd1, 0xb9, 0xb9, 0x92, 0x8b, 0xf3, 0x0b, 0xf2, 0x37, 0x7c, 0xf4, 0x31, + 0x27, 0x3b, 0x45, 0x1d, 0x72, 0xc8, 0x9f, 0x48, 0xcd, 0xe0, 0xcd, 0x87, 0xb2, 0xaa, 0xc4, 0x37, + 0xcc, 0x4c, 0xf7, 0xd7, 0xdd, 0xd3, 0xdd, 0x5f, 0x0f, 0xd0, 0x3e, 0x8d, 0x24, 0x70, 0x32, 0xc1, + 0x34, 0x72, 0x05, 0x90, 0x84, 0x53, 0x39, 0x1d, 0x10, 0x92, 0x0e, 0x62, 0xce, 0x52, 0xea, 0x03, + 0x1f, 0xa4, 0x7b, 0xe5, 0xb7, 0x1d, 0x73, 0x26, 0x99, 0xf9, 0xee, 0x35, 0x3a, 0x36, 0x21, 0xa9, + 0x5d, 0xca, 0xa5, 0x7b, 0xf7, 0x37, 0xc7, 0x6c, 0xcc, 0xb4, 0xfc, 0x40, 0x7d, 0x65, 0xaa, 0xf7, + 0x77, 0xc6, 0x8c, 0x8d, 0x03, 0x18, 0xe8, 0x95, 0x97, 0x3c, 0x1f, 0x48, 0x1a, 0x82, 0x90, 0x38, + 0x8c, 0x73, 0x81, 0xde, 0x65, 0x01, 0x3f, 0xe1, 0x58, 0x52, 0x16, 0x15, 0x00, 0xd4, 0x23, 0x03, + 0xc2, 0x38, 0x0c, 0x48, 0x40, 0x21, 0x92, 0xca, 0xbd, 0xec, 0x2b, 0x17, 0x18, 0x28, 0x81, 0x80, + 0x8e, 0x27, 0x32, 0xdb, 0x16, 0x03, 0x09, 0x91, 0x0f, 0x3c, 0xa4, 0x99, 0x70, 0xb5, 0xca, 0x15, + 0xb6, 0x6b, 0xe7, 0x84, 0x4f, 0x63, 0xc9, 0x06, 0xe7, 0x30, 0x15, 0xf9, 0xe9, 0x7b, 0x84, 0x89, + 0x90, 0x89, 0x01, 0xa8, 0xc0, 0x22, 0x02, 0x83, 0x74, 0xcf, 0x03, 0x89, 0xf7, 0xca, 0x8d, 0xc2, + 0xef, 0x5c, 0xce, 0xc3, 0xa2, 0x92, 0x21, 0x8c, 0xe6, 0x7e, 0x5b, 0x3f, 0x2c, 0xa1, 0xee, 0x90, + 0x45, 0x22, 0x09, 0x81, 0x1f, 0xf8, 0x3e, 0x55, 0x21, 0x8d, 0x38, 0x8b, 0x99, 0xc0, 0x81, 0xb9, + 0x89, 0x16, 0x25, 0x95, 0x01, 0x74, 0x8d, 0xbe, 0xb1, 0xdb, 0x76, 0xb2, 0x85, 0xd9, 0x47, 0x1d, + 0x1f, 0x04, 0xe1, 0x34, 0x56, 0xc2, 0xdd, 0x79, 0x7d, 0x56, 0xdf, 0x32, 0xb7, 0xd0, 0x4a, 0x96, + 0x05, 0xea, 0x77, 0x5b, 0xfa, 0x78, 0x59, 0xaf, 0x8f, 0x7c, 0xf3, 0x53, 0xb4, 0x4e, 0x23, 0x2a, + 0x29, 0x0e, 0xdc, 0x09, 0xa8, 0xdb, 0xe8, 0x2e, 0xf4, 0x8d, 0xdd, 0xce, 0xfe, 0x7d, 0x9b, 0x7a, + 0xc4, 0x56, 0x17, 0x68, 0xe7, 0xd7, 0x96, 0xee, 0xd9, 0x4f, 0xb4, 0xc4, 0xe1, 0xc2, 0xb7, 0xdf, + 0xef, 0xcc, 0x39, 0x6b, 0xb9, 0x5e, 0xb6, 0x69, 0x3e, 0x40, 0xab, 0x63, 0x88, 0x40, 0x50, 0xe1, + 0x4e, 0xb0, 0x98, 0x74, 0x17, 0xfb, 0xc6, 0xee, 0xaa, 0xd3, 0xc9, 0xf7, 0x9e, 0x60, 0x31, 0x31, + 0x77, 0x50, 0xc7, 0xa3, 0x11, 0xe6, 0xd3, 0x4c, 0x62, 0x49, 0x4b, 0xa0, 0x6c, 0x4b, 0x0b, 0x0c, + 0x11, 0x12, 0x31, 0x7e, 0x19, 0xb9, 0x2a, 0xdb, 0xdd, 0xe5, 0xdc, 0x91, 0x2c, 0xd3, 0x76, 0x91, + 0x69, 0xfb, 0xb4, 0x28, 0x85, 0xc3, 0x15, 0xe5, 0xc8, 0x57, 0x3f, 0xec, 0x18, 0x4e, 0x5b, 0xeb, + 0xa9, 0x13, 0xf3, 0x0b, 0x74, 0x2b, 0x89, 0x3c, 0x16, 0xf9, 0x34, 0x1a, 0xbb, 0x31, 0x70, 0xca, + 0xfc, 0xee, 0x8a, 0x86, 0xda, 0xba, 0x02, 0xf5, 0x28, 0x2f, 0x9a, 0x0c, 0xe9, 0x6b, 0x85, 0xb4, + 0x51, 0x2a, 0x8f, 0xb4, 0xae, 0xf9, 0x25, 0x32, 0x09, 0x49, 0xb5, 0x4b, 0x2c, 0x91, 0x05, 0x62, + 0x7b, 0x76, 0xc4, 0x5b, 0x84, 0xa4, 0xa7, 0x99, 0x76, 0x0e, 0xf9, 0x07, 0x74, 0x4f, 0x72, 0x1c, + 0x89, 0xe7, 0xc0, 0x2f, 0xe3, 0xa2, 0xd9, 0x71, 0xef, 0x16, 0x18, 0x4d, 0xf0, 0x27, 0xa8, 0x4f, + 0xf2, 0x02, 0x72, 0x39, 0xf8, 0x54, 0x48, 0x4e, 0xbd, 0x44, 0xe9, 0xba, 0xcf, 0x39, 0x26, 0xba, + 0x46, 0x3a, 0xba, 0x08, 0x7a, 0x85, 0x9c, 0xd3, 0x10, 0x7b, 0x9c, 0x4b, 0x99, 0x4f, 0xd1, 0xcf, + 0xbc, 0x80, 0x91, 0x73, 0xa1, 0x9c, 0x73, 0x1b, 0x48, 0xda, 0x74, 0x48, 0x85, 0x50, 0x68, 0xab, + 0x7d, 0x63, 0xb7, 0xe5, 0x3c, 0xc8, 0x64, 0x47, 0xc0, 0x1f, 0xd5, 0x24, 0x4f, 0x6b, 0x82, 0xe6, + 0x07, 0xc8, 0x9c, 0x50, 0x21, 0x19, 0xa7, 0x04, 0x07, 0x2e, 0x44, 0x92, 0x53, 0x10, 0xdd, 0x35, + 0xad, 0x7e, 0xbb, 0x3a, 0xf9, 0x24, 0x3b, 0x30, 0x3f, 0x43, 0x0f, 0x6e, 0x34, 0xea, 0x92, 0x09, + 0x8e, 0x22, 0x08, 0xba, 0xeb, 0x3a, 0x94, 0x1d, 0xff, 0x06, 0x9b, 0xc3, 0x4c, 0xec, 0xe1, 0xca, + 0x9f, 0xbe, 0xd9, 0x99, 0xfb, 0xfa, 0x9b, 0x9d, 0x39, 0xeb, 0xef, 0x06, 0xba, 0x37, 0x2c, 0x03, + 0x0f, 0x59, 0x8a, 0x83, 0x1f, 0xb3, 0xc1, 0x0e, 0x50, 0x5b, 0x48, 0x16, 0x67, 0x25, 0xbd, 0xf0, + 0x16, 0x25, 0xbd, 0xa2, 0xd4, 0xd4, 0x81, 0xf5, 0x57, 0x03, 0x6d, 0x7e, 0xf2, 0x22, 0xa1, 0x29, + 0x23, 0xf8, 0xff, 0xc2, 0x07, 0xc7, 0x68, 0x0d, 0x6a, 0x78, 0xa2, 0xdb, 0xea, 0xb7, 0x76, 0x3b, + 0xfb, 0x3f, 0xb7, 0x33, 0x72, 0xb2, 0x4b, 0xce, 0xca, 0x09, 0xca, 0xae, 0x5b, 0x77, 0x9a, 0xba, + 0xd6, 0xbf, 0x0d, 0x74, 0xeb, 0xd3, 0x80, 0x79, 0x38, 0x38, 0x09, 0xb0, 0x98, 0xa8, 0xe4, 0x4d, + 0x55, 0xd4, 0x1c, 0xf2, 0xae, 0xd1, 0xde, 0xcd, 0x1c, 0xb5, 0x52, 0xd3, 0x7d, 0xfc, 0x31, 0xba, + 0x5d, 0xd6, 0x71, 0x79, 0xb9, 0x3a, 0x98, 0xc3, 0x3b, 0x17, 0xdf, 0xef, 0x6c, 0x14, 0x39, 0x1c, + 0xea, 0x8b, 0x7e, 0xe4, 0x6c, 0x90, 0xc6, 0x86, 0x6f, 0xf6, 0x50, 0x87, 0x7a, 0xc4, 0x15, 0xf0, + 0xc2, 0x8d, 0x92, 0x50, 0xe7, 0x65, 0xc1, 0x69, 0x53, 0x8f, 0x9c, 0xc0, 0x8b, 0x2f, 0x92, 0xd0, + 0xfc, 0x10, 0xbd, 0x53, 0x0c, 0x22, 0x37, 0xc5, 0x81, 0xab, 0xf4, 0x5d, 0xec, 0xfb, 0x5c, 0xa7, + 0x69, 0xd5, 0xb9, 0x53, 0x9c, 0x9e, 0xe1, 0x40, 0x19, 0x3b, 0xf0, 0x7d, 0x6e, 0xfd, 0x6b, 0x11, + 0x2d, 0x8d, 0x30, 0xc7, 0xa1, 0x30, 0x4f, 0xd1, 0x86, 0x84, 0x30, 0x0e, 0xb0, 0x04, 0x37, 0xe3, + 0xc8, 0x3c, 0xd2, 0xf7, 0x35, 0x77, 0xd6, 0x67, 0x8b, 0x5d, 0x9b, 0x26, 0xe9, 0x9e, 0x3d, 0xd4, + 0xbb, 0x27, 0x12, 0x4b, 0x70, 0xd6, 0x0b, 0x8c, 0x6c, 0xd3, 0xfc, 0x15, 0xea, 0x4a, 0x9e, 0x08, + 0x59, 0xb1, 0x57, 0xd5, 0xb6, 0x59, 0x2a, 0xdf, 0x29, 0xce, 0xb3, 0x86, 0x2f, 0xdb, 0xf5, 0x7a, + 0xa2, 0x6a, 0xfd, 0x2f, 0x44, 0x75, 0x82, 0xee, 0x28, 0x96, 0xbf, 0x8c, 0xb9, 0x30, 0x3b, 0xe6, + 0x6d, 0xa5, 0xdf, 0x04, 0xfd, 0x12, 0x99, 0xa9, 0x20, 0x97, 0x31, 0x17, 0xdf, 0xc2, 0xcf, 0x54, + 0x90, 0x26, 0xa4, 0x8f, 0xb6, 0x85, 0x2a, 0x3e, 0x37, 0x04, 0xa9, 0x69, 0x2f, 0x0e, 0x20, 0xa2, + 0x62, 0x52, 0x80, 0x2f, 0xcd, 0x0e, 0xbe, 0xa5, 0x81, 0x3e, 0x57, 0x38, 0x4e, 0x01, 0x93, 0x5b, + 0x19, 0xa2, 0xde, 0xf5, 0x56, 0xca, 0x04, 0x2d, 0xeb, 0x04, 0xfd, 0xe4, 0x1a, 0x88, 0x32, 0x4b, + 0xfb, 0xe8, 0x6e, 0x88, 0x5f, 0xb9, 0x72, 0xc2, 0x99, 0x94, 0x01, 0xf8, 0x6e, 0x8c, 0xc9, 0x39, + 0x48, 0xa1, 0x67, 0x54, 0xcb, 0xb9, 0x13, 0xe2, 0x57, 0xa7, 0xc5, 0xd9, 0x28, 0x3b, 0x32, 0x05, + 0x7a, 0xaf, 0x46, 0xe9, 0x2f, 0x31, 0xf7, 0x5d, 0x1f, 0x22, 0x16, 0xba, 0x1c, 0xc6, 0x8a, 0xf7, + 0x70, 0xc6, 0xee, 0x00, 0xe5, 0x58, 0xca, 0x1b, 0x59, 0xbd, 0x32, 0xca, 0x26, 0x1e, 0x32, 0x1a, + 0xe5, 0xb3, 0xdb, 0xaa, 0x98, 0x5f, 0xa1, 0x3d, 0x52, 0x60, 0x4e, 0x0d, 0xeb, 0x31, 0x80, 0xe5, + 0xa1, 0xdb, 0x4f, 0x70, 0xe4, 0x8b, 0x09, 0x3e, 0x87, 0xcf, 0x41, 0x62, 0x1f, 0x4b, 0xdc, 0xe8, + 0x99, 0xe7, 0x00, 0x6e, 0xcc, 0x58, 0x90, 0xf5, 0x4c, 0x46, 0x41, 0x65, 0xcf, 0x3c, 0x06, 0x18, + 0x31, 0x16, 0xa8, 0x9e, 0x31, 0xbb, 0x68, 0x39, 0x05, 0x2e, 0xaa, 0x0a, 0x2e, 0x96, 0xd6, 0x2f, + 0x50, 0x5b, 0x93, 0xc6, 0x01, 0x39, 0x17, 0xe6, 0x36, 0x6a, 0x2b, 0x24, 0x10, 0x02, 0x44, 0xd7, + 0xe8, 0xb7, 0x76, 0xdb, 0x4e, 0xb5, 0x61, 0x49, 0xb4, 0x75, 0xd3, 0xbb, 0x48, 0x98, 0xcf, 0xd0, + 0x72, 0x0c, 0x7a, 0x68, 0x6b, 0xc5, 0xce, 0xfe, 0x47, 0xf6, 0x0c, 0x6f, 0x4f, 0xfb, 0x26, 0x40, + 0xa7, 0x40, 0xb3, 0x78, 0xf5, 0x1a, 0xbb, 0x34, 0x2b, 0x84, 0x79, 0x76, 0xd9, 0xe8, 0xaf, 0xdf, + 0xca, 0xe8, 0x25, 0xbc, 0xca, 0xe6, 0xfb, 0xa8, 0x73, 0x90, 0x85, 0xfd, 0x1b, 0x2a, 0xe4, 0xd5, + 0x6b, 0x59, 0xad, 0x5f, 0xcb, 0x67, 0x68, 0x3d, 0x1f, 0x71, 0xa7, 0x4c, 0x13, 0x9f, 0xf9, 0x53, + 0x84, 0xf2, 0xd9, 0xa8, 0x08, 0x33, 0x4b, 0x4b, 0x3b, 0xdf, 0x39, 0xf2, 0x1b, 0xa3, 0x6a, 0xbe, + 0x31, 0xaa, 0x2c, 0x07, 0x6d, 0x9c, 0x09, 0xf2, 0xdb, 0xe2, 0xfd, 0xf3, 0x34, 0x16, 0xe6, 0x5d, + 0xb4, 0xa4, 0x7a, 0x35, 0x07, 0x5a, 0x70, 0x16, 0x53, 0x41, 0x8e, 0x7c, 0x73, 0xb7, 0xfe, 0xc6, + 0x62, 0xb1, 0x4b, 0x7d, 0xd1, 0x9d, 0xef, 0xb7, 0x76, 0x17, 0x9c, 0xf5, 0xa4, 0x52, 0x3f, 0xf2, + 0x85, 0xf5, 0x3b, 0xd4, 0xa9, 0x01, 0x9a, 0xeb, 0x68, 0xbe, 0xc4, 0x9a, 0xa7, 0xbe, 0xf9, 0x10, + 0x6d, 0x55, 0x40, 0x4d, 0xba, 0xcf, 0x10, 0xdb, 0xce, 0xbd, 0x52, 0xa0, 0xc1, 0xf8, 0xc2, 0x7a, + 0x8a, 0x36, 0x8f, 0x2a, 0x72, 0x29, 0x87, 0x49, 0x23, 0x42, 0xa3, 0x39, 0x8c, 0xb7, 0x51, 0xbb, + 0xfc, 0x91, 0xd0, 0xd1, 0x2f, 0x38, 0xd5, 0x86, 0x15, 0xa2, 0x5b, 0x67, 0x82, 0x9c, 0x40, 0xe4, + 0x57, 0x60, 0x37, 0x5c, 0xc0, 0xe1, 0x65, 0xa0, 0x99, 0x1f, 0xaa, 0x95, 0xb9, 0x3f, 0x1b, 0xa8, + 0x7b, 0x0c, 0xd3, 0x03, 0x21, 0xe8, 0x38, 0x0a, 0x21, 0x92, 0x8a, 0x2c, 0x30, 0x01, 0xf5, 0x69, + 0xbe, 0x8b, 0xd6, 0xca, 0x46, 0x2b, 0xfb, 0x6b, 0xd5, 0x59, 0x2d, 0x36, 0x75, 0x63, 0x3d, 0x44, + 0x28, 0xe6, 0x90, 0xba, 0xc4, 0x3d, 0x87, 0x69, 0xee, 0xc6, 0x76, 0x7d, 0xd6, 0x64, 0xff, 0x29, + 0xf6, 0x28, 0xf1, 0x02, 0x4a, 0x8e, 0x61, 0xea, 0xac, 0x28, 0xf9, 0xe1, 0x31, 0x4c, 0xd5, 0xdb, + 0x21, 0x66, 0x2f, 0x81, 0xeb, 0x01, 0xd1, 0x72, 0xb2, 0x85, 0xf5, 0x17, 0x03, 0xdd, 0x3b, 0xc3, + 0x01, 0xf5, 0xb1, 0x64, 0xbc, 0xb8, 0xef, 0x51, 0xe2, 0x29, 0x8d, 0x37, 0xdc, 0xeb, 0x15, 0x6f, + 0xe7, 0xaf, 0xf1, 0xf6, 0x63, 0xb4, 0x5a, 0x66, 0x58, 0xf9, 0xdb, 0x9a, 0xc1, 0xdf, 0x4e, 0xa1, + 0x71, 0x0c, 0x53, 0xeb, 0x8f, 0x35, 0xdf, 0x0e, 0xa7, 0xb5, 0xe6, 0xe5, 0xff, 0xc5, 0xb7, 0xd2, + 0x6c, 0xdd, 0x37, 0x52, 0xd7, 0xbf, 0x12, 0x40, 0xeb, 0x6a, 0x00, 0xd6, 0xdf, 0x0c, 0xb4, 0x59, + 0xb7, 0x2a, 0x4e, 0xd9, 0x88, 0x27, 0x11, 0xbc, 0xc9, 0x7a, 0x55, 0x3f, 0xf3, 0xf5, 0xfa, 0x79, + 0x86, 0xd6, 0x1b, 0x4e, 0x89, 0xfc, 0x36, 0x7e, 0x39, 0x13, 0x85, 0xd4, 0xe8, 0xc1, 0x59, 0xab, + 0xc7, 0x21, 0x0e, 0x9f, 0x7d, 0x7b, 0xd1, 0x33, 0xbe, 0xbb, 0xe8, 0x19, 0xff, 0xbc, 0xe8, 0x19, + 0x5f, 0xbd, 0xee, 0xcd, 0x7d, 0xf7, 0xba, 0x37, 0xf7, 0x8f, 0xd7, 0xbd, 0xb9, 0xdf, 0x7f, 0x34, + 0xa6, 0x72, 0x92, 0x78, 0x36, 0x61, 0xe1, 0x20, 0xff, 0x09, 0xad, 0x6c, 0x7d, 0x50, 0xfe, 0xd3, + 0xa7, 0xfb, 0x83, 0x57, 0xcd, 0x1f, 0x7b, 0x39, 0x8d, 0x41, 0x78, 0x4b, 0xba, 0xac, 0x3f, 0xfc, + 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7b, 0x4c, 0xb0, 0x24, 0x09, 0x10, 0x00, 0x00, } func (m *ConsumerAdditionProposal) Marshal() (dAtA []byte, err error) { @@ -1342,6 +1350,13 @@ func (m *ConsumerAdditionProposal) MarshalToSizedBuffer(dAtA []byte) (int, error _ = i var l int _ = l + if len(m.DistributionTransmissionChannel) > 0 { + i -= len(m.DistributionTransmissionChannel) + copy(dAtA[i:], m.DistributionTransmissionChannel) + i = encodeVarintProvider(dAtA, i, uint64(len(m.DistributionTransmissionChannel))) + i-- + dAtA[i] = 0x72 + } if m.HistoricalEntries != 0 { i = encodeVarintProvider(dAtA, i, uint64(m.HistoricalEntries)) i-- @@ -2298,6 +2313,10 @@ func (m *ConsumerAdditionProposal) Size() (n int) { if m.HistoricalEntries != 0 { n += 1 + sovProvider(uint64(m.HistoricalEntries)) } + l = len(m.DistributionTransmissionChannel) + if l > 0 { + n += 1 + l + sovProvider(uint64(l)) + } return n } @@ -3080,6 +3099,38 @@ func (m *ConsumerAdditionProposal) Unmarshal(dAtA []byte) error { break } } + case 14: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DistributionTransmissionChannel", 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.DistributionTransmissionChannel = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipProvider(dAtA[iNdEx:]) diff --git a/x/ccv/types/shared_params.go b/x/ccv/types/shared_params.go index 000a4c3815..04f1cf54e1 100644 --- a/x/ccv/types/shared_params.go +++ b/x/ccv/types/shared_params.go @@ -57,6 +57,16 @@ func ValidateString(i interface{}) error { return nil } +func ValidateDistributionTransmissionChannel(i interface{}) error { + // Accept empty string as valid, since this means a new + // distribution transmission channel will be created + if i == "" { + return nil + } + // Otherwise validate as usual for a channelID + return ValidateChannelIdentifier(i) +} + func ValidateChannelIdentifier(i interface{}) error { value, ok := i.(string) if !ok { From 05c2dae7c6372b1252b9e97215d07c6aa7618f33 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Fri, 16 Jun 2023 15:39:51 -0700 Subject: [PATCH 017/134] docs: ADR for throttle with retries (#1005) * all of ADR is filled out except design portion * design * Update adr-008-throttle-retries.md * Update adr-008-throttle-retries.md * Update adr-008-throttle-retries.md * Apply suggestions from code review Co-authored-by: Marius Poke * nit formatting * describe consumer changes first * add comment on rareness of throttling being triggered * split out paragraph * hopefully better explanation * Update adr-008-throttle-retries.md * accepted * TOC entry --------- Co-authored-by: Marius Poke --- docs/docs/adrs/adr-008-throttle-retries.md | 105 +++++++++++++++++++++ docs/docs/adrs/intro.md | 3 +- 2 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 docs/docs/adrs/adr-008-throttle-retries.md diff --git a/docs/docs/adrs/adr-008-throttle-retries.md b/docs/docs/adrs/adr-008-throttle-retries.md new file mode 100644 index 0000000000..a8f0d250ce --- /dev/null +++ b/docs/docs/adrs/adr-008-throttle-retries.md @@ -0,0 +1,105 @@ +--- +sidebar_position: 7 +title: Throttle with retries +--- + +## ADR 008: Throttle with retries + +## Changelog + +* 6/9/23: Initial draft + +## Status + +Accepted + +## Context + +For context on why the throttling mechanism exists, see [ADR 002](./adr-002-throttle.md). + +Note the terms slash throttling and jail throttling are synonymous, since in replicated security a `SlashPacket` simply jails a validator for downtime infractions. + +Currently the throttling mechanism is designed so that provider logic (slash meter, etc.) dictates how many slash packets can be handled over time. Throttled slash packets are persisted on the provider, leading to multiple possible issues. Namely: + +* If slash or vsc matured packets are actually throttled/queued on the provider, state can grow and potentially lead to a DoS attack. We have short term solutions around this, but overall they come with their own weaknesses. See [#594](https://github.com/cosmos/interchain-security/issues/594). +* If a jailing attack described in [ADR 002](adr-002-throttle.md) were actually to be carried out with the current throttling design, we'd likely have to halt the provider, and perform an emergency upgrade and/or migration to clear the queues of slash packets that were deemed to be malicious. Alternatively, validators would just have to _tough it out_ and wait for the queues to clear, during which all/most validators would be jailed. Right after being jailed, vals would have to unjail themselves promptly to ensure safety. The synchronous coordination required to maintain safety in such a scenario is not ideal. + +So what's the solution? We can improve the throttling mechanism to instead queue/persist relevant data on each consumer, and have consumers retry slash requests as needed. + +## Decision + +### Consumer changes + +Note the consumer already queues up both slash and vsc matured packets via `AppendPendingPacket`. Those packets are dequeued every endblock in `SendPackets` and sent to the provider. + +Instead, we will now introduce the following logic on endblock: + +* Slash packets will always be sent to the provider once they're at the head of the queue. However, once sent, the consumer will not send any trailing vsc matured packets from the queue until the provider responds with an ack that the slash packet has been handled (ie. val was jailed). That is, slash packets block the sending of trailing vsc matured packets in the consumer queue. +* If two slash packets are at the head of the queue, the consumer will send the first slash packet, and then wait for a success ack from the provider before sending the second slash packet. This seems like it'd simplify implementation. +* VSC matured packets at the head of the queue (ie. NOT trailing a slash packet) can be sent immediately, and do not block any other packets in the queue, since the provider always handles them immediately. + +To prevent the provider from having to keep track of what slash packets have been rejected, the consumer will have to retry the sending of slash packets over some period of time. This can be achieved with an on-chain consumer param. The suggested param value would probably be 1/2 of the provider's `SlashMeterReplenishmentPeriod`, although it doesn't matter too much as long as the param value is sane. + +Note to prevent weird edge case behavior, a retry would not be attempted until either a success ack or failure ack has been recv from the provider. + +With the behavior described, we maintain very similar behavior to the current throttling mechanism regarding the timing that slash and vsc matured packets are handled on the provider. Obviously the queueing and blocking logic is moved, and the two chains would have to send more messages between one another (only in the case the throttling mechanism is triggered). + +In the normal case, when no or a few slash packets are being sent, the VSCMaturedPackets will not be delayed, and hence unbonding will not be delayed. + +### Provider changes + +The main change needed for the provider is the removal of queuing logic for slash and vsc matured packets upon being received. + +Instead, the provider will consult the slash meter to determine if a slash packet can be handled immediately. If not, the provider will return an ack message to the consumer communicating that the slash packet could not be handled, and needs to be sent again in the future (retried). + +VSCMatured packets will always be handled immediately upon being received by the provider. + +Note [spec](https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/system_model_and_properties.md#consumer-initiated-slashing). Specifically the section on _VSC Maturity and Slashing Order_. Previously the onus was on the provider to maintain this property via queuing packets and handling them FIFO. + +Now this property will be maintained by the consumer sending packets in the correct order, and blocking the sending of VSCMatured packets as needed. Then, the ordered IBC channel will ensure that Slash/VSCMatured packets are received in the correct order on the provider. + +The provider's main responsibility regarding throttling will now be to determine if a recv slash packet can be handled via slash meter etc., and appropriately ack to the sending consumer. + +### Why the provider can handle VSCMatured packets immediately + +First we answer, what does a VSCMatured packet communicate to the provider? A VSCMatured packet communicates that a VSC has been applied to a consumer long enough that infractions committed on the consumer could have been submitted. + +If the consumer is following the queuing/blocking protocol described. No bad behavior occurs, `VSC Maturity and Slashing Order` property is maintained. + +If a consumer sends VSCMatured packets too leniently: The consumer is malicious and sending duplicate vsc matured packets, or sending the packets sooner than the ccv protocol specifies. In this scenario, the provider needs to handle vsc matured packets immediately to prevent DOS, state bloat, or other issues. The only possible negative outcome is that the malicious consumer may not be able to jail a validator who should have been jailed. The malicious behavior only creates a negative outcome for the chain that is being malicious. + +If a consumer blocks the sending of VSCMatured packets: The consumer is malicious and blocking vsc matured packets that should have been sent. This will block unbonding only up until the VSC timeout period has elapsed. At that time, the consumer is removed. Again the malicious behavior only creates a negative outcome for the chain that is being malicious. + +### Splitting of PRs + +We could split this feature into two PRs, one affecting the consumer and one affecting the provider, along with a third PR which could setup a clever way to upgrade the provider in multiple steps, ensuring that queued slash packets at upgrade time are handled properly. + +## Consequences + +* Consumers will now have to manage their own queues, and retry logic. +* Consumers still aren't trustless, but the provider is now less susceptible to mismanaged or malicious consumers. +* Recovering from the "jailing attack" is more elegant. +* Some issues like [#1001](https://github.com/cosmos/interchain-security/issues/1001) will now be handled implicitly by the improved throttling mechanism. +* Slash and vsc matured packets can be handled immediately once recv by the provider if the slash meter allows. +* In general, we reduce the amount of computation that happens in the provider end-blocker. + +### Positive + +* We no longer have to reason about a "global queue" and a "chain specific queue", and keeping those all in-sync. Now slash and vsc matured packet queuing is handled on each consumer individually. +* Due to the above, the throttling protocol becomes less complex overall. +* We no longer have to worry about throttle related DoS attack on the provider, since no queuing exists on the provider. + +### Negative + +* Increased number of IBC packets being relayed anytime throttling logic is triggered. +* Consumer complexity increases, since consumers now have manage queuing themselves, and implement packet retry logic. + +### Neutral + +* Core throttling logic on the provider remains unchanged, ie. slash meter, replenishment cycles, etc. + +## References + +* [EPIC](https://github.com/cosmos/interchain-security/issues/713) tracking the changes proposed by this ADR +* [ADR 002: Jail Throttling](./adr-002-throttle.md) +* [#594](https://github.com/cosmos/interchain-security/issues/594) \ No newline at end of file diff --git a/docs/docs/adrs/intro.md b/docs/docs/adrs/intro.md index 528b4799ae..bdd59ad20b 100644 --- a/docs/docs/adrs/intro.md +++ b/docs/docs/adrs/intro.md @@ -36,4 +36,5 @@ To suggest an ADR, please make use of the [ADR template](./adr-template.md) prov | [002](./adr-002-throttle.md) | Jail Throttling | Accepted, Implemented | | [003](./adr-003-equivocation-gov-proposal.md) | Equivocation governance proposal | Accepted, Implemented | | [004](./adr-004-denom-dos-fixes) | Denom DOS fixes | Accepted, Implemented | -| [007](./adr-007-pause-unbonding-on-eqv-prop.md) | Pause validator unbonding during equivocation proposal | Proposed | \ No newline at end of file +| [007](./adr-007-pause-unbonding-on-eqv-prop.md) | Pause validator unbonding during equivocation proposal | Proposed | +| [008](./adr-008-throttle-retries.md) | Throttle with retries | Accepted, In-progress | From 8c8e6a0804d39f14e7a030de19539ed037cddbc0 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Date: Mon, 19 Jun 2023 09:59:40 +0200 Subject: [PATCH 018/134] Add time and block advancement integration for CometMock (#1017) * Add time and block advancement * Adhere to gocritic: use += * Remove extra debug output * Fix: use correct key when consumer key is not assigned * Correct private key address field * Clarify comment for WaitTime * Use bool instead of *bool type * Add review comments --- tests/e2e/actions.go | 103 ++++++++++++++++++++++++++++++++++++++++--- tests/e2e/config.go | 29 +++++++++--- tests/e2e/state.go | 26 ++++++++++- tests/e2e/steps.go | 1 + 4 files changed, 146 insertions(+), 13 deletions(-) diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index 06bcb7f5f7..ecad541290 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "log" + "math" "os/exec" "strconv" "strings" @@ -72,7 +73,7 @@ type StartChainValidator struct { stake uint } -func (tr TestRun) startChain( +func (tr *TestRun) startChain( action StartChainAction, verbose bool, ) { @@ -171,6 +172,14 @@ func (tr TestRun) startChain( chain: action.chain, validator: action.validators[0].id, }, verbose) + + // store the fact that we started the chain + tr.runningChains[action.chain] = true + fmt.Println("Started chain", action.chain) + if tr.timeOffset != 0 { + // advance time for this chain so that it is in sync with the rest of the network + tr.AdvanceTimeForChain(action.chain, tr.timeOffset) + } } type submitTextProposalAction struct { @@ -489,7 +498,7 @@ type voteGovProposalAction struct { propNumber uint } -func (tr TestRun) voteGovProposal( +func (tr *TestRun) voteGovProposal( action voteGovProposalAction, verbose bool, ) { @@ -521,7 +530,7 @@ func (tr TestRun) voteGovProposal( } wg.Wait() - time.Sleep(time.Duration(tr.chainConfigs[action.chain].votingWaitTime) * time.Second) + tr.WaitTime(time.Duration(tr.chainConfigs[action.chain].votingWaitTime) * time.Second) } type startConsumerChainAction struct { @@ -531,7 +540,7 @@ type startConsumerChainAction struct { genesisChanges string } -func (tr TestRun) startConsumerChain( +func (tr *TestRun) startConsumerChain( action startConsumerChainAction, verbose bool, ) { @@ -1219,8 +1228,8 @@ func (tr TestRun) transferChannelComplete( executeCommand(chanOpenConfirmCmd, "transferChanOpenConfirm") } -func executeCommand(cmd *exec.Cmd, cmdName string) { - if verbose != nil && *verbose { +func executeCommandWithVerbosity(cmd *exec.Cmd, cmdName string, verbose bool) { + if verbose { fmt.Println(cmdName+" cmd:", cmd.String()) } @@ -1238,7 +1247,7 @@ func executeCommand(cmd *exec.Cmd, cmdName string) { for scanner.Scan() { out := scanner.Text() - if verbose != nil && *verbose { + if verbose { fmt.Println(cmdName + ": " + out) } } @@ -1247,6 +1256,11 @@ func executeCommand(cmd *exec.Cmd, cmdName string) { } } +// Executes a command with verbosity specified by CLI flag +func executeCommand(cmd *exec.Cmd, cmdName string) { + executeCommandWithVerbosity(cmd, cmdName, *verbose) +} + type relayPacketsAction struct { chainA chainID chainB chainID @@ -1284,6 +1298,8 @@ func (tr TestRun) relayPacketsGorelayer( if err != nil { log.Fatal(err, "\n", string(bz)) } + + tr.waitBlocks(action.chainA, 1, 30*time.Second) } func (tr TestRun) relayPacketsHermes( @@ -1466,6 +1482,8 @@ func (tr TestRun) redelegateTokens(action redelegateTokensAction, verbose bool) if err != nil { log.Fatal(err, "\n", string(bz)) } + + tr.waitBlocks(action.chain, 1, 10*time.Second) } type downtimeSlashAction struct { @@ -1473,6 +1491,20 @@ type downtimeSlashAction struct { validator validatorID } +// takes a string representation of the private key like +// `{"address":"DF090A4880B54CD57B2A79E64D9E969BD7514B09","pub_key":{"type":"tendermint/PubKeyEd25519","value":"ujY14AgopV907IYgPAk/5x8c9267S4fQf89nyeCPTes="},"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"TRJgf7lkTjs/sj43pyweEOanyV7H7fhnVivOi0A4yjW6NjXgCCilX3TshiA8CT/nHxz3brtLh9B/z2fJ4I9N6w=="}}` +// and returns the value of the "address" field +func (tr TestRun) getValidatorKeyAddressFromString(keystring string) string { + var key struct { + Address string `json:"address"` + } + err := json.Unmarshal([]byte(keystring), &key) + if err != nil { + log.Fatal(err) + } + return key.Address +} + func (tr TestRun) invokeDowntimeSlash(action downtimeSlashAction, verbose bool) { // Bring validator down tr.setValidatorDowntime(action.chain, action.validator, true, verbose) @@ -1491,6 +1523,30 @@ func (tr TestRun) setValidatorDowntime(chain chainID, validator validatorID, dow lastArg = "up" } + if tr.useCometmock { + // send set_signing_status either to down or up for validator + var validatorAddress string + if chain == chainID("provi") { + validatorAddress = tr.getValidatorKeyAddressFromString(tr.validatorConfigs[validator].privValidatorKey) + } else { + var valAddressString string + if tr.validatorConfigs[validator].useConsumerKey { + valAddressString = tr.validatorConfigs[validator].consumerPrivValidatorKey + } else { + valAddressString = tr.validatorConfigs[validator].privValidatorKey + } + validatorAddress = tr.getValidatorKeyAddressFromString(valAddressString) + } + + method := "set_signing_status" + params := fmt.Sprintf(`{"private_key_address":"%s","status":"%s"}`, validatorAddress, lastArg) + address := tr.getQueryNodeRPCAddress(chain) + + tr.curlJsonRPCRequest(method, params, address) + tr.waitBlocks(chain, 1, 10*time.Second) + return + } + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. cmd := exec.Command( "docker", @@ -1764,6 +1820,8 @@ func (tr TestRun) assignConsumerPubKey(action assignConsumerPubKeyAction, verbos // TODO: @MSalopek refactor this so test config is not changed at runtime // make the validator use consumer key + // @POfftermatt I am currently using this for downtime slashing with cometmock + // (I need to find the currently used validator key address)Í valCfg.useConsumerKey = true tr.validatorConfigs[action.validator] = valCfg } @@ -1828,3 +1886,34 @@ func (tr TestRun) GetPathNameForGorelayer(chainA, chainB chainID) string { return pathName } + +// WaitTime waits for the given duration. +// The CometMock version of this takes a pointer to the TestRun as it needs to manipulate +// information in the testrun that stores how much each chain has waited, to keep times in sync. +// Be careful that all functions calling WaitTime should therefore also take a pointer to the TestRun. +func (tr *TestRun) WaitTime(duration time.Duration) { + if !tr.useCometmock { + time.Sleep(duration) + } else { + tr.timeOffset += duration + for chain, running := range tr.runningChains { + if !running { + continue + } + tr.AdvanceTimeForChain(chain, duration) + } + } +} + +func (tr TestRun) AdvanceTimeForChain(chain chainID, duration time.Duration) { + // cometmock avoids sleeping, and instead advances time for all chains + method := "advance_time" + params := fmt.Sprintf(`{"duration_in_seconds": "%d"}`, int(math.Ceil(duration.Seconds()))) + + address := tr.getQueryNodeRPCAddress(chain) + + tr.curlJsonRPCRequest(method, params, address) + + // wait for 1 block of the chain to get a block with the advanced timestamp + tr.waitBlocks(chain, 1, time.Minute) +} diff --git a/tests/e2e/config.go b/tests/e2e/config.go index 3038f69f4e..94fae8438f 100644 --- a/tests/e2e/config.go +++ b/tests/e2e/config.go @@ -76,10 +76,19 @@ type TestRun struct { useCometmock bool // if false, nodes run CometBFT useGorelayer bool // if false, Hermes is used as the relayer gaiaTag string + // chains which are running, i.e. producing blocks, at the moment + runningChains map[chainID]bool + // Used with CometMock. The time by which chains have been advanced. Used to keep chains in sync: when a new chain is started, advance its time by this value to keep chains in sync. + timeOffset time.Duration name string } +// Initialize initializes the TestRun instance by setting the runningChains field to an empty map. +func (tr *TestRun) Initialize() { + tr.runningChains = make(map[chainID]bool) +} + func getDefaultValidators() map[validatorID]ValidatorConfig { return map[validatorID]ValidatorConfig{ validatorID("alice"): { @@ -143,7 +152,7 @@ func getDefaultValidators() map[validatorID]ValidatorConfig { } func SlashThrottleTestRun() TestRun { - return TestRun{ + tr := TestRun{ name: "slash-throttling", containerConfig: ContainerConfig{ containerName: "interchain-security-slash-container", @@ -183,10 +192,12 @@ func SlashThrottleTestRun() TestRun { tendermintConfigOverride: `s/timeout_commit = "5s"/timeout_commit = "1s"/;` + `s/peer_gossip_sleep_duration = "100ms"/peer_gossip_sleep_duration = "50ms"/;`, } + tr.Initialize() + return tr } func DefaultTestRun() TestRun { - return TestRun{ + tr := TestRun{ name: "default", containerConfig: ContainerConfig{ containerName: "interchain-security-container", @@ -226,6 +237,8 @@ func DefaultTestRun() TestRun { tendermintConfigOverride: `s/timeout_commit = "5s"/timeout_commit = "1s"/;` + `s/peer_gossip_sleep_duration = "100ms"/peer_gossip_sleep_duration = "50ms"/;`, } + tr.Initialize() + return tr } func DemocracyTestRun(allowReward bool) TestRun { @@ -241,7 +254,7 @@ func DemocracyTestRun(allowReward bool) TestRun { consumerGenChanges += " | .app_state.ccvconsumer.params.reward_denoms = [\"stake\"]" } - return TestRun{ + tr := TestRun{ name: "democracy", containerConfig: ContainerConfig{ containerName: "interchain-security-democ-container", @@ -276,10 +289,12 @@ func DemocracyTestRun(allowReward bool) TestRun { tendermintConfigOverride: `s/timeout_commit = "5s"/timeout_commit = "1s"/;` + `s/peer_gossip_sleep_duration = "100ms"/peer_gossip_sleep_duration = "50ms"/;`, } + tr.Initialize() + return tr } func MultiConsumerTestRun() TestRun { - return TestRun{ + tr := TestRun{ name: "multi-consumer", containerConfig: ContainerConfig{ containerName: "interchain-security-multic-container", @@ -329,10 +344,12 @@ func MultiConsumerTestRun() TestRun { tendermintConfigOverride: `s/timeout_commit = "5s"/timeout_commit = "3s"/;` + `s/peer_gossip_sleep_duration = "100ms"/peer_gossip_sleep_duration = "100ms"/;`, } + tr.Initialize() + return tr } func ChangeoverTestRun() TestRun { - return TestRun{ + tr := TestRun{ name: "changeover", containerConfig: ContainerConfig{ containerName: "interchain-security-changeover-container", @@ -374,6 +391,8 @@ func ChangeoverTestRun() TestRun { tendermintConfigOverride: `s/timeout_commit = "5s"/timeout_commit = "1s"/;` + `s/peer_gossip_sleep_duration = "100ms"/peer_gossip_sleep_duration = "50ms"/;`, } + tr.Initialize() + return tr } func (s *TestRun) SetDockerConfig(localSdkPath string, useGaia bool, gaiaTag string) { diff --git a/tests/e2e/state.go b/tests/e2e/state.go index 15500dd01f..4de28277d2 100644 --- a/tests/e2e/state.go +++ b/tests/e2e/state.go @@ -210,6 +210,16 @@ func (tr TestRun) getBlockHeight(chain chainID) uint { } func (tr TestRun) waitBlocks(chain chainID, blocks uint, timeout time.Duration) { + if tr.useCometmock { + // call advance_blocks method on cometmock + // curl -H 'Content-Type: application/json' -H 'Accept:application/json' --data '{"jsonrpc":"2.0","method":"advance_blocks","params":{"num_blocks": "36000000"},"id":1}' 127.0.0.1:22331 + tcpAddress := tr.getQueryNodeRPCAddress(chain) + method := "advance_blocks" + params := fmt.Sprintf(`{"num_blocks": "%d"}`, blocks) + + tr.curlJsonRPCRequest(method, params, tcpAddress) + return + } startBlock := tr.getBlockHeight(chain) start := time.Now() @@ -722,7 +732,11 @@ func (tr TestRun) getValidatorHome(chain chainID, validator validatorID) string // getQueryNode returns query node tcp address on chain. func (tr TestRun) getQueryNode(chain chainID) string { - return fmt.Sprintf("tcp://%s:26658", tr.getQueryNodeIP(chain)) + return fmt.Sprintf("tcp://%s", tr.getQueryNodeRPCAddress(chain)) +} + +func (tr TestRun) getQueryNodeRPCAddress(chain chainID) string { + return fmt.Sprintf("%s:26658", tr.getQueryNodeIP(chain)) } // getQueryNodeIP returns query node IP for chain, @@ -737,3 +751,13 @@ func (tr TestRun) getQueryNodeIP(chain chainID) string { } return fmt.Sprintf("%s.253", tr.chainConfigs[chain].ipPrefix) } + +func (tr TestRun) curlJsonRPCRequest(method, params, address string) { + cmd_template := `curl -H 'Content-Type: application/json' -H 'Accept:application/json' --data '{"jsonrpc":"2.0","method":"%s","params":%s,"id":1}' %s` + + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, "bash", "-c", fmt.Sprintf(cmd_template, method, params, address)) + + verbosity := false + executeCommandWithVerbosity(cmd, "curlJsonRPCRequest", verbosity) +} diff --git a/tests/e2e/steps.go b/tests/e2e/steps.go index 7613b05558..ee53e9fd2a 100644 --- a/tests/e2e/steps.go +++ b/tests/e2e/steps.go @@ -35,6 +35,7 @@ var shortHappyPathSteps = concatSteps( stepsDelegate("consu"), stepsUnbond("consu"), stepsRedelegateShort("consu"), + stepsDowntime("consu"), stepsStartRelayer(), stepsConsumerRemovalPropNotPassing("consu", 2), // submit removal prop but vote no on it - chain should stay stepsStopChain("consu", 3), // stop chain From 8068773887b55204b9825e61492496ea69aad052 Mon Sep 17 00:00:00 2001 From: Marius Poke Date: Tue, 20 Jun 2023 18:45:29 +0200 Subject: [PATCH 019/134] ci: update sonar.exclusions (#1036) * update sonar.exclusions * fix comment --- sonar-project.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonar-project.properties b/sonar-project.properties index 585cf1700f..34d8d28397 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -14,7 +14,7 @@ sonar.organization=cosmos # All golang artifacts sonar.sources=. # Do not calculate coverage metrics for statements in these files -sonar.exclusions=**/vendor/**,**/*.pb.go,**/*.pb.gw.go,proto,**/*_test.go,tests/**,testutil/**,legacy_ibc_testing/**,app/consumer/app.go +sonar.exclusions=**/vendor/**,**/*.pb.go,**/*.pb.gw.go,proto,**/*_test.go,tests/**,testutil/**,legacy_ibc_testing/**,docs/**,app/**,cmd/**, sonar.tests=. # Run unit and integration tests, but not E2E tests sonar.test.inclusions=**/*_test.go From 827eece97aa4f209c9aded543f13edb3d3e99904 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Tue, 20 Jun 2023 11:24:02 -0700 Subject: [PATCH 020/134] docs: soft opt out adr (#1014) * context and decision * consequences * everything stays on consumer * Update adr-009-soft-opt-out.md * Update adr-009-soft-opt-out.md * Apply suggestions from code review Co-authored-by: Marius Poke * ToC entry * update wasted computation consequence * Apply suggestions from code review Co-authored-by: Marius Poke --------- Co-authored-by: Marius Poke --- docs/docs/adrs/adr-009-soft-opt-out.md | 48 ++++++++++++++++++++++++++ docs/docs/adrs/intro.md | 1 + 2 files changed, 49 insertions(+) create mode 100644 docs/docs/adrs/adr-009-soft-opt-out.md diff --git a/docs/docs/adrs/adr-009-soft-opt-out.md b/docs/docs/adrs/adr-009-soft-opt-out.md new file mode 100644 index 0000000000..6d90710317 --- /dev/null +++ b/docs/docs/adrs/adr-009-soft-opt-out.md @@ -0,0 +1,48 @@ +--- +sidebar_position: 10 +title: Soft Opt-Out +--- +## ADR 009: Soft Opt-Out + +## Changelog + +* 6/13/23: Initial draft of ADR. Feature already implemented and in production. + +## Status + +Accepted + +## Context + +Some small validators may not have the resources needed to validate all consumer chains. Therefore a need exists to allow the bottom `x%` of validators to opt-out of validating a consumer chain. Meaning downtime infractions for these validators are dropped without ever reaching the provider. + +This document specifies a modification to the ccv protocol which allows the bottom x% of the validator set by power to opt out of validating consumer chains without being jailed or otherwise punished for it. The feature is implemented with entirely consumer-side code. + +## Decision + +A consumer param exists, known as `SoftOptOutThreshold`, which is a string decimal in the range of [0, 0.2], that determines the portion of validators which are allowed to opt out of validating that specific consumer. + +In every consumer beginblocker, a function is ran which determines the so called _smallest non opt-out voting power_. Validators with voting power greater than or equal to this value must validate the consumer chain, while validators below this value may opt out of validating the consumer chain. + +The smallest non opt-out voting power is recomputed every beginblocker in `UpdateSmallestNonOptOutPower()`. In a nutshell, the method obtains the total voting power of the consumer, iterates through the full valset (ordered power ascending) keeping track of a power sum, and when `powerSum / totalPower > SoftOptOutThreshold`, the `SmallestNonOptOutPower` is found and persisted. + +Then, whenever the `Slash()` interface is executed on the consumer, if the voting power of the relevant validator being slashed is less than `SmallestNonOptOutPower` for that block, the slash request is dropped and never sent to the provider. + +## Consequences + +### Positive + +* Small validators can opt out of validating specific consumers without being punished for it. + +### Negative + +* The bottom `x%` is still part of the total voting power of the consumer chain. This means that if the soft opt-out threshold is set to `10%` for example, and every validator in the bottom `10%` opts out from validating the consumer, then a `24%` downtime of the remaining voting power would halt the chain. This may be especially problematic during consumer upgrades. +* In nominal scenarios, consumers with soft opt out enabled will be constructing slash packets for small vals, which may be dropped. This is wasted computation, but necessary to keep implementation simple. Note that the sdk's [full downtime logic](https://github.com/cosmos/cosmos-sdk/blob/d3f09c222243bb3da3464969f0366330dcb977a8/x/slashing/keeper/infractions.go#L75) is always executed on the consumer, which can be computationally expensive and slow down certain blocks. + +### Neutral + +* Validators in the bottom of the valset who don't have to validate, may receive large delegation(s) which suddenly boost the validator to the subset that has to validate. This may catch the validator off guard. + +## References + +* Original issue with some napkin math [#784](https://github.com/cosmos/interchain-security/issues/784) diff --git a/docs/docs/adrs/intro.md b/docs/docs/adrs/intro.md index bdd59ad20b..d0c097fb06 100644 --- a/docs/docs/adrs/intro.md +++ b/docs/docs/adrs/intro.md @@ -38,3 +38,4 @@ To suggest an ADR, please make use of the [ADR template](./adr-template.md) prov | [004](./adr-004-denom-dos-fixes) | Denom DOS fixes | Accepted, Implemented | | [007](./adr-007-pause-unbonding-on-eqv-prop.md) | Pause validator unbonding during equivocation proposal | Proposed | | [008](./adr-008-throttle-retries.md) | Throttle with retries | Accepted, In-progress | +| [009](./adr-009-soft-opt-out.md) | Soft Opt-out | Accepted, Implemented | From 7b7bd65c305d45125993e94e5af1d90565edfcda Mon Sep 17 00:00:00 2001 From: Marius Poke Date: Tue, 20 Jun 2023 20:43:20 +0200 Subject: [PATCH 021/134] chore: update meaning of `type-prefix!` in production PRs (#1021) update meaning of in PRs Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> --- .github/PULL_REQUEST_TEMPLATE/production.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE/production.md b/.github/PULL_REQUEST_TEMPLATE/production.md index 0d197d890c..885d852cf0 100644 --- a/.github/PULL_REQUEST_TEMPLATE/production.md +++ b/.github/PULL_REQUEST_TEMPLATE/production.md @@ -19,7 +19,7 @@ please add links to any relevant follow up issues.* I have... * [ ] Included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title -* [ ] Added `!` to the type prefix if API or client breaking change +* [ ] Added `!` to the type prefix if state-machine breaking change (i.e., requires coordinated upgrade) * [ ] Confirmed this PR does not introduce changes requiring state migrations, OR migration code has been added to consumer and/or provider modules * [ ] Targeted the correct branch (see [PR Targeting](https://github.com/cosmos/interchain-security/blob/main/CONTRIBUTING.md#pr-targeting)) * [ ] Provided a link to the relevant issue or specification From d4dde74b062c2fded0d3b3dbef4b3b0229e317f3 Mon Sep 17 00:00:00 2001 From: MSalopek Date: Wed, 21 Jun 2023 11:23:16 +0200 Subject: [PATCH 022/134] feat!: upgrade ics sdk47 ibc7 (#1019) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Merge main into feat/upgrade-ics-sdk47-ibc7 (#955) * build(deps): bump gaurav-nelson/github-action-markdown-link-check from 1.0.13 to 1.0.15 (#928) build(deps): bump gaurav-nelson/github-action-markdown-link-check Bumps [gaurav-nelson/github-action-markdown-link-check](https://github.com/gaurav-nelson/github-action-markdown-link-check) from 1.0.13 to 1.0.15. - [Release notes](https://github.com/gaurav-nelson/github-action-markdown-link-check/releases) - [Commits](https://github.com/gaurav-nelson/github-action-markdown-link-check/compare/1.0.13...1.0.15) --- updated-dependencies: - dependency-name: gaurav-nelson/github-action-markdown-link-check dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore: bump hermes (#921) * bump the version of hermes used in docs and images * use the multiplatform ghcr.io build of hermes --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jacob Gadikian * feat!: upgrade ics to ibc-go/v7 and cosmos-sdk/v0.47 (#918) * change ibc module paths * Squashed commit of the following: commit ece7bc92a0b388fde32efc39358e3a096949457a Merge: 8763d99c ead0d214 Author: Jacob Gadikian Date: Fri Apr 21 16:26:55 2023 +0700 Merge remote-tracking branch 'filter/new_branch_sdk47' into new-new-new-sdk47 commit ead0d21487858fef5e30ddbaf7cedb47b41d7296 Author: Jacob Gadikian Date: Thu Apr 20 14:22:26 2023 +0700 remove proto files completely commit 79f565a4d51c08a961e48450be108f6a08ee7a23 Author: Jacob Gadikian Date: Thu Apr 20 14:16:49 2023 +0700 make protos match exactly commit c4c856c049c4a718ebf063df279a613d5db56819 Author: Jacob Gadikian Date: Thu Apr 20 14:14:51 2023 +0700 make protos match the v7.0.x branch exactly commit af812332d52cb972204490e89e1e3d75bb626141 Author: Jacob Gadikian Date: Thu Apr 20 14:11:31 2023 +0700 remove even more proto code commit 97e7021559eaa10a3a8020df5b930f688c7a3ecd Author: Jacob Gadikian Date: Thu Apr 20 13:56:33 2023 +0700 remove unneeded proto deps and build with many fewer commit ddb6218eccad467013b7c585a70bac2eb039d017 Author: Jacob Gadikian Date: Thu Apr 20 12:25:46 2023 +0700 update proto build image commit 19fc8a0da6ddd86bb295d413e8ae4928b33f4f0c Author: Ruslan Akhtariev Date: Thu Apr 20 11:35:55 2023 +0800 Revert "remove code from third party -> add deps directly to buf.yml" This reverts commit a53d890f831a20060da57877f19ec769d6a506f6. commit a53d890f831a20060da57877f19ec769d6a506f6 Author: Ruslan Akhtariev Date: Thu Apr 20 11:34:07 2023 +0800 remove code from third party -> add deps directly to buf.yml commit 88d79f88b8724754ca4a4a6a21f41a6c2d370d51 Merge: b672630b d0ee1ee6 Author: Jacob Gadikian Date: Wed Apr 19 23:13:10 2023 +0800 Merge branch 'main' into new_branch_sdk47 commit d0ee1ee66b2eb69c039402f5d3e34a2e2a01a51a Author: Thomas Bruyelle Date: Wed Apr 19 16:55:22 2023 +0200 fix(build): make proto-update-deps (#830) * fix(build): make proto-update-deps The URL to the cosmos-sdk SDK_PROTO_URL was using a branch that doesn't exists (any more I presume). As a result, `make proto-update-deps` wasn't working properly and was filling all the cosmos proto files with `404 Not Found`. Fix by using the correct branch name, which is `interchain-security-rebase.0.45.11`. * use SDK latest tag commit b672630bada19249db7bd759c0af771cae5697b8 Merge: 7ca44282 f7fb129e Author: Jacob Gadikian Date: Mon Apr 17 21:36:20 2023 +0700 Merge remote-tracking branch 'origin/main' into new_branch_sdk47 commit 7ca44282579d579874a6d9ea504e3184e63f1b96 Merge: 1909670e 5a94f896 Author: vuong <56973102+vuong177@users.noreply.github.com> Date: Fri Apr 14 16:17:35 2023 +0700 Merge pull request #1 from notional-labs/vuong/fix-proto fix gogo proto commit 5a94f896bbd909e75f32b83c084e355d276b1bdb Author: vuong Date: Fri Apr 14 16:14:41 2023 +0700 fix gogo proto commit f7fb129e9db991a6ab714ad6689221e84c7b894b Author: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Thu Apr 13 06:58:33 2023 -0700 Soft opt out (#833) * WIP soft opt out code with incomplete boilerplate * proto changes * Seems like it should work * Unit test for UpdateLargestSoftOptOutValidatorPower * fixes and renames, unit tests work * update comment * log * Update proto/interchain_security/ccv/consumer/v1/consumer.proto Co-authored-by: Marius Poke * better validation for soft opt out threshhold * improve test * slicestable * semantics and improved test * use correct key util * Update module.go * comment * updated semantics * separate files * fix TestMakeConsumerGenesis test * fix naming * change upper bound on soft opt out thresh * fix test * allow empty valset for tests * gofumpt and fix from merge * Update x/ccv/consumer/types/params_test.go * Update x/ccv/consumer/types/params.go * Soft opt out diff tests (#847) * wip * fixes for ts build * AI fixed my bug lol * throw error when needed * comment * disable soft opt-out in diff testing * update diff testing model * update UTs --------- Co-authored-by: mpoke * add comment about beginblocker order requirement for soft opt-out --------- Co-authored-by: Jehan Tremback Co-authored-by: Marius Poke Co-authored-by: Simon Noetzlin commit 673b6c44af8fd0eddbc90c7c3db05fc25cc8ae85 Author: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Wed Apr 12 03:24:41 2023 -0700 Fix Makefile (#837) Update Makefile Co-authored-by: Simon Noetzlin commit 1909670e298a3d2dc94da45d6ec296e57fdca4de Merge: c76c7284 7fd358f4 Author: sontrinh16 Date: Wed Apr 5 15:48:00 2023 +0700 fix bug commit 7fd358f47df7c1ebef4548ed2bb507c33671a81f Author: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Tue Apr 4 20:43:46 2023 -0700 feat: standalone to consumer changeover part 1 (#757) * on-chain upgrade to consumer chain wip * add preCCV store and use it on democracy staking * add TODOs and one more packet possibility * status update * Resolve hermes start issue for trusted validator set by changing revision height * remove intermediary logs * remove further unused codebase * updates for endblocker test, existing test fixes, get last validators * update for slashing sovereign validators for the fault made before consumer chain upgrade height * resolve comments on github and slack communication * update sovereign app to use v4 ibc from v3 & resolve consumer module merge conflict fix issue * Update app/sovereign/upgrades/v3/upgrades.go Co-authored-by: yaruwangway <69694322+yaruwangway@users.noreply.github.com> * rm sovereign chain and tests. Will be replaced by simapp and integration tests * duplicate module name * add comment * small rename * remove democracy staking changes * consumer ccv beginblock, endblock, and initgenesis order shouldn't matter * add mock calls to compile * adjust tests for new keeper field * add registerDemocConsumer method * split out preCCV flag and initial valset * cleanup consumer module * cleanup * more cleanup * temp changes to validators.go * comment out test * rm bad code from merge * comment * Update app.go * UTs for CRUD * UTs for keys * use make for mocks * todo * changeover method and test * resolve #783 * comment * comments * add appropriate TODOs, restore changes to main * final nits before non-draft * comment on ChangeoverToConsumer * more clear comment * small comment change * update InitGenesis comment * sovereign -> standalone * missed a file * builds now * update comment after debug * naming refactor * edge case for val in old and new sets * restore keys after rebase --------- Co-authored-by: jstr1121 Co-authored-by: jstr1121 <118450565+jstr1121@users.noreply.github.com> Co-authored-by: yaruwangway <69694322+yaruwangway@users.noreply.github.com> commit c76c7284804f7a56f5a240c68c43fcb1c6db6d6b Merge: b9db2396 46f568f5 Author: sontrinh16 Date: Wed Apr 5 10:30:54 2023 +0700 fixing merge conflict commit 46f568f57de69b3462c167e898a770399c68c891 Author: Simon Noetzlin Date: Tue Apr 4 14:12:45 2023 +0200 chore: swap name of 'e2e' and 'integration' tests (#681) * save first changes * fix gh workflow * update gh actions * fix bug * squash commits * Simply use Test rather than Ingt for naming integration test keepers * update git workflows commit b9db2396b53235873072a26484e654ebfe2e9afa Author: Son Trinh Date: Thu Mar 30 17:06:37 2023 +0700 fix x folder commit b4103d3644db155df36653a873ddf3d06512efde Author: Son Trinh Date: Wed Mar 29 17:14:43 2023 +0700 add forked staking proto commit d8c696e45b6b7522665b55b4e05e9981126300b9 Author: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Thu Mar 23 11:35:58 2023 -0700 Introduce docs website (#759) * init docusaurus repo * unify theme with cosmos-sdk docs * update config * add FAQ sections * terms * Create overview.md * consumer dev folder * smol * Create technical-specification.md * add new stuff * add key assignment documentation * fix typo * add clarification * update documentation; add features section; improve overview * mv website to docs root; mv old readmes to old_docs * add doc deployer * make deployable to github pages * add consumer initiated slashing doc page * sovereign -> standalone * add validators section * fix typos * update small things * rename validator stuff * add joining-testnet docs * add title to joining testnet * minor refactors * refactor faq, update testnet guide * update footers * update testnet repo links * Fix typo Change ". Ie." to ", i.e." * Fix typo: you key => your key * Fix typo: cosumer => consumer * update copyright section so docusaurus builds * Add . at the end of info boxes * Minor grammar change * Add missing word "the" * Fix typo * update broken link for ics-testnets * Remove duplicated paragraphs * Adjust wording --------- Co-authored-by: Matija Salopek Co-authored-by: MSalopek <35486649+MSalopek@users.noreply.github.com> Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> commit 0f7ba20ec157afc8c0af2b974f08fdc000837c0c Author: Thomas Bruyelle Date: Thu Mar 16 08:13:24 2023 +0100 chore: add Makefile target to generate mocks (#769) commit 85235c8b0efabfce98c98bf5628bac46b9c8b7a4 Author: MSalopek <35486649+MSalopek@users.noreply.github.com> Date: Mon Mar 6 18:53:41 2023 +0100 allow using gaia as provider in integration tests (#735) * allow using gaia as provider in integration tests * add changes to makefile * add gaia dockerfile * update testing docs * update Makefile; validate gaia tags (support >= v9.x.x) --------- Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> commit cf02d4f45b0c935e890acfd1a7a1efc5869a033a Author: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Thu Mar 2 13:48:08 2023 -0800 Key assignment type safety (#725) * pb changes * nvm dont wanna open that can of worms * still wip * more fixes * almost * builds * helpers and fixed one file * comments * mas * test fix * fix another * types * smol * un mas * un mas * nit * reformat * mas * fix last bug * to fix integration test * proper way to do stringer * Update slashing.go * Update slashing.go * links * comments * Update keeper.go * smol * nit * changes to TestHandleEquivocationProposal * merge with fixes * merge fix * comment --------- Co-authored-by: MSalopek <35486649+MSalopek@users.noreply.github.com> commit 7f2207ad77b6faf568e8ff4b9d1d372d33b09692 Author: MSalopek <35486649+MSalopek@users.noreply.github.com> Date: Thu Mar 2 17:52:59 2023 +0100 update protos; fix missing proto dependencies (#752) commit 7ee9fcd763d712bede87748ada7b41590f731c10 Author: MSalopek <35486649+MSalopek@users.noreply.github.com> Date: Tue Feb 28 18:03:17 2023 +0100 add interchain security consumer QueryParams (#746) add QueryParams commit 0ddbd12b762d1120bb8fa1432edc10ed5de88689 Author: Thomas Bruyelle Date: Mon Feb 6 18:17:31 2023 +0100 feat: Equivocation gov proposal (#703) This change adds a new kind of gov proposal that will slash and tombstone validators for double-signing. The proposal handler is added in the `provider` module, and use the `evidence` module to handle the equivocations. Co-authored-by: Albert Le Batteux Co-authored-by: Jehan commit 0724edce7de9327dc57f50b95bc64738714824bf Author: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Mon Jan 30 10:16:30 2023 -0800 fix: slash meter replenishment (#687) * this test should fail * changes * refactors * smol * comments * naming * smalls * update E2e tests to validate new behavior * nit * whoops * change key name * set time w/in method * fix typo commit ac4be76bf07788ae5aae6fc40907aac51b531926 Author: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Fri Jan 20 05:01:36 2023 -0800 Bump IBC refs to ver 4.2.0 (#654) * Update gitignore * Add ibc testing folder * WIP replacing ibcsim * Tests pass * Update ibc-go dependency * Remove TODOs * Remove unused code * Fixes ibcsim simapp dep * Remove unneeded simapp code from #632 (#636) delete code * Fix lint * Update dependencies and linters * Test gosec ignore * Fix gosec * Fix linting * Update sonarcloud ignore for ibc * Revert lint change * Removed unused code * Refactor ibc directory * Add back gaia tests and add ibc-testing disclosure * wip * compiles * tests pass * todos * fix codeql file indentation * 2nd attempt to fix codeql * 3rd attempt * update OnChanOpenInit version handling to follow ics26 * revert module version * remove version checking in provider OnChanOpenInit * address left TODOs Co-authored-by: lg Co-authored-by: Daniel Co-authored-by: lg <8335464+glnro@users.noreply.github.com> Co-authored-by: Simon Noetzlin Co-authored-by: Marius Poke commit 2e064193dd1e0aeea2149548818d23dc849ed189 Author: MSalopek <35486649+MSalopek@users.noreply.github.com> Date: Fri Jan 20 12:09:51 2023 +0100 run happy path tests on push; bump hermes version (#659) * use official hermes release * refactor integration test main.go * update automated-tests integration test run * fix worng container teardown * refactor main.go; add parallel execution * update Makefile * simplify code * refactor for naming consistency * fix string formatting commit 7c9d0934002377f2b95d7d722fe0101df5f190fc Author: Marius Poke Date: Fri Dec 23 18:44:10 2022 +0100 Fix: Iteration through PacketMaturityTimes assumes maturity time order (#622) * WIP convert iterators to array getters. Still need to rename functions, and some compile errors in tests. * WIP - compiles, fixing tests * Unit and e2e tests work * add notes about stopping iteration * WIP - rename and add some notes * Add types to proto * delete unused code * resolve naming conflict * implement another type as proto * fixing more stuff * delete TODOJEHAN.md * adds many of Marius's iteration order comments from 599, and does some small refactors for clarity * fix nil pointer deref * call GetAllConsumerChains once * expand TestGetAllChannelToChains * expand TestGetAllUnbondingOps * GetAllUnbondingOpIndexes; cleanup proto files * fix GetAllValsetUpdateBlockHeights and UTs * remove GetAllSlashAck * add tests for GetFirstVscSendTimestamp * key assignment iterators * reviewed proposals * add TestGetAllValsetUpdateBlockHeights * add TestGetAllOutstandingDowntimes * add GetElapsedPacketMaturityTimes * fix linter * fix linter * prevent implicit memory aliasing * add UTC to TestPacketMaturityTime * fix TestPacketMaturityTime * avoid local variable name shadowing * Update x/ccv/consumer/keeper/keeper.go Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> * replace cases with packets in TestPacketMaturityTime * add expected order to TestPacketMaturityTime * add expected order to TestGetAllHeightToValsetUpdateIDs * add expected order to TestGetAllOutstandingDowntimes * add TestGetAllCCValidator * add expected order to TestGetAllConsumerChains * add expected order to TestGetAllChannelToChains * add expected order to TestGetAllUnbondingOps * add expected order to TestGetAllUnbondingOpIndexes * add expected order to TestGetAllValsetUpdateBlockHeights * add expected order to TestInitTimeoutTimestamp * add expected order to TestVscSendTimestamp * add expected order to TestGetAllValidatorConsumerPubKey * add expected order to TestGetAllValidatorsByConsumerAddr * add expected order to TestGetAllKeyAssignmentReplacements * add expected order to TestGetAllConsumerAddrsToPrune * iterate over packet maturities in order of time * fix linter * move AppendMany to utils * review suggestions * refactor TestPacketMaturityTime UT * nits Co-authored-by: Jehan Tremback Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> commit 4063734e3584a93175159ef1e09843360fae3335 Author: Simon Noetzlin Date: Thu Dec 22 17:43:04 2022 +0100 refactor: wrap VSCMatured/Slash packets into a consumer packet type (#626) * refactor: create a consumer packet type - Create a ConsumerPacketData type definition at the CCV protocol level - Update consumer to send ConsumerPacketData to provider - Update provider to receive ConsumerPacketData Co-authored-by: mpoke commit e8bc5b878efef22b5dde5df4977abda5645d3322 Author: Jehan Date: Wed Dec 21 15:18:02 2022 -0800 Refactor: Convert iterators to array getters (#596) * WIP convert iterators to array getters. Still need to rename functions, and some compile errors in tests. * WIP - compiles, fixing tests * Unit and e2e tests work * add notes about stopping iteration * WIP - rename and add some notes * Add types to proto * delete unused code * resolve naming conflict * implement another type as proto * fixing more stuff * delete TODOJEHAN.md * adds many of Marius's iteration order comments from 599, and does some small refactors for clarity * fix nil pointer deref * call GetAllConsumerChains once * expand TestGetAllChannelToChains * expand TestGetAllUnbondingOps * GetAllUnbondingOpIndexes; cleanup proto files * fix GetAllValsetUpdateBlockHeights and UTs * remove GetAllSlashAck * add tests for GetFirstVscSendTimestamp * key assignment iterators * reviewed proposals * add TestGetAllValsetUpdateBlockHeights * add TestGetAllOutstandingDowntimes * add GetElapsedPacketMaturityTimes * fix linter * fix linter * prevent implicit memory aliasing * add UTC to TestPacketMaturityTime * fix TestPacketMaturityTime * avoid local variable name shadowing * Update x/ccv/consumer/keeper/keeper.go Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> * replace cases with packets in TestPacketMaturityTime * add expected order to TestPacketMaturityTime * add expected order to TestGetAllHeightToValsetUpdateIDs * add expected order to TestGetAllOutstandingDowntimes * add TestGetAllCCValidator * add expected order to TestGetAllConsumerChains * add expected order to TestGetAllChannelToChains * add expected order to TestGetAllUnbondingOps * add expected order to TestGetAllUnbondingOpIndexes * add expected order to TestGetAllValsetUpdateBlockHeights * add expected order to TestInitTimeoutTimestamp * add expected order to TestVscSendTimestamp * add expected order to TestGetAllValidatorConsumerPubKey * add expected order to TestGetAllValidatorsByConsumerAddr * add expected order to TestGetAllKeyAssignmentReplacements * add expected order to TestGetAllConsumerAddrsToPrune * Add test for GetSlashAndTrailingData (#623) * add test * comments * Update throttle.go * use InitTimeoutTimestamp instead of two slices * Fix: Change keys for storing proposals (#620) * change keys for storing proposals * apply review suggestions * Apply suggestions from code review Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Co-authored-by: Jehan Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Co-authored-by: mpoke Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> commit 8603f9c97548fb4f3979e85e99bb6979b0eaf269 Author: MSalopek <35486649+MSalopek@users.noreply.github.com> Date: Tue Dec 20 20:29:32 2022 +0100 add slash throttling queries (#600) * add slash throttle queries * add slash throttle integration tests * add integration tests * add integration tests * make tests pass * should build now * implicit memory aliasing stuff * rm file * refactor queries * changes * new wrapper type * Throttle queries refactors (#614) * refactors * Update state.go * rm duplicated imports * change slash meter params in default test run * add comment * move state checks to provider Co-authored-by: Shawn Marshall-Spitzbart <44221603+smarshall-spitzbart@users.noreply.github.com> commit 0657172ad63490f62ddbb22f7518e0b223cd9844 Author: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Tue Dec 20 06:11:53 2022 -0800 GlobalSlashEntry protobuf type (#613) * changes * indentation fix * un mas commit 61608316cf01d1388907e18290c7f2c894c2c0fa Author: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Mon Dec 19 10:37:17 2022 -0800 Throttle refactors (#611) * comments and move panic * proto changes * naming * remove break label * refactor HandlePacketDataForChain * Revert "refactor HandlePacketDataForChain" This reverts commit 8f6a29679e1499d605579e941ed74ba67b1d4e05. * comment * comments commit a6716a6a6e6e00992a0f2b05b985edf98b76bad9 Author: lg <8335464+glnro@users.noreply.github.com> Date: Fri Dec 16 16:52:09 2022 +0100 refactor: TrustingPeriodFraction should be a fraction. (#593) * WIP * Refactor TrustingPeriodFraction * Update default TrustingPeriodFraction to 2/3 or 66% Co-authored-by: Jehan commit 3a8d0a27dfdb2abece8ce5dd86ae5172e8652581 Author: MSalopek <35486649+MSalopek@users.noreply.github.com> Date: Thu Dec 8 09:57:42 2022 +0100 update consumer addition proposal (#558) * update ConsumerAdditionProposal in provider.proto * add ValidateBasic for ConsumerAdditionProposal message * fix failing ValidateBasic tests * make all tests work * make all tests work * update proposal in integration tests * update comment * refactor after rebase * run make proto-gen after rebase on main * remove LockUnbonding flag and references from repo (PR #551) * refactor after reviews commit f57c604c2e2a51c1e9dafad1d9e0332e461e2bf4 Author: Marius Poke Date: Wed Dec 7 11:52:49 2022 +0100 Key assignment (#515) * add MsgAssignConsumerKey * add MsgAssignConsumerKey * fix package name * add keys * add keeper methods for key assignment * handle MsgAssignConsumerKey * map addresses in slash requests * prune old consumer addresses * move AssignConsumerKey logic to keeper * update consumer initial valset * add ApplyKeyAssignmentToValUpdates * fix client creation * do not check init valset on consumer * clean state on val removal * fix TestAssignConsensusKeyForConsumerChain * delete on val removal * remove reverse mapping on val removal * remove pending key assignment in EndBlock * add query endpoints add summary of indexes change ConsumerValidatorByVscID to ConsumerAddrsToPrune * Refactor AssignConsumerKey for clarity (IMO) * finish key assignment genesis code- untested * FIxed mocks compile issue - not sure if it works right though. * add test for init and export genesis * set after get in AssignConsumerKey * enable AssignConsumerKey to be called twice * remove key assignment on chain removal * apply some review comments * fix bug: two validator with same consumer key * rename key: ConsumerValidatorsByVscIDBytePrefix -> ConsumerAddrsToPruneBytePrefix * PendingKeyAssignment -> KeyAssignmentReplacements * msg.ProviderAddr is a validator addr * fix: key assignment genesis tests (#517) * Fix consumer init genesis test * fix provider genesis tests * fix key assignement handler * fix linter * fix merge conflict * fix ProviderValidatorAddress * remove unused expectation Co-authored-by: Marius Poke * add key assignment CRUD operations unit tests (#516) * test val consumer key related CRUD * test val consumer addr related CRUD * test pending key assignments related CRUD * refactor after review session * refactor after review session * add prune key CRUD tests * renamings in testfiles * improve KeyAssignmentReplacement set and get * remove ApplyKeyAssignmentToInitialValset (redundant) * add invariant to docstring of AppendConsumerAddrsToPrune * fix address conversion * adding e2e tests * fix linter * add queries; setup integration tests (#519) * add queries; setup integration testse * test key assignment before chain start * fix state queries; refactor * rm extra comment * rm unused action field * bump voting times in all tests * add provider address query to tests * Adds some very basic random testing and unit tests (#522) * Adds imports * Does multi iterations: fails! * Handle errs * checkpoint debug * Pre introduce dynamic mock * Issue seems to be resolved * Removes prints in key asisgn * Removes debug, pre reintroduce all test features * Fix some magic numbers, bring back prune check * Pre rework initial assignments * Refactor and tidyup * Better docs, clarity, org Co-authored-by: Daniel * Enable key assignment testing for all e2e tests (#524) * split CCVTestSuite.setupCallback in two * pre-assign keys for all vals of first consumer * fix linter * remove TestConsumerGenesis * adding ADR * move handler.go outside client/ * replace [][]byte with AddressList * remove IterateAllConsumerAddrsToPrune; not needed * apply review suggestions * fix linter * Danwt/key assignment slash test (#545) * cp * wip * note * cp * Adds slash test Co-authored-by: Daniel * Fixes #503 prevents two key assignment key overlap security issues (#556) * Deletes out of date duplicate code * Adds check that validator with key does not already exist * Partially adjust assign unit test * Finishes adjusting unit * Updates stress test to never find a validator * Improves comment * Fixes handler_test * Adds validatorI iterator to expected keeper * Implements AfterValidatorCreated hook * Names * Simplifies validator query * Adds hooks test * Remove TODO * Fix random sim test Co-authored-by: Daniel * Bump AssignConsumerKey comment * improve comments for iterators * Masa/key assignment integration tests amend (#548) * handle gosec false positive * add err checks for key assign; rm multiconsumer tests * guestimate block window for keyswaps in happyPeth * start multiconsumer with flag * remove node_modules * fix comment Co-authored-by: Jehan Tremback Co-authored-by: Simon Noetzlin Co-authored-by: MSalopek <35486649+MSalopek@users.noreply.github.com> Co-authored-by: Daniel T <30197399+danwt@users.noreply.github.com> Co-authored-by: Daniel Co-authored-by: Jehan commit 174f4cd5965b28fc7cb34fc1f4841857d71a8a18 Author: MSalopek <35486649+MSalopek@users.noreply.github.com> Date: Mon Dec 5 09:27:28 2022 +0100 refactor provider pending packets handling (#552) commit fb63b1849862b7d28541065a3636f48bb59555d7 Author: Simon Noetzlin Date: Thu Dec 1 22:05:17 2022 +0100 update provider genesis validation (#525) * update provider genesis validation * Update client ID validation for provider genesis * Make provider VSCID to be stricly positive Update provider genesis validation * update comment * remove tmp files * fix provider genesis validation bugs * remove wrongly introduced ibc-go dep * typo * improve coverage Co-authored-by: Shawn Marshall-Spitzbart <44221603+smarshall-spitzbart@users.noreply.github.com> commit b1a3e53ef301606be0dd09f231fd362c9cee92a9 Author: MSalopek <35486649+MSalopek@users.noreply.github.com> Date: Tue Nov 22 19:49:19 2022 +0100 add consumer addition proposal documentation (#502) * add consumer addition proposal documentation * update after reviews Co-authored-by: Shawn Marshall-Spitzbart <44221603+smarshall-spitzbart@users.noreply.github.com> commit 2466b26406258501f7d9b7c955a81d7248a84944 Author: Simon Noetzlin Date: Fri Nov 18 19:15:43 2022 +0100 Update #264 - updates genesis and genesis tests (#382) * reformat consumer genesis test * remove validator fill in of ExportAppStateAndValidators * checkpoint, testing export genesis consumer * test consumer export * make pass the tests * fix export height to valset update id in consumer * pass the tests * pass the tests * * Update the provider and consumer export/init genesis with the new CCV states * Improve consumer export genesis UT when channel is established or not * Set the consumer ExportAppStateAndValidators to not return validators * Add the new CCV states to the provider and consumer gensis proto files * remove pendingVSCPackets * remove references in create consumer chain proposal setters and getters * fix unchecked errors * fix iterator bug * fix linter * format provider genesis tests * format consumer genesis tests * clarify consumer keeper genesis * remove unused test helpers * Feat: update consumer init and export genesis * Stop exporting client and consensus states in consumer genesis * Add LastTransmissionBlockHeight to genesis proto * Revert "Feat: update consumer init and export genesis" This reverts commit eb59e502aa4c8adb35435ff006a7db0fdb5f14c0. * * Add LastTransmissionBlockHeight to consumer genesis proto * Set slashing states and LastTransmissionBlockHeight during consumer init genesis * Update consumer init * Update consumer genesis export * fix last nits * Fix consumer InitGenesis * Update comments in genesis.proto * format consumer genesis test * update comments * Update provider genesis comments * fix small lint errs * * Update consumer genesis validation * Fix export genesis bug * Document consumer genesis validation * Document consumer genesis validation * Update after #448 merge * Update x/ccv/consumer/types/genesis.go Co-authored-by: Marius Poke Co-authored-by: Jehan Co-authored-by: Shawn Marshall-Spitzbart <44221603+smarshall-spitzbart@users.noreply.github.com> Co-authored-by: Marius Poke commit 3362a1ccc44b62339be1c101da22ef14a485ba0c Author: Marius Poke Date: Fri Nov 18 09:45:29 2022 +0100 handle provider and consumer client expiration (#448) * handle expired client when sending packets * add e2e test * add upgradeExpiredClient to e2e tests * improve incrementTime... functions * fix golangci-lint error * add client expired check * replace incrementTimeBy w/ incrementTime * replace AppendPendingVSC w/ AppendPendingVSCs * simplify logic of sendValidatorUpdates * separate PrepareIBCPacketSend from SendIBCPacket * error handling on SendPacket * export pending VSC packets * improve comments * use k.GetCCVTimeoutPeriod * remove GetUpgradeKeeper * AppendPendingVSCs: use variadic function * remove unnecessary if * refactor pending VSC CRUD methods * refactor sending valset updates to chains * add tests for VSC queueing * refactor after reviews * refactor after reviews * Merge marius/435-client-expired-consumer into marius/435-client-expired Squashed commit of the following: commit 3d82d19304a49938bfef573c99d2a77182167645 Author: mpoke Date: Fri Nov 11 10:37:06 2022 +0100 fix typo commit 1efa9909162acb22a0e6d70e8da540ba437a3a59 Author: mpoke Date: Wed Nov 9 19:07:30 2022 +0100 avoid trying to send on expired client commit a0cb6452776cdf68bf1f35ec5c069bdd76086991 Author: mpoke Date: Wed Nov 9 15:56:59 2022 +0100 error handling on SendPacket commit 7c9c7629966a7d0b894fde3be9ad83f36afac97f Author: mpoke Date: Wed Nov 9 13:55:05 2022 +0100 use PrepareIBCPacketSend pattern on consumer commit e7ff9d96fd325f851c1c1eb7dc1ed87c65274878 Author: mpoke Date: Wed Nov 9 10:17:18 2022 +0100 update QA plan commit d7fafe8e9987f3b449e3cff07733f8316c484027 Author: mpoke Date: Wed Nov 9 10:09:41 2022 +0100 add e2e test TestConsumerPacketSendExpiredClient commit 1722f1319edb44e3dd867329c6c6875436d9457e Author: mpoke Date: Tue Nov 8 20:20:13 2022 +0100 remove SlashRequest from proto commit 241e13b2d9d47b641a9054973f4d109c78e68ec6 Author: mpoke Date: Tue Nov 8 20:17:52 2022 +0100 remove pending slash requests from genesis commit 073f10160dd9a1d4cd857043e4dcff494230e489 Author: mpoke Date: Tue Nov 8 19:44:46 2022 +0100 replace pending SlashRequests w/ peding DataPackets commit a2d1069459f99de0c3d2ce8d4794e51cff5cd8ed Author: mpoke Date: Tue Nov 8 19:08:33 2022 +0100 code for pending data packets commit acc3454279052237054abab26bf20c7f5a42c386 Author: mpoke Date: Mon Nov 7 21:03:03 2022 +0100 add e2e test commit 6170fa879745bb8f1e12f82b47deee13462f3c0e Author: mpoke Date: Mon Nov 7 11:37:57 2022 +0100 handle expired client when sending packets * and packet queueing to consumer keeper * refactor e2e tests * refactor after review session * additional refactor after reviews Co-authored-by: Matija Salopek Co-authored-by: Jehan commit 34c28bcd3f00afd6c2f0c7b4096abf4169accbec Author: Shawn Marshall-Spitzbart <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Mon Nov 14 16:32:31 2022 -0800 circuit breaker params (#444) * changes * Update params.go commit b0840486632e85dffc18420d53a720619949e09f Author: Marius Poke Date: Fri Nov 4 21:49:06 2022 +0100 VSCPackets should have timeout on provider (#422) * add provider-based timeout params * add InitTimeoutTimestamp to store * add init timeout logic * params boilerplate code & making tests pass * add TestInitTimeout* e2e tests * improve e2e tests; add test case to TestUndelegationDuringInit * remove VSC timeout * remove VSC timeout param * add testcase to TestValidateParams * handle StopConsumerChain error & gofmt * add VSC timeout period param * Fix init timeout conflicts (#409) * Importable e2e tests (#401) * fixes * add comment to GetInitTimeoutTimestamp * add VscTimeoutTimestamp key and tests * change VSCTimeoutTimestamp key * fix e2e tests * add e2e test * remove useless code * improve comment * copy -> append in provider key definitions (#426) Update keys.go * Update tests/e2e/unbonding.go Co-authored-by: Shawn Marshall-Spitzbart <44221603+smarshall-spitzbart@users.noreply.github.com> * Update x/ccv/provider/keeper/keeper_test.go Co-authored-by: Shawn Marshall-Spitzbart <44221603+smarshall-spitzbart@users.noreply.github.com> * update comment * replace removedChainIds w/ chainIdsToRemove * changing keys from (chainID, ts) to (chainID, vscID) * make UnbondingOpIndexKey consistent with VscSendingTimestampKey Co-authored-by: Shawn Marshall-Spitzbart <44221603+smarshall-spitzbart@users.noreply.github.com> commit 46d5c056aa2affe2683dae389274afc4e81fdbf8 Author: Marius Poke Date: Tue Nov 1 20:39:30 2022 +0100 Channel initialization timeout (#406) * add provider-based timeout params * add InitTimeoutTimestamp to store * add init timeout logic * params boilerplate code & making tests pass * add TestInitTimeout* e2e tests * improve e2e tests; add test case to TestUndelegationDuringInit * remove VSC timeout * remove VSC timeout param * add testcase to TestValidateParams * handle StopConsumerChain error & gofmt * Fix init timeout conflicts (#409) * Importable e2e tests (#401) * fixes * add comment to GetInitTimeoutTimestamp * Update proto/interchain_security/ccv/provider/v1/provider.proto Co-authored-by: Aditya * fix formatting in proto file * add comment to SetConsumerChain * fix typo * add comment re. EndBlock order * change name of testcase in TestUndelegationDuringInit Co-authored-by: Shawn Marshall-Spitzbart <44221603+smarshall-spitzbart@users.noreply.github.com> Co-authored-by: Aditya commit a6b8233c72c17019c187e0b6698a260741bd7416 Author: Shawn Marshall-Spitzbart <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Fri Oct 28 08:34:26 2022 -0700 Consumer Unbonding As Param (#410) Co-authored-by: Daniel T <30197399+danwt@users.noreply.github.com> Co-authored-by: Daniel commit 2046d8fff17840f166bd0a0f49a3fa938022103a Author: MSalopek <35486649+MSalopek@users.noreply.github.com> Date: Tue Oct 25 15:55:40 2022 +0200 324 create queries for internal ccv state (#366) * add query protos * add ConsumerChains provider query * wip: add queries for pending proposals and distributions * wip: add queries for pending proposals and distributions * add stop, start proposals to queries * add stop, start proposals queries to cli * add consumer queries * add fee distribution tests * test getting consumer chain add/remove proposals * register consumer queries * rm unnecessary iterator checks * unify naming in query functions * remove matured proposals * refactor tests and grpc queries * add client ID to consumer list query * run make proto-gen after rebase on main * fix failing tests; reflect repo changes in testutils * address review comments and refactor * refactor query consumer chains * add missing newline in query.proto Co-authored-by: Marius Poke Co-authored-by: Jehan commit d7bfd3a03b220618a9b5c82eaa8dc217384f39d8 Author: Shawn Marshall-Spitzbart <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Thu Oct 20 10:47:27 2022 -0700 Replace hardcoded constants with params (#393) * changes * edits * Update params_test.go * small * Update genesis_test.go * remove "num" from historical entries param * comment * use params p1 * use params p2 * use params p3 * p4 * change default transfer timeout period * Update proposal_test.go * default historical entries * is negative * add test case * forgot one * comment commit a8d1ee86ba8a96cc53f9475c30db0e98f699c007 Author: Shawn Marshall-Spitzbart <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Mon Oct 10 02:11:38 2022 -0700 Make CCV packet timeout a param (#376) * large commit * got ridda stuff * Update params.go Co-authored-by: Jehan Co-authored-by: Daniel T <30197399+danwt@users.noreply.github.com> commit 46a9e1a0a5456617511ed18bf720d86f82ab8c92 Author: Shawn Marshall-Spitzbart <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Tue Oct 4 15:41:29 2022 -0700 close 339 (#373) Co-authored-by: Jehan commit 45d52e962e87239988297fd2cd4377fbf44f7b31 Author: Simon Noetzlin Date: Wed Oct 5 00:09:58 2022 +0200 Update export and init genesis (#264) * reformat consumer genesis test * remove validator fill in of ExportAppStateAndValidators * checkpoint, testing export genesis consumer * test consumer export * make pass the tests * fix export height to valset update id in consumer * pass the tests * pass the tests * * Update the provider and consumer export/init genesis with the new CCV states * Improve consumer export genesis UT when channel is established or not * Set the consumer ExportAppStateAndValidators to not return validators * Add the new CCV states to the provider and consumer gensis proto files * remove pendingVSCPackets * remove references in create consumer chain proposal setters and getters * fix unchecked errors * fix iterator bug * fix linter * format provider genesis tests * format consumer genesis tests Co-authored-by: Jehan commit 8ac91e113f156d812e9dca22f74991905372b985 Author: Marius Poke Date: Fri Sep 23 01:22:54 2022 +0200 gov-distribution module (#130) * distribution alternative allocation * update distribution to work off of bonded validators not votes * copy of consumer app * added ccvstaking, ccvdistribution, ccvgov and ccvminting * add cmd interchain-security-cdd * distribution tokens should be coming from ConsumerRedistributeName not feeCollector * beginning of tests * Rebase and fix build errors * Democracy chain integration tests, part 1 * Democracy chain integration tests, part 2 * Clean up and e2e test for democracy distribution * gov-distribution module - cr fix * fix small merge issue Co-authored-by: rigelrozanski Co-authored-by: billy rennekamp Co-authored-by: dusan-ethernal Co-authored-by: stana-ethernal Co-authored-by: Jehan Co-authored-by: Jehan Tremback commit 2f1f620775e3f5450bc47e651db2d24ad11df03d Author: MSalopek <35486649+MSalopek@users.noreply.github.com> Date: Wed Sep 21 00:55:21 2022 +0200 use protobufs to define ccv state (#332) * refactor UnbondingOpsIndex operations Define message UnbondingOpsIndex in ccv protos. Use UnbondingOpsIndex instead of []uint64 where applicable. * update UnbondingOpsIndex tests * refactor MaturedUnboundingOps store operations Define message MaturedUnboundingOps in ccv protos. Refactor code to use new message where applicable. * update e2e tests * refactor protobuf usage for ccv state * add slash requests message * use protobuf for storing slashes on consumer * use protobuf for storing slash acks on provider Co-authored-by: Jehan commit 25bd62758a9940e55401075a2cb8505765e797aa Author: Shawn Marshall-Spitzbart <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Tue Sep 20 14:13:48 2022 -0700 Proposal naming refactors (#354) * consumer addition props * missed one * acronyms * consumer removal props * the rest * comment * handle cli and integration tests * remove unneeded returned err Co-authored-by: Jehan commit d6a3b1cf62a7d35d2db82b0e2c44fa383c12b802 Author: MSalopek <35486649+MSalopek@users.noreply.github.com> Date: Fri Sep 9 14:15:12 2022 +0200 update buf googleapis dependency (#352) * update buf googleapis dependency Updated buf dependencies usin buf mod update --only buf.build/googleapis/googleapis Changed tidy to be compatible to 1.18 only Closes: #347 * update proto-builder; third party staking module commit ea292999b84d5d075199cbc0d59f9fb0de459e24 Author: Shawn Marshall-Spitzbart <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Thu Sep 8 11:44:13 2022 -0700 Extend #350 (#355) readme and makefile commit 5dd941386ff560a92619a2f3cb9ee377449eb603 Author: MSalopek <35486649+MSalopek@users.noreply.github.com> Date: Thu Sep 8 15:43:38 2022 +0200 allow selecting test granularity using make (#350) * allow selecting test granularity using make Adds new commands to makefile: * make test-short (unit, e2e) * make test-diff (difference tests only) * make test-integration (integration tests only) * make test-no-cache (equivalent to make test with caching disabled) Closes: #345 * Update README.md (remove static analysis) Co-authored-by: Daniel T <30197399+danwt@users.noreply.github.com> commit bfd886d4201d0dd7247df378e9d6e3c68379348b Author: Marius Poke Date: Thu Jul 7 14:15:10 2022 +0200 Add VSCMatured packets instead of acks (#188) * iterate over all consumer chains * add pending VSCs * replace UnbondingTime with PacketMaturityTime; add method to compute consumer unbonding time * store unbonding time on consumer chain * Update x/ccv/consumer/keeper/keeper.go * fix EndBlockCallback on provider; add test for pendingVSCs * fix GetConsumerClient for nonexisting chainID * fix client unbonding times in tests * wip * TestUndelegationDuringInit done * fix TestUnbondingNoConsumer * test multiple pending VSC packets * add VSCMaturedPacketData and remove packets from UnbondingSequence * add found return to GetPendingVSCs * apply changes from review * fix TestUndelegationDuringInit * fix TestUndelegationEdgeCase * fix TestTimelyUndelegation1 and rename to TestUndelegationConsumerFirst * fix TestTimelyUndelegation2 and rename to TestUndelegationProviderFirst * cleanup unbonding tests * fix KeeperTestSuite/TestOnRecvPacket * fix KeeperTestSuite/TestUnbondMaturePackets * fix TestPacketRoundtrip * fixing ibc ack handling - wip * handle ibc acks correctly * remove TODO * fix typo * Update x/ccv/consumer/keeper/relay.go Co-authored-by: Aditya * add logging error on ErrorAcknowledgement * add logging error on ErrorAcknowledgement Co-authored-by: Aditya commit 744d4a7dbfc17f737d6097ebd7a3d589e982ae8d Merge: 27ab2ba5 d91b4101 Author: Simon Noetzlin Date: Fri Jun 24 14:19:06 2022 +0200 Merge pull request #124 from cosmos/sainoe/remove-consumer-chain Remove consumer chain from provider commit d91b4101043625b715e3ee0301f92fac6be3f2c9 Merge: eeb3c9dc 27ab2ba5 Author: Simon Date: Fri Jun 24 14:15:15 2022 +0200 merge main commit 27ab2ba594ab1f12e7490be5e4d702cd25ccafd7 Merge: e552182b df4138df Author: Simon Noetzlin Date: Mon Jun 20 11:02:55 2022 +0200 Merge pull request #150 from cosmos/sainoe/mvcc-hist-info Add Historical Info to consumer commit eeb3c9dca7af122fa514ab68f19a0c2f199cbac2 Author: Simon Date: Thu Jun 16 10:02:12 2022 +0200 * Move LockUbdOnTimeout from consumer parameters to CreateConsumerChainProposal to follow the spec * Close provider channel's end only for a passing governance StopChainProposal * Move LockUbdOnTimeout and ClientInfo setters and getters to keeper commit df4138dfc0d8f9ed18c35328f14c2d54830e888a Author: Simon Date: Tue Jun 14 11:05:08 2022 +0200 Implement Historical Info to consumer chain to work with IBC * Add validator public key to consumer chain states * Implement historical info and call TrackHistoricalInfo in consumer BeginBlock * Hardcode HistoricalEntries to 1000 like the staking module DefaultHistoricalEntries parameter commit c1e2c196db7d6937ea32c0ce7dc554235830fe13 Author: Simon Noetzlin Date: Tue Jun 7 08:44:38 2022 +0200 Update proto/interchain_security/ccv/provider/v1/provider.proto Co-authored-by: Marius Poke commit d8c5f4fd2807329d94a859254e823b22eab86b93 Author: Simon Date: Fri Jun 3 11:42:57 2022 +0200 fix nits commit 1b168595b20b76986b17c8f1210b9a66b1a6e921 Author: Simon Date: Thu Jun 2 17:37:31 2022 +0200 * Add lock_unbonding_on_timeout to consumer chain parameter * Create a new provider chain proposal to stop a consumer chain * Implement unbonding ops iterator to release locked fund in case of timeout * Implement StopConsumerChain * Generalize ConsumerChainProposal route in provider/app.go * Add StopConsumerChain call to in proposal handler, OnTimeout and BeginBlock logic * Add shutdown consumer if channel was established then closed commit e552182bf2c4531542be7c1ca9e68f2a7d02d28f Author: frog power 4000 Date: Mon May 30 11:19:09 2022 -0700 ConsumerRedistributeFrac now hardcoded (#102) * ConsumerRedistributeFrac now hardcoded * Update x/ccv/consumer/keeper/distribution.go * fix test to use 75% redistribution fraction Co-authored-by: Marius Poke commit 1ef5da1d808ab0b942d92d5ac54b9373cfa5bfd9 Author: Marius Poke Date: Mon May 30 20:10:59 2022 +0200 Fix proto-gen (#116) * fix proto-gen * go mod tidy commit bf808402157c306b506164395896ec7ef82ecf8c Merge: 616905be 3f7332b1 Author: Simon Noetzlin Date: Mon May 23 20:35:40 2022 +0200 Merge pull request #97 from cosmos/sainoe/consumer-initiated-slashing Add double-sign slashing commit 3f7332b1812faa685dd1f00173be171773f7bc61 Merge: 852e3e7c 616905be Author: Simon Date: Mon May 23 19:02:30 2022 +0200 Merge branch 'main' into sainoe/consumer-initiated-slashing commit 852e3e7c6d3bfa9d6a3fcf8fb577e8c0ff2d523f Author: Simon Date: Mon May 23 13:40:32 2022 +0200 Squashed commit of the following: * Use InfractionType enum in PendingSlashRequest * Reformat TestHandleSlashPacketDistribution * Update Cosmos-SDK import in go.mod * Vefify slash packet commit values in tests * Update Slash function to return when infraction argument is unspecified * Allow to slash jailed and not-tombstoned validator commit aaa0ce4658c0041cd8d53f381f9c30e833f81d93 Author: Marius Poke Date: Fri May 20 16:34:06 2022 +0200 Add proto-gen to Makefile (#92) * enable make proto-gen * add validator.proto and proto docs * remove proto docs * Update Makefile Co-authored-by: Marko * Update Makefile Co-authored-by: Marko * Update Makefile Co-authored-by: Marko * remove abci path duplicate from makefile * make proto generation work with buf (#108) * make proto generation work with buf * remove vscode * revert title change * proto cleanup (#109) * minor cleanup * fix test to comply with json * fix enabled authored-by: Marko Baricevic * go mod tidy -compat=1.17 * go mod tidy -go=1.16 && go mod tidy -go=1.17 Co-authored-by: Marko commit 616905beadecfe0ffe4739a4a443b92e1668081b Author: Marius Poke Date: Mon May 23 18:06:05 2022 +0200 Remove CCV channel state (rebased) (#110) * remove CCV channel state from code * go mod tidy -go=1.16 && go mod tidy -go=1.17 commit 85fac9c6e0c809c14cf7f37bb8e2b0333801dbe0 Author: Marius Poke Date: Fri May 20 16:34:06 2022 +0200 Add proto-gen to Makefile (#92) * enable make proto-gen * add validator.proto and proto docs * remove proto docs * Update Makefile Co-authored-by: Marko * Update Makefile Co-authored-by: Marko * Update Makefile Co-authored-by: Marko * remove abci path duplicate from makefile * make proto generation work with buf (#108) * make proto generation work with buf * remove vscode * revert title change * proto cleanup (#109) * minor cleanup * fix test to comply with json * fix enabled authored-by: Marko Baricevic * go mod tidy -compat=1.17 * go mod tidy -go=1.16 && go mod tidy -go=1.17 Co-authored-by: Marko commit 1961abfc5d9839094639fc88934ad55a5dbf5660 Merge: 01a1b45e 247d4e9d Author: Simon Date: Thu May 12 10:26:51 2022 +0200 Merge branch 'main' into cis-merge-main commit 247d4e9dcacbe4d3e510051f580544b0d3f5b91f Merge: dcda8d3b 2115750f Author: Daniel T <30197399+danwt@users.noreply.github.com> Date: Tue May 10 17:50:51 2022 +0100 Merge pull request #84 from cosmos/danwt/support-different-app.go Support different app.go's for consumer and provider commit 01a1b45ec03813935b5f8ef1569e96c7e468b1ee Author: Simon Date: Tue May 10 10:48:47 2022 +0200 Double-sign slashing Close #65 * Update the CCV slashing logic to handle double-signing evidences. * Add `InfractionType` enum to the `SlashPacketData` fields * Use `InfractionType` enum to distinguish between downtime and double-signing infractions in the logic * Use the provider chain slash fraction and jail duration parameters * Change the evidence keeper instantiation in app.go to use the CCV module instead of the staking module commit 2115750fbbf076d383bcc9f33065c0d0a2e5c621 Author: Daniel Date: Fri May 6 09:48:40 2022 +0100 Updates integration tests to use 2 app.go's commit dcda8d3b90e2c2aec45af7b05e11ffbb3d03214c Merge: ef119ede 67443cd3 Author: Simon Noetzlin Date: Tue May 3 16:15:21 2022 +0100 Merge pull request #75 from cosmos/frog/naming-update Naming Updates commit 67443cd33b21d79427ac24c69abad0bc7c813810 Author: rigelrozanski Date: Thu Apr 28 11:15:41 2022 -0700 child/baby->consumer, parent->provider renames commit ef119ede0299b347b29bbc835bb2640fe6b9e19c Merge: bcad4ce1 8eaf5882 Author: Jehan Date: Wed Apr 27 15:53:42 2022 -0700 Merge pull request #32 from cosmos/frog/simple-distr Simple Distribution commit 8eaf5882b8c69753f388400d3b27db3974d03ed9 Merge: d9dbf450 bcad4ce1 Author: Jehan Tremback Date: Wed Apr 27 15:49:51 2022 -0700 Merge branch 'main' into frog/simple-distr commit bcad4ce125c702112ed46318c038ca54c63e9057 Merge: 3b2fc9ea 3623b3b3 Author: Simon Noetzlin Date: Wed Apr 27 08:25:16 2022 +0100 Merge pull request #56 from cosmos/sainoe/consumer-initiated-slashing Add Pending Slashing commit 3b2fc9eaf6856e4c0137f95cb69e0e0f5a46525c Merge: 97223237 2c30f5ab Author: Jehan Date: Tue Apr 26 15:54:03 2022 -0700 Merge pull request #62 from cosmos/finish-staking-hooks-cherry-pick Finish staking hooks commit 2c30f5ab116e27923a464627c8752a67e10f01be Author: Jehan Tremback Date: Tue Apr 26 15:53:47 2022 -0700 removed unused field commit d9dbf450c55d92fe53b7d1d0c26188c4fdf02b33 Author: rigelrozanski Date: Tue Apr 26 11:06:03 2022 -0700 distribution param comments commit 9ed45afc1fd88f6c213f71b65cfe562a1e5a47f2 Author: Jehan Tremback Date: Wed Apr 20 15:23:24 2022 -0700 renaming cleanup and WIP parent tests commit 3623b3b385deea17bcb56aa63cdd81c8802d919c Author: Simon Date: Wed Apr 20 17:13:27 2022 +0200 Feat: add pending slash requests logic on consumer - Store slash packet data into pending slash requests when ccv channel isn't established - Send and clear pending slash requests once CCV channel is established commit 68089656b7402054dd623db6b23fac18062c147c Author: rigelrozanski Date: Tue Apr 5 16:36:40 2022 -0700 consumer redistribution split commit 511daef17d75c78988404abfe8511236e7c57755 Author: rigelrozanski Date: Tue Apr 5 12:07:51 2022 -0700 rebase, debug cleanup commit 841a2b247c31f542b6680fb3a87ce9ba630d13fb Author: rigelrozanski Date: Mon Mar 7 12:07:40 2022 -0800 params update, breaks tests commit 9ab56c67f115478fd97d3cd7caa71a9830367d87 Author: rigelrozanski Date: Wed Mar 2 12:40:39 2022 -0800 distr code compiling, existing tests pass, fix old ibc in proto commit 7917cf7f8b71707f612932b1f5970d062bbd6422 Author: rigelrozanski Date: Mon Jan 10 18:29:57 2022 -0800 Simple Distribution dist docs working dist ccv dist diagram diagram cleanup diagram update dist diagram diagram updates, excess model simplified distribution simple distribution . aditya ibc notes distr token transfer ibc working working parent-addr handshake information pass working simple distribution distribution near compiling, blocked on ibc-go upgrades address WIP PR comments connHops update merge conflict resolve commit 972232378fa5d5b07e03b2d24182562d3a0d0d43 Merge: 4174b794 3087ab79 Author: Simon Noetzlin Date: Tue Apr 5 16:48:19 2022 +0200 Merge pull request #52 from sainoe/sainoe/consumer-initiated-slashing Consumer downtime slashing commit 3087ab79932ea833d228ada01baed1e17c39cf85 Author: Simon Date: Fri Apr 1 13:04:10 2022 +0200 remove white space child proto commit 358fcf548b414fd9db2a07777aa3600ec8371dd5 Author: Simon Date: Fri Apr 1 12:59:19 2022 +0200 * remove pubkey from cross-chain validators type fields * update and test ApplyCCValidatorChanges commit 6750e1ef9819080ef6bc2123b45beb4b7edb3bc7 Author: Simon Noetzlin Date: Mon Mar 28 17:34:08 2022 +0200 Fix typo in app.go Co-authored-by: Aditya commit a06ee0628f626425a7b6707f08d62a02c2bb0c3b Author: Simon Date: Fri Mar 25 18:18:35 2022 +0100 - Fix validator address issue - Merge PR#48 changes commit 4174b794570e5d6ac4e8a47b18b0dc212547b4ed Merge: 770d5cdc 7c534426 Author: Jehan Date: Mon Mar 14 15:14:37 2022 -0700 Merge pull request #31 from cosmos/gov-cli-and-query Gov proposal cli and genesis state query commit 7c5344267a4d99f6ec6b7571514ba8adf9949078 Merge: e9e00ec0 770d5cdc Author: Jehan Tremback Date: Mon Mar 14 15:13:19 2022 -0700 Merge branch 'main' into gov-cli-and-query commit 770d5cdcb9a15a0bb83aab09e99409b15e9119ed Author: rigelrozanski Date: Mon Feb 14 13:43:49 2022 -0800 upgrade compile errors worked through commit da1a1211f04316b8d66766f1b6067459ad063d99 Merge: d5c395d5 359b4ae6 Author: Jehan Date: Wed Feb 2 14:08:53 2022 -0800 Merge pull request #29 from cosmos/local-testnet Gonna merge this myself because it is very small and does not involve any logic commit e9e00ec0a85b8ba8b63c57b24b6ff1f7803b65a7 Author: Jehan Tremback Date: Tue Feb 1 16:46:33 2022 -0800 genesis query finished but untested commit 863edec34d5d6df783b5d4474944e8697d5ce617 Author: Jehan Tremback Date: Fri Jan 14 11:30:22 2022 -0800 add minimal makefile commit d5c395d52c4824d03510836a16024f673f9a0a80 Merge: db485fac … * chore: sdk47 post upgrade cleanup (#970) * Finish legacy querier LCD/REST cleaning https://github.com/cosmos/cosmos-sdk/blob/release/v0.47.x/UPGRADING.md#appmodule-interface https://github.com/cosmos/cosmos-sdk/pull/9594 https://github.com/cosmos/cosmos-sdk/pull/11797 * Finish simulation migration https://github.com/cosmos/cosmos-sdk/blob/release/v0.47.x/UPGRADING.md#simulation * Replace usage of deprecated gov method * Remove duplicate ante.DeductFeeDecorator * fix!: avoid panicking on CancelUnbondingDelegation (#977) * handle CancelUnbondingDelegation message * tests: add cancel-unbond e2e test * fix: appease linter * chore: Hardcode golangci-lint version (#990) * Hardcode golangci-lint version * Hardcode version in CI config --------- Co-authored-by: MSalopek Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * refactor: first batch of post-merge changes * refactor: batch sovereign changes with v47 * refactor: another batch of post-merge changes * changes to go.mod * refactor: final batch of changes post-merge * refactor: rebuild protos for v47 * refactor: rebuild mocks for v47 * refactor: testing changes * refactor: update proto tooling and rebuild protos * lint: appease gosec * chore: rm unused string from Makefile * chore: rm unused in makefile .phony * temporarily disable proto-check to run automated tests * refactor: merge main into feature branch with fixes (#1038) * build(deps): bump gaurav-nelson/github-action-markdown-link-check from 1.0.13 to 1.0.15 (#928) build(deps): bump gaurav-nelson/github-action-markdown-link-check Bumps [gaurav-nelson/github-action-markdown-link-check](https://github.com/gaurav-nelson/github-action-markdown-link-check) from 1.0.13 to 1.0.15. - [Release notes](https://github.com/gaurav-nelson/github-action-markdown-link-check/releases) - [Commits](https://github.com/gaurav-nelson/github-action-markdown-link-check/compare/1.0.13...1.0.15) --- updated-dependencies: - dependency-name: gaurav-nelson/github-action-markdown-link-check dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore: bump hermes (#921) * bump the version of hermes used in docs and images * use the multiplatform ghcr.io build of hermes * build(deps): bump github.com/spf13/cast from 1.5.0 to 1.5.1 (#961) Bumps [github.com/spf13/cast](https://github.com/spf13/cast) from 1.5.0 to 1.5.1. - [Release notes](https://github.com/spf13/cast/releases) - [Commits](https://github.com/spf13/cast/compare/v1.5.0...v1.5.1) --- updated-dependencies: - dependency-name: github.com/spf13/cast dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * refactor: adopt the errors module to reduce the changeset for 47 (#920) adopt the errors module to reduce the changeset for 47 Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> * fix!: prevent denom DOS (#931) * Merge pull request from GHSA-chqw-ff63-95r8 * squash commit of multisig fix + everything involving denom fix * rebuild proto * fix todos --------- Co-authored-by: Jehan Tremback * regen proto * fix cherrypick issues * lint * cleans * gosec * restore param, remove tech debt from tests * ibc denom as const * add check for consumer reward denom already registered * lint * remove unneeded expect --------- Co-authored-by: Jehan Tremback Co-authored-by: Marius Poke * fix: all feature branches should have CI (#958) * Update automated-tests.yml * Update build.yml * all feature branches will now run all ci jobs relevant to them --------- Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> * fix!: consumer key prefix order to avoid complex migrations (#963) proper order matching v1.0.0 Co-authored-by: Marius Poke * docs: update changelog to prep for v1.3.0 release (#953) * wip * Update CHANGELOG.md * small comment * comment * progress save * another progress save * progress save * done * Update CHANGELOG.md * add denom dos entry * remove extraneous changelog entries * restore a couple entries * Changes from PR review * add entry for 963 * fix: mitigate e2e tests relaying and non-determinism (#968) * fix: mitigate e2e tests relaying non-determinism * fix: bump signed blocks windows in e2e test configs * deps: bump cometbft to v0.34.28 (#906) this bumps only cometbft Co-authored-by: MSalopek * fix!: Remove panics on failure to send IBC packets (#876) * provider: replace panic with StopConsumerChain * provider: replace panic with error message * Info logging on client expiration * add test for consumer * add test for provider * linter * Update CHANGELOG.md --------- Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> * build(deps): bump github.com/stretchr/testify from 1.8.2 to 1.8.3 (#969) Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.8.2 to 1.8.3. - [Release notes](https://github.com/stretchr/testify/releases) - [Commits](https://github.com/stretchr/testify/compare/v1.8.2...v1.8.3) --- updated-dependencies: - dependency-name: github.com/stretchr/testify dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> * build(deps): bump slackapi/slack-github-action from 1.23.0 to 1.24.0 (#971) Bumps [slackapi/slack-github-action](https://github.com/slackapi/slack-github-action) from 1.23.0 to 1.24.0. - [Release notes](https://github.com/slackapi/slack-github-action/releases) - [Commits](https://github.com/slackapi/slack-github-action/compare/v1.23.0...v1.24.0) --- updated-dependencies: - dependency-name: slackapi/slack-github-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * refactor!: upgrade ICS imports to v2 (#974) * v2 imports * Update CHANGELOG.md * docs: update PR template to consider migrations (#976) Update PULL_REQUEST_TEMPLATE.md * fix: v2 imports proto go_package option (#978) * add v2 to proto files, adjust protocgen scripts * regen proto * fix: partially revert key assignment type safety PR (#980) * use bytes in place where possible * fix tests * add v2 to proto files, adjust protocgen scripts * regen proto * change protos, define custom types, fix references * Update key_assignment_test.go * Update key_assignment.go * format * Update CHANGELOG.md * nit for better diff * docs: update top level readme for repo (#981) * Update base.css * Update README.md * smol --------- Co-authored-by: Marius Poke * ci: makefile target for checking if protos are updated (#979) * proto-check makefile target * comment * add to GH actions workflow * put proto check before other tests * gotta regenerate protos --------- Co-authored-by: Marius Poke * build(deps): bump github.com/cosmos/ibc-go/v4 from 4.4.0 to 4.4.2 (#982) * build(deps): bump github.com/cosmos/ibc-go/v4 from 4.4.0 to 4.4.2 Bumps [github.com/cosmos/ibc-go/v4](https://github.com/cosmos/ibc-go) from 4.4.0 to 4.4.2. - [Release notes](https://github.com/cosmos/ibc-go/releases) - [Changelog](https://github.com/cosmos/ibc-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/cosmos/ibc-go/compare/v4.4.0...v4.4.2) --- updated-dependencies: - dependency-name: github.com/cosmos/ibc-go/v4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * update changelog --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: mpoke Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> * build(deps): bump JamesIves/github-pages-deploy-action from 4.4.1 to 4.4.2 (#983) build(deps): bump JamesIves/github-pages-deploy-action Bumps [JamesIves/github-pages-deploy-action](https://github.com/JamesIves/github-pages-deploy-action) from 4.4.1 to 4.4.2. - [Release notes](https://github.com/JamesIves/github-pages-deploy-action/releases) - [Commits](https://github.com/JamesIves/github-pages-deploy-action/compare/v4.4.1...v4.4.2) --- updated-dependencies: - dependency-name: JamesIves/github-pages-deploy-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> * build(deps): bump github.com/stretchr/testify from 1.8.3 to 1.8.4 (#985) Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.8.3 to 1.8.4. - [Release notes](https://github.com/stretchr/testify/releases) - [Commits](https://github.com/stretchr/testify/compare/v1.8.3...v1.8.4) --- updated-dependencies: - dependency-name: github.com/stretchr/testify dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Marius Poke * feat: v2 migrations (#975) * v2 imports * Squashed commit of the following: commit a4c9224f854ecef9b8a0216a4c348c13368cdd06 Author: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Wed May 24 10:13:10 2023 -0700 Revert "Merge branch 'shawn/v2-imports' into shawn/ccv-migrations" This reverts commit 53e3362749c05de1a44da1bbe632d8b7265eee5a, reversing changes made to 9c3f3380cbffe43f3a6d2c2b5e71c1412869786d. commit 6885ad1dffed403e21fe5a97421d21afe321ae98 Author: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Wed May 24 10:12:49 2023 -0700 Revert "Merge branch 'shawn/v2-imports' into shawn/ccv-migrations" This reverts commit 45d74c70ff6e41d585255f039c5f814340e4bed1, reversing changes made to 53e3362749c05de1a44da1bbe632d8b7265eee5a. commit 958914412a72ebd2b79dccdfd92ec43104a431bb Author: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Tue May 23 14:48:06 2023 -0700 provider migration boilerplate commit 9521ecb3a8b9e7d87df183f879b3680bf65613e3 Author: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Tue May 23 12:25:14 2023 -0700 lint commit fc3f27364c283aef53c305730f75f0e9e299d60b Author: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Tue May 23 12:20:33 2023 -0700 old default params commit 80a490cb57dc684dd740a27d753508f0a118c174 Author: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Tue May 23 12:15:30 2023 -0700 naming commit 45d74c70ff6e41d585255f039c5f814340e4bed1 Merge: 53e33627 8e6bdfb2 Author: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Tue May 23 12:12:03 2023 -0700 Merge branch 'shawn/v2-imports' into shawn/ccv-migrations commit 8e6bdfb21f53374874c3ea102ce04fe07f162b1d Author: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Tue May 23 12:10:22 2023 -0700 proto name for gov prop registration commit 53e3362749c05de1a44da1bbe632d8b7265eee5a Merge: 9c3f3380 5ca68d14 Author: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Tue May 23 12:05:39 2023 -0700 Merge branch 'shawn/v2-imports' into shawn/ccv-migrations commit 5ca68d142070a8995b34c5111bc8e85363eac257 Author: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Tue May 23 11:53:12 2023 -0700 fix e2e tests commit aa6bd0c87c93f6b1963ce7d71b51e22afe35b821 Author: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Tue May 23 11:42:47 2023 -0700 rm bad files commit 6e3dc88d5a08cdaf039b0eef9c078e4461278f82 Author: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Tue May 23 11:42:14 2023 -0700 correct generation commit 056ef7a71ef2b78ee22442be4978e02da9f2ca27 Author: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Tue May 23 11:29:45 2023 -0700 proto upgrade too commit 9c3f3380cbffe43f3a6d2c2b5e71c1412869786d Author: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Tue May 23 10:57:25 2023 -0700 remove hardcoded old code commit 1e731730f34dd9bc5a0dda6a63095d9703c4379b Merge: dbf9dede 8769fd56 Author: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Tue May 23 10:07:31 2023 -0700 Merge branch 'shawn/v2-imports' into shawn/ccv-migrations commit 8769fd5649713445c1770b8eb98d88ba5ded2d84 Author: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Tue May 23 09:58:28 2023 -0700 v2 imports commit dbf9dede2a8935098cddae7db111b86659f92a4a Author: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Mon May 22 16:10:05 2023 -0700 provider migration commit 2d95e2e41bcf9812b5a22e06de8e5444ce0ed60a Author: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Mon May 22 15:01:47 2023 -0700 improve consumer test commit 85f4cfdd418d464bdd935f0ae2ceab6fe04e73c2 Author: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Mon May 22 14:03:20 2023 -0700 consumer params * rm old code * go.mod restore * better naming of hardcodes * consumer boilerplate * comments * migrate consumer genesis states * test and cleans * lint * migration and partial test * cleans * finish test * comments and doc * Update migration_test.go * Update CHANGELOG.md * expand in changelog * increment consensus ver * set key table on construction * rm semver migration funcs * comment explaining consensus version * docs: cleanup changelog for v2.0.0 on main (#988) cleans * chore: Hardcode golangci-lint version (#990) * Hardcode golangci-lint version * Hardcode version in CI config * docs: Increase the validator set of cosmos hub to 180 from 175 (#999) Updated number of validators to 180 * fix: proper consumer key prefix ordering (#991) * Update keys.go * tests * fix another bug * fix comments * feat: Remove consumer genesis migration on provider (#997) * Update keys.go * tests * fix another bug * remove consumer genesis deletion, link to test * remove unused bond denom method * Revert "remove unused bond denom method" This reverts commit f930eca428bade49a05368fe5dae2d96842659cc. * remove test too * update changelog * docs: Update reward-distribution.md (#994) * Update reward-distribution.md * docs: add instructions for registering denoms * Update docs/docs/features/reward-distribution.md Co-authored-by: Marius Poke * Update reward-distribution.md * Update docs/docs/features/reward-distribution.md Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> --------- Co-authored-by: MSalopek Co-authored-by: Marius Poke * chore: update workflow re. issues and PRs (#1002) * update PR workflow * update issue workflow * rename other.md to others.md * fix typo --------- Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> * docs(adr): ADR-007 pause unbonding period during equivocation proposal (#964) * docs(adr): pause unbonding period during equivocation proposal Co-authored-by: Albert Le Batteux Co-authored-by: Giuseppe Natale * fix voting period duration * remove issue reference * docs: filter out unbonding operations before pause/unpause Co-authored-by: Albert Le Batteux Co-authored-by: Giuseppe Natale --------- Co-authored-by: Albert Le Batteux Co-authored-by: Giuseppe Natale * docs: Add type prefix link to CONTRIBUTING.md (#1007) Update CONTRIBUTING.md * chore: enable mergify (#1009) * add config for mergify * enable security dependecies for v2.0.x * Markdownlint (#907) markdownlint Co-authored-by: Jacob Gadikian * fix: limit vsc matured packets handled per endblocker (#1004) * initial implementation, still need tests * UTs * integration test * linter * Update CHANGELOG.md * make vsc matured handled this block a var * comment * feat: integrate cometmock (#989) * Add gorelayer and CometMock to Dockerfile * Add option to start with cometmock in start-chain script * Start adding support for rly * Adjust relayer start action * Add entrypoint for short happy path steps * Add . nosec G204 and waiting for blocks * Adjust rly config: Gas is free * Remove optout steps from short happy path * Use separate redelegate step for short happy path * Wait for blocks after unbonding * Make naming more descriptive and add comments * Add comment to chain name sorting and improve comments * Update start-chain.sh Address comments form joint review session with @MSalopek * Fix typo * docs: Create adr-004-denom-dos-fixes.md (#934) * Create adr-006-denom-dos-fixes * Update docs/docs/adrs/adr-006-denom-dos-fixes Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> * Update docs/docs/adrs/adr-006-denom-dos-fixes Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> * Update docs/docs/adrs/adr-006-denom-dos-fixes Co-authored-by: Marius Poke * Update docs/docs/adrs/adr-006-denom-dos-fixes * Update docs/docs/adrs/adr-006-denom-dos-fixes * rename to adr 004 * remove extra file * add entry to Table of Contents * add ADR 7 to ToC --------- Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Co-authored-by: Marius Poke * docs: Fix link to template (#1027) Fix link to template Fixes typo in contributing.md * feat!: Add DistributionTransmissionChannel to ConsumerAdditionProposal (#965) * update proto * remove transfer_channel_id from consumer genesis * ConsumerAdditionProposal: transfer_channel_id -> distribution_transmission_channel * send updated ConsumerAdditionProposal * validate consumer genesis param * remove StandaloneTransferChannelID from store * fix TestOnChanOpenAck * remove state breaking change * finalize merge and fix issues * chore: update docs and changelog * chore: regenerate protos * re-add integrationt tests around changeover * mv entry in changelog * test: add sovereign to consumer changeover e2e (#1025) * tests: add sovereign to consumer e2e test * rm unused bash scripts * partially address review comments * apply remaining review comments * chore: apply formatting rules --------- Co-authored-by: MSalopek * docs: ADR for throttle with retries (#1005) * all of ADR is filled out except design portion * design * Update adr-008-throttle-retries.md * Update adr-008-throttle-retries.md * Update adr-008-throttle-retries.md * Apply suggestions from code review Co-authored-by: Marius Poke * nit formatting * describe consumer changes first * add comment on rareness of throttling being triggered * split out paragraph * hopefully better explanation * Update adr-008-throttle-retries.md * accepted * TOC entry --------- Co-authored-by: Marius Poke * Add time and block advancement integration for CometMock (#1017) * Add time and block advancement * Adhere to gocritic: use += * Remove extra debug output * Fix: use correct key when consumer key is not assigned * Correct private key address field * Clarify comment for WaitTime * Use bool instead of *bool type * Add review comments * refactor: first batch of post-merge changes * refactor: batch sovereign changes with v47 * refactor: another batch of post-merge changes * changes to go.mod * refactor: final batch of changes post-merge * refactor: rebuild protos for v47 * refactor: rebuild mocks for v47 * refactor: testing changes * refactor: update proto tooling and rebuild protos * lint: appease gosec * chore: rm unused string from Makefile * chore: rm unused in makefile .phony * temporarily disable proto-check to run automated tests --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jacob Gadikian Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Co-authored-by: Jehan Tremback Co-authored-by: Marius Poke Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Co-authored-by: Milan Mulji <98309852+mmulji-ic@users.noreply.github.com> Co-authored-by: Thomas Bruyelle Co-authored-by: Albert Le Batteux Co-authored-by: Giuseppe Natale Co-authored-by: Ruslan Akhtariev <46343690+pysel@users.noreply.github.com> Co-authored-by: Jehan * chore: bump sdk to v0.47.3 (#1040) --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jacob Gadikian Co-authored-by: vuong177 Co-authored-by: sontrinh16 Co-authored-by: Ruslan Akhtariev Co-authored-by: Ruslan Akhtariev <46343690+pysel@users.noreply.github.com> Co-authored-by: vuong <56973102+vuong177@users.noreply.github.com> Co-authored-by: sontrinh16 <48055119+sontrinh16@users.noreply.github.com> Co-authored-by: mpoke Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Co-authored-by: Thomas Bruyelle Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Co-authored-by: Jehan Tremback Co-authored-by: Milan Mulji <98309852+mmulji-ic@users.noreply.github.com> Co-authored-by: Albert Le Batteux Co-authored-by: Giuseppe Natale Co-authored-by: Jehan --- .dockerignore | 9 + .github/workflows/automated-tests.yml | 4 +- Dockerfile | 3 +- Dockerfile.gaia | 4 +- Makefile | 102 +- .../ante/forbidden_proposals_ante.go | 40 +- .../ante/forbidden_proposals_ante_test.go | 124 ++- app/consumer-democracy/ante_handler.go | 13 +- app/consumer-democracy/app.go | 343 ++++--- app/consumer-democracy/export.go | 6 +- .../proposals_whitelisting.go | 57 +- .../proposals_whitelisting_test.go | 2 +- .../ante/disabled_modules_ante_test.go | 2 +- app/consumer/ante/msg_filter_ante_test.go | 2 +- app/consumer/ante_handler.go | 12 +- app/consumer/app.go | 260 +++-- app/consumer/export.go | 6 +- app/params/encoding.go | 2 +- app/params/proto.go | 2 +- app/provider/ante_handler.go | 11 +- app/provider/app.go | 308 +++--- app/provider/export.go | 19 +- app/sovereign/ante_handler.go | 11 +- app/sovereign/app.go | 268 +++--- app/sovereign/export.go | 21 +- buf.work.yaml | 1 - cmd/interchain-security-cd/cmd/genaccounts.go | 180 ---- cmd/interchain-security-cd/cmd/root.go | 277 +++--- cmd/interchain-security-cd/main.go | 4 +- .../cmd/genaccounts.go | 180 ---- cmd/interchain-security-cdd/cmd/root.go | 276 +++--- cmd/interchain-security-cdd/main.go | 4 +- cmd/interchain-security-pd/cmd/genaccounts.go | 180 ---- cmd/interchain-security-pd/cmd/root.go | 272 +++--- cmd/interchain-security-pd/main.go | 4 +- cmd/interchain-security-sd/cmd/genaccounts.go | 180 ---- cmd/interchain-security-sd/cmd/root.go | 274 +++--- cmd/interchain-security-sd/main.go | 4 +- docs/docs/features/key-assignment.md | 16 +- docs/docs/validators/joining-testnet.md | 26 +- go.mod | 180 ++-- go.sum | 890 ++++++++++++------ legacy_ibc_testing/core/events.go | 8 +- legacy_ibc_testing/simapp/test_helpers.go | 13 +- legacy_ibc_testing/testing/app.go | 39 +- legacy_ibc_testing/testing/chain.go | 35 +- legacy_ibc_testing/testing/config.go | 10 +- legacy_ibc_testing/testing/coordinator.go | 2 +- legacy_ibc_testing/testing/endpoint.go | 30 +- legacy_ibc_testing/testing/events.go | 8 +- legacy_ibc_testing/testing/path.go | 2 +- legacy_ibc_testing/testing/utils.go | 4 +- legacy_ibc_testing/testing/values.go | 8 +- proto/buf.lock | 20 +- proto/buf.yaml | 4 + .../ccv/consumer/v1/consumer.proto | 23 +- .../ccv/consumer/v1/genesis.proto | 25 +- .../ccv/consumer/v1/query.proto | 6 +- .../ccv/provider/v1/genesis.proto | 46 +- .../ccv/provider/v1/provider.proto | 231 ++--- .../ccv/provider/v1/query.proto | 64 +- .../ccv/provider/v1/tx.proto | 20 +- proto/interchain_security/ccv/v1/ccv.proto | 30 +- scripts/protocgen.sh | 1 - tests/difference/core/driver/common.go | 11 +- tests/difference/core/driver/core_test.go | 16 +- .../core/driver/seed_gen_fuzzy_test.go | 4 +- tests/difference/core/driver/setup.go | 53 +- tests/e2e/actions.go | 210 +++-- tests/e2e/config.go | 36 +- tests/e2e/main.go | 4 +- tests/e2e/state.go | 31 +- tests/e2e/step_delegation.go | 91 ++ tests/e2e/steps.go | 1 + tests/e2e/steps_democracy.go | 17 +- tests/e2e/steps_reward_denom.go | 15 +- tests/e2e/steps_sovereign_changeover.go | 2 +- tests/e2e/steps_start_chains.go | 2 +- .../testnet-scripts/sovereign-genesis.json | 518 +++++----- tests/e2e/testnet-scripts/start-chain.sh | 6 +- tests/integration/changeover.go | 4 +- tests/integration/common.go | 29 +- tests/integration/democracy.go | 62 +- tests/integration/distribution.go | 13 +- tests/integration/expired_client.go | 15 +- tests/integration/key_assignment.go | 7 +- tests/integration/normal_operations.go | 2 +- tests/integration/setup.go | 11 +- tests/integration/slashing.go | 39 +- tests/integration/stop_consumer.go | 5 +- tests/integration/throttle.go | 47 +- tests/integration/unbonding.go | 9 +- tests/integration/valset_update.go | 6 +- testutil/crypto/crypto.go | 6 +- testutil/ibc_testing/generic_setup.go | 6 +- testutil/ibc_testing/specific_setup.go | 22 +- testutil/integration/interfaces.go | 17 +- testutil/keeper/expectations.go | 14 +- testutil/keeper/mocks.go | 237 +++-- testutil/keeper/unit_test_helpers.go | 16 +- testutil/simibc/chain_util.go | 8 +- testutil/simibc/ordered_outbox.go | 2 +- testutil/simibc/relay_util.go | 10 +- testutil/simibc/relayed_path.go | 2 +- third_party/gogoproto/gogo.proto | 145 --- third_party/google/api/annotations.proto | 31 - third_party/google/api/http.proto | 318 ------- third_party/google/api/httpbody.proto | 78 -- third_party/google/protobuf/any.proto | 164 ---- third_party/proto/buf.lock | 10 - third_party/proto/buf.yaml | 37 - third_party/proto/confio/proofs.proto | 235 ----- .../base/query/v1beta1/pagination.proto | 55 -- .../proto/cosmos/base/v1beta1/coin.proto | 40 - .../cosmos/evidence/v1beta1/evidence.proto | 21 - .../cosmos/staking/v1beta1/staking.proto | 370 -------- .../cosmos/upgrade/v1beta1/upgrade.proto | 78 -- third_party/proto/cosmos_proto/cosmos.proto | 16 - .../proto/ibc/core/channel/v1/channel.proto | 148 --- .../proto/ibc/core/channel/v1/genesis.proto | 32 - .../proto/ibc/core/channel/v1/query.proto | 376 -------- .../proto/ibc/core/channel/v1/tx.proto | 211 ----- .../proto/ibc/core/client/v1/client.proto | 100 -- .../proto/ibc/core/client/v1/genesis.proto | 48 - .../proto/ibc/core/client/v1/query.proto | 184 ---- third_party/proto/ibc/core/client/v1/tx.proto | 100 -- .../ibc/core/commitment/v1/commitment.proto | 41 - .../ibc/core/connection/v1/connection.proto | 114 --- .../ibc/core/connection/v1/genesis.proto | 18 - .../proto/ibc/core/connection/v1/query.proto | 138 --- .../proto/ibc/core/connection/v1/tx.proto | 119 --- .../proto/ibc/core/types/v1/genesis.proto | 23 - .../lightclients/localhost/v1/localhost.proto | 18 - .../solomachine/v1/solomachine.proto | 189 ---- .../solomachine/v2/solomachine.proto | 189 ---- .../tendermint/v1/tendermint.proto | 115 --- third_party/proto/tendermint/abci/types.proto | 407 -------- .../proto/tendermint/crypto/keys.proto | 17 - .../proto/tendermint/crypto/proof.proto | 41 - .../proto/tendermint/libs/bits/types.proto | 9 - .../proto/tendermint/types/params.proto | 80 -- .../proto/tendermint/types/types.proto | 157 --- .../proto/tendermint/types/validator.proto | 25 - .../proto/tendermint/version/types.proto | 24 - x/ccv/consumer/ibc_module.go | 15 +- x/ccv/consumer/ibc_module_test.go | 9 +- x/ccv/consumer/keeper/changeover.go | 2 +- x/ccv/consumer/keeper/changeover_test.go | 2 +- x/ccv/consumer/keeper/distribution.go | 32 +- x/ccv/consumer/keeper/distribution_test.go | 2 +- x/ccv/consumer/keeper/genesis.go | 5 +- x/ccv/consumer/keeper/genesis_test.go | 24 +- x/ccv/consumer/keeper/grpc_query.go | 2 +- x/ccv/consumer/keeper/hooks.go | 6 +- x/ccv/consumer/keeper/keeper.go | 47 +- x/ccv/consumer/keeper/keeper_test.go | 10 +- x/ccv/consumer/keeper/migration.go | 79 -- x/ccv/consumer/keeper/migration_test.go | 146 --- x/ccv/consumer/keeper/params.go | 12 +- x/ccv/consumer/keeper/params_test.go | 4 +- x/ccv/consumer/keeper/relay.go | 14 +- x/ccv/consumer/keeper/relay_test.go | 15 +- x/ccv/consumer/keeper/soft_opt_out_test.go | 4 +- x/ccv/consumer/keeper/validators.go | 44 +- x/ccv/consumer/keeper/validators_test.go | 23 +- x/ccv/consumer/module.go | 42 +- x/ccv/consumer/types/consumer.pb.go | 44 +- x/ccv/consumer/types/genesis.go | 6 +- x/ccv/consumer/types/genesis.pb.go | 36 +- x/ccv/consumer/types/genesis_test.go | 16 +- x/ccv/consumer/types/query.pb.go | 6 +- x/ccv/democracy/distribution/module.go | 7 +- x/ccv/democracy/governance/module.go | 76 +- x/ccv/democracy/staking/module.go | 9 +- x/ccv/provider/client/cli/tx.go | 7 +- x/ccv/provider/client/proposal_handler.go | 122 +-- x/ccv/provider/handler_test.go | 2 +- x/ccv/provider/ibc_module.go | 10 +- x/ccv/provider/ibc_module_test.go | 11 +- x/ccv/provider/keeper/genesis_test.go | 2 +- x/ccv/provider/keeper/hooks.go | 73 +- x/ccv/provider/keeper/keeper.go | 25 +- x/ccv/provider/keeper/keeper_test.go | 5 +- x/ccv/provider/keeper/key_assignment.go | 4 +- x/ccv/provider/keeper/key_assignment_test.go | 4 +- x/ccv/provider/keeper/migration.go | 172 ---- x/ccv/provider/keeper/migration_test.go | 171 ---- x/ccv/provider/keeper/msg_server.go | 5 +- x/ccv/provider/keeper/params.go | 2 +- x/ccv/provider/keeper/params_test.go | 9 +- x/ccv/provider/keeper/proposal.go | 16 +- x/ccv/provider/keeper/proposal_test.go | 8 +- x/ccv/provider/keeper/relay.go | 25 +- x/ccv/provider/keeper/relay_test.go | 33 +- x/ccv/provider/keeper/throttle.go | 12 +- x/ccv/provider/keeper/throttle_test.go | 33 +- x/ccv/provider/module.go | 43 +- x/ccv/provider/module_test.go | 4 +- x/ccv/provider/proposal_handler.go | 7 +- x/ccv/provider/proposal_handler_test.go | 17 +- x/ccv/provider/types/codec.go | 8 +- x/ccv/provider/types/genesis.go | 3 +- x/ccv/provider/types/genesis.pb.go | 12 +- x/ccv/provider/types/genesis_test.go | 45 +- x/ccv/provider/types/params.go | 10 +- x/ccv/provider/types/params_test.go | 36 +- x/ccv/provider/types/proposal.go | 29 +- x/ccv/provider/types/proposal_test.go | 14 +- x/ccv/provider/types/provider.pb.go | 175 ++-- x/ccv/provider/types/query.pb.go | 47 +- x/ccv/provider/types/tx.pb.go | 11 +- x/ccv/types/ccv.go | 6 +- x/ccv/types/ccv.pb.go | 107 +-- x/ccv/types/ccv_test.go | 2 +- x/ccv/types/expected_keepers.go | 43 +- x/ccv/types/shared_params.go | 2 +- x/ccv/types/utils.go | 43 +- x/ccv/types/utils_test.go | 2 +- 218 files changed, 4416 insertions(+), 9075 deletions(-) create mode 100644 .dockerignore delete mode 100644 cmd/interchain-security-cd/cmd/genaccounts.go delete mode 100644 cmd/interchain-security-cdd/cmd/genaccounts.go delete mode 100644 cmd/interchain-security-pd/cmd/genaccounts.go delete mode 100644 cmd/interchain-security-sd/cmd/genaccounts.go delete mode 100644 third_party/gogoproto/gogo.proto delete mode 100644 third_party/google/api/annotations.proto delete mode 100644 third_party/google/api/http.proto delete mode 100644 third_party/google/api/httpbody.proto delete mode 100644 third_party/google/protobuf/any.proto delete mode 100644 third_party/proto/buf.lock delete mode 100644 third_party/proto/buf.yaml delete mode 100644 third_party/proto/confio/proofs.proto delete mode 100644 third_party/proto/cosmos/base/query/v1beta1/pagination.proto delete mode 100644 third_party/proto/cosmos/base/v1beta1/coin.proto delete mode 100644 third_party/proto/cosmos/evidence/v1beta1/evidence.proto delete mode 100644 third_party/proto/cosmos/staking/v1beta1/staking.proto delete mode 100644 third_party/proto/cosmos/upgrade/v1beta1/upgrade.proto delete mode 100644 third_party/proto/cosmos_proto/cosmos.proto delete mode 100644 third_party/proto/ibc/core/channel/v1/channel.proto delete mode 100644 third_party/proto/ibc/core/channel/v1/genesis.proto delete mode 100644 third_party/proto/ibc/core/channel/v1/query.proto delete mode 100644 third_party/proto/ibc/core/channel/v1/tx.proto delete mode 100644 third_party/proto/ibc/core/client/v1/client.proto delete mode 100644 third_party/proto/ibc/core/client/v1/genesis.proto delete mode 100644 third_party/proto/ibc/core/client/v1/query.proto delete mode 100644 third_party/proto/ibc/core/client/v1/tx.proto delete mode 100644 third_party/proto/ibc/core/commitment/v1/commitment.proto delete mode 100644 third_party/proto/ibc/core/connection/v1/connection.proto delete mode 100644 third_party/proto/ibc/core/connection/v1/genesis.proto delete mode 100644 third_party/proto/ibc/core/connection/v1/query.proto delete mode 100644 third_party/proto/ibc/core/connection/v1/tx.proto delete mode 100644 third_party/proto/ibc/core/types/v1/genesis.proto delete mode 100644 third_party/proto/ibc/lightclients/localhost/v1/localhost.proto delete mode 100644 third_party/proto/ibc/lightclients/solomachine/v1/solomachine.proto delete mode 100644 third_party/proto/ibc/lightclients/solomachine/v2/solomachine.proto delete mode 100644 third_party/proto/ibc/lightclients/tendermint/v1/tendermint.proto delete mode 100644 third_party/proto/tendermint/abci/types.proto delete mode 100644 third_party/proto/tendermint/crypto/keys.proto delete mode 100644 third_party/proto/tendermint/crypto/proof.proto delete mode 100644 third_party/proto/tendermint/libs/bits/types.proto delete mode 100644 third_party/proto/tendermint/types/params.proto delete mode 100644 third_party/proto/tendermint/types/types.proto delete mode 100644 third_party/proto/tendermint/types/validator.proto delete mode 100644 third_party/proto/tendermint/version/types.proto delete mode 100644 x/ccv/consumer/keeper/migration.go delete mode 100644 x/ccv/consumer/keeper/migration_test.go delete mode 100644 x/ccv/provider/keeper/migration.go delete mode 100644 x/ccv/provider/keeper/migration_test.go diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..333418f12d --- /dev/null +++ b/.dockerignore @@ -0,0 +1,9 @@ +.git/ +Dockerfile +*.md +.gitignore +.gitattributes +scripts/ +.vscode/ +.github/ +proto/ diff --git a/.github/workflows/automated-tests.yml b/.github/workflows/automated-tests.yml index 0a4a8fc6a0..175bec9545 100644 --- a/.github/workflows/automated-tests.yml +++ b/.github/workflows/automated-tests.yml @@ -24,8 +24,8 @@ jobs: uses: actions/setup-go@v4 with: go-version: "1.19" # The Go version to download (if necessary) and use. - - name: Proto Check - run: make proto-check + # - name: Proto Check + # run: make proto-check - name: Unit, integration and difference tests run: go test ./... - name: E2E tests diff --git a/Dockerfile b/Dockerfile index 4d81392316..dee88dae7c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,7 @@ # syntax=docker/dockerfile:1 -FROM golang:1.19-alpine AS is-builder + +FROM golang:1.20-alpine AS is-builder ENV PACKAGES curl make git libc-dev bash gcc linux-headers RUN apk add --no-cache $PACKAGES diff --git a/Dockerfile.gaia b/Dockerfile.gaia index 87448a1d63..b9f6ff007f 100644 --- a/Dockerfile.gaia +++ b/Dockerfile.gaia @@ -1,7 +1,7 @@ # syntax=docker/dockerfile:1 # build latest tagged gaia -FROM golang:1.19-alpine AS gaia-builder +FROM golang:1.20-alpine AS gaia-builder # WORKDIR is set to /go by default ARG USE_GAIA_TAG ENV GAIA_TAG=${USE_GAIA_TAG} @@ -43,7 +43,7 @@ RUN go mod tidy RUN go list -m github.com/cosmos/cosmos-sdk RUN make build -FROM golang:1.19-alpine AS is-builder +FROM golang:1.20-alpine AS is-builder ENV PACKAGES curl make git libc-dev bash gcc linux-headers RUN apk add --no-cache $PACKAGES diff --git a/Makefile b/Makefile index 351852cd21..69cdfa74be 100644 --- a/Makefile +++ b/Makefile @@ -13,6 +13,10 @@ install: go.sum test: go test ./... && go run ./tests/e2e/... +# run all unit tests +test-unit: + go test ./... + # run unit and integration tests test-short: go test ./x/... ./app/... ./tests/integration/... @@ -102,18 +106,20 @@ $(BUILDDIR)/: ### Protobuf ### ############################################################################### -containerProtoVer=0.9.0 +DOCKER := $(shell which docker) +HTTPS_GIT := https://github.com/cosmos/interchain-security.git + +containerProtoVer=0.13.0 containerProtoImage=ghcr.io/cosmos/proto-builder:$(containerProtoVer) -containerProtoGen=cosmos-sdk-proto-gen-$(containerProtoVer) -containerProtoGenSwagger=cosmos-sdk-proto-gen-swagger-$(containerProtoVer) -containerProtoFmt=cosmos-sdk-proto-fmt-$(containerProtoVer) + +protoImage=$(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace $(containerProtoImage) + proto-all: proto-format proto-lint proto-gen proto-gen: @echo "Generating Protobuf files" - @if docker ps -a --format '{{.Names}}' | grep -Eq "^${containerProtoGen}$$"; then docker start -a $(containerProtoGen); else docker run --name $(containerProtoGen) -v $(CURDIR):/workspace --workdir /workspace $(containerProtoImage) \ - sh ./scripts/protocgen.sh; fi + @$(protoImage) sh ./scripts/protocgen.sh; proto-check: @if git diff --quiet; then \ @@ -130,95 +136,25 @@ proto-check: exit 1; \ fi - proto-format: @echo "Formatting Protobuf files" - @if docker ps -a --format '{{.Names}}' | grep -Eq "^${containerProtoFmt}$$"; then docker start -a $(containerProtoFmt); else docker run --name $(containerProtoFmt) -v $(CURDIR):/workspace --workdir /workspace tendermintdev/docker-build-proto \ - find ./ -not -path "./third_party/*" -name "*.proto" -exec clang-format -i {} \; ; fi + @$(protoImage) find ./ -name "*.proto" -exec clang-format -i {} \; proto-swagger-gen: @echo "Generating Protobuf Swagger" - @if docker ps -a --format '{{.Names}}' | grep -Eq "^${containerProtoGenSwagger}$$"; then docker start -a $(containerProtoGenSwagger); else docker run --name $(containerProtoGenSwagger) -v $(CURDIR):/workspace --workdir /workspace $(containerProtoImage) \ - sh ./scripts/protoc-swagger-gen.sh; fi + @$(protoImage) sh ./scripts/protocgen.sh proto-lint: - @$(DOCKER_BUF) lint --error-format=json + @$(protoImage) buf lint --error-format=json proto-check-breaking: - @$(DOCKER_BUF) breaking --against $(HTTPS_GIT)#branch=main - -TM_URL = https://raw.githubusercontent.com/tendermint/tendermint/v0.34.5/proto/tendermint -GOGO_PROTO_URL = https://raw.githubusercontent.com/regen-network/protobuf/cosmos -CONFIO_URL = https://raw.githubusercontent.com/confio/ics23/v0.7.1 -COSMOS_PROTO_URL = https://raw.githubusercontent.com/regen-network/cosmos-proto/master -SDK_PROTO_URL = https://raw.githubusercontent.com/cosmos/cosmos-sdk/v0.45.13-ics/proto/cosmos - -TM_CRYPTO_TYPES = third_party/proto/tendermint/crypto -TM_ABCI_TYPES = third_party/proto/tendermint/abci -TM_TYPES = third_party/proto/tendermint/types -TM_VERSION = third_party/proto/tendermint/version -TM_LIBS = third_party/proto/tendermint/libs/bits -TM_P2P = third_party/proto/tendermint/p2p - -SDK_QUERY = third_party/proto/cosmos/base/query/v1beta1 -SDK_BASE = third_party/proto/cosmos/base/v1beta1 -SDK_UPGRADE = third_party/proto/cosmos/upgrade/v1beta1 -SDK_STAKING = third_party/proto/cosmos/staking/v1beta1 -SDK_EVIDENCE = third_party/proto/cosmos/evidence/v1beta1 - -GOGO_PROTO_TYPES = third_party/proto/gogoproto -CONFIO_TYPES = third_party/proto/confio -COSMOS_PROTO_TYPES = third_party/proto/cosmos_proto + @$(protoImage) buf breaking --against $(HTTPS_GIT)#branch=main proto-update-deps: - @mkdir -p $(COSMOS_PROTO_TYPES) - @curl -sSL $(COSMOS_PROTO_URL)/cosmos.proto > $(COSMOS_PROTO_TYPES)/cosmos.proto - - @mkdir -p $(SDK_QUERY) - @curl -sSL $(SDK_PROTO_URL)/base/query/v1beta1/pagination.proto > $(SDK_QUERY)/pagination.proto - - @mkdir -p $(SDK_BASE) - @curl -sSL $(SDK_PROTO_URL)/base/v1beta1/coin.proto > $(SDK_BASE)/coin.proto - - @mkdir -p $(SDK_UPGRADE) - @curl -sSL $(SDK_PROTO_URL)/upgrade/v1beta1/upgrade.proto > $(SDK_UPGRADE)/upgrade.proto - - @mkdir -p $(SDK_STAKING) - @curl -sSL $(SDK_PROTO_URL)/staking/v1beta1/staking.proto > $(SDK_STAKING)/staking.proto - - @mkdir -p $(SDK_EVIDENCE) - @curl -sSL $(SDK_PROTO_URL)/evidence/v1beta1/evidence.proto > $(SDK_EVIDENCE)/evidence.proto - -## Importing of tendermint protobuf definitions currently requires the -## use of `sed` in order to build properly with cosmos-sdk's proto file layout -## (which is the standard Buf.build FILE_LAYOUT) -## Issue link: https://github.com/tendermint/tendermint/issues/5021 - @mkdir -p $(TM_TYPES) - @curl -sSL $(TM_URL)/types/types.proto > $(TM_TYPES)/types.proto - @curl -sSL $(TM_URL)/types/params.proto > $(TM_TYPES)/params.proto - @curl -sSL $(TM_URL)/types/validator.proto > $(TM_TYPES)/validator.proto - - @mkdir -p $(TM_ABCI_TYPES) - @curl -sSL $(TM_URL)/abci/types.proto > $(TM_ABCI_TYPES)/types.proto - - @mkdir -p $(TM_VERSION) - @curl -sSL $(TM_URL)/version/types.proto > $(TM_VERSION)/types.proto - - @mkdir -p $(TM_LIBS) - @curl -sSL $(TM_URL)/libs/bits/types.proto > $(TM_LIBS)/types.proto - - @mkdir -p $(TM_CRYPTO_TYPES) - @curl -sSL $(TM_URL)/crypto/proof.proto > $(TM_CRYPTO_TYPES)/proof.proto - @curl -sSL $(TM_URL)/crypto/keys.proto > $(TM_CRYPTO_TYPES)/keys.proto - - @mkdir -p $(CONFIO_TYPES) - @curl -sSL $(CONFIO_URL)/proofs.proto > $(CONFIO_TYPES)/proofs.proto - -## insert go package option into proofs.proto file -## Issue link: https://github.com/confio/ics23/issues/32 - @perl -i -l -p -e 'print "option go_package = \"github.com/confio/ics23/go\";" if $$. == 4' $(CONFIO_TYPES)/proofs.proto + @echo "Updating Protobuf dependencies" + $(protoImage) buf mod update -.PHONY: proto-all proto-gen proto-gen-any proto-swagger-gen proto-format proto-lint proto-check-breaking proto-update-deps mocks +.PHONY: proto-all proto-gen proto-format proto-lint proto-check proto-check-breaking proto-update-deps mocks ############################################################################### ### Documentation ### diff --git a/app/consumer-democracy/ante/forbidden_proposals_ante.go b/app/consumer-democracy/ante/forbidden_proposals_ante.go index dd1b3d5e1e..f8acfd8bc5 100644 --- a/app/consumer-democracy/ante/forbidden_proposals_ante.go +++ b/app/consumer-democracy/ante/forbidden_proposals_ante.go @@ -4,25 +4,51 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + + govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" ) type ForbiddenProposalsDecorator struct { - IsProposalWhitelisted func(govtypes.Content) bool + isLegacyProposalWhitelisted func(govv1beta1.Content) bool + isModuleWhiteList func(string) bool } -func NewForbiddenProposalsDecorator(whiteListFn func(govtypes.Content) bool) ForbiddenProposalsDecorator { - return ForbiddenProposalsDecorator{IsProposalWhitelisted: whiteListFn} +func NewForbiddenProposalsDecorator( + whiteListFn func(govv1beta1.Content) bool, + isModuleWhiteList func(string) bool, +) ForbiddenProposalsDecorator { + return ForbiddenProposalsDecorator{ + isLegacyProposalWhitelisted: whiteListFn, + isModuleWhiteList: isModuleWhiteList, + } } func (decorator ForbiddenProposalsDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { currHeight := ctx.BlockHeight() for _, msg := range tx.GetMsgs() { - submitProposalMgs, ok := msg.(*govtypes.MsgSubmitProposal) // if the message is MsgSubmitProposal, check if proposal is whitelisted - if ok { - if !decorator.IsProposalWhitelisted(submitProposalMgs.GetContent()) { + submitProposalMgs, ok := msg.(*govv1.MsgSubmitProposal) + if !ok { + continue + } + + messages := submitProposalMgs.GetMessages() + for _, message := range messages { + if sdkMsg, isLegacyProposal := message.GetCachedValue().(*govv1.MsgExecLegacyContent); isLegacyProposal { + // legacy gov proposal content + content, err := govv1.LegacyContentFromMessage(sdkMsg) + if err != nil { + return ctx, fmt.Errorf("tx contains invalid LegacyContent") + } + if !decorator.isLegacyProposalWhitelisted(content) { + return ctx, fmt.Errorf("tx contains unsupported proposal message types at height %d", currHeight) + } + continue + } + // not legacy gov proposal content and not whitelisted + if !decorator.isModuleWhiteList(message.TypeUrl) { return ctx, fmt.Errorf("tx contains unsupported proposal message types at height %d", currHeight) } } diff --git a/app/consumer-democracy/ante/forbidden_proposals_ante_test.go b/app/consumer-democracy/ante/forbidden_proposals_ante_test.go index 00e5adc6e2..5c67506e7c 100644 --- a/app/consumer-democracy/ante/forbidden_proposals_ante_test.go +++ b/app/consumer-democracy/ante/forbidden_proposals_ante_test.go @@ -7,15 +7,35 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" "github.com/cosmos/cosmos-sdk/x/params/types/proposal" app "github.com/cosmos/interchain-security/v2/app/consumer-democracy" "github.com/cosmos/interchain-security/v2/app/consumer-democracy/ante" "github.com/stretchr/testify/require" + + ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" ) +// in SDKv47 parameter updates full params object is required +// either all params can be updated or none can be updated func TestForbiddenProposalsDecorator(t *testing.T) { txCfg := app.MakeTestEncodingConfig().TxConfig + // here we try to set whatever params exist to their default values + // the actual parameter setting is not important, what's being tested is the ante handle filter + // Note: mint params CAN be changed according to WhiteListModule in proposals_whitelisting.go + updateMintParams := &minttypes.MsgUpdateParams{ + Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), + Params: minttypes.DefaultParams(), + } + + // Note: auth params CANNOT be changed according to WhiteListModule in proposals_whitelisting.go + updateAuthParams := &authtypes.MsgUpdateParams{ + Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), + Params: authtypes.DefaultParams(), + } + testCases := []struct { name string ctx sdk.Context @@ -23,12 +43,78 @@ func TestForbiddenProposalsDecorator(t *testing.T) { expectErr bool }{ { - name: "Allowed param change", + name: "Allowed param change - mint module", + ctx: sdk.Context{}, + msgs: []sdk.Msg{ + newParamChangeProposalMsg([]sdk.Msg{updateMintParams}), + }, + expectErr: false, + }, + { + name: "Forbidden param change - auth module", + ctx: sdk.Context{}, + msgs: []sdk.Msg{ + newParamChangeProposalMsg([]sdk.Msg{updateAuthParams}), + }, + expectErr: true, + }, + { + name: "Allowed and forbidden param changes in the same msg", ctx: sdk.Context{}, msgs: []sdk.Msg{ - newParamChangeProposalMsg([]proposal.ParamChange{ + newParamChangeProposalMsg([]sdk.Msg{updateMintParams, updateAuthParams}), + }, + expectErr: true, + }, + { + name: "Allowed and forbidden param changes in different msg", + ctx: sdk.Context{}, + msgs: []sdk.Msg{ + newParamChangeProposalMsg([]sdk.Msg{updateMintParams}), + newParamChangeProposalMsg([]sdk.Msg{updateAuthParams}), + }, + expectErr: true, + }, + } + + for _, tc := range testCases { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + handler := ante.NewForbiddenProposalsDecorator(app.IsProposalWhitelisted, app.IsModuleWhiteList) + + txBuilder := txCfg.NewTxBuilder() + require.NoError(t, txBuilder.SetMsgs(tc.msgs...)) + + _, err := handler.AnteHandle(tc.ctx, txBuilder.GetTx(), false, + func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { return ctx, nil }) + if tc.expectErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} + +// Only ibctransfertypes.SendEnabled/ReceiveEnabled support legacy proposals for changing params +// Note: see LegacyWhitelistedParams in proposals_whitelisting.go +func TestForbiddenLegacyProposalsDecorator(t *testing.T) { + txCfg := app.MakeTestEncodingConfig().TxConfig + + testCases := []struct { + name string + ctx sdk.Context + msgs []sdk.Msg + expectErr bool + }{ + { + name: "Allowed legacy param change -- only for ibctransfertypes.SendEnabled/ReceiveEnabled", + ctx: sdk.Context{}, + msgs: []sdk.Msg{ + newLegacyParamChangeProposalMsg([]proposal.ParamChange{ // only subspace and key are relevant for testing - {Subspace: banktypes.ModuleName, Key: "SendEnabled", Value: ""}, + {Subspace: ibctransfertypes.ModuleName, Key: "SendEnabled", Value: "true"}, }), }, expectErr: false, @@ -37,7 +123,7 @@ func TestForbiddenProposalsDecorator(t *testing.T) { name: "Forbidden param change", ctx: sdk.Context{}, msgs: []sdk.Msg{ - newParamChangeProposalMsg([]proposal.ParamChange{ + newLegacyParamChangeProposalMsg([]proposal.ParamChange{ {Subspace: authtypes.ModuleName, Key: "MaxMemoCharacters", Value: ""}, }), }, @@ -47,8 +133,10 @@ func TestForbiddenProposalsDecorator(t *testing.T) { name: "Allowed and forbidden param changes in the same msg", ctx: sdk.Context{}, msgs: []sdk.Msg{ - newParamChangeProposalMsg([]proposal.ParamChange{ - {Subspace: banktypes.ModuleName, Key: "SendEnabled", Value: ""}, + newLegacyParamChangeProposalMsg([]proposal.ParamChange{ + // allowed + {Subspace: ibctransfertypes.ModuleName, Key: "SendEnabled", Value: "true"}, + // disallowed {Subspace: authtypes.ModuleName, Key: "MaxMemoCharacters", Value: ""}, }), }, @@ -58,11 +146,13 @@ func TestForbiddenProposalsDecorator(t *testing.T) { name: "Allowed and forbidden param changes in different msg", ctx: sdk.Context{}, msgs: []sdk.Msg{ - newParamChangeProposalMsg([]proposal.ParamChange{ + newLegacyParamChangeProposalMsg([]proposal.ParamChange{ + // disallowed {Subspace: banktypes.ModuleName, Key: "SendEnabled", Value: ""}, }), - newParamChangeProposalMsg([]proposal.ParamChange{ - {Subspace: authtypes.ModuleName, Key: "MaxMemoCharacters", Value: ""}, + newLegacyParamChangeProposalMsg([]proposal.ParamChange{ + // allowed + {Subspace: ibctransfertypes.ModuleName, Key: "SendEnabled", Value: "true"}, }), }, expectErr: true, @@ -73,7 +163,7 @@ func TestForbiddenProposalsDecorator(t *testing.T) { tc := tc t.Run(tc.name, func(t *testing.T) { - handler := ante.NewForbiddenProposalsDecorator(app.IsProposalWhitelisted) + handler := ante.NewForbiddenProposalsDecorator(app.IsProposalWhitelisted, app.IsModuleWhiteList) txBuilder := txCfg.NewTxBuilder() require.NoError(t, txBuilder.SetMsgs(tc.msgs...)) @@ -89,8 +179,18 @@ func TestForbiddenProposalsDecorator(t *testing.T) { } } -func newParamChangeProposalMsg(changes []proposal.ParamChange) *govtypes.MsgSubmitProposal { +// Use ParamChangeProposal +func newLegacyParamChangeProposalMsg(changes []proposal.ParamChange) *govv1.MsgSubmitProposal { paramChange := proposal.ParameterChangeProposal{Changes: changes} - msg, _ := govtypes.NewMsgSubmitProposal(¶mChange, sdk.NewCoins(), sdk.AccAddress{}) + msgContent, err := govv1.NewLegacyContent(¶mChange, authtypes.NewModuleAddress(govtypes.ModuleName).String()) + if err != nil { + return nil + } + msg, _ := govv1.NewMsgSubmitProposal([]sdk.Msg{msgContent}, sdk.NewCoins(), sdk.AccAddress{}.String(), "", "", "") + return msg +} + +func newParamChangeProposalMsg(msgs []sdk.Msg) *govv1.MsgSubmitProposal { + msg, _ := govv1.NewMsgSubmitProposal(msgs, sdk.NewCoins(), sdk.AccAddress{}.String(), "", "", "") return msg } diff --git a/app/consumer-democracy/ante_handler.go b/app/consumer-democracy/ante_handler.go index b50d209312..b031c9fadc 100644 --- a/app/consumer-democracy/ante_handler.go +++ b/app/consumer-democracy/ante_handler.go @@ -5,8 +5,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth/ante" - ibcante "github.com/cosmos/ibc-go/v4/modules/core/ante" - ibckeeper "github.com/cosmos/ibc-go/v4/modules/core/keeper" + ibcante "github.com/cosmos/ibc-go/v7/modules/core/ante" + ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" democracyante "github.com/cosmos/interchain-security/v2/app/consumer-democracy/ante" consumerante "github.com/cosmos/interchain-security/v2/app/consumer/ante" ibcconsumerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/consumer/keeper" @@ -39,23 +39,22 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { anteDecorators := []sdk.AnteDecorator{ ante.NewSetUpContextDecorator(), - ante.NewRejectExtensionOptionsDecorator(), + ante.NewExtensionOptionsDecorator(nil), consumerante.NewMsgFilterDecorator(options.ConsumerKeeper), consumerante.NewDisabledModulesDecorator("/cosmos.evidence", "/cosmos.slashing"), - democracyante.NewForbiddenProposalsDecorator(IsProposalWhitelisted), - ante.NewMempoolFeeDecorator(), + democracyante.NewForbiddenProposalsDecorator(IsProposalWhitelisted, IsModuleWhiteList), ante.NewValidateBasicDecorator(), ante.NewTxTimeoutHeightDecorator(), ante.NewValidateMemoDecorator(options.AccountKeeper), ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), - ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper), + ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), // SetPubKeyDecorator must be called before all signature verification decorators ante.NewSetPubKeyDecorator(options.AccountKeeper), ante.NewValidateSigCountDecorator(options.AccountKeeper), ante.NewSigGasConsumeDecorator(options.AccountKeeper, sigGasConsumer), ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler), ante.NewIncrementSequenceDecorator(options.AccountKeeper), - ibcante.NewAnteDecorator(options.IBCKeeper), + ibcante.NewRedundantRelayDecorator(options.IBCKeeper), } return sdk.ChainAnteDecorators(anteDecorators...), nil diff --git a/app/consumer-democracy/app.go b/app/consumer-democracy/app.go index e9406cfecd..e72b62c9e5 100644 --- a/app/consumer-democracy/app.go +++ b/app/consumer-democracy/app.go @@ -4,31 +4,37 @@ import ( "fmt" "io" stdlog "log" - "net/http" "os" "path/filepath" + "github.com/cosmos/cosmos-sdk/client/flags" + nodeservice "github.com/cosmos/cosmos-sdk/client/grpc/node" + "github.com/cosmos/cosmos-sdk/runtime" + "github.com/cosmos/cosmos-sdk/x/consensus" + consensusparamkeeper "github.com/cosmos/cosmos-sdk/x/consensus/keeper" + consensusparamtypes "github.com/cosmos/cosmos-sdk/x/consensus/types" + "github.com/cosmos/cosmos-sdk/x/genutil" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" appparams "github.com/cosmos/interchain-security/v2/app/params" + autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" + reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/grpc/tmservice" - "github.com/cosmos/cosmos-sdk/client/rpc" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/server/api" "github.com/cosmos/cosmos-sdk/server/config" servertypes "github.com/cosmos/cosmos-sdk/server/types" - "github.com/cosmos/cosmos-sdk/simapp" "github.com/cosmos/cosmos-sdk/std" - store "github.com/cosmos/cosmos-sdk/store/types" + storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth/ante" - authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest" authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation" authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" @@ -39,6 +45,8 @@ import ( authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper" authzmodule "github.com/cosmos/cosmos-sdk/x/authz/module" "github.com/cosmos/cosmos-sdk/x/bank" + + runtimeservices "github.com/cosmos/cosmos-sdk/runtime/services" bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/cosmos/cosmos-sdk/x/capability" @@ -59,34 +67,29 @@ import ( paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" upgradeclient "github.com/cosmos/cosmos-sdk/x/upgrade/client" + dbm "github.com/cometbft/cometbft-db" + abci "github.com/cometbft/cometbft/abci/types" + tmjson "github.com/cometbft/cometbft/libs/json" + "github.com/cometbft/cometbft/libs/log" + tmos "github.com/cometbft/cometbft/libs/os" "github.com/cosmos/cosmos-sdk/x/slashing" slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" "github.com/cosmos/cosmos-sdk/x/upgrade" upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - "github.com/cosmos/ibc-go/v4/modules/apps/transfer" - ibctransferkeeper "github.com/cosmos/ibc-go/v4/modules/apps/transfer/keeper" - ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" - ibc "github.com/cosmos/ibc-go/v4/modules/core" - ibcconnectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" - porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" - ibchost "github.com/cosmos/ibc-go/v4/modules/core/24-host" - ibckeeper "github.com/cosmos/ibc-go/v4/modules/core/keeper" + "github.com/cosmos/ibc-go/v7/modules/apps/transfer" + ibctransferkeeper "github.com/cosmos/ibc-go/v7/modules/apps/transfer/keeper" + ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + ibc "github.com/cosmos/ibc-go/v7/modules/core" + ibcconnectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" + porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" + ibchost "github.com/cosmos/ibc-go/v7/modules/core/exported" + ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" ibctestingcore "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/core" ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" - "github.com/gorilla/mux" - "github.com/rakyll/statik/fs" "github.com/spf13/cast" - abci "github.com/tendermint/tendermint/abci/types" - tmjson "github.com/tendermint/tendermint/libs/json" - "github.com/tendermint/tendermint/libs/log" - tmos "github.com/tendermint/tendermint/libs/os" - dbm "github.com/tendermint/tm-db" - - distr "github.com/cosmos/cosmos-sdk/x/distribution" - distrclient "github.com/cosmos/cosmos-sdk/x/distribution/client" distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" testutil "github.com/cosmos/interchain-security/v2/testutil/integration" @@ -97,8 +100,10 @@ import ( ccvstaking "github.com/cosmos/interchain-security/v2/x/ccv/democracy/staking" gov "github.com/cosmos/cosmos-sdk/x/gov" + govclient "github.com/cosmos/cosmos-sdk/x/gov/client" 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" ccvgov "github.com/cosmos/interchain-security/v2/x/ccv/democracy/governance" // add mint @@ -107,6 +112,7 @@ import ( minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" paramproposal "github.com/cosmos/cosmos-sdk/x/params/types/proposal" + tendermint "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" consumer "github.com/cosmos/interchain-security/v2/x/ccv/consumer" consumerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/consumer/keeper" consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" @@ -130,6 +136,7 @@ var ( // and genesis verification. ModuleBasics = module.NewBasicManager( auth.AppModuleBasic{}, + genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator), bank.AppModuleBasic{}, capability.AppModuleBasic{}, ccvstaking.AppModuleBasic{}, @@ -137,7 +144,11 @@ var ( ccvdistr.AppModuleBasic{}, gov.NewAppModuleBasic( // TODO: eventually remove upgrade proposal handler and cancel proposal handler - paramsclient.ProposalHandler, distrclient.ProposalHandler, upgradeclient.ProposalHandler, upgradeclient.CancelProposalHandler, + []govclient.ProposalHandler{ + paramsclient.ProposalHandler, + upgradeclient.LegacyProposalHandler, + upgradeclient.LegacyCancelProposalHandler, + }, ), params.AppModuleBasic{}, crisis.AppModuleBasic{}, @@ -149,8 +160,10 @@ var ( evidence.AppModuleBasic{}, transfer.AppModuleBasic{}, vesting.AppModuleBasic{}, + tendermint.AppModuleBasic{}, // router.AppModuleBasic{}, consumer.AppModuleBasic{}, + consensus.AppModuleBasic{}, ) // module account permissions @@ -168,7 +181,7 @@ var ( ) var ( - _ simapp.App = (*App)(nil) + _ runtime.AppI = (*App)(nil) _ servertypes.Application = (*App)(nil) _ ibctesting.TestingApp = (*App)(nil) ) @@ -180,33 +193,33 @@ type App struct { // nolint: golint *baseapp.BaseApp legacyAmino *codec.LegacyAmino appCodec codec.Codec + txConfig client.TxConfig interfaceRegistry types.InterfaceRegistry - invCheckPeriod uint - // keys to access the substores - keys map[string]*sdk.KVStoreKey - tkeys map[string]*sdk.TransientStoreKey - memKeys map[string]*sdk.MemoryStoreKey + keys map[string]*storetypes.KVStoreKey + tkeys map[string]*storetypes.TransientStoreKey + memKeys map[string]*storetypes.MemoryStoreKey // keepers - AccountKeeper authkeeper.AccountKeeper - BankKeeper bankkeeper.Keeper - CapabilityKeeper *capabilitykeeper.Keeper - StakingKeeper stakingkeeper.Keeper - SlashingKeeper slashingkeeper.Keeper - MintKeeper mintkeeper.Keeper - DistrKeeper distrkeeper.Keeper - GovKeeper govkeeper.Keeper - CrisisKeeper crisiskeeper.Keeper - UpgradeKeeper upgradekeeper.Keeper - ParamsKeeper paramskeeper.Keeper - IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly - EvidenceKeeper evidencekeeper.Keeper - TransferKeeper ibctransferkeeper.Keeper - FeeGrantKeeper feegrantkeeper.Keeper - AuthzKeeper authzkeeper.Keeper - ConsumerKeeper consumerkeeper.Keeper + AccountKeeper authkeeper.AccountKeeper + BankKeeper bankkeeper.Keeper + CapabilityKeeper *capabilitykeeper.Keeper + StakingKeeper *stakingkeeper.Keeper + SlashingKeeper slashingkeeper.Keeper + MintKeeper mintkeeper.Keeper + DistrKeeper distrkeeper.Keeper + GovKeeper govkeeper.Keeper + CrisisKeeper crisiskeeper.Keeper + UpgradeKeeper upgradekeeper.Keeper + ParamsKeeper paramskeeper.Keeper + IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly + EvidenceKeeper evidencekeeper.Keeper + TransferKeeper ibctransferkeeper.Keeper + FeeGrantKeeper feegrantkeeper.Keeper + AuthzKeeper authzkeeper.Keeper + ConsumerKeeper consumerkeeper.Keeper + ConsensusParamsKeeper consensusparamkeeper.Keeper // make scoped keepers public for test purposes ScopedIBCKeeper capabilitykeeper.ScopedKeeper @@ -236,16 +249,15 @@ func New( db dbm.DB, traceStore io.Writer, loadLatest bool, - skipUpgradeHeights map[int64]bool, - homePath string, - invCheckPeriod uint, - encodingConfig appparams.EncodingConfig, appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp), ) *App { - appCodec := encodingConfig.Marshaler + encodingConfig := makeEncodingConfig() + + appCodec := encodingConfig.Codec legacyAmino := encodingConfig.Amino interfaceRegistry := encodingConfig.InterfaceRegistry + txConfig := encodingConfig.TxConfig bApp := baseapp.NewBaseApp(AppName, logger, db, encodingConfig.TxConfig.TxDecoder(), baseAppOptions...) bApp.SetCommitMultiStoreTracer(traceStore) @@ -253,11 +265,11 @@ func New( bApp.SetInterfaceRegistry(interfaceRegistry) keys := sdk.NewKVStoreKeys( - authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, + authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, crisistypes.StoreKey, minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey, govtypes.StoreKey, paramstypes.StoreKey, ibchost.StoreKey, upgradetypes.StoreKey, feegrant.StoreKey, evidencetypes.StoreKey, ibctransfertypes.StoreKey, - capabilitytypes.StoreKey, authzkeeper.StoreKey, + capabilitytypes.StoreKey, authzkeeper.StoreKey, consensusparamtypes.StoreKey, consumertypes.StoreKey, ) tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey) @@ -267,8 +279,8 @@ func New( BaseApp: bApp, legacyAmino: legacyAmino, appCodec: appCodec, + txConfig: txConfig, interfaceRegistry: interfaceRegistry, - invCheckPeriod: invCheckPeriod, keys: keys, tkeys: tkeys, memKeys: memKeys, @@ -282,10 +294,8 @@ func New( ) // set the BaseApp's parameter store - bApp.SetParamStore( - app.ParamsKeeper.Subspace(baseapp.Paramspace).WithKeyTable( - paramskeeper.ConsensusParamsKeyTable()), - ) + app.ConsensusParamsKeeper = consensusparamkeeper.NewKeeper(appCodec, keys[upgradetypes.StoreKey], authtypes.NewModuleAddress(govtypes.ModuleName).String()) + bApp.SetParamStore(&app.ConsensusParamsKeeper) // add capability keeper and ScopeToModule for ibc module app.CapabilityKeeper = capabilitykeeper.NewKeeper( @@ -302,9 +312,10 @@ func New( app.AccountKeeper = authkeeper.NewAccountKeeper( appCodec, keys[authtypes.StoreKey], - app.GetSubspace(authtypes.ModuleName), authtypes.ProtoBaseAccount, maccPerms, + AccountAddressPrefix, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) // Remove the fee-pool from the group of blocked recipient addresses in bank @@ -318,13 +329,14 @@ func New( appCodec, keys[banktypes.StoreKey], app.AccountKeeper, - app.GetSubspace(banktypes.ModuleName), bankBlockedAddrs, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) app.AuthzKeeper = authzkeeper.NewKeeper( keys[authzkeeper.StoreKey], appCodec, app.BaseApp.MsgServiceRouter(), + app.AccountKeeper, ) app.FeeGrantKeeper = feegrantkeeper.NewKeeper( appCodec, @@ -332,72 +344,108 @@ func New( app.AccountKeeper, ) - stakingKeeper := stakingkeeper.NewKeeper( + app.StakingKeeper = stakingkeeper.NewKeeper( appCodec, keys[stakingtypes.StoreKey], app.AccountKeeper, app.BankKeeper, - app.GetSubspace(stakingtypes.ModuleName), + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) app.MintKeeper = mintkeeper.NewKeeper( - appCodec, keys[minttypes.StoreKey], app.GetSubspace(minttypes.ModuleName), &stakingKeeper, - app.AccountKeeper, app.BankKeeper, authtypes.FeeCollectorName, + appCodec, + keys[minttypes.StoreKey], + app.StakingKeeper, + app.AccountKeeper, + app.BankKeeper, + authtypes.FeeCollectorName, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) app.SlashingKeeper = slashingkeeper.NewKeeper( appCodec, + legacyAmino, keys[slashingtypes.StoreKey], &app.ConsumerKeeper, - app.GetSubspace(slashingtypes.ModuleName), + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) app.DistrKeeper = distrkeeper.NewKeeper( appCodec, keys[distrtypes.StoreKey], - app.GetSubspace(distrtypes.ModuleName), app.AccountKeeper, app.BankKeeper, - &stakingKeeper, + app.StakingKeeper, consumertypes.ConsumerRedistributeName, - app.ModuleAccountAddrs(), + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) - app.CrisisKeeper = crisiskeeper.NewKeeper( - app.GetSubspace(crisistypes.ModuleName), + + invCheckPeriod := cast.ToUint(appOpts.Get(server.FlagInvCheckPeriod)) + app.CrisisKeeper = *crisiskeeper.NewKeeper( + appCodec, + keys[crisistypes.StoreKey], invCheckPeriod, app.BankKeeper, authtypes.FeeCollectorName, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) - app.UpgradeKeeper = upgradekeeper.NewKeeper( + + // get skipUpgradeHeights from the app options + skipUpgradeHeights := map[int64]bool{} + for _, h := range cast.ToIntSlice(appOpts.Get(server.FlagUnsafeSkipUpgrades)) { + skipUpgradeHeights[int64(h)] = true + } + homePath := cast.ToString(appOpts.Get(flags.FlagHome)) + // set the governance module account as the authority for conducting upgrades + app.UpgradeKeeper = *upgradekeeper.NewKeeper( skipUpgradeHeights, keys[upgradetypes.StoreKey], appCodec, homePath, app.BaseApp, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) // register the staking hooks // NOTE: stakingKeeper above is passed by reference, so that it will contain these hooks // NOTE: slashing hook was removed since it's only relevant for consumerKeeper - app.StakingKeeper = *stakingKeeper.SetHooks( + app.StakingKeeper.SetHooks( stakingtypes.NewMultiStakingHooks(app.DistrKeeper.Hooks()), ) // register the proposal types - ccvgovRouter := govtypes.NewRouter() - ccvgovRouter.AddRoute(govtypes.RouterKey, govtypes.ProposalHandler). + ccvgovRouter := govv1beta1.NewRouter() + ccvgovRouter.AddRoute(govtypes.RouterKey, govv1beta1.ProposalHandler). AddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(app.ParamsKeeper)). - AddRoute(distrtypes.RouterKey, distr.NewCommunityPoolSpendProposalHandler(app.DistrKeeper)). // TODO: remove upgrade handler from gov once admin module or decision for only signaling proposal is made. - AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper)) + AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(&app.UpgradeKeeper)) + + govConfig := govtypes.DefaultConfig() govKeeper := govkeeper.NewKeeper( - appCodec, keys[govtypes.StoreKey], app.GetSubspace(govtypes.ModuleName), app.AccountKeeper, app.BankKeeper, - &stakingKeeper, ccvgovRouter, + appCodec, keys[govtypes.StoreKey], app.AccountKeeper, app.BankKeeper, + app.StakingKeeper, app.MsgServiceRouter(), govConfig, authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) - app.GovKeeper = *govKeeper.SetHooks( - govtypes.NewMultiGovHooks( - // register the governance hooks - ), + govKeeper.SetLegacyRouter(ccvgovRouter) + + app.GovKeeper = *govKeeper + + // pre-initialize ConsumerKeeper to satsfy ibckeeper.NewKeeper + // which would panic on nil or zero keeper + // ConsumerKeeper implements StakingKeeper but all function calls result in no-ops so this is safe + // communication over IBC is not affected by these changes + app.ConsumerKeeper = consumerkeeper.NewNonZeroKeeper( + appCodec, + keys[consumertypes.StoreKey], + app.GetSubspace(consumertypes.ModuleName), + ) + + app.IBCKeeper = ibckeeper.NewKeeper( + appCodec, + keys[ibchost.StoreKey], + app.GetSubspace(ibchost.ModuleName), + app.ConsumerKeeper, + app.UpgradeKeeper, + scopedIBCKeeper, ) app.IBCKeeper = ibckeeper.NewKeeper( @@ -434,9 +482,10 @@ func New( // of the slashing module app.SlashingKeeper = slashingkeeper.NewKeeper( appCodec, + legacyAmino, keys[slashingtypes.StoreKey], &app.ConsumerKeeper, - app.GetSubspace(slashingtypes.ModuleName), + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) // register slashing module StakingHooks to the consumer keeper @@ -478,24 +527,31 @@ func New( // NOTE: Any module instantiated in the module manager that is later modified // must be passed by reference here. app.MM = module.NewManager( - auth.NewAppModule(appCodec, app.AccountKeeper, nil), + genutil.NewAppModule( + app.AccountKeeper, + app.ConsumerKeeper, + app.BaseApp.DeliverTx, + encodingConfig.TxConfig, + ), + auth.NewAppModule(appCodec, app.AccountKeeper, nil, app.GetSubspace(authtypes.ModuleName)), vesting.NewAppModule(app.AccountKeeper, app.BankKeeper), - bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper), - capability.NewAppModule(appCodec, *app.CapabilityKeeper), - crisis.NewAppModule(&app.CrisisKeeper, skipGenesisInvariants), + bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper, app.GetSubspace(banktypes.ModuleName)), + capability.NewAppModule(appCodec, *app.CapabilityKeeper, false), + crisis.NewAppModule(&app.CrisisKeeper, skipGenesisInvariants, app.GetSubspace(crisistypes.ModuleName)), feegrantmodule.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry), - ccvgov.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper, IsProposalWhitelisted), - mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper), - slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.ConsumerKeeper), - ccvdistr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, authtypes.FeeCollectorName), - ccvstaking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper), - upgrade.NewAppModule(app.UpgradeKeeper), + ccvgov.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper, IsProposalWhitelisted, app.GetSubspace(govtypes.ModuleName), IsModuleWhiteList), + mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper, nil, app.GetSubspace(minttypes.ModuleName)), + slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.ConsumerKeeper, app.GetSubspace(slashingtypes.ModuleName)), + ccvdistr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, *app.StakingKeeper, authtypes.FeeCollectorName, app.GetSubspace(distrtypes.ModuleName)), + ccvstaking.NewAppModule(appCodec, *app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(stakingtypes.ModuleName)), + upgrade.NewAppModule(&app.UpgradeKeeper), evidence.NewAppModule(app.EvidenceKeeper), params.NewAppModule(app.ParamsKeeper), authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), ibc.NewAppModule(app.IBCKeeper), transferModule, consumerModule, + consensus.NewAppModule(appCodec, app.ConsensusParamsKeeper), ) // During begin block slashing happens after distr.BeginBlocker so that @@ -521,6 +577,8 @@ func New( feegrant.ModuleName, paramstypes.ModuleName, vestingtypes.ModuleName, + genutiltypes.ModuleName, + consensusparamtypes.ModuleName, ibctransfertypes.ModuleName, ibchost.ModuleName, consumertypes.ModuleName, @@ -540,6 +598,8 @@ func New( feegrant.ModuleName, paramstypes.ModuleName, upgradetypes.ModuleName, + genutiltypes.ModuleName, + consensusparamtypes.ModuleName, vestingtypes.ModuleName, ibctransfertypes.ModuleName, ibchost.ModuleName, @@ -568,14 +628,14 @@ func New( paramstypes.ModuleName, upgradetypes.ModuleName, vestingtypes.ModuleName, + genutiltypes.ModuleName, + consensusparamtypes.ModuleName, ibchost.ModuleName, ibctransfertypes.ModuleName, consumertypes.ModuleName, ) app.MM.RegisterInvariants(&app.CrisisKeeper) - app.MM.RegisterRoutes(app.Router(), app.QueryRouter(), encodingConfig.Amino) - app.configurator = module.NewConfigurator(app.appCodec, app.MsgServiceRouter(), app.GRPCQueryRouter()) app.MM.RegisterServices(app.configurator) @@ -584,15 +644,15 @@ func New( // NOTE: this is not required apps that don't use the simulator for fuzz testing // transactions app.sm = module.NewSimulationManager( - auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts), - bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper), - capability.NewAppModule(appCodec, *app.CapabilityKeeper), + auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts, app.GetSubspace(authtypes.ModuleName)), + bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper, app.GetSubspace(banktypes.ModuleName)), + capability.NewAppModule(appCodec, *app.CapabilityKeeper, false), feegrantmodule.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry), - ccvgov.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper, IsProposalWhitelisted), - mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper), - ccvstaking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper), - ccvdistr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, authtypes.FeeCollectorName), - slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper), + ccvgov.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper, IsProposalWhitelisted, app.GetSubspace(govtypes.ModuleName), IsModuleWhiteList), + mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper, nil, app.GetSubspace(minttypes.ModuleName)), + ccvstaking.NewAppModule(appCodec, *app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(stakingtypes.ModuleName)), + ccvdistr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, *app.StakingKeeper, authtypes.FeeCollectorName, app.GetSubspace(distrtypes.ModuleName)), + slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, *app.StakingKeeper, app.GetSubspace(slashingtypes.ModuleName)), params.NewAppModule(app.ParamsKeeper), evidence.NewAppModule(app.EvidenceKeeper), ibc.NewAppModule(app.IBCKeeper), authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), @@ -637,8 +697,11 @@ func New( fromVM := make(map[string]uint64) - for moduleName, eachModule := range app.MM.Modules { - fromVM[moduleName] = eachModule.ConsensusVersion() + for moduleName := range app.MM.Modules { + m := app.MM.Modules[moduleName] + if module, ok := m.(module.HasConsensusVersion); ok { + fromVM[moduleName] = module.ConsensusVersion() + } } // For a new consumer chain, this code (together with the entire SetUpgradeHandler) is not needed at all, @@ -681,7 +744,7 @@ func New( // Chains may need to add a KV store to their application. The following code // is needed for standalone chains that're changing over to a consumer chain, with a consumer ccv module. // When a chain starts from height 0 (like for testing purposes in this repo), the following code is not needed. - storeUpgrades := store.StoreUpgrades{ + storeUpgrades := storetypes.StoreUpgrades{ Added: []string{consumertypes.ModuleName}, } @@ -699,6 +762,14 @@ func New( app.ScopedTransferKeeper = scopedTransferKeeper app.ScopedIBCConsumerKeeper = scopedIBCConsumerKeeper + autocliv1.RegisterQueryServer(app.GRPCQueryRouter(), runtimeservices.NewAutoCLIQueryService(app.MM.Modules)) + + reflectionSvc, err := runtimeservices.NewReflectionService() + if err != nil { + panic(err) + } + reflectionv1.RegisterReflectionServiceServer(app.GRPCQueryRouter(), reflectionSvc) + return app } @@ -765,21 +836,21 @@ func (app *App) InterfaceRegistry() types.InterfaceRegistry { // GetKey returns the KVStoreKey for the provided store key. // // NOTE: This is solely to be used for testing purposes. -func (app *App) GetKey(storeKey string) *sdk.KVStoreKey { +func (app *App) GetKey(storeKey string) *storetypes.KVStoreKey { return app.keys[storeKey] } // GetTKey returns the TransientStoreKey for the provided store key. // // NOTE: This is solely to be used for testing purposes. -func (app *App) GetTKey(storeKey string) *sdk.TransientStoreKey { +func (app *App) GetTKey(storeKey string) *storetypes.TransientStoreKey { return app.tkeys[storeKey] } // GetMemKey returns the MemStoreKey for the provided mem key. // // NOTE: This is solely used for testing purposes. -func (app *App) GetMemKey(storeKey string) *sdk.MemoryStoreKey { +func (app *App) GetMemKey(storeKey string) *storetypes.MemoryStoreKey { return app.memKeys[storeKey] } @@ -870,25 +941,29 @@ func (app *App) GetTxConfig() client.TxConfig { return MakeTestEncodingConfig().TxConfig } +// TxConfig returns SimApp's TxConfig +func (app *App) TxConfig() client.TxConfig { + return app.txConfig +} + // RegisterAPIRoutes registers all application module routes with the provided // API server. func (app *App) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig) { clientCtx := apiSvr.ClientCtx - rpc.RegisterRoutes(clientCtx, apiSvr.Router) - // Register legacy tx routes. - authrest.RegisterTxRoutes(clientCtx, apiSvr.Router) // Register new tx routes from grpc-gateway. authtx.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) // Register new tendermint queries routes from grpc-gateway. tmservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) - // Register legacy and grpc-gateway routes for all modules. - ModuleBasics.RegisterRESTRoutes(clientCtx, apiSvr.Router) + // Register node gRPC service for grpc-gateway. + nodeservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) + + // Register grpc-gateway routes for all modules. ModuleBasics.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) // register swagger API from root so that other applications can override easily - if apiConfig.Swagger { - RegisterSwaggerAPI(apiSvr.Router) + if err := server.RegisterSwaggerAPI(apiSvr.ClientCtx, apiSvr.Router, apiConfig.Swagger); err != nil { + panic(err) } } @@ -897,20 +972,13 @@ func (app *App) RegisterTxService(clientCtx client.Context) { authtx.RegisterTxService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.BaseApp.Simulate, app.interfaceRegistry) } -// RegisterTendermintService implements the Application.RegisterTendermintService method. -func (app *App) RegisterTendermintService(clientCtx client.Context) { - tmservice.RegisterTendermintService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.interfaceRegistry) +func (app *App) RegisterNodeService(clientCtx client.Context) { + nodeservice.RegisterNodeService(clientCtx, app.GRPCQueryRouter()) } -// RegisterSwaggerAPI registers swagger route with API Server -func RegisterSwaggerAPI(rtr *mux.Router) { - statikFS, err := fs.New() - if err != nil { - panic(err) - } - - staticServer := http.FileServer(statikFS) - rtr.PathPrefix("/swagger/").Handler(http.StripPrefix("/swagger/", staticServer)) +// RegisterTendermintService implements the Application.RegisterTendermintService method. +func (app *App) RegisterTendermintService(clientCtx client.Context) { + tmservice.RegisterTendermintService(clientCtx, app.BaseApp.GRPCQueryRouter(), app.interfaceRegistry, app.Query) } // GetMaccPerms returns a copy of the module account permissions @@ -923,16 +991,16 @@ func GetMaccPerms() map[string][]string { } // initParamsKeeper init params keeper and its subspaces -func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey sdk.StoreKey) paramskeeper.Keeper { +func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey storetypes.StoreKey) paramskeeper.Keeper { paramsKeeper := paramskeeper.NewKeeper(appCodec, legacyAmino, key, tkey) - paramsKeeper.Subspace(authtypes.ModuleName) + paramsKeeper.Subspace(authtypes.ModuleName).WithKeyTable(authtypes.ParamKeyTable()) //nolint:staticcheck // TODO: remove this temorary solution paramsKeeper.Subspace(banktypes.ModuleName) paramsKeeper.Subspace(stakingtypes.ModuleName) - paramsKeeper.Subspace(minttypes.ModuleName) + paramsKeeper.Subspace(minttypes.ModuleName).WithKeyTable(minttypes.ParamKeyTable()) //nolint:staticcheck // TODO: remove this temorary solution paramsKeeper.Subspace(distrtypes.ModuleName) paramsKeeper.Subspace(slashingtypes.ModuleName) - paramsKeeper.Subspace(govtypes.ModuleName).WithKeyTable(govtypes.ParamKeyTable()) + paramsKeeper.Subspace(govtypes.ModuleName).WithKeyTable(gov.ProvideKeyTable()) paramsKeeper.Subspace(crisistypes.ModuleName) paramsKeeper.Subspace(ibctransfertypes.ModuleName) paramsKeeper.Subspace(ibchost.ModuleName) @@ -953,3 +1021,12 @@ func MakeTestEncodingConfig() appparams.EncodingConfig { ModuleBasics.RegisterInterfaces(encodingConfig.InterfaceRegistry) return encodingConfig } + +func makeEncodingConfig() appparams.EncodingConfig { + encodingConfig := appparams.MakeTestEncodingConfig() + std.RegisterLegacyAminoCodec(encodingConfig.Amino) + std.RegisterInterfaces(encodingConfig.InterfaceRegistry) + ModuleBasics.RegisterLegacyAminoCodec(encodingConfig.Amino) + ModuleBasics.RegisterInterfaces(encodingConfig.InterfaceRegistry) + return encodingConfig +} diff --git a/app/consumer-democracy/export.go b/app/consumer-democracy/export.go index 36867df66a..6c511d6871 100644 --- a/app/consumer-democracy/export.go +++ b/app/consumer-democracy/export.go @@ -4,18 +4,18 @@ import ( "encoding/json" "fmt" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + tmtypes "github.com/cometbft/cometbft/types" servertypes "github.com/cosmos/cosmos-sdk/server/types" sdk "github.com/cosmos/cosmos-sdk/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" - tmtypes "github.com/tendermint/tendermint/types" ) // ExportAppStateAndValidators exports the state of the application for a genesis // file. func (app *App) ExportAppStateAndValidators( - forZeroHeight bool, jailAllowedAddrs []string, + forZeroHeight bool, jailAllowedAddrs, modulesToExport []string, ) (servertypes.ExportedApp, error) { // as if they could withdraw from the start of the next block ctx := app.NewContext(true, tmproto.Header{Height: app.LastBlockHeight()}) diff --git a/app/consumer-democracy/proposals_whitelisting.go b/app/consumer-democracy/proposals_whitelisting.go index 3f6f65b17f..ab9114343f 100644 --- a/app/consumer-democracy/proposals_whitelisting.go +++ b/app/consumer-democracy/proposals_whitelisting.go @@ -1,28 +1,24 @@ package app import ( - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" "github.com/cosmos/cosmos-sdk/x/params/types/proposal" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" ) -func IsProposalWhitelisted(content govtypes.Content) bool { +func IsProposalWhitelisted(content v1beta1.Content) bool { switch c := content.(type) { case *proposal.ParameterChangeProposal: - return isParamChangeWhitelisted(c.Changes) + return isLegacyParamChangeWhitelisted(c.Changes) default: return false } } -func isParamChangeWhitelisted(paramChanges []proposal.ParamChange) bool { +func isLegacyParamChangeWhitelisted(paramChanges []proposal.ParamChange) bool { for _, paramChange := range paramChanges { - _, found := WhitelistedParams[paramChangeKey{Subspace: paramChange.Subspace, Key: paramChange.Key}] + _, found := LegacyWhitelistedParams[legacyParamChangeKey{Subspace: paramChange.Subspace, Key: paramChange.Key}] if !found { return false } @@ -30,37 +26,26 @@ func isParamChangeWhitelisted(paramChanges []proposal.ParamChange) bool { return true } -type paramChangeKey struct { +type legacyParamChangeKey struct { Subspace, Key string } -var WhitelistedParams = map[paramChangeKey]struct{}{ - // bank - {Subspace: banktypes.ModuleName, Key: "SendEnabled"}: {}, - // governance - {Subspace: govtypes.ModuleName, Key: "depositparams"}: {}, // min_deposit, max_deposit_period - {Subspace: govtypes.ModuleName, Key: "votingparams"}: {}, // voting_period - {Subspace: govtypes.ModuleName, Key: "tallyparams"}: {}, // quorum,threshold,veto_threshold - // staking - {Subspace: stakingtypes.ModuleName, Key: "UnbondingTime"}: {}, - {Subspace: stakingtypes.ModuleName, Key: "MaxValidators"}: {}, - {Subspace: stakingtypes.ModuleName, Key: "MaxEntries"}: {}, - {Subspace: stakingtypes.ModuleName, Key: "HistoricalEntries"}: {}, - {Subspace: stakingtypes.ModuleName, Key: "BondDenom"}: {}, - // distribution - {Subspace: distrtypes.ModuleName, Key: "communitytax"}: {}, - {Subspace: distrtypes.ModuleName, Key: "baseproposerreward"}: {}, - {Subspace: distrtypes.ModuleName, Key: "bonusproposerreward"}: {}, - {Subspace: distrtypes.ModuleName, Key: "withdrawaddrenabled"}: {}, - // mint - {Subspace: minttypes.ModuleName, Key: "MintDenom"}: {}, - {Subspace: minttypes.ModuleName, Key: "InflationRateChange"}: {}, - {Subspace: minttypes.ModuleName, Key: "InflationMax"}: {}, - {Subspace: minttypes.ModuleName, Key: "InflationMin"}: {}, - {Subspace: minttypes.ModuleName, Key: "GoalBonded"}: {}, - {Subspace: minttypes.ModuleName, Key: "BlocksPerYear"}: {}, +var LegacyWhitelistedParams = map[legacyParamChangeKey]struct{}{ // ibc transfer {Subspace: ibctransfertypes.ModuleName, Key: "SendEnabled"}: {}, {Subspace: ibctransfertypes.ModuleName, Key: "ReceiveEnabled"}: {}, // add interchain account params(HostEnabled, AllowedMessages) once the module is added to the consumer app } + +var WhiteListModule = map[string]struct{}{ + "/cosmos.gov.v1.MsgUpdateParams": {}, + "/cosmos.bank.v1beta1.MsgUpdateParams": {}, + "/cosmos.staking.v1beta1.MsgUpdateParams": {}, + "/cosmos.distribution.v1beta1.MsgUpdateParams": {}, + "/cosmos.mint.v1beta1.MsgUpdateParams": {}, +} + +func IsModuleWhiteList(typeUrl string) bool { + _, found := WhiteListModule[typeUrl] + return found +} diff --git a/app/consumer-democracy/proposals_whitelisting_test.go b/app/consumer-democracy/proposals_whitelisting_test.go index ecc14be44d..3b8bbdb855 100644 --- a/app/consumer-democracy/proposals_whitelisting_test.go +++ b/app/consumer-democracy/proposals_whitelisting_test.go @@ -13,7 +13,7 @@ func TestDemocracyGovernanceWhitelistingKeys(t *testing.T) { chain := ibctesting.NewTestChain(t, ibctesting.NewCoordinator(t, 0), icstestingutils.DemocracyConsumerAppIniter, "test") paramKeeper := chain.App.(*appConsumer.App).ParamsKeeper - for paramKey := range appConsumer.WhitelistedParams { + for paramKey := range appConsumer.LegacyWhitelistedParams { ss, ok := paramKeeper.GetSubspace(paramKey.Subspace) require.True(t, ok, "Unknown subspace %s", paramKey.Subspace) hasKey := ss.Has(chain.GetContext(), []byte(paramKey.Key)) diff --git a/app/consumer/ante/disabled_modules_ante_test.go b/app/consumer/ante/disabled_modules_ante_test.go index a41605b5df..2eb95e1ddb 100644 --- a/app/consumer/ante/disabled_modules_ante_test.go +++ b/app/consumer/ante/disabled_modules_ante_test.go @@ -7,7 +7,7 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" - ibcclienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + ibcclienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" "github.com/cosmos/interchain-security/v2/app/consumer/ante" "github.com/cosmos/interchain-security/v2/app/params" "github.com/stretchr/testify/require" diff --git a/app/consumer/ante/msg_filter_ante_test.go b/app/consumer/ante/msg_filter_ante_test.go index a8771f399e..7ff11dc10f 100644 --- a/app/consumer/ante/msg_filter_ante_test.go +++ b/app/consumer/ante/msg_filter_ante_test.go @@ -5,7 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - ibcclienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + ibcclienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" "github.com/cosmos/interchain-security/v2/app/consumer/ante" "github.com/cosmos/interchain-security/v2/app/params" "github.com/stretchr/testify/require" diff --git a/app/consumer/ante_handler.go b/app/consumer/ante_handler.go index 12e0b3c5db..be33266f8d 100644 --- a/app/consumer/ante_handler.go +++ b/app/consumer/ante_handler.go @@ -5,8 +5,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth/ante" - ibcante "github.com/cosmos/ibc-go/v4/modules/core/ante" - ibckeeper "github.com/cosmos/ibc-go/v4/modules/core/keeper" + ibcante "github.com/cosmos/ibc-go/v7/modules/core/ante" + ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" + consumerante "github.com/cosmos/interchain-security/v2/app/consumer/ante" ibcconsumerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/consumer/keeper" ) @@ -38,22 +39,21 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { anteDecorators := []sdk.AnteDecorator{ ante.NewSetUpContextDecorator(), - ante.NewRejectExtensionOptionsDecorator(), + ante.NewExtensionOptionsDecorator(nil), consumerante.NewMsgFilterDecorator(options.ConsumerKeeper), consumerante.NewDisabledModulesDecorator("/cosmos.evidence", "/cosmos.slashing"), - ante.NewMempoolFeeDecorator(), ante.NewValidateBasicDecorator(), ante.NewTxTimeoutHeightDecorator(), ante.NewValidateMemoDecorator(options.AccountKeeper), ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), - ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper), + ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), // SetPubKeyDecorator must be called before all signature verification decorators ante.NewSetPubKeyDecorator(options.AccountKeeper), ante.NewValidateSigCountDecorator(options.AccountKeeper), ante.NewSigGasConsumeDecorator(options.AccountKeeper, sigGasConsumer), ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler), ante.NewIncrementSequenceDecorator(options.AccountKeeper), - ibcante.NewAnteDecorator(options.IBCKeeper), + ibcante.NewRedundantRelayDecorator(options.IBCKeeper), } return sdk.ChainAnteDecorators(anteDecorators...), nil diff --git a/app/consumer/app.go b/app/consumer/app.go index 343349b040..34c18bb249 100644 --- a/app/consumer/app.go +++ b/app/consumer/app.go @@ -4,28 +4,40 @@ import ( "fmt" "io" stdlog "log" - "net/http" "os" "path/filepath" + autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" + reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" + + dbm "github.com/cometbft/cometbft-db" + abci "github.com/cometbft/cometbft/abci/types" + tmjson "github.com/cometbft/cometbft/libs/json" + "github.com/cometbft/cometbft/libs/log" + tmos "github.com/cometbft/cometbft/libs/os" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + nodeservice "github.com/cosmos/cosmos-sdk/client/grpc/node" "github.com/cosmos/cosmos-sdk/client/grpc/tmservice" - "github.com/cosmos/cosmos-sdk/client/rpc" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/runtime" + runtimeservices "github.com/cosmos/cosmos-sdk/runtime/services" + "github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/server/api" "github.com/cosmos/cosmos-sdk/server/config" servertypes "github.com/cosmos/cosmos-sdk/server/types" - "github.com/cosmos/cosmos-sdk/simapp" "github.com/cosmos/cosmos-sdk/std" - store "github.com/cosmos/cosmos-sdk/store/types" + storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth/ante" - authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest" + "github.com/cosmos/cosmos-sdk/x/genutil" + genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation" authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" @@ -41,6 +53,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/capability" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + consensusparamkeeper "github.com/cosmos/cosmos-sdk/x/consensus/keeper" "github.com/cosmos/cosmos-sdk/x/crisis" crisiskeeper "github.com/cosmos/cosmos-sdk/x/crisis/keeper" crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types" @@ -50,6 +63,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/feegrant" feegrantkeeper "github.com/cosmos/cosmos-sdk/x/feegrant/keeper" feegrantmodule "github.com/cosmos/cosmos-sdk/x/feegrant/module" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/cosmos/cosmos-sdk/x/params" paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" @@ -59,26 +73,20 @@ import ( "github.com/cosmos/cosmos-sdk/x/upgrade" upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - "github.com/cosmos/ibc-go/v4/modules/apps/transfer" - ibctransferkeeper "github.com/cosmos/ibc-go/v4/modules/apps/transfer/keeper" - ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" - ibc "github.com/cosmos/ibc-go/v4/modules/core" - ibcconnectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" - porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" - ibchost "github.com/cosmos/ibc-go/v4/modules/core/24-host" - ibckeeper "github.com/cosmos/ibc-go/v4/modules/core/keeper" + "github.com/cosmos/ibc-go/v7/modules/apps/transfer" + ibctransferkeeper "github.com/cosmos/ibc-go/v7/modules/apps/transfer/keeper" + ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + ibc "github.com/cosmos/ibc-go/v7/modules/core" + ibcconnectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" + porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" + ibchost "github.com/cosmos/ibc-go/v7/modules/core/exported" + ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" appparams "github.com/cosmos/interchain-security/v2/app/params" ibctestingcore "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/core" ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" - "github.com/gorilla/mux" - "github.com/rakyll/statik/fs" "github.com/spf13/cast" - abci "github.com/tendermint/tendermint/abci/types" - tmjson "github.com/tendermint/tendermint/libs/json" - "github.com/tendermint/tendermint/libs/log" - tmos "github.com/tendermint/tendermint/libs/os" - dbm "github.com/tendermint/tm-db" + tendermint "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" ibcconsumer "github.com/cosmos/interchain-security/v2/x/ccv/consumer" ibcconsumerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/consumer/keeper" ibcconsumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" @@ -103,6 +111,7 @@ var ( // and genesis verification. ModuleBasics = module.NewBasicManager( auth.AppModuleBasic{}, + genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator), bank.AppModuleBasic{}, capability.AppModuleBasic{}, params.AppModuleBasic{}, @@ -115,6 +124,7 @@ var ( evidence.AppModuleBasic{}, transfer.AppModuleBasic{}, vesting.AppModuleBasic{}, + tendermint.AppModuleBasic{}, // router.AppModuleBasic{}, ibcconsumer.AppModuleBasic{}, ) @@ -129,7 +139,7 @@ var ( ) var ( - _ simapp.App = (*App)(nil) + _ runtime.AppI = (*App)(nil) _ servertypes.Application = (*App)(nil) _ ibctesting.TestingApp = (*App)(nil) ) @@ -141,14 +151,13 @@ type App struct { // nolint: golint *baseapp.BaseApp legacyAmino *codec.LegacyAmino appCodec codec.Codec + txConfig client.TxConfig interfaceRegistry types.InterfaceRegistry - invCheckPeriod uint - // keys to access the substores - keys map[string]*sdk.KVStoreKey - tkeys map[string]*sdk.TransientStoreKey - memKeys map[string]*sdk.MemoryStoreKey + keys map[string]*storetypes.KVStoreKey + tkeys map[string]*storetypes.TransientStoreKey + memKeys map[string]*storetypes.MemoryStoreKey // keepers AccountKeeper authkeeper.AccountKeeper @@ -160,15 +169,16 @@ type App struct { // nolint: golint // from consumer chain or set to use an independent // different fee-pool from the consumer chain ConsumerKeeper - CrisisKeeper crisiskeeper.Keeper - UpgradeKeeper upgradekeeper.Keeper - ParamsKeeper paramskeeper.Keeper - IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly - EvidenceKeeper evidencekeeper.Keeper - TransferKeeper ibctransferkeeper.Keeper - FeeGrantKeeper feegrantkeeper.Keeper - AuthzKeeper authzkeeper.Keeper - ConsumerKeeper ibcconsumerkeeper.Keeper + CrisisKeeper crisiskeeper.Keeper + UpgradeKeeper upgradekeeper.Keeper + ParamsKeeper paramskeeper.Keeper + IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly + EvidenceKeeper evidencekeeper.Keeper + TransferKeeper ibctransferkeeper.Keeper + FeeGrantKeeper feegrantkeeper.Keeper + AuthzKeeper authzkeeper.Keeper + ConsumerKeeper ibcconsumerkeeper.Keeper + ConsensusParamsKeeper consensusparamkeeper.Keeper // make scoped keepers public for test purposes ScopedIBCKeeper capabilitykeeper.ScopedKeeper @@ -198,16 +208,15 @@ func New( db dbm.DB, traceStore io.Writer, loadLatest bool, - skipUpgradeHeights map[int64]bool, - homePath string, - invCheckPeriod uint, - encodingConfig appparams.EncodingConfig, appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp), ) *App { - appCodec := encodingConfig.Marshaler + encodingConfig := makeEncodingConfig() + + appCodec := encodingConfig.Codec legacyAmino := encodingConfig.Amino interfaceRegistry := encodingConfig.InterfaceRegistry + txConfig := encodingConfig.TxConfig bApp := baseapp.NewBaseApp(AppName, logger, db, encodingConfig.TxConfig.TxDecoder(), baseAppOptions...) bApp.SetCommitMultiStoreTracer(traceStore) @@ -215,7 +224,7 @@ func New( bApp.SetInterfaceRegistry(interfaceRegistry) keys := sdk.NewKVStoreKeys( - authtypes.StoreKey, banktypes.StoreKey, slashingtypes.StoreKey, + authtypes.StoreKey, banktypes.StoreKey, slashingtypes.StoreKey, crisistypes.StoreKey, paramstypes.StoreKey, ibchost.StoreKey, upgradetypes.StoreKey, evidencetypes.StoreKey, ibctransfertypes.StoreKey, capabilitytypes.StoreKey, feegrant.StoreKey, authzkeeper.StoreKey, @@ -228,8 +237,8 @@ func New( BaseApp: bApp, legacyAmino: legacyAmino, appCodec: appCodec, + txConfig: txConfig, interfaceRegistry: interfaceRegistry, - invCheckPeriod: invCheckPeriod, keys: keys, tkeys: tkeys, memKeys: memKeys, @@ -243,10 +252,8 @@ func New( ) // set the BaseApp's parameter store - bApp.SetParamStore( - app.ParamsKeeper.Subspace(baseapp.Paramspace).WithKeyTable( - paramskeeper.ConsensusParamsKeyTable()), - ) + app.ConsensusParamsKeeper = consensusparamkeeper.NewKeeper(appCodec, keys[upgradetypes.StoreKey], authtypes.NewModuleAddress(govtypes.ModuleName).String()) + bApp.SetParamStore(&app.ConsensusParamsKeeper) // add capability keeper and ScopeToModule for ibc module app.CapabilityKeeper = capabilitykeeper.NewKeeper( @@ -263,9 +270,10 @@ func New( app.AccountKeeper = authkeeper.NewAccountKeeper( appCodec, keys[authtypes.StoreKey], - app.GetSubspace(authtypes.ModuleName), authtypes.ProtoBaseAccount, maccPerms, + AccountAddressPrefix, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) // Remove the fee-pool from the group of blocked recipient addresses in bank @@ -279,13 +287,14 @@ func New( appCodec, keys[banktypes.StoreKey], app.AccountKeeper, - app.GetSubspace(banktypes.ModuleName), bankBlockedAddrs, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) app.AuthzKeeper = authzkeeper.NewKeeper( keys[authzkeeper.StoreKey], appCodec, app.BaseApp.MsgServiceRouter(), + app.AccountKeeper, ) app.FeeGrantKeeper = feegrantkeeper.NewKeeper( appCodec, @@ -297,33 +306,58 @@ func New( // of the slashing module app.SlashingKeeper = slashingkeeper.NewKeeper( appCodec, + legacyAmino, keys[slashingtypes.StoreKey], &app.ConsumerKeeper, - app.GetSubspace(slashingtypes.ModuleName), + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) - app.CrisisKeeper = crisiskeeper.NewKeeper( - app.GetSubspace(crisistypes.ModuleName), + + invCheckPeriod := cast.ToUint(appOpts.Get(server.FlagInvCheckPeriod)) + app.CrisisKeeper = *crisiskeeper.NewKeeper( + appCodec, + keys[crisistypes.StoreKey], invCheckPeriod, app.BankKeeper, authtypes.FeeCollectorName, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) - app.UpgradeKeeper = upgradekeeper.NewKeeper( + + // get skipUpgradeHeights from the app options + skipUpgradeHeights := map[int64]bool{} + for _, h := range cast.ToIntSlice(appOpts.Get(server.FlagUnsafeSkipUpgrades)) { + skipUpgradeHeights[int64(h)] = true + } + homePath := cast.ToString(appOpts.Get(flags.FlagHome)) + // set the governance module account as the authority for conducting upgrades + app.UpgradeKeeper = *upgradekeeper.NewKeeper( skipUpgradeHeights, keys[upgradetypes.StoreKey], appCodec, homePath, app.BaseApp, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + ) + + // pre-initialize ConsumerKeeper to satsfy ibckeeper.NewKeeper + // which would panic on nil or zero keeper + // ConsumerKeeper implements StakingKeeper but all function calls result in no-ops so this is safe + // communication over IBC is not affected by these changes + app.ConsumerKeeper = ibcconsumerkeeper.NewNonZeroKeeper( + appCodec, + keys[ibcconsumertypes.StoreKey], + app.GetSubspace(ibcconsumertypes.ModuleName), ) + app.IBCKeeper = ibckeeper.NewKeeper( appCodec, keys[ibchost.StoreKey], app.GetSubspace(ibchost.ModuleName), - &app.ConsumerKeeper, + app.ConsumerKeeper, app.UpgradeKeeper, scopedIBCKeeper, ) - // Create CCV consumer and modules + // initialize the actual consumer keeper app.ConsumerKeeper = ibcconsumerkeeper.NewKeeper( appCodec, keys[ibcconsumertypes.StoreKey], @@ -380,13 +414,19 @@ func New( // NOTE: Any module instantiated in the module manager that is later modified // must be passed by reference here. app.MM = module.NewManager( - auth.NewAppModule(appCodec, app.AccountKeeper, nil), + genutil.NewAppModule( + app.AccountKeeper, + app.ConsumerKeeper, + app.BaseApp.DeliverTx, + encodingConfig.TxConfig, + ), + auth.NewAppModule(appCodec, app.AccountKeeper, nil, app.GetSubspace(authtypes.ModuleName)), vesting.NewAppModule(app.AccountKeeper, app.BankKeeper), - bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper), - capability.NewAppModule(appCodec, *app.CapabilityKeeper), - crisis.NewAppModule(&app.CrisisKeeper, skipGenesisInvariants), - slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.ConsumerKeeper), - upgrade.NewAppModule(app.UpgradeKeeper), + bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper, app.GetSubspace(banktypes.ModuleName)), + capability.NewAppModule(appCodec, *app.CapabilityKeeper, false), + crisis.NewAppModule(&app.CrisisKeeper, skipGenesisInvariants, app.GetSubspace(crisistypes.ModuleName)), + slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.ConsumerKeeper, app.GetSubspace(slashingtypes.ModuleName)), + upgrade.NewAppModule(&app.UpgradeKeeper), evidence.NewAppModule(app.EvidenceKeeper), feegrantmodule.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry), authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), @@ -411,6 +451,7 @@ func New( authtypes.ModuleName, banktypes.ModuleName, slashingtypes.ModuleName, + genutiltypes.ModuleName, evidencetypes.ModuleName, authz.ModuleName, feegrant.ModuleName, @@ -428,6 +469,7 @@ func New( authtypes.ModuleName, banktypes.ModuleName, slashingtypes.ModuleName, + genutiltypes.ModuleName, evidencetypes.ModuleName, paramstypes.ModuleName, upgradetypes.ModuleName, @@ -453,7 +495,7 @@ func New( ibctransfertypes.ModuleName, feegrant.ModuleName, authz.ModuleName, - + genutiltypes.ModuleName, paramstypes.ModuleName, upgradetypes.ModuleName, vestingtypes.ModuleName, @@ -461,8 +503,6 @@ func New( ) app.MM.RegisterInvariants(&app.CrisisKeeper) - app.MM.RegisterRoutes(app.Router(), app.QueryRouter(), encodingConfig.Amino) - app.configurator = module.NewConfigurator(app.appCodec, app.MsgServiceRouter(), app.GRPCQueryRouter()) app.MM.RegisterServices(app.configurator) @@ -471,9 +511,9 @@ func New( // NOTE: this is not required apps that don't use the simulator for fuzz testing // transactions app.sm = module.NewSimulationManager( - auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts), - bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper), - capability.NewAppModule(appCodec, *app.CapabilityKeeper), + auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts, app.GetSubspace(authtypes.ModuleName)), + bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper, app.GetSubspace(banktypes.ModuleName)), + capability.NewAppModule(appCodec, *app.CapabilityKeeper, false), feegrantmodule.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry), authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), params.NewAppModule(app.ParamsKeeper), @@ -519,8 +559,11 @@ func New( fromVM := make(map[string]uint64) - for moduleName, eachModule := range app.MM.Modules { - fromVM[moduleName] = eachModule.ConsensusVersion() + for moduleName := range app.MM.Modules { + m := app.MM.Modules[moduleName] + if module, ok := m.(module.HasConsensusVersion); ok { + fromVM[moduleName] = module.ConsensusVersion() + } } ctx.Logger().Info("start to run module migrations...") @@ -535,7 +578,7 @@ func New( } if upgradeInfo.Name == upgradeName && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { - storeUpgrades := store.StoreUpgrades{} + storeUpgrades := storetypes.StoreUpgrades{} // configure store loader that checks if version == upgradeHeight and applies store upgrades app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades)) @@ -551,6 +594,14 @@ func New( app.ScopedTransferKeeper = scopedTransferKeeper app.ScopedIBCConsumerKeeper = scopedIBCConsumerKeeper + autocliv1.RegisterQueryServer(app.GRPCQueryRouter(), runtimeservices.NewAutoCLIQueryService(app.MM.Modules)) + + reflectionSvc, err := runtimeservices.NewReflectionService() + if err != nil { + panic(err) + } + reflectionv1.RegisterReflectionServiceServer(app.GRPCQueryRouter(), reflectionSvc) + return app } @@ -617,21 +668,21 @@ func (app *App) InterfaceRegistry() types.InterfaceRegistry { // GetKey returns the KVStoreKey for the provided store key. // // NOTE: This is solely to be used for testing purposes. -func (app *App) GetKey(storeKey string) *sdk.KVStoreKey { +func (app *App) GetKey(storeKey string) *storetypes.KVStoreKey { return app.keys[storeKey] } // GetTKey returns the TransientStoreKey for the provided store key. // // NOTE: This is solely to be used for testing purposes. -func (app *App) GetTKey(storeKey string) *sdk.TransientStoreKey { +func (app *App) GetTKey(storeKey string) *storetypes.TransientStoreKey { return app.tkeys[storeKey] } // GetMemKey returns the MemStoreKey for the provided mem key. // // NOTE: This is solely used for testing purposes. -func (app *App) GetMemKey(storeKey string) *sdk.MemoryStoreKey { +func (app *App) GetMemKey(storeKey string) *storetypes.MemoryStoreKey { return app.memKeys[storeKey] } @@ -699,29 +750,26 @@ func (app *App) GetScopedIBCKeeper() capabilitykeeper.ScopedKeeper { // GetTxConfig implements the TestingApp interface. func (app *App) GetTxConfig() client.TxConfig { - return MakeTestEncodingConfig().TxConfig + return app.txConfig +} + +// TxConfig returns SimApp's TxConfig +func (app *App) TxConfig() client.TxConfig { + return app.txConfig } // RegisterAPIRoutes registers all application module routes with the provided // API server. func (app *App) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig) { clientCtx := apiSvr.ClientCtx - rpc.RegisterRoutes(clientCtx, apiSvr.Router) - // Register legacy tx routes. - authrest.RegisterTxRoutes(clientCtx, apiSvr.Router) + // Register new tx routes from grpc-gateway. authtx.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) // Register new tendermint queries routes from grpc-gateway. tmservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) - // Register legacy and grpc-gateway routes for all modules. - ModuleBasics.RegisterRESTRoutes(clientCtx, apiSvr.Router) + // Register grpc query routes. ModuleBasics.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) - - // register swagger API from root so that other applications can override easily - if apiConfig.Swagger { - RegisterSwaggerAPI(apiSvr.Router) - } } // RegisterTxService implements the Application.RegisterTxService method. @@ -729,20 +777,13 @@ func (app *App) RegisterTxService(clientCtx client.Context) { authtx.RegisterTxService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.BaseApp.Simulate, app.interfaceRegistry) } -// RegisterTendermintService implements the Application.RegisterTendermintService method. -func (app *App) RegisterTendermintService(clientCtx client.Context) { - tmservice.RegisterTendermintService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.interfaceRegistry) +func (app *App) RegisterNodeService(clientCtx client.Context) { + nodeservice.RegisterNodeService(clientCtx, app.GRPCQueryRouter()) } -// RegisterSwaggerAPI registers swagger route with API Server -func RegisterSwaggerAPI(rtr *mux.Router) { - statikFS, err := fs.New() - if err != nil { - panic(err) - } - - staticServer := http.FileServer(statikFS) - rtr.PathPrefix("/swagger/").Handler(http.StripPrefix("/swagger/", staticServer)) +// RegisterTendermintService implements the Application.RegisterTendermintService method. +func (app *App) RegisterTendermintService(clientCtx client.Context) { + tmservice.RegisterTendermintService(clientCtx, app.BaseApp.GRPCQueryRouter(), app.interfaceRegistry, app.Query) } // GetMaccPerms returns a copy of the module account permissions @@ -755,7 +796,7 @@ func GetMaccPerms() map[string][]string { } // initParamsKeeper init params keeper and its subspaces -func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey sdk.StoreKey) paramskeeper.Keeper { +func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey storetypes.StoreKey) paramskeeper.Keeper { paramsKeeper := paramskeeper.NewKeeper(appCodec, legacyAmino, key, tkey) paramsKeeper.Subspace(authtypes.ModuleName) @@ -773,6 +814,24 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino // should be used only in tests or when creating a new app instance (NewApp*()). // App user shouldn't create new codecs - use the app.AppCodec instead. // [DEPRECATED] +// func MakeTestEncodingConfig() appparams.EncodingConfig { +// encodingConfig := appparams.MakeTestEncodingConfig() +// std.RegisterLegacyAminoCodec(encodingConfig.Amino) +// std.RegisterInterfaces(encodingConfig.InterfaceRegistry) +// ModuleBasics.RegisterLegacyAminoCodec(encodingConfig.Amino) +// ModuleBasics.RegisterInterfaces(encodingConfig.InterfaceRegistry) +// return encodingConfig +// } + +// func makeEncodingConfig() simappparams.EncodingConfig { +// encodingConfig := simappparams.MakeTestEncodingConfig() +// std.RegisterLegacyAminoCodec(encodingConfig.Amino) +// std.RegisterInterfaces(encodingConfig.InterfaceRegistry) +// ModuleBasics.RegisterLegacyAminoCodec(encodingConfig.Amino) +// ModuleBasics.RegisterInterfaces(encodingConfig.InterfaceRegistry) +// return encodingConfig +// } + func MakeTestEncodingConfig() appparams.EncodingConfig { encodingConfig := appparams.MakeTestEncodingConfig() std.RegisterLegacyAminoCodec(encodingConfig.Amino) @@ -781,3 +840,12 @@ func MakeTestEncodingConfig() appparams.EncodingConfig { ModuleBasics.RegisterInterfaces(encodingConfig.InterfaceRegistry) return encodingConfig } + +func makeEncodingConfig() appparams.EncodingConfig { + encodingConfig := appparams.MakeTestEncodingConfig() + std.RegisterLegacyAminoCodec(encodingConfig.Amino) + std.RegisterInterfaces(encodingConfig.InterfaceRegistry) + ModuleBasics.RegisterLegacyAminoCodec(encodingConfig.Amino) + ModuleBasics.RegisterInterfaces(encodingConfig.InterfaceRegistry) + return encodingConfig +} diff --git a/app/consumer/export.go b/app/consumer/export.go index e0397dc61e..168e5385a1 100644 --- a/app/consumer/export.go +++ b/app/consumer/export.go @@ -4,18 +4,18 @@ import ( "encoding/json" "fmt" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + tmtypes "github.com/cometbft/cometbft/types" servertypes "github.com/cosmos/cosmos-sdk/server/types" sdk "github.com/cosmos/cosmos-sdk/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" - tmtypes "github.com/tendermint/tendermint/types" ) // ExportAppStateAndValidators implements the simapp app interface // by exporting the state of the application func (app *App) ExportAppStateAndValidators( - forZeroHeight bool, jailAllowedAddrs []string, + forZeroHeight bool, jailAllowedAddrs, modulesToExport []string, ) (servertypes.ExportedApp, error) { // as if they could withdraw from the start of the next block ctx := app.NewContext(true, tmproto.Header{Height: app.LastBlockHeight()}) diff --git a/app/params/encoding.go b/app/params/encoding.go index 3d634abf16..8ff9ea04b3 100644 --- a/app/params/encoding.go +++ b/app/params/encoding.go @@ -10,7 +10,7 @@ import ( // This is provided for compatibility between protobuf and amino implementations. type EncodingConfig struct { InterfaceRegistry types.InterfaceRegistry - Marshaler codec.Codec + Codec codec.Codec TxConfig client.TxConfig Amino *codec.LegacyAmino } diff --git a/app/params/proto.go b/app/params/proto.go index 5c5f3c3d4c..d11fe8d06c 100644 --- a/app/params/proto.go +++ b/app/params/proto.go @@ -15,7 +15,7 @@ func MakeTestEncodingConfig() EncodingConfig { return EncodingConfig{ InterfaceRegistry: interfaceRegistry, - Marshaler: chainCodec, + Codec: chainCodec, TxConfig: txCfg, Amino: amino, } diff --git a/app/provider/ante_handler.go b/app/provider/ante_handler.go index 3b1a3b7d38..0a71573b07 100644 --- a/app/provider/ante_handler.go +++ b/app/provider/ante_handler.go @@ -5,8 +5,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth/ante" - ibcante "github.com/cosmos/ibc-go/v4/modules/core/ante" - ibckeeper "github.com/cosmos/ibc-go/v4/modules/core/keeper" + ibcante "github.com/cosmos/ibc-go/v7/modules/core/ante" + ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" ) // HandlerOptions extend the SDK's AnteHandler options by requiring the IBC @@ -35,20 +35,19 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { anteDecorators := []sdk.AnteDecorator{ ante.NewSetUpContextDecorator(), - ante.NewRejectExtensionOptionsDecorator(), - ante.NewMempoolFeeDecorator(), + ante.NewExtensionOptionsDecorator(nil), ante.NewValidateBasicDecorator(), ante.NewTxTimeoutHeightDecorator(), ante.NewValidateMemoDecorator(options.AccountKeeper), ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), - ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper), + ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), // SetPubKeyDecorator must be called before all signature verification decorators ante.NewSetPubKeyDecorator(options.AccountKeeper), ante.NewValidateSigCountDecorator(options.AccountKeeper), ante.NewSigGasConsumeDecorator(options.AccountKeeper, sigGasConsumer), ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler), ante.NewIncrementSequenceDecorator(options.AccountKeeper), - ibcante.NewAnteDecorator(options.IBCKeeper), + ibcante.NewRedundantRelayDecorator(options.IBCKeeper), } return sdk.ChainAnteDecorators(anteDecorators...), nil diff --git a/app/provider/app.go b/app/provider/app.go index 94719cf2c6..1c73131b63 100644 --- a/app/provider/app.go +++ b/app/provider/app.go @@ -4,30 +4,35 @@ import ( "fmt" "io" stdlog "log" - "net/http" "os" "path/filepath" + "github.com/cosmos/cosmos-sdk/client/flags" + nodeservice "github.com/cosmos/cosmos-sdk/client/grpc/node" + "github.com/cosmos/cosmos-sdk/runtime" + "github.com/cosmos/cosmos-sdk/server" + + autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" + reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" appparams "github.com/cosmos/interchain-security/v2/app/params" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/grpc/tmservice" - "github.com/cosmos/cosmos-sdk/client/rpc" "github.com/cosmos/cosmos-sdk/codec" + runtimeservices "github.com/cosmos/cosmos-sdk/runtime/services" + "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/server/api" "github.com/cosmos/cosmos-sdk/server/config" servertypes "github.com/cosmos/cosmos-sdk/server/types" - "github.com/cosmos/cosmos-sdk/simapp" "github.com/cosmos/cosmos-sdk/std" - store "github.com/cosmos/cosmos-sdk/store/types" + storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth/ante" - authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest" authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation" authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" @@ -40,11 +45,11 @@ import ( "github.com/cosmos/cosmos-sdk/x/capability" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + consensusparamkeeper "github.com/cosmos/cosmos-sdk/x/consensus/keeper" "github.com/cosmos/cosmos-sdk/x/crisis" crisiskeeper "github.com/cosmos/cosmos-sdk/x/crisis/keeper" crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types" distr "github.com/cosmos/cosmos-sdk/x/distribution" - distrclient "github.com/cosmos/cosmos-sdk/x/distribution/client" distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" "github.com/cosmos/cosmos-sdk/x/evidence" @@ -53,8 +58,10 @@ import ( "github.com/cosmos/cosmos-sdk/x/genutil" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" "github.com/cosmos/cosmos-sdk/x/gov" + govclient "github.com/cosmos/cosmos-sdk/x/gov/client" 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" "github.com/cosmos/cosmos-sdk/x/mint" mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" @@ -73,28 +80,28 @@ import ( upgradeclient "github.com/cosmos/cosmos-sdk/x/upgrade/client" upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - "github.com/cosmos/ibc-go/v4/modules/apps/transfer" - ibctransferkeeper "github.com/cosmos/ibc-go/v4/modules/apps/transfer/keeper" - ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" - ibc "github.com/cosmos/ibc-go/v4/modules/core" - ibcclient "github.com/cosmos/ibc-go/v4/modules/core/02-client" - ibcclientclient "github.com/cosmos/ibc-go/v4/modules/core/02-client/client" - ibcclienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - ibcconnectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" - porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" - ibchost "github.com/cosmos/ibc-go/v4/modules/core/24-host" - ibckeeper "github.com/cosmos/ibc-go/v4/modules/core/keeper" + "github.com/cosmos/ibc-go/v7/modules/apps/transfer" + ibctransferkeeper "github.com/cosmos/ibc-go/v7/modules/apps/transfer/keeper" + ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + ibc "github.com/cosmos/ibc-go/v7/modules/core" + ibcclient "github.com/cosmos/ibc-go/v7/modules/core/02-client" + ibcclientclient "github.com/cosmos/ibc-go/v7/modules/core/02-client/client" + ibcclienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + ibcconnectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" + porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" + ibchost "github.com/cosmos/ibc-go/v7/modules/core/exported" + ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" + tendermint "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + ibctestingcore "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/core" ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" - "github.com/gorilla/mux" - "github.com/rakyll/statik/fs" + dbm "github.com/cometbft/cometbft-db" + abci "github.com/cometbft/cometbft/abci/types" + tmjson "github.com/cometbft/cometbft/libs/json" + "github.com/cometbft/cometbft/libs/log" + tmos "github.com/cometbft/cometbft/libs/os" "github.com/spf13/cast" - abci "github.com/tendermint/tendermint/abci/types" - tmjson "github.com/tendermint/tendermint/libs/json" - "github.com/tendermint/tendermint/libs/log" - tmos "github.com/tendermint/tendermint/libs/os" - dbm "github.com/tendermint/tm-db" ibcprovider "github.com/cosmos/interchain-security/v2/x/ccv/provider" ibcproviderclient "github.com/cosmos/interchain-security/v2/x/ccv/provider/client" @@ -124,22 +131,23 @@ var ( // and genesis verification. ModuleBasics = module.NewBasicManager( auth.AppModuleBasic{}, - genutil.AppModuleBasic{}, + genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator), bank.AppModuleBasic{}, capability.AppModuleBasic{}, staking.AppModuleBasic{}, mint.AppModuleBasic{}, distr.AppModuleBasic{}, gov.NewAppModuleBasic( - paramsclient.ProposalHandler, - distrclient.ProposalHandler, - upgradeclient.ProposalHandler, - upgradeclient.CancelProposalHandler, - ibcclientclient.UpdateClientProposalHandler, - ibcclientclient.UpgradeProposalHandler, - ibcproviderclient.ConsumerAdditionProposalHandler, - ibcproviderclient.ConsumerRemovalProposalHandler, - ibcproviderclient.EquivocationProposalHandler, + []govclient.ProposalHandler{ + paramsclient.ProposalHandler, + upgradeclient.LegacyProposalHandler, + upgradeclient.LegacyCancelProposalHandler, + ibcclientclient.UpdateClientProposalHandler, + ibcclientclient.UpgradeProposalHandler, + ibcproviderclient.ConsumerAdditionProposalHandler, + ibcproviderclient.ConsumerRemovalProposalHandler, + ibcproviderclient.EquivocationProposalHandler, + }, ), params.AppModuleBasic{}, crisis.AppModuleBasic{}, @@ -149,6 +157,7 @@ var ( evidence.AppModuleBasic{}, transfer.AppModuleBasic{}, vesting.AppModuleBasic{}, + tendermint.AppModuleBasic{}, // router.AppModuleBasic{}, ibcprovider.AppModuleBasic{}, ) @@ -167,7 +176,7 @@ var ( ) var ( - _ simapp.App = (*App)(nil) + _ runtime.AppI = (*App)(nil) _ servertypes.Application = (*App)(nil) _ ibctesting.TestingApp = (*App)(nil) ) @@ -180,19 +189,18 @@ type App struct { // nolint: golint legacyAmino *codec.LegacyAmino appCodec codec.Codec interfaceRegistry types.InterfaceRegistry - - invCheckPeriod uint + txConfig client.TxConfig // keys to access the substores - keys map[string]*sdk.KVStoreKey - tkeys map[string]*sdk.TransientStoreKey - memKeys map[string]*sdk.MemoryStoreKey + keys map[string]*storetypes.KVStoreKey + tkeys map[string]*storetypes.TransientStoreKey + memKeys map[string]*storetypes.MemoryStoreKey // keepers AccountKeeper authkeeper.AccountKeeper BankKeeper bankkeeper.Keeper CapabilityKeeper *capabilitykeeper.Keeper - StakingKeeper stakingkeeper.Keeper + StakingKeeper *stakingkeeper.Keeper SlashingKeeper slashingkeeper.Keeper MintKeeper mintkeeper.Keeper @@ -201,14 +209,15 @@ type App struct { // nolint: golint // different fee-pool from the consumer chain ConsumerKeeper DistrKeeper distrkeeper.Keeper - GovKeeper govkeeper.Keeper - CrisisKeeper crisiskeeper.Keeper - UpgradeKeeper upgradekeeper.Keeper - ParamsKeeper paramskeeper.Keeper - IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly - EvidenceKeeper evidencekeeper.Keeper - TransferKeeper ibctransferkeeper.Keeper - ProviderKeeper ibcproviderkeeper.Keeper + GovKeeper govkeeper.Keeper + CrisisKeeper crisiskeeper.Keeper + UpgradeKeeper upgradekeeper.Keeper + ParamsKeeper paramskeeper.Keeper + IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly + EvidenceKeeper evidencekeeper.Keeper + TransferKeeper ibctransferkeeper.Keeper + ProviderKeeper ibcproviderkeeper.Keeper + ConsensusParamsKeeper consensusparamkeeper.Keeper // make scoped keepers public for test purposes ScopedIBCKeeper capabilitykeeper.ScopedKeeper @@ -238,14 +247,12 @@ func New( db dbm.DB, traceStore io.Writer, loadLatest bool, - skipUpgradeHeights map[int64]bool, - homePath string, - invCheckPeriod uint, - encodingConfig appparams.EncodingConfig, appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp), ) *App { - appCodec := encodingConfig.Marshaler + encodingConfig := makeEncodingConfig() + + appCodec := encodingConfig.Codec legacyAmino := encodingConfig.Amino interfaceRegistry := encodingConfig.InterfaceRegistry @@ -255,7 +262,7 @@ func New( bApp.SetInterfaceRegistry(interfaceRegistry) keys := sdk.NewKVStoreKeys( - authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, + authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, crisistypes.StoreKey, minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey, govtypes.StoreKey, paramstypes.StoreKey, ibchost.StoreKey, upgradetypes.StoreKey, evidencetypes.StoreKey, ibctransfertypes.StoreKey, @@ -270,10 +277,10 @@ func New( legacyAmino: legacyAmino, appCodec: appCodec, interfaceRegistry: interfaceRegistry, - invCheckPeriod: invCheckPeriod, keys: keys, tkeys: tkeys, memKeys: memKeys, + txConfig: encodingConfig.TxConfig, } app.ParamsKeeper = initParamsKeeper( @@ -284,10 +291,9 @@ func New( ) // set the BaseApp's parameter store - bApp.SetParamStore( - app.ParamsKeeper.Subspace(baseapp.Paramspace).WithKeyTable( - paramskeeper.ConsensusParamsKeyTable()), - ) + // upgradetypes.StoreKey -> maybe consensusparamtypes.StoreKey (package consensusparamtypes ("github.com/cosmos/cosmos-sdk/x/consensus/types") + app.ConsensusParamsKeeper = consensusparamkeeper.NewKeeper(appCodec, keys[upgradetypes.StoreKey], authtypes.NewModuleAddress(govtypes.ModuleName).String()) + bApp.SetParamStore(&app.ConsensusParamsKeeper) // add capability keeper and ScopeToModule for ibc module app.CapabilityKeeper = capabilitykeeper.NewKeeper( @@ -304,9 +310,10 @@ func New( app.AccountKeeper = authkeeper.NewAccountKeeper( appCodec, keys[authtypes.StoreKey], - app.GetSubspace(authtypes.ModuleName), authtypes.ProtoBaseAccount, maccPerms, + AccountAddressPrefix, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) // Remove the ConsumerRewardsPool from the group of blocked recipient addresses in bank @@ -320,59 +327,72 @@ func New( appCodec, keys[banktypes.StoreKey], app.AccountKeeper, - app.GetSubspace(banktypes.ModuleName), bankBlockedAddrs, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) - stakingKeeper := stakingkeeper.NewKeeper( + app.StakingKeeper = stakingkeeper.NewKeeper( appCodec, keys[stakingtypes.StoreKey], app.AccountKeeper, app.BankKeeper, - app.GetSubspace(stakingtypes.ModuleName), + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) app.MintKeeper = mintkeeper.NewKeeper( appCodec, keys[minttypes.StoreKey], - app.GetSubspace(minttypes.ModuleName), - &stakingKeeper, + app.StakingKeeper, app.AccountKeeper, app.BankKeeper, authtypes.FeeCollectorName, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) app.DistrKeeper = distrkeeper.NewKeeper( appCodec, keys[distrtypes.StoreKey], - app.GetSubspace(distrtypes.ModuleName), app.AccountKeeper, app.BankKeeper, - &stakingKeeper, + app.StakingKeeper, authtypes.FeeCollectorName, - app.ModuleAccountAddrs(), + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) app.SlashingKeeper = slashingkeeper.NewKeeper( appCodec, + legacyAmino, keys[slashingtypes.StoreKey], - &stakingKeeper, - app.GetSubspace(slashingtypes.ModuleName), + app.StakingKeeper, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) - app.CrisisKeeper = crisiskeeper.NewKeeper( - app.GetSubspace(crisistypes.ModuleName), + + invCheckPeriod := cast.ToUint(appOpts.Get(server.FlagInvCheckPeriod)) + app.CrisisKeeper = *crisiskeeper.NewKeeper( + appCodec, + keys[crisistypes.StoreKey], invCheckPeriod, app.BankKeeper, authtypes.FeeCollectorName, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) - app.UpgradeKeeper = upgradekeeper.NewKeeper( + + // get skipUpgradeHeights from the app options + skipUpgradeHeights := map[int64]bool{} + for _, h := range cast.ToIntSlice(appOpts.Get(server.FlagUnsafeSkipUpgrades)) { + skipUpgradeHeights[int64(h)] = true + } + homePath := cast.ToString(appOpts.Get(flags.FlagHome)) + // set the governance module account as the authority for conducting upgrades + app.UpgradeKeeper = *upgradekeeper.NewKeeper( skipUpgradeHeights, keys[upgradetypes.StoreKey], appCodec, homePath, app.BaseApp, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) // register the staking hooks // NOTE: stakingKeeper above is passed by reference, so that it will contain these hooks - app.StakingKeeper = *stakingKeeper.SetHooks( + app.StakingKeeper.SetHooks( stakingtypes.NewMultiStakingHooks( app.DistrKeeper.Hooks(), app.SlashingKeeper.Hooks(), @@ -418,26 +438,30 @@ func New( providerModule := ibcprovider.NewAppModule(&app.ProviderKeeper, app.GetSubspace(providertypes.ModuleName)) // register the proposal types - govRouter := govtypes.NewRouter() + govRouter := govv1beta1.NewRouter() govRouter. - AddRoute(govtypes.RouterKey, govtypes.ProposalHandler). + AddRoute(govtypes.RouterKey, govv1beta1.ProposalHandler). AddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(app.ParamsKeeper)). - AddRoute(distrtypes.RouterKey, distr.NewCommunityPoolSpendProposalHandler(app.DistrKeeper)). - AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper)). + AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(&app.UpgradeKeeper)). AddRoute(ibchost.RouterKey, ibcclient.NewClientProposalHandler(app.IBCKeeper.ClientKeeper)). AddRoute(providertypes.RouterKey, ibcprovider.NewProviderProposalHandler(app.ProviderKeeper)). AddRoute(ibcclienttypes.RouterKey, ibcclient.NewClientProposalHandler(app.IBCKeeper.ClientKeeper)) + govConfig := govtypes.DefaultConfig() - app.GovKeeper = govkeeper.NewKeeper( + app.GovKeeper = *govkeeper.NewKeeper( appCodec, keys[govtypes.StoreKey], - app.GetSubspace(govtypes.ModuleName), app.AccountKeeper, app.BankKeeper, - &stakingKeeper, - govRouter, + app.StakingKeeper, + app.MsgServiceRouter(), + govConfig, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) + // Set legacy router for backwards compatibility with gov v1beta1 + app.GovKeeper.SetLegacyRouter(govRouter) + app.TransferKeeper = ibctransferkeeper.NewKeeper( appCodec, keys[ibctransfertypes.StoreKey], @@ -469,17 +493,17 @@ func New( app.BaseApp.DeliverTx, encodingConfig.TxConfig, ), - auth.NewAppModule(appCodec, app.AccountKeeper, nil), + auth.NewAppModule(appCodec, app.AccountKeeper, nil, app.GetSubspace(authtypes.ModuleName)), vesting.NewAppModule(app.AccountKeeper, app.BankKeeper), - bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper), - capability.NewAppModule(appCodec, *app.CapabilityKeeper), - crisis.NewAppModule(&app.CrisisKeeper, skipGenesisInvariants), - gov.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper), - mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper), - slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper), - distr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper), - staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper), - upgrade.NewAppModule(app.UpgradeKeeper), + bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper, app.GetSubspace(banktypes.ModuleName)), + capability.NewAppModule(appCodec, *app.CapabilityKeeper, false), + crisis.NewAppModule(&app.CrisisKeeper, skipGenesisInvariants, app.GetSubspace(crisistypes.ModuleName)), + gov.NewAppModule(appCodec, &app.GovKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(govtypes.ModuleName)), + mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper, nil, app.GetSubspace(minttypes.ModuleName)), + slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.GetSubspace(slashingtypes.ModuleName)), + distr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.GetSubspace(distrtypes.ModuleName)), + staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(stakingtypes.ModuleName)), + upgrade.NewAppModule(&app.UpgradeKeeper), evidence.NewAppModule(app.EvidenceKeeper), ibc.NewAppModule(app.IBCKeeper), params.NewAppModule(app.ParamsKeeper), @@ -565,8 +589,6 @@ func New( ) app.MM.RegisterInvariants(&app.CrisisKeeper) - app.MM.RegisterRoutes(app.Router(), app.QueryRouter(), encodingConfig.Amino) - app.configurator = module.NewConfigurator(app.appCodec, app.MsgServiceRouter(), app.GRPCQueryRouter()) app.MM.RegisterServices(app.configurator) @@ -575,14 +597,14 @@ func New( // NOTE: this is not required apps that don't use the simulator for fuzz testing // transactions app.sm = module.NewSimulationManager( - auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts), - bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper), - capability.NewAppModule(appCodec, *app.CapabilityKeeper), - gov.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper), - mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper), - staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper), - distr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper), - slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper), + auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts, app.GetSubspace(authtypes.ModuleName)), + bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper, app.GetSubspace(banktypes.ModuleName)), + capability.NewAppModule(appCodec, *app.CapabilityKeeper, false), + gov.NewAppModule(appCodec, &app.GovKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(govtypes.ModuleName)), + mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper, nil, app.GetSubspace(minttypes.ModuleName)), + staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(stakingtypes.ModuleName)), + distr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.GetSubspace(distrtypes.ModuleName)), + slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.GetSubspace(slashingtypes.ModuleName)), params.NewAppModule(app.ParamsKeeper), evidence.NewAppModule(app.EvidenceKeeper), ibc.NewAppModule(app.IBCKeeper), @@ -625,8 +647,11 @@ func New( fromVM := make(map[string]uint64) - for moduleName, eachModule := range app.MM.Modules { - fromVM[moduleName] = eachModule.ConsensusVersion() + for moduleName := range app.MM.Modules { + m := app.MM.Modules[moduleName] + if module, ok := m.(module.HasConsensusVersion); ok { + fromVM[moduleName] = module.ConsensusVersion() + } } ctx.Logger().Info("start to run module migrations...") @@ -641,7 +666,7 @@ func New( } if upgradeInfo.Name == upgradeName && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { - storeUpgrades := store.StoreUpgrades{} + storeUpgrades := storetypes.StoreUpgrades{} // configure store loader that checks if version == upgradeHeight and applies store upgrades app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades)) @@ -657,6 +682,14 @@ func New( app.ScopedTransferKeeper = scopedTransferKeeper app.ScopedIBCProviderKeeper = scopedIBCProviderKeeper + autocliv1.RegisterQueryServer(app.GRPCQueryRouter(), runtimeservices.NewAutoCLIQueryService(app.MM.Modules)) + + reflectionSvc, err := runtimeservices.NewReflectionService() + if err != nil { + panic(err) + } + reflectionv1.RegisterReflectionServiceServer(app.GRPCQueryRouter(), reflectionSvc) + return app } @@ -724,21 +757,21 @@ func (app *App) InterfaceRegistry() types.InterfaceRegistry { // GetKey returns the KVStoreKey for the provided store key. // // NOTE: This is solely to be used for testing purposes. -func (app *App) GetKey(storeKey string) *sdk.KVStoreKey { +func (app *App) GetKey(storeKey string) *storetypes.KVStoreKey { return app.keys[storeKey] } // GetTKey returns the TransientStoreKey for the provided store key. // // NOTE: This is solely to be used for testing purposes. -func (app *App) GetTKey(storeKey string) *sdk.TransientStoreKey { +func (app *App) GetTKey(storeKey string) *storetypes.TransientStoreKey { return app.tkeys[storeKey] } // GetMemKey returns the MemStoreKey for the provided mem key. // // NOTE: This is solely used for testing purposes. -func (app *App) GetMemKey(storeKey string) *sdk.MemoryStoreKey { +func (app *App) GetMemKey(storeKey string) *storetypes.MemoryStoreKey { return app.memKeys[storeKey] } @@ -811,28 +844,32 @@ func (app *App) GetScopedIBCKeeper() capabilitykeeper.ScopedKeeper { // GetTxConfig implements the TestingApp interface. func (app *App) GetTxConfig() client.TxConfig { - return MakeTestEncodingConfig().TxConfig + return app.txConfig +} + +// TxConfig returns SimApp's TxConfig +func (app *App) TxConfig() client.TxConfig { + return app.txConfig } // RegisterAPIRoutes registers all application module routes with the provided // API server. func (app *App) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig) { clientCtx := apiSvr.ClientCtx - rpc.RegisterRoutes(clientCtx, apiSvr.Router) - // Register legacy tx routes. - authrest.RegisterTxRoutes(clientCtx, apiSvr.Router) // Register new tx routes from grpc-gateway. authtx.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) // Register new tendermint queries routes from grpc-gateway. tmservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) + // Register node gRPC service for grpc-gateway. + nodeservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) + // Register legacy and grpc-gateway routes for all modules. - ModuleBasics.RegisterRESTRoutes(clientCtx, apiSvr.Router) ModuleBasics.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) // register swagger API from root so that other applications can override easily - if apiConfig.Swagger { - RegisterSwaggerAPI(apiSvr.Router) + if err := server.RegisterSwaggerAPI(apiSvr.ClientCtx, apiSvr.Router, apiConfig.Swagger); err != nil { + panic(err) } } @@ -841,20 +878,13 @@ func (app *App) RegisterTxService(clientCtx client.Context) { authtx.RegisterTxService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.BaseApp.Simulate, app.interfaceRegistry) } -// RegisterTendermintService implements the Application.RegisterTendermintService method. -func (app *App) RegisterTendermintService(clientCtx client.Context) { - tmservice.RegisterTendermintService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.interfaceRegistry) +func (app *App) RegisterNodeService(clientCtx client.Context) { + nodeservice.RegisterNodeService(clientCtx, app.GRPCQueryRouter()) } -// RegisterSwaggerAPI registers swagger route with API Server -func RegisterSwaggerAPI(rtr *mux.Router) { - statikFS, err := fs.New() - if err != nil { - panic(err) - } - - staticServer := http.FileServer(statikFS) - rtr.PathPrefix("/swagger/").Handler(http.StripPrefix("/swagger/", staticServer)) +// RegisterTendermintService implements the Application.RegisterTendermintService method. +func (app *App) RegisterTendermintService(clientCtx client.Context) { + tmservice.RegisterTendermintService(clientCtx, app.BaseApp.GRPCQueryRouter(), app.interfaceRegistry, app.Query) } // GetMaccPerms returns a copy of the module account permissions @@ -867,7 +897,7 @@ func GetMaccPerms() map[string][]string { } // initParamsKeeper init params keeper and its subspaces -func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey sdk.StoreKey) paramskeeper.Keeper { +func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey storetypes.StoreKey) paramskeeper.Keeper { paramsKeeper := paramskeeper.NewKeeper(appCodec, legacyAmino, key, tkey) paramsKeeper.Subspace(authtypes.ModuleName) @@ -876,7 +906,7 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino paramsKeeper.Subspace(minttypes.ModuleName) paramsKeeper.Subspace(distrtypes.ModuleName) paramsKeeper.Subspace(slashingtypes.ModuleName) - paramsKeeper.Subspace(govtypes.ModuleName).WithKeyTable(govtypes.ParamKeyTable()) + paramsKeeper.Subspace(govtypes.ModuleName).WithKeyTable(gov.ProvideKeyTable()) paramsKeeper.Subspace(crisistypes.ModuleName) paramsKeeper.Subspace(ibctransfertypes.ModuleName) paramsKeeper.Subspace(ibchost.ModuleName) @@ -889,6 +919,15 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino // should be used only in tests or when creating a new app instance (NewApp*()). // App user shouldn't create new codecs - use the app.AppCodec instead. // [DEPRECATED] +// func MakeTestEncodingConfig() appparams.EncodingConfig { +// encodingConfig := appparams.MakeTestEncodingConfig() +// std.RegisterLegacyAminoCodec(encodingConfig.Amino) +// std.RegisterInterfaces(encodingConfig.InterfaceRegistry) +// ModuleBasics.RegisterLegacyAminoCodec(encodingConfig.Amino) +// ModuleBasics.RegisterInterfaces(encodingConfig.InterfaceRegistry) +// return encodingConfig +// } + func MakeTestEncodingConfig() appparams.EncodingConfig { encodingConfig := appparams.MakeTestEncodingConfig() std.RegisterLegacyAminoCodec(encodingConfig.Amino) @@ -897,3 +936,12 @@ func MakeTestEncodingConfig() appparams.EncodingConfig { ModuleBasics.RegisterInterfaces(encodingConfig.InterfaceRegistry) return encodingConfig } + +func makeEncodingConfig() appparams.EncodingConfig { + encodingConfig := appparams.MakeTestEncodingConfig() + std.RegisterLegacyAminoCodec(encodingConfig.Amino) + std.RegisterInterfaces(encodingConfig.InterfaceRegistry) + ModuleBasics.RegisterLegacyAminoCodec(encodingConfig.Amino) + ModuleBasics.RegisterInterfaces(encodingConfig.InterfaceRegistry) + return encodingConfig +} diff --git a/app/provider/export.go b/app/provider/export.go index f0b3e3ed76..3865026b01 100644 --- a/app/provider/export.go +++ b/app/provider/export.go @@ -4,7 +4,7 @@ import ( "encoding/json" "log" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" servertypes "github.com/cosmos/cosmos-sdk/server/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -16,7 +16,7 @@ import ( // ExportAppStateAndValidators exports the state of the application for a genesis // file. func (app *App) ExportAppStateAndValidators( - forZeroHeight bool, jailAllowedAddrs []string, + forZeroHeight bool, jailAllowedAddrs, modulesToExport []string, ) (servertypes.ExportedApp, error) { // as if they could withdraw from the start of the next block ctx := app.NewContext(true, tmproto.Header{Height: app.LastBlockHeight()}) @@ -110,14 +110,23 @@ func (app *App) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs []str feePool.CommunityPool = feePool.CommunityPool.Add(scraps...) app.DistrKeeper.SetFeePool(ctx, feePool) - app.DistrKeeper.Hooks().AfterValidatorCreated(ctx, val.GetOperator()) + err := app.DistrKeeper.Hooks().AfterValidatorCreated(ctx, val.GetOperator()) + if err != nil { + panic(err) + } return false }) // reinitialize all delegations for _, del := range dels { - app.DistrKeeper.Hooks().BeforeDelegationCreated(ctx, del.GetDelegatorAddr(), del.GetValidatorAddr()) - app.DistrKeeper.Hooks().AfterDelegationModified(ctx, del.GetDelegatorAddr(), del.GetValidatorAddr()) + err := app.DistrKeeper.Hooks().BeforeDelegationCreated(ctx, del.GetDelegatorAddr(), del.GetValidatorAddr()) + if err != nil { + panic(err) + } + err = app.DistrKeeper.Hooks().AfterDelegationModified(ctx, del.GetDelegatorAddr(), del.GetValidatorAddr()) + if err != nil { + panic(err) + } } // reset context height diff --git a/app/sovereign/ante_handler.go b/app/sovereign/ante_handler.go index 3b1a3b7d38..0a71573b07 100644 --- a/app/sovereign/ante_handler.go +++ b/app/sovereign/ante_handler.go @@ -5,8 +5,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth/ante" - ibcante "github.com/cosmos/ibc-go/v4/modules/core/ante" - ibckeeper "github.com/cosmos/ibc-go/v4/modules/core/keeper" + ibcante "github.com/cosmos/ibc-go/v7/modules/core/ante" + ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" ) // HandlerOptions extend the SDK's AnteHandler options by requiring the IBC @@ -35,20 +35,19 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { anteDecorators := []sdk.AnteDecorator{ ante.NewSetUpContextDecorator(), - ante.NewRejectExtensionOptionsDecorator(), - ante.NewMempoolFeeDecorator(), + ante.NewExtensionOptionsDecorator(nil), ante.NewValidateBasicDecorator(), ante.NewTxTimeoutHeightDecorator(), ante.NewValidateMemoDecorator(options.AccountKeeper), ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), - ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper), + ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), // SetPubKeyDecorator must be called before all signature verification decorators ante.NewSetPubKeyDecorator(options.AccountKeeper), ante.NewValidateSigCountDecorator(options.AccountKeeper), ante.NewSigGasConsumeDecorator(options.AccountKeeper, sigGasConsumer), ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler), ante.NewIncrementSequenceDecorator(options.AccountKeeper), - ibcante.NewAnteDecorator(options.IBCKeeper), + ibcante.NewRedundantRelayDecorator(options.IBCKeeper), } return sdk.ChainAnteDecorators(anteDecorators...), nil diff --git a/app/sovereign/app.go b/app/sovereign/app.go index 43d732884b..9c729885f4 100644 --- a/app/sovereign/app.go +++ b/app/sovereign/app.go @@ -4,7 +4,6 @@ import ( "fmt" "io" stdlog "log" - "net/http" "os" "path/filepath" @@ -12,22 +11,25 @@ import ( "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + nodeservice "github.com/cosmos/cosmos-sdk/client/grpc/node" "github.com/cosmos/cosmos-sdk/client/grpc/tmservice" - "github.com/cosmos/cosmos-sdk/client/rpc" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/runtime" + "github.com/cosmos/cosmos-sdk/server" + "github.com/cosmos/cosmos-sdk/server/api" "github.com/cosmos/cosmos-sdk/server/config" servertypes "github.com/cosmos/cosmos-sdk/server/types" - "github.com/cosmos/cosmos-sdk/simapp" "github.com/cosmos/cosmos-sdk/std" - store "github.com/cosmos/cosmos-sdk/store/types" + storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/auth/ante" - authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest" authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -42,6 +44,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/capability" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + consensusparamkeeper "github.com/cosmos/cosmos-sdk/x/consensus/keeper" "github.com/cosmos/cosmos-sdk/x/crisis" crisiskeeper "github.com/cosmos/cosmos-sdk/x/crisis/keeper" crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types" @@ -51,39 +54,39 @@ import ( "github.com/cosmos/cosmos-sdk/x/feegrant" feegrantkeeper "github.com/cosmos/cosmos-sdk/x/feegrant/keeper" feegrantmodule "github.com/cosmos/cosmos-sdk/x/feegrant/module" + govclient "github.com/cosmos/cosmos-sdk/x/gov/client" + govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + "github.com/cosmos/cosmos-sdk/x/params" paramsclient "github.com/cosmos/cosmos-sdk/x/params/client" paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" upgradeclient "github.com/cosmos/cosmos-sdk/x/upgrade/client" + dbm "github.com/cometbft/cometbft-db" + abci "github.com/cometbft/cometbft/abci/types" + tmjson "github.com/cometbft/cometbft/libs/json" + "github.com/cometbft/cometbft/libs/log" + tmos "github.com/cometbft/cometbft/libs/os" "github.com/cosmos/cosmos-sdk/x/slashing" slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" "github.com/cosmos/cosmos-sdk/x/upgrade" upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - "github.com/cosmos/ibc-go/v4/modules/apps/transfer" - ibctransferkeeper "github.com/cosmos/ibc-go/v4/modules/apps/transfer/keeper" - ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" - ibc "github.com/cosmos/ibc-go/v4/modules/core" - ibcconnectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" - porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" - ibchost "github.com/cosmos/ibc-go/v4/modules/core/24-host" - ibckeeper "github.com/cosmos/ibc-go/v4/modules/core/keeper" + "github.com/cosmos/ibc-go/v7/modules/apps/transfer" + ibctransferkeeper "github.com/cosmos/ibc-go/v7/modules/apps/transfer/keeper" + ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + ibc "github.com/cosmos/ibc-go/v7/modules/core" + ibcconnectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" + porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" + ibchost "github.com/cosmos/ibc-go/v7/modules/core/exported" + ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" ibctestingcore "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/core" ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" - "github.com/gorilla/mux" - "github.com/rakyll/statik/fs" "github.com/spf13/cast" - abci "github.com/tendermint/tendermint/abci/types" - tmjson "github.com/tendermint/tendermint/libs/json" - "github.com/tendermint/tendermint/libs/log" - tmos "github.com/tendermint/tendermint/libs/os" - dbm "github.com/tendermint/tm-db" sdkdistr "github.com/cosmos/cosmos-sdk/x/distribution" - distrclient "github.com/cosmos/cosmos-sdk/x/distribution/client" distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" testutil "github.com/cosmos/interchain-security/v2/testutil/integration" @@ -129,8 +132,11 @@ var ( mint.AppModuleBasic{}, sdkdistr.AppModuleBasic{}, sdkgov.NewAppModuleBasic( - // TODO: eventually remove upgrade proposal handler and cancel proposal handler - paramsclient.ProposalHandler, distrclient.ProposalHandler, upgradeclient.ProposalHandler, upgradeclient.CancelProposalHandler, + []govclient.ProposalHandler{ + paramsclient.ProposalHandler, + upgradeclient.LegacyProposalHandler, + upgradeclient.LegacyCancelProposalHandler, + }, ), params.AppModuleBasic{}, crisis.AppModuleBasic{}, @@ -157,7 +163,7 @@ var ( ) var ( - _ simapp.App = (*App)(nil) + _ runtime.AppI = (*App)(nil) _ servertypes.Application = (*App)(nil) _ ibctesting.TestingApp = (*App)(nil) ) @@ -170,13 +176,12 @@ type App struct { // nolint: golint legacyAmino *codec.LegacyAmino appCodec codec.Codec interfaceRegistry types.InterfaceRegistry - - invCheckPeriod uint + txConfig client.TxConfig // keys to access the substores - keys map[string]*sdk.KVStoreKey - tkeys map[string]*sdk.TransientStoreKey - memKeys map[string]*sdk.MemoryStoreKey + keys map[string]*storetypes.KVStoreKey + tkeys map[string]*storetypes.TransientStoreKey + memKeys map[string]*storetypes.MemoryStoreKey // keepers AccountKeeper authkeeper.AccountKeeper @@ -188,15 +193,16 @@ type App struct { // nolint: golint DistrKeeper distrkeeper.Keeper - GovKeeper govkeeper.Keeper - CrisisKeeper crisiskeeper.Keeper - UpgradeKeeper upgradekeeper.Keeper - ParamsKeeper paramskeeper.Keeper - IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly - EvidenceKeeper evidencekeeper.Keeper - TransferKeeper ibctransferkeeper.Keeper - FeeGrantKeeper feegrantkeeper.Keeper - AuthzKeeper authzkeeper.Keeper + ConsensusParamsKeeper consensusparamkeeper.Keeper + GovKeeper govkeeper.Keeper + CrisisKeeper crisiskeeper.Keeper + UpgradeKeeper upgradekeeper.Keeper + ParamsKeeper paramskeeper.Keeper + IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly + EvidenceKeeper evidencekeeper.Keeper + TransferKeeper ibctransferkeeper.Keeper + FeeGrantKeeper feegrantkeeper.Keeper + AuthzKeeper authzkeeper.Keeper // make scoped keepers public for test purposes ScopedIBCKeeper capabilitykeeper.ScopedKeeper @@ -225,14 +231,12 @@ func New( db dbm.DB, traceStore io.Writer, loadLatest bool, - skipUpgradeHeights map[int64]bool, - homePath string, - invCheckPeriod uint, - encodingConfig appparams.EncodingConfig, appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp), ) *App { - appCodec := encodingConfig.Marshaler + encodingConfig := makeEncodingConfig() + + appCodec := encodingConfig.Codec legacyAmino := encodingConfig.Amino interfaceRegistry := encodingConfig.InterfaceRegistry @@ -256,7 +260,6 @@ func New( legacyAmino: legacyAmino, appCodec: appCodec, interfaceRegistry: interfaceRegistry, - invCheckPeriod: invCheckPeriod, keys: keys, tkeys: tkeys, memKeys: memKeys, @@ -270,10 +273,9 @@ func New( ) // set the BaseApp's parameter store - bApp.SetParamStore( - app.ParamsKeeper.Subspace(baseapp.Paramspace).WithKeyTable( - paramskeeper.ConsensusParamsKeyTable()), - ) + // upgradetypes.StoreKey -> maybe consensusparamtypes.StoreKey (package consensusparamtypes ("github.com/cosmos/cosmos-sdk/x/consensus/types") + app.ConsensusParamsKeeper = consensusparamkeeper.NewKeeper(appCodec, keys[upgradetypes.StoreKey], authtypes.NewModuleAddress(govtypes.ModuleName).String()) + bApp.SetParamStore(&app.ConsensusParamsKeeper) // add capability keeper and ScopeToModule for ibc module app.CapabilityKeeper = capabilitykeeper.NewKeeper( @@ -289,9 +291,10 @@ func New( app.AccountKeeper = authkeeper.NewAccountKeeper( appCodec, keys[authtypes.StoreKey], - app.GetSubspace(authtypes.ModuleName), authtypes.ProtoBaseAccount, maccPerms, + AccountAddressPrefix, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) bankBlockedAddrs := app.ModuleAccountAddrs() @@ -300,13 +303,14 @@ func New( appCodec, keys[banktypes.StoreKey], app.AccountKeeper, - app.GetSubspace(banktypes.ModuleName), bankBlockedAddrs, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) app.AuthzKeeper = authzkeeper.NewKeeper( keys[authzkeeper.StoreKey], appCodec, app.BaseApp.MsgServiceRouter(), + app.AccountKeeper, ) app.FeeGrantKeeper = feegrantkeeper.NewKeeper( appCodec, @@ -314,52 +318,70 @@ func New( app.AccountKeeper, ) - stakingKeeper := stakingkeeper.NewKeeper( + app.StakingKeeper = *stakingkeeper.NewKeeper( appCodec, keys[stakingtypes.StoreKey], app.AccountKeeper, app.BankKeeper, - app.GetSubspace(stakingtypes.ModuleName), + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) app.MintKeeper = mintkeeper.NewKeeper( - appCodec, keys[minttypes.StoreKey], app.GetSubspace(minttypes.ModuleName), &stakingKeeper, - app.AccountKeeper, app.BankKeeper, authtypes.FeeCollectorName, + appCodec, + keys[minttypes.StoreKey], + app.StakingKeeper, + app.AccountKeeper, + app.BankKeeper, + authtypes.FeeCollectorName, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) app.SlashingKeeper = slashingkeeper.NewKeeper( appCodec, + legacyAmino, keys[slashingtypes.StoreKey], - &app.StakingKeeper, - app.GetSubspace(slashingtypes.ModuleName), + app.StakingKeeper, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) + app.DistrKeeper = distrkeeper.NewKeeper( appCodec, keys[distrtypes.StoreKey], - app.GetSubspace(distrtypes.ModuleName), app.AccountKeeper, app.BankKeeper, - &stakingKeeper, + app.StakingKeeper, authtypes.FeeCollectorName, - app.ModuleAccountAddrs(), + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) - app.CrisisKeeper = crisiskeeper.NewKeeper( - app.GetSubspace(crisistypes.ModuleName), + + invCheckPeriod := cast.ToUint(appOpts.Get(server.FlagInvCheckPeriod)) + app.CrisisKeeper = *crisiskeeper.NewKeeper( + appCodec, + keys[crisistypes.StoreKey], invCheckPeriod, app.BankKeeper, authtypes.FeeCollectorName, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) - app.UpgradeKeeper = upgradekeeper.NewKeeper( + + // get skipUpgradeHeights from the app options + skipUpgradeHeights := map[int64]bool{} + for _, h := range cast.ToIntSlice(appOpts.Get(server.FlagUnsafeSkipUpgrades)) { + skipUpgradeHeights[int64(h)] = true + } + homePath := cast.ToString(appOpts.Get(flags.FlagHome)) + app.UpgradeKeeper = *upgradekeeper.NewKeeper( skipUpgradeHeights, keys[upgradetypes.StoreKey], appCodec, homePath, app.BaseApp, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) // register the staking hooks // NOTE: stakingKeeper above is passed by reference, so that it will contain these hooks - app.StakingKeeper = *stakingKeeper.SetHooks( + app.StakingKeeper.SetHooks( stakingtypes.NewMultiStakingHooks( app.DistrKeeper.Hooks(), app.SlashingKeeper.Hooks(), @@ -367,25 +389,25 @@ func New( ) // register the proposal types - sdkgovRouter := govtypes.NewRouter() - sdkgovRouter.AddRoute(govtypes.RouterKey, govtypes.ProposalHandler). + sdkgovRouter := govv1beta1.NewRouter() + sdkgovRouter. + AddRoute(govtypes.RouterKey, govv1beta1.ProposalHandler). AddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(app.ParamsKeeper)). - AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper)) - govKeeper := govkeeper.NewKeeper( + AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(&app.UpgradeKeeper)) + govConfig := govtypes.DefaultConfig() + + app.GovKeeper = *govkeeper.NewKeeper( appCodec, keys[govtypes.StoreKey], - app.GetSubspace(govtypes.ModuleName), app.AccountKeeper, app.BankKeeper, - &stakingKeeper, - sdkgovRouter, + app.StakingKeeper, + app.MsgServiceRouter(), + govConfig, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) - app.GovKeeper = *govKeeper.SetHooks( - govtypes.NewMultiGovHooks( - // register the governance hooks - ), - ) + app.GovKeeper.SetLegacyRouter(sdkgovRouter) app.IBCKeeper = ibckeeper.NewKeeper( appCodec, @@ -398,9 +420,10 @@ func New( app.SlashingKeeper = slashingkeeper.NewKeeper( appCodec, + legacyAmino, keys[slashingtypes.StoreKey], - &app.StakingKeeper, - app.GetSubspace(slashingtypes.ModuleName), + app.StakingKeeper, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) app.TransferKeeper = ibctransferkeeper.NewKeeper( @@ -443,18 +466,18 @@ func New( app.BaseApp.DeliverTx, encodingConfig.TxConfig, ), - auth.NewAppModule(appCodec, app.AccountKeeper, nil), + auth.NewAppModule(appCodec, app.AccountKeeper, nil, app.GetSubspace(authtypes.ModuleName)), vesting.NewAppModule(app.AccountKeeper, app.BankKeeper), - bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper), - capability.NewAppModule(appCodec, *app.CapabilityKeeper), - crisis.NewAppModule(&app.CrisisKeeper, skipGenesisInvariants), + bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper, app.GetSubspace(banktypes.ModuleName)), + capability.NewAppModule(appCodec, *app.CapabilityKeeper, false), + crisis.NewAppModule(&app.CrisisKeeper, skipGenesisInvariants, app.GetSubspace(crisistypes.ModuleName)), feegrantmodule.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry), - sdkgov.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper), - mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper), - slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper), - sdkdistr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper), - sdkstaking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper), - upgrade.NewAppModule(app.UpgradeKeeper), + sdkgov.NewAppModule(appCodec, &app.GovKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(govtypes.ModuleName)), + mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper, nil, app.GetSubspace(minttypes.ModuleName)), + slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.GetSubspace(slashingtypes.ModuleName)), + sdkdistr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.GetSubspace(distrtypes.ModuleName)), + sdkstaking.NewAppModule(appCodec, &app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(stakingtypes.ModuleName)), + upgrade.NewAppModule(&app.UpgradeKeeper), evidence.NewAppModule(app.EvidenceKeeper), params.NewAppModule(app.ParamsKeeper), authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), @@ -531,7 +554,6 @@ func New( ) app.MM.RegisterInvariants(&app.CrisisKeeper) - app.MM.RegisterRoutes(app.Router(), app.QueryRouter(), encodingConfig.Amino) app.configurator = module.NewConfigurator(app.appCodec, app.MsgServiceRouter(), app.GRPCQueryRouter()) app.MM.RegisterServices(app.configurator) @@ -569,8 +591,11 @@ func New( fromVM := make(map[string]uint64) - for moduleName, eachModule := range app.MM.Modules { - fromVM[moduleName] = eachModule.ConsensusVersion() + for moduleName := range app.MM.Modules { + m := app.MM.Modules[moduleName] + if module, ok := m.(module.HasConsensusVersion); ok { + fromVM[moduleName] = module.ConsensusVersion() + } } ctx.Logger().Info("start to run module migrations...") @@ -585,7 +610,7 @@ func New( } if upgradeInfo.Name == upgradeName && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { - storeUpgrades := store.StoreUpgrades{} + storeUpgrades := storetypes.StoreUpgrades{} app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades)) } @@ -664,21 +689,21 @@ func (app *App) InterfaceRegistry() types.InterfaceRegistry { // GetKey returns the KVStoreKey for the provided store key. // // NOTE: This is solely to be used for testing purposes. -func (app *App) GetKey(storeKey string) *sdk.KVStoreKey { +func (app *App) GetKey(storeKey string) *storetypes.KVStoreKey { return app.keys[storeKey] } // GetTKey returns the TransientStoreKey for the provided store key. // // NOTE: This is solely to be used for testing purposes. -func (app *App) GetTKey(storeKey string) *sdk.TransientStoreKey { +func (app *App) GetTKey(storeKey string) *storetypes.TransientStoreKey { return app.tkeys[storeKey] } // GetMemKey returns the MemStoreKey for the provided mem key. // // NOTE: This is solely used for testing purposes. -func (app *App) GetMemKey(storeKey string) *sdk.MemoryStoreKey { +func (app *App) GetMemKey(storeKey string) *storetypes.MemoryStoreKey { return app.memKeys[storeKey] } @@ -751,29 +776,31 @@ func (app *App) GetScopedIBCKeeper() capabilitykeeper.ScopedKeeper { // GetTxConfig implements the TestingApp interface. func (app *App) GetTxConfig() client.TxConfig { - return MakeTestEncodingConfig().TxConfig + return app.txConfig +} + +// TxConfig returns SimApp's TxConfig +func (app *App) TxConfig() client.TxConfig { + return app.txConfig } // RegisterAPIRoutes registers all application module routes with the provided // API server. func (app *App) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig) { clientCtx := apiSvr.ClientCtx - rpc.RegisterRoutes(clientCtx, apiSvr.Router) - // Register legacy tx routes. - authrest.RegisterTxRoutes(clientCtx, apiSvr.Router) // Register new tx routes from grpc-gateway. authtx.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) // Register new tendermint queries routes from grpc-gateway. tmservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) + // Register node gRPC service for grpc-gateway. + nodeservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) // Register legacy and grpc-gateway routes for all modules. - ModuleBasics.RegisterRESTRoutes(clientCtx, apiSvr.Router) ModuleBasics.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) +} - // register swagger API from root so that other applications can override easily - if apiConfig.Swagger { - RegisterSwaggerAPI(apiSvr.Router) - } +func (app *App) RegisterNodeService(clientCtx client.Context) { + nodeservice.RegisterNodeService(clientCtx, app.GRPCQueryRouter()) } // RegisterTxService implements the Application.RegisterTxService method. @@ -783,18 +810,7 @@ func (app *App) RegisterTxService(clientCtx client.Context) { // RegisterTendermintService implements the Application.RegisterTendermintService method. func (app *App) RegisterTendermintService(clientCtx client.Context) { - tmservice.RegisterTendermintService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.interfaceRegistry) -} - -// RegisterSwaggerAPI registers swagger route with API Server -func RegisterSwaggerAPI(rtr *mux.Router) { - statikFS, err := fs.New() - if err != nil { - panic(err) - } - - staticServer := http.FileServer(statikFS) - rtr.PathPrefix("/swagger/").Handler(http.StripPrefix("/swagger/", staticServer)) + tmservice.RegisterTendermintService(clientCtx, app.BaseApp.GRPCQueryRouter(), app.interfaceRegistry, app.Query) } // GetMaccPerms returns a copy of the module account permissions @@ -807,7 +823,7 @@ func GetMaccPerms() map[string][]string { } // initParamsKeeper init params keeper and its subspaces -func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey sdk.StoreKey) paramskeeper.Keeper { +func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey storetypes.StoreKey) paramskeeper.Keeper { paramsKeeper := paramskeeper.NewKeeper(appCodec, legacyAmino, key, tkey) paramsKeeper.Subspace(authtypes.ModuleName) @@ -816,7 +832,7 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino paramsKeeper.Subspace(minttypes.ModuleName) paramsKeeper.Subspace(distrtypes.ModuleName) paramsKeeper.Subspace(slashingtypes.ModuleName) - paramsKeeper.Subspace(govtypes.ModuleName).WithKeyTable(govtypes.ParamKeyTable()) + paramsKeeper.Subspace(govtypes.ModuleName).WithKeyTable(sdkgov.ProvideKeyTable()) paramsKeeper.Subspace(crisistypes.ModuleName) paramsKeeper.Subspace(ibctransfertypes.ModuleName) paramsKeeper.Subspace(ibchost.ModuleName) @@ -828,6 +844,15 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino // should be used only in tests or when creating a new app instance (NewApp*()). // App user shouldn't create new codecs - use the app.AppCodec instead. // [DEPRECATED] +// func MakeTestEncodingConfig() appparams.EncodingConfig { +// encodingConfig := appparams.MakeTestEncodingConfig() +// std.RegisterLegacyAminoCodec(encodingConfig.Amino) +// std.RegisterInterfaces(encodingConfig.InterfaceRegistry) +// ModuleBasics.RegisterLegacyAminoCodec(encodingConfig.Amino) +// ModuleBasics.RegisterInterfaces(encodingConfig.InterfaceRegistry) +// return encodingConfig +// } + func MakeTestEncodingConfig() appparams.EncodingConfig { encodingConfig := appparams.MakeTestEncodingConfig() std.RegisterLegacyAminoCodec(encodingConfig.Amino) @@ -836,3 +861,12 @@ func MakeTestEncodingConfig() appparams.EncodingConfig { ModuleBasics.RegisterInterfaces(encodingConfig.InterfaceRegistry) return encodingConfig } + +func makeEncodingConfig() appparams.EncodingConfig { + encodingConfig := appparams.MakeTestEncodingConfig() + std.RegisterLegacyAminoCodec(encodingConfig.Amino) + std.RegisterInterfaces(encodingConfig.InterfaceRegistry) + ModuleBasics.RegisterLegacyAminoCodec(encodingConfig.Amino) + ModuleBasics.RegisterInterfaces(encodingConfig.InterfaceRegistry) + return encodingConfig +} diff --git a/app/sovereign/export.go b/app/sovereign/export.go index f0b3e3ed76..770d9b540f 100644 --- a/app/sovereign/export.go +++ b/app/sovereign/export.go @@ -4,7 +4,7 @@ import ( "encoding/json" "log" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" servertypes "github.com/cosmos/cosmos-sdk/server/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -16,7 +16,7 @@ import ( // ExportAppStateAndValidators exports the state of the application for a genesis // file. func (app *App) ExportAppStateAndValidators( - forZeroHeight bool, jailAllowedAddrs []string, + forZeroHeight bool, jailAllowedAddrs, modulesToExport []string, ) (servertypes.ExportedApp, error) { // as if they could withdraw from the start of the next block ctx := app.NewContext(true, tmproto.Header{Height: app.LastBlockHeight()}) @@ -35,7 +35,7 @@ func (app *App) ExportAppStateAndValidators( return servertypes.ExportedApp{}, err } - validators, err := staking.WriteValidators(ctx, app.StakingKeeper) + validators, err := staking.WriteValidators(ctx, &app.StakingKeeper) if err != nil { return servertypes.ExportedApp{}, err } @@ -110,14 +110,23 @@ func (app *App) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs []str feePool.CommunityPool = feePool.CommunityPool.Add(scraps...) app.DistrKeeper.SetFeePool(ctx, feePool) - app.DistrKeeper.Hooks().AfterValidatorCreated(ctx, val.GetOperator()) + err := app.DistrKeeper.Hooks().AfterValidatorCreated(ctx, val.GetOperator()) + if err != nil { + panic(err) + } return false }) // reinitialize all delegations for _, del := range dels { - app.DistrKeeper.Hooks().BeforeDelegationCreated(ctx, del.GetDelegatorAddr(), del.GetValidatorAddr()) - app.DistrKeeper.Hooks().AfterDelegationModified(ctx, del.GetDelegatorAddr(), del.GetValidatorAddr()) + err := app.DistrKeeper.Hooks().BeforeDelegationCreated(ctx, del.GetDelegatorAddr(), del.GetValidatorAddr()) + if err != nil { + panic(err) + } + err = app.DistrKeeper.Hooks().AfterDelegationModified(ctx, del.GetDelegatorAddr(), del.GetValidatorAddr()) + if err != nil { + panic(err) + } } // reset context height diff --git a/buf.work.yaml b/buf.work.yaml index 98094695ff..1b4a0d95c2 100644 --- a/buf.work.yaml +++ b/buf.work.yaml @@ -6,4 +6,3 @@ version: v1 directories: - proto - - third_party/proto diff --git a/cmd/interchain-security-cd/cmd/genaccounts.go b/cmd/interchain-security-cd/cmd/genaccounts.go deleted file mode 100644 index c3340dccad..0000000000 --- a/cmd/interchain-security-cd/cmd/genaccounts.go +++ /dev/null @@ -1,180 +0,0 @@ -package cmd - -import ( - "bufio" - "encoding/json" - "errors" - "fmt" - - "github.com/spf13/cobra" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/crypto/keyring" - "github.com/cosmos/cosmos-sdk/server" - sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - authvesting "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/cosmos/cosmos-sdk/x/genutil" - genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" -) - -const ( - flagVestingStart = "vesting-start-time" - flagVestingEnd = "vesting-end-time" - flagVestingAmt = "vesting-amount" -) - -// AddGenesisAccountCmd returns add-genesis-account cobra Command. -func AddGenesisAccountCmd(defaultNodeHome string) *cobra.Command { - cmd := &cobra.Command{ - Use: "add-genesis-account [address_or_key_name] [coin][,[coin]]", - Short: "Add a genesis account to genesis.json", - Long: `Add a genesis account to genesis.json. The provided account must specify -the account address or key name and a list of initial coins. If a key name is given, -the address will be looked up in the local Keybase. The list of initial tokens must -contain valid denominations. Accounts may optionally be supplied with vesting parameters. -`, - Args: cobra.ExactArgs(2), - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) - serverCtx := server.GetServerContextFromCmd(cmd) - config := serverCtx.Config - - config.SetRoot(clientCtx.HomeDir) - - var kr keyring.Keyring - addr, err := sdk.AccAddressFromBech32(args[0]) - if err != nil { - inBuf := bufio.NewReader(cmd.InOrStdin()) - keyringBackend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend) - if keyringBackend != "" && clientCtx.Keyring == nil { - var err error - kr, err = keyring.New(sdk.KeyringServiceName(), keyringBackend, clientCtx.HomeDir, inBuf) - if err != nil { - return err - } - } else { - kr = clientCtx.Keyring - } - - info, err := kr.Key(args[0]) - if err != nil { - return fmt.Errorf("failed to get address from Keyring: %w", err) - } - addr = info.GetAddress() - } - - coins, err := sdk.ParseCoinsNormalized(args[1]) - if err != nil { - return fmt.Errorf("failed to parse coins: %w", err) - } - - vestingStart, _ := cmd.Flags().GetInt64(flagVestingStart) - vestingEnd, _ := cmd.Flags().GetInt64(flagVestingEnd) - vestingAmtStr, _ := cmd.Flags().GetString(flagVestingAmt) - - vestingAmt, err := sdk.ParseCoinsNormalized(vestingAmtStr) - if err != nil { - return fmt.Errorf("failed to parse vesting amount: %w", err) - } - - // create concrete account type based on input parameters - var genAccount authtypes.GenesisAccount - - balances := banktypes.Balance{Address: addr.String(), Coins: coins.Sort()} - baseAccount := authtypes.NewBaseAccount(addr, nil, 0, 0) - - if !vestingAmt.IsZero() { - baseVestingAccount := authvesting.NewBaseVestingAccount(baseAccount, vestingAmt.Sort(), vestingEnd) - - if (balances.Coins.IsZero() && !baseVestingAccount.OriginalVesting.IsZero()) || - baseVestingAccount.OriginalVesting.IsAnyGT(balances.Coins) { - return errors.New("vesting amount cannot be greater than total amount") - } - - switch { - case vestingStart != 0 && vestingEnd != 0: - genAccount = authvesting.NewContinuousVestingAccountRaw(baseVestingAccount, vestingStart) - - case vestingEnd != 0: - genAccount = authvesting.NewDelayedVestingAccountRaw(baseVestingAccount) - - default: - return errors.New("invalid vesting parameters; must supply start and end time or end time") - } - } else { - genAccount = baseAccount - } - - if err := genAccount.Validate(); err != nil { - return fmt.Errorf("failed to validate new genesis account: %w", err) - } - - genFile := config.GenesisFile() - appState, genDoc, err := genutiltypes.GenesisStateFromGenFile(genFile) - if err != nil { - return fmt.Errorf("failed to unmarshal genesis state: %w", err) - } - - authGenState := authtypes.GetGenesisStateFromAppState(clientCtx.Codec, appState) - - accs, err := authtypes.UnpackAccounts(authGenState.Accounts) - if err != nil { - return fmt.Errorf("failed to get accounts from any: %w", err) - } - - if accs.Contains(addr) { - return fmt.Errorf("cannot add account at existing address %s", addr) - } - - // Add the new account to the set of genesis accounts and sanitize the - // accounts afterwards. - accs = append(accs, genAccount) - accs = authtypes.SanitizeGenesisAccounts(accs) - - genAccs, err := authtypes.PackAccounts(accs) - if err != nil { - return fmt.Errorf("failed to convert accounts into any's: %w", err) - } - authGenState.Accounts = genAccs - - authGenStateBz, err := clientCtx.Codec.MarshalJSON(&authGenState) - if err != nil { - return fmt.Errorf("failed to marshal auth genesis state: %w", err) - } - - appState[authtypes.ModuleName] = authGenStateBz - - bankGenState := banktypes.GetGenesisStateFromAppState(clientCtx.Codec, appState) - bankGenState.Balances = append(bankGenState.Balances, balances) - bankGenState.Balances = banktypes.SanitizeGenesisBalances(bankGenState.Balances) - bankGenState.Supply = bankGenState.Supply.Add(balances.Coins...) - - bankGenStateBz, err := clientCtx.Codec.MarshalJSON(bankGenState) - if err != nil { - return fmt.Errorf("failed to marshal bank genesis state: %w", err) - } - - appState[banktypes.ModuleName] = bankGenStateBz - - appStateJSON, err := json.Marshal(appState) - if err != nil { - return fmt.Errorf("failed to marshal application genesis state: %w", err) - } - - genDoc.AppState = appStateJSON - return genutil.ExportGenesisFile(genDoc, genFile) - }, - } - - cmd.Flags().String(flags.FlagHome, defaultNodeHome, "The application home directory") - cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|kwallet|pass|test)") - cmd.Flags().String(flagVestingAmt, "", "amount of coins for vesting accounts") - cmd.Flags().Int64(flagVestingStart, 0, "schedule start time (unix epoch) for vesting accounts") - cmd.Flags().Int64(flagVestingEnd, 0, "schedule end time (unix epoch) for vesting accounts") - flags.AddQueryFlagsToCmd(cmd) - - return cmd -} diff --git a/cmd/interchain-security-cd/cmd/root.go b/cmd/interchain-security-cd/cmd/root.go index d6b2b95098..10af60f25f 100644 --- a/cmd/interchain-security-cd/cmd/root.go +++ b/cmd/interchain-security-cd/cmd/root.go @@ -4,16 +4,16 @@ import ( "errors" "io" "os" - "path/filepath" + dbm "github.com/cometbft/cometbft-db" + tmcfg "github.com/cometbft/cometbft/config" + "github.com/cometbft/cometbft/libs/log" serverconfig "github.com/cosmos/cosmos-sdk/server/config" - "github.com/spf13/cast" + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" "github.com/spf13/cobra" - tmcli "github.com/tendermint/tendermint/libs/cli" - "github.com/tendermint/tendermint/libs/log" - dbm "github.com/tendermint/tm-db" + "github.com/spf13/viper" - "github.com/cosmos/cosmos-sdk/baseapp" + rosettaCmd "cosmossdk.io/tools/rosetta/cmd" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/config" "github.com/cosmos/cosmos-sdk/client/debug" @@ -23,35 +23,40 @@ import ( "github.com/cosmos/cosmos-sdk/client/rpc" "github.com/cosmos/cosmos-sdk/server" servertypes "github.com/cosmos/cosmos-sdk/server/types" - "github.com/cosmos/cosmos-sdk/snapshots" - "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" "github.com/cosmos/cosmos-sdk/x/auth/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/cosmos/cosmos-sdk/x/crisis" genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" - simapp "github.com/cosmos/interchain-security/v2/app/consumer" + consumer "github.com/cosmos/interchain-security/v2/app/consumer" "github.com/cosmos/interchain-security/v2/app/params" ) // NewRootCmd creates a new root command for simd. It is called once in the // main function. -func NewRootCmd() (*cobra.Command, params.EncodingConfig) { - encodingConfig := simapp.MakeTestEncodingConfig() +func NewRootCmd() *cobra.Command { + // we "pre"-instantiate the application for getting the injected/configured encoding configuration + tempApp := consumer.New(log.NewNopLogger(), dbm.NewMemDB(), nil, true, simtestutil.NewAppOptionsWithFlagHome(consumer.DefaultNodeHome)) + encodingConfig := params.EncodingConfig{ + InterfaceRegistry: tempApp.InterfaceRegistry(), + Codec: tempApp.AppCodec(), + TxConfig: tempApp.TxConfig(), + Amino: tempApp.LegacyAmino(), + } + initClientCtx := client.Context{}. - WithCodec(encodingConfig.Marshaler). + WithCodec(encodingConfig.Codec). WithInterfaceRegistry(encodingConfig.InterfaceRegistry). WithTxConfig(encodingConfig.TxConfig). WithLegacyAmino(encodingConfig.Amino). WithInput(os.Stdin). WithAccountRetriever(types.AccountRetriever{}). - WithHomeDir(simapp.DefaultNodeHome). + WithHomeDir(consumer.DefaultNodeHome). WithViper("") // In simapp, we don't use any prefix for env variables. rootCmd := &cobra.Command{ - Use: "simd", - Short: "simulation app", + Use: "interchain-security-cd", + Short: "interchain-security consumer simulation app", PersistentPreRunE: func(cmd *cobra.Command, _ []string) error { // set the default command outputs cmd.SetOut(cmd.OutOrStdout()) @@ -72,14 +77,53 @@ func NewRootCmd() (*cobra.Command, params.EncodingConfig) { } customAppTemplate, customAppConfig := initAppConfig() + customTMConfig := initTendermintConfig() - return server.InterceptConfigsPreRunHandler(cmd, customAppTemplate, customAppConfig) + return server.InterceptConfigsPreRunHandler(cmd, customAppTemplate, customAppConfig, customTMConfig) }, } initRootCmd(rootCmd, encodingConfig) - return rootCmd, encodingConfig + return rootCmd +} + +// initTendermintConfig helps to override default Tendermint Config values. +// return tmcfg.DefaultConfig if no custom configuration is required for the application. +func initTendermintConfig() *tmcfg.Config { + cfg := tmcfg.DefaultConfig() + + // these values put a higher strain on node memory + // cfg.P2P.MaxNumInboundPeers = 100 + // cfg.P2P.MaxNumOutboundPeers = 40 + + return cfg +} + +func txCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "tx", + Short: "Transactions subcommands", + DisableFlagParsing: false, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand( + authcmd.GetSignCommand(), + authcmd.GetSignBatchCommand(), + authcmd.GetMultiSignCommand(), + authcmd.GetMultiSignBatchCmd(), + authcmd.GetValidateSignaturesCommand(), + authcmd.GetBroadcastCommand(), + authcmd.GetEncodeCommand(), + authcmd.GetDecodeCommand(), + authcmd.GetAuxToFeeCommand(), + ) + + consumer.ModuleBasics.AddTxCommands(cmd) + + return cmd } // initAppConfig helps to override default appConfig template and configs. @@ -143,44 +187,107 @@ func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) { cfg := sdk.GetConfig() cfg.Seal() - a := appCreator{encodingConfig} rootCmd.AddCommand( - genutilcli.InitCmd(simapp.ModuleBasics, simapp.DefaultNodeHome), - genutilcli.CollectGenTxsCmd(banktypes.GenesisBalancesIterator{}, simapp.DefaultNodeHome), - genutilcli.MigrateGenesisCmd(), - genutilcli.GenTxCmd(simapp.ModuleBasics, encodingConfig.TxConfig, banktypes.GenesisBalancesIterator{}, simapp.DefaultNodeHome), - genutilcli.ValidateGenesisCmd(simapp.ModuleBasics), - AddGenesisAccountCmd(simapp.DefaultNodeHome), - tmcli.NewCompletionCmd(rootCmd, true), + genutilcli.InitCmd(consumer.ModuleBasics, consumer.DefaultNodeHome), debug.Cmd(), config.Cmd(), - pruning.PruningCmd(a.newApp), + pruning.PruningCmd(newApp), ) - server.AddCommands(rootCmd, simapp.DefaultNodeHome, a.newApp, a.appExport, addModuleInitFlags) + server.AddCommands(rootCmd, consumer.DefaultNodeHome, newApp, appExport, addModuleInitFlags) - // add keybase, auxiliary RPC, query, and tx child commands + // add keybase, auxiliary RPC, query, genesis, and tx child commands rootCmd.AddCommand( rpc.StatusCommand(), + genesisCommand(encodingConfig), queryCommand(), txCommand(), - keys.Commands(simapp.DefaultNodeHome), + keys.Commands(consumer.DefaultNodeHome), ) // add rosetta - rootCmd.AddCommand(server.RosettaCommand(encodingConfig.InterfaceRegistry, encodingConfig.Marshaler)) + rootCmd.AddCommand(rosettaCmd.RosettaCommand(encodingConfig.InterfaceRegistry, encodingConfig.Codec)) +} + +// newApp is an appCreator +// newApp creates the application +func newApp( + logger log.Logger, + db dbm.DB, + traceStore io.Writer, + appOpts servertypes.AppOptions, +) servertypes.Application { + baseappOptions := server.DefaultBaseappOptions(appOpts) + + return consumer.New( + logger, db, traceStore, true, + appOpts, + baseappOptions..., + ) +} + +// appExport creates a new simapp (optionally at a given height) and exports state. +func appExport( + logger log.Logger, + db dbm.DB, + traceStore io.Writer, + height int64, + forZeroHeight bool, + jailAllowedAddrs []string, + appOpts servertypes.AppOptions, + modulesToExport []string, +) (servertypes.ExportedApp, error) { + var simApp *consumer.App + + // this check is necessary as we use the flag in x/upgrade. + // we can exit more gracefully by checking the flag here. + homePath, ok := appOpts.Get(flags.FlagHome).(string) + if !ok || homePath == "" { + return servertypes.ExportedApp{}, errors.New("application home not set") + } + + viperAppOpts, ok := appOpts.(*viper.Viper) + if !ok { + return servertypes.ExportedApp{}, errors.New("appOpts is not viper.Viper") + } + + // overwrite the FlagInvCheckPeriod + viperAppOpts.Set(server.FlagInvCheckPeriod, 1) + appOpts = viperAppOpts + + if height != -1 { + simApp = consumer.New(logger, db, traceStore, false, appOpts) + + if err := simApp.LoadHeight(height); err != nil { + return servertypes.ExportedApp{}, err + } + } else { + simApp = consumer.New(logger, db, traceStore, true, appOpts) + } + + return simApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs, modulesToExport) } func addModuleInitFlags(startCmd *cobra.Command) { crisis.AddModuleInitFlags(startCmd) } +// genesisCommand builds genesis-related `simd genesis` command. Users may provide application specific commands as a parameter +func genesisCommand(encodingConfig params.EncodingConfig, cmds ...*cobra.Command) *cobra.Command { + cmd := genutilcli.GenesisCoreCommand(encodingConfig.TxConfig, consumer.ModuleBasics, consumer.DefaultNodeHome) + + for _, sub_cmd := range cmds { + cmd.AddCommand(sub_cmd) + } + return cmd +} + func queryCommand() *cobra.Command { cmd := &cobra.Command{ Use: "query", Aliases: []string{"q"}, Short: "Querying subcommands", - DisableFlagParsing: true, + DisableFlagParsing: false, SuggestionsMinimumDistance: 2, RunE: client.ValidateCmd, } @@ -191,115 +298,11 @@ func queryCommand() *cobra.Command { rpc.BlockCommand(), authcmd.QueryTxsByEventsCmd(), authcmd.QueryTxCmd(), - ) - - simapp.ModuleBasics.AddQueryCommands(cmd) - cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID") - - return cmd -} - -func txCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "tx", - Short: "Transactions subcommands", - DisableFlagParsing: true, - SuggestionsMinimumDistance: 2, - RunE: client.ValidateCmd, - } - - cmd.AddCommand( - authcmd.GetSignCommand(), - authcmd.GetSignBatchCommand(), - authcmd.GetMultiSignCommand(), - authcmd.GetMultiSignBatchCmd(), - authcmd.GetValidateSignaturesCommand(), - authcmd.GetBroadcastCommand(), authcmd.GetEncodeCommand(), authcmd.GetDecodeCommand(), ) - simapp.ModuleBasics.AddTxCommands(cmd) - cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID") + consumer.ModuleBasics.AddQueryCommands(cmd) return cmd } - -type appCreator struct { - encCfg params.EncodingConfig -} - -// newApp is an appCreator -func (a appCreator) newApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts servertypes.AppOptions) servertypes.Application { - var cache sdk.MultiStorePersistentCache - - if cast.ToBool(appOpts.Get(server.FlagInterBlockCache)) { - cache = store.NewCommitKVStoreCacheManager() - } - - skipUpgradeHeights := make(map[int64]bool) - for _, h := range cast.ToIntSlice(appOpts.Get(server.FlagUnsafeSkipUpgrades)) { - skipUpgradeHeights[int64(h)] = true - } - - pruningOpts, err := server.GetPruningOptionsFromFlags(appOpts) - if err != nil { - panic(err) - } - - snapshotDir := filepath.Join(cast.ToString(appOpts.Get(flags.FlagHome)), "data", "snapshots") - snapshotDB, err := sdk.NewLevelDB("metadata", snapshotDir) - if err != nil { - panic(err) - } - snapshotStore, err := snapshots.NewStore(snapshotDB, snapshotDir) - if err != nil { - panic(err) - } - - return simapp.New( - logger, db, traceStore, true, skipUpgradeHeights, - cast.ToString(appOpts.Get(flags.FlagHome)), - cast.ToUint(appOpts.Get(server.FlagInvCheckPeriod)), - a.encCfg, - appOpts, - baseapp.SetPruning(pruningOpts), - baseapp.SetMinGasPrices(cast.ToString(appOpts.Get(server.FlagMinGasPrices))), - baseapp.SetHaltHeight(cast.ToUint64(appOpts.Get(server.FlagHaltHeight))), - baseapp.SetHaltTime(cast.ToUint64(appOpts.Get(server.FlagHaltTime))), - baseapp.SetMinRetainBlocks(cast.ToUint64(appOpts.Get(server.FlagMinRetainBlocks))), - baseapp.SetInterBlockCache(cache), - baseapp.SetTrace(cast.ToBool(appOpts.Get(server.FlagTrace))), - baseapp.SetIndexEvents(cast.ToStringSlice(appOpts.Get(server.FlagIndexEvents))), - baseapp.SetSnapshotStore(snapshotStore), - baseapp.SetSnapshotInterval(cast.ToUint64(appOpts.Get(server.FlagStateSyncSnapshotInterval))), - baseapp.SetSnapshotKeepRecent(cast.ToUint32(appOpts.Get(server.FlagStateSyncSnapshotKeepRecent))), - baseapp.SetIAVLCacheSize(cast.ToInt(appOpts.Get(server.FlagIAVLCacheSize))), - baseapp.SetIAVLDisableFastNode(cast.ToBool(appOpts.Get(server.FlagDisableIAVLFastNode))), - ) -} - -// appExport creates a new simapp (optionally at a given height) -// and exports state. -func (a appCreator) appExport( - logger log.Logger, db dbm.DB, traceStore io.Writer, height int64, forZeroHeight bool, jailAllowedAddrs []string, - appOpts servertypes.AppOptions, -) (servertypes.ExportedApp, error) { - var simApp *simapp.App - homePath, ok := appOpts.Get(flags.FlagHome).(string) - if !ok || homePath == "" { - return servertypes.ExportedApp{}, errors.New("application home not set") - } - - if height != -1 { - simApp = simapp.New(logger, db, traceStore, false, map[int64]bool{}, homePath, uint(1), a.encCfg, appOpts) - - if err := simApp.LoadHeight(height); err != nil { - return servertypes.ExportedApp{}, err - } - } else { - simApp = simapp.New(logger, db, traceStore, true, map[int64]bool{}, homePath, uint(1), a.encCfg, appOpts) - } - - return simApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs) -} diff --git a/cmd/interchain-security-cd/main.go b/cmd/interchain-security-cd/main.go index abccff8eae..589869cd43 100644 --- a/cmd/interchain-security-cd/main.go +++ b/cmd/interchain-security-cd/main.go @@ -10,9 +10,9 @@ import ( ) func main() { - rootCmd, _ := cmd.NewRootCmd() + rootCmd := cmd.NewRootCmd() - if err := svrcmd.Execute(rootCmd, app.DefaultNodeHome); err != nil { + if err := svrcmd.Execute(rootCmd, "", app.DefaultNodeHome); err != nil { switch e := err.(type) { case server.ErrorCode: os.Exit(e.Code) diff --git a/cmd/interchain-security-cdd/cmd/genaccounts.go b/cmd/interchain-security-cdd/cmd/genaccounts.go deleted file mode 100644 index c3340dccad..0000000000 --- a/cmd/interchain-security-cdd/cmd/genaccounts.go +++ /dev/null @@ -1,180 +0,0 @@ -package cmd - -import ( - "bufio" - "encoding/json" - "errors" - "fmt" - - "github.com/spf13/cobra" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/crypto/keyring" - "github.com/cosmos/cosmos-sdk/server" - sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - authvesting "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/cosmos/cosmos-sdk/x/genutil" - genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" -) - -const ( - flagVestingStart = "vesting-start-time" - flagVestingEnd = "vesting-end-time" - flagVestingAmt = "vesting-amount" -) - -// AddGenesisAccountCmd returns add-genesis-account cobra Command. -func AddGenesisAccountCmd(defaultNodeHome string) *cobra.Command { - cmd := &cobra.Command{ - Use: "add-genesis-account [address_or_key_name] [coin][,[coin]]", - Short: "Add a genesis account to genesis.json", - Long: `Add a genesis account to genesis.json. The provided account must specify -the account address or key name and a list of initial coins. If a key name is given, -the address will be looked up in the local Keybase. The list of initial tokens must -contain valid denominations. Accounts may optionally be supplied with vesting parameters. -`, - Args: cobra.ExactArgs(2), - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) - serverCtx := server.GetServerContextFromCmd(cmd) - config := serverCtx.Config - - config.SetRoot(clientCtx.HomeDir) - - var kr keyring.Keyring - addr, err := sdk.AccAddressFromBech32(args[0]) - if err != nil { - inBuf := bufio.NewReader(cmd.InOrStdin()) - keyringBackend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend) - if keyringBackend != "" && clientCtx.Keyring == nil { - var err error - kr, err = keyring.New(sdk.KeyringServiceName(), keyringBackend, clientCtx.HomeDir, inBuf) - if err != nil { - return err - } - } else { - kr = clientCtx.Keyring - } - - info, err := kr.Key(args[0]) - if err != nil { - return fmt.Errorf("failed to get address from Keyring: %w", err) - } - addr = info.GetAddress() - } - - coins, err := sdk.ParseCoinsNormalized(args[1]) - if err != nil { - return fmt.Errorf("failed to parse coins: %w", err) - } - - vestingStart, _ := cmd.Flags().GetInt64(flagVestingStart) - vestingEnd, _ := cmd.Flags().GetInt64(flagVestingEnd) - vestingAmtStr, _ := cmd.Flags().GetString(flagVestingAmt) - - vestingAmt, err := sdk.ParseCoinsNormalized(vestingAmtStr) - if err != nil { - return fmt.Errorf("failed to parse vesting amount: %w", err) - } - - // create concrete account type based on input parameters - var genAccount authtypes.GenesisAccount - - balances := banktypes.Balance{Address: addr.String(), Coins: coins.Sort()} - baseAccount := authtypes.NewBaseAccount(addr, nil, 0, 0) - - if !vestingAmt.IsZero() { - baseVestingAccount := authvesting.NewBaseVestingAccount(baseAccount, vestingAmt.Sort(), vestingEnd) - - if (balances.Coins.IsZero() && !baseVestingAccount.OriginalVesting.IsZero()) || - baseVestingAccount.OriginalVesting.IsAnyGT(balances.Coins) { - return errors.New("vesting amount cannot be greater than total amount") - } - - switch { - case vestingStart != 0 && vestingEnd != 0: - genAccount = authvesting.NewContinuousVestingAccountRaw(baseVestingAccount, vestingStart) - - case vestingEnd != 0: - genAccount = authvesting.NewDelayedVestingAccountRaw(baseVestingAccount) - - default: - return errors.New("invalid vesting parameters; must supply start and end time or end time") - } - } else { - genAccount = baseAccount - } - - if err := genAccount.Validate(); err != nil { - return fmt.Errorf("failed to validate new genesis account: %w", err) - } - - genFile := config.GenesisFile() - appState, genDoc, err := genutiltypes.GenesisStateFromGenFile(genFile) - if err != nil { - return fmt.Errorf("failed to unmarshal genesis state: %w", err) - } - - authGenState := authtypes.GetGenesisStateFromAppState(clientCtx.Codec, appState) - - accs, err := authtypes.UnpackAccounts(authGenState.Accounts) - if err != nil { - return fmt.Errorf("failed to get accounts from any: %w", err) - } - - if accs.Contains(addr) { - return fmt.Errorf("cannot add account at existing address %s", addr) - } - - // Add the new account to the set of genesis accounts and sanitize the - // accounts afterwards. - accs = append(accs, genAccount) - accs = authtypes.SanitizeGenesisAccounts(accs) - - genAccs, err := authtypes.PackAccounts(accs) - if err != nil { - return fmt.Errorf("failed to convert accounts into any's: %w", err) - } - authGenState.Accounts = genAccs - - authGenStateBz, err := clientCtx.Codec.MarshalJSON(&authGenState) - if err != nil { - return fmt.Errorf("failed to marshal auth genesis state: %w", err) - } - - appState[authtypes.ModuleName] = authGenStateBz - - bankGenState := banktypes.GetGenesisStateFromAppState(clientCtx.Codec, appState) - bankGenState.Balances = append(bankGenState.Balances, balances) - bankGenState.Balances = banktypes.SanitizeGenesisBalances(bankGenState.Balances) - bankGenState.Supply = bankGenState.Supply.Add(balances.Coins...) - - bankGenStateBz, err := clientCtx.Codec.MarshalJSON(bankGenState) - if err != nil { - return fmt.Errorf("failed to marshal bank genesis state: %w", err) - } - - appState[banktypes.ModuleName] = bankGenStateBz - - appStateJSON, err := json.Marshal(appState) - if err != nil { - return fmt.Errorf("failed to marshal application genesis state: %w", err) - } - - genDoc.AppState = appStateJSON - return genutil.ExportGenesisFile(genDoc, genFile) - }, - } - - cmd.Flags().String(flags.FlagHome, defaultNodeHome, "The application home directory") - cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|kwallet|pass|test)") - cmd.Flags().String(flagVestingAmt, "", "amount of coins for vesting accounts") - cmd.Flags().Int64(flagVestingStart, 0, "schedule start time (unix epoch) for vesting accounts") - cmd.Flags().Int64(flagVestingEnd, 0, "schedule end time (unix epoch) for vesting accounts") - flags.AddQueryFlagsToCmd(cmd) - - return cmd -} diff --git a/cmd/interchain-security-cdd/cmd/root.go b/cmd/interchain-security-cdd/cmd/root.go index 3586edafd8..615bdf499c 100644 --- a/cmd/interchain-security-cdd/cmd/root.go +++ b/cmd/interchain-security-cdd/cmd/root.go @@ -4,16 +4,15 @@ import ( "errors" "io" "os" - "path/filepath" + dbm "github.com/cometbft/cometbft-db" + "github.com/cometbft/cometbft/libs/log" serverconfig "github.com/cosmos/cosmos-sdk/server/config" - "github.com/spf13/cast" "github.com/spf13/cobra" - tmcli "github.com/tendermint/tendermint/libs/cli" - "github.com/tendermint/tendermint/libs/log" - dbm "github.com/tendermint/tm-db" + "github.com/spf13/viper" - "github.com/cosmos/cosmos-sdk/baseapp" + rosettaCmd "cosmossdk.io/tools/rosetta/cmd" + tmcfg "github.com/cometbft/cometbft/config" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/config" "github.com/cosmos/cosmos-sdk/client/debug" @@ -23,30 +22,37 @@ import ( "github.com/cosmos/cosmos-sdk/client/rpc" "github.com/cosmos/cosmos-sdk/server" servertypes "github.com/cosmos/cosmos-sdk/server/types" - "github.com/cosmos/cosmos-sdk/snapshots" - "github.com/cosmos/cosmos-sdk/store" + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" sdk "github.com/cosmos/cosmos-sdk/types" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" "github.com/cosmos/cosmos-sdk/x/auth/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/cosmos/cosmos-sdk/x/crisis" genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" - simapp "github.com/cosmos/interchain-security/v2/app/consumer-democracy" + + cdd "github.com/cosmos/interchain-security/v2/app/consumer-democracy" "github.com/cosmos/interchain-security/v2/app/params" ) // NewRootCmd creates a new root command for simd. It is called once in the // main function. -func NewRootCmd() (*cobra.Command, params.EncodingConfig) { - encodingConfig := simapp.MakeTestEncodingConfig() +func NewRootCmd() *cobra.Command { + // we "pre"-instantiate the application for getting the injected/configured encoding configuration + tempApp := cdd.New(log.NewNopLogger(), dbm.NewMemDB(), nil, true, simtestutil.NewAppOptionsWithFlagHome(cdd.DefaultNodeHome)) + encodingConfig := params.EncodingConfig{ + InterfaceRegistry: tempApp.InterfaceRegistry(), + Codec: tempApp.AppCodec(), + TxConfig: tempApp.TxConfig(), + Amino: tempApp.LegacyAmino(), + } + initClientCtx := client.Context{}. - WithCodec(encodingConfig.Marshaler). + WithCodec(encodingConfig.Codec). WithInterfaceRegistry(encodingConfig.InterfaceRegistry). WithTxConfig(encodingConfig.TxConfig). WithLegacyAmino(encodingConfig.Amino). WithInput(os.Stdin). WithAccountRetriever(types.AccountRetriever{}). - WithHomeDir(simapp.DefaultNodeHome). + WithHomeDir(cdd.DefaultNodeHome). WithViper("") // In simapp, we don't use any prefix for env variables. rootCmd := &cobra.Command{ @@ -72,14 +78,53 @@ func NewRootCmd() (*cobra.Command, params.EncodingConfig) { } customAppTemplate, customAppConfig := initAppConfig() + customTMConfig := initTendermintConfig() - return server.InterceptConfigsPreRunHandler(cmd, customAppTemplate, customAppConfig) + return server.InterceptConfigsPreRunHandler(cmd, customAppTemplate, customAppConfig, customTMConfig) }, } initRootCmd(rootCmd, encodingConfig) - return rootCmd, encodingConfig + return rootCmd +} + +// initTendermintConfig helps to override default Tendermint Config values. +// return tmcfg.DefaultConfig if no custom configuration is required for the application. +func initTendermintConfig() *tmcfg.Config { + cfg := tmcfg.DefaultConfig() + + // these values put a higher strain on node memory + // cfg.P2P.MaxNumInboundPeers = 100 + // cfg.P2P.MaxNumOutboundPeers = 40 + + return cfg +} + +func txCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "tx", + Short: "Transactions subcommands", + DisableFlagParsing: false, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand( + authcmd.GetSignCommand(), + authcmd.GetSignBatchCommand(), + authcmd.GetMultiSignCommand(), + authcmd.GetMultiSignBatchCmd(), + authcmd.GetValidateSignaturesCommand(), + authcmd.GetBroadcastCommand(), + authcmd.GetEncodeCommand(), + authcmd.GetDecodeCommand(), + authcmd.GetAuxToFeeCommand(), + ) + + cdd.ModuleBasics.AddTxCommands(cmd) + + return cmd } // initAppConfig helps to override default appConfig template and configs. @@ -143,44 +188,107 @@ func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) { cfg := sdk.GetConfig() cfg.Seal() - a := appCreator{encodingConfig} rootCmd.AddCommand( - genutilcli.InitCmd(simapp.ModuleBasics, simapp.DefaultNodeHome), - genutilcli.CollectGenTxsCmd(banktypes.GenesisBalancesIterator{}, simapp.DefaultNodeHome), - genutilcli.MigrateGenesisCmd(), - genutilcli.GenTxCmd(simapp.ModuleBasics, encodingConfig.TxConfig, banktypes.GenesisBalancesIterator{}, simapp.DefaultNodeHome), - genutilcli.ValidateGenesisCmd(simapp.ModuleBasics), - AddGenesisAccountCmd(simapp.DefaultNodeHome), - tmcli.NewCompletionCmd(rootCmd, true), + genutilcli.InitCmd(cdd.ModuleBasics, cdd.DefaultNodeHome), debug.Cmd(), config.Cmd(), - pruning.PruningCmd(a.newApp), + pruning.PruningCmd(newApp), ) - server.AddCommands(rootCmd, simapp.DefaultNodeHome, a.newApp, a.appExport, addModuleInitFlags) + server.AddCommands(rootCmd, cdd.DefaultNodeHome, newApp, appExport, addModuleInitFlags) - // add keybase, auxiliary RPC, query, and tx child commands + // add keybase, auxiliary RPC, query, genesis, and tx child commands rootCmd.AddCommand( rpc.StatusCommand(), + genesisCommand(encodingConfig), queryCommand(), txCommand(), - keys.Commands(simapp.DefaultNodeHome), + keys.Commands(cdd.DefaultNodeHome), ) // add rosetta - rootCmd.AddCommand(server.RosettaCommand(encodingConfig.InterfaceRegistry, encodingConfig.Marshaler)) + rootCmd.AddCommand(rosettaCmd.RosettaCommand(encodingConfig.InterfaceRegistry, encodingConfig.Codec)) +} + +// newApp is an appCreator +// newApp creates the application +func newApp( + logger log.Logger, + db dbm.DB, + traceStore io.Writer, + appOpts servertypes.AppOptions, +) servertypes.Application { + baseappOptions := server.DefaultBaseappOptions(appOpts) + + return cdd.New( + logger, db, traceStore, true, + appOpts, + baseappOptions..., + ) +} + +// appExport creates a new simapp (optionally at a given height) and exports state. +func appExport( + logger log.Logger, + db dbm.DB, + traceStore io.Writer, + height int64, + forZeroHeight bool, + jailAllowedAddrs []string, + appOpts servertypes.AppOptions, + modulesToExport []string, +) (servertypes.ExportedApp, error) { + var simApp *cdd.App + + // this check is necessary as we use the flag in x/upgrade. + // we can exit more gracefully by checking the flag here. + homePath, ok := appOpts.Get(flags.FlagHome).(string) + if !ok || homePath == "" { + return servertypes.ExportedApp{}, errors.New("application home not set") + } + + viperAppOpts, ok := appOpts.(*viper.Viper) + if !ok { + return servertypes.ExportedApp{}, errors.New("appOpts is not viper.Viper") + } + + // overwrite the FlagInvCheckPeriod + viperAppOpts.Set(server.FlagInvCheckPeriod, 1) + appOpts = viperAppOpts + + if height != -1 { + simApp = cdd.New(logger, db, traceStore, false, appOpts) + + if err := simApp.LoadHeight(height); err != nil { + return servertypes.ExportedApp{}, err + } + } else { + simApp = cdd.New(logger, db, traceStore, true, appOpts) + } + + return simApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs, modulesToExport) } func addModuleInitFlags(startCmd *cobra.Command) { crisis.AddModuleInitFlags(startCmd) } +// genesisCommand builds genesis-related `simd genesis` command. Users may provide application specific commands as a parameter +func genesisCommand(encodingConfig params.EncodingConfig, cmds ...*cobra.Command) *cobra.Command { + cmd := genutilcli.GenesisCoreCommand(encodingConfig.TxConfig, cdd.ModuleBasics, cdd.DefaultNodeHome) + + for _, sub_cmd := range cmds { + cmd.AddCommand(sub_cmd) + } + return cmd +} + func queryCommand() *cobra.Command { cmd := &cobra.Command{ Use: "query", Aliases: []string{"q"}, Short: "Querying subcommands", - DisableFlagParsing: true, + DisableFlagParsing: false, SuggestionsMinimumDistance: 2, RunE: client.ValidateCmd, } @@ -193,113 +301,7 @@ func queryCommand() *cobra.Command { authcmd.QueryTxCmd(), ) - simapp.ModuleBasics.AddQueryCommands(cmd) - cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID") - - return cmd -} - -func txCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "tx", - Short: "Transactions subcommands", - DisableFlagParsing: true, - SuggestionsMinimumDistance: 2, - RunE: client.ValidateCmd, - } - - cmd.AddCommand( - authcmd.GetSignCommand(), - authcmd.GetSignBatchCommand(), - authcmd.GetMultiSignCommand(), - authcmd.GetMultiSignBatchCmd(), - authcmd.GetValidateSignaturesCommand(), - authcmd.GetBroadcastCommand(), - authcmd.GetEncodeCommand(), - authcmd.GetDecodeCommand(), - ) - - simapp.ModuleBasics.AddTxCommands(cmd) - cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID") + cdd.ModuleBasics.AddQueryCommands(cmd) return cmd } - -type appCreator struct { - encCfg params.EncodingConfig -} - -// newApp is an appCreator -func (a appCreator) newApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts servertypes.AppOptions) servertypes.Application { - var cache sdk.MultiStorePersistentCache - - if cast.ToBool(appOpts.Get(server.FlagInterBlockCache)) { - cache = store.NewCommitKVStoreCacheManager() - } - - skipUpgradeHeights := make(map[int64]bool) - for _, h := range cast.ToIntSlice(appOpts.Get(server.FlagUnsafeSkipUpgrades)) { - skipUpgradeHeights[int64(h)] = true - } - - pruningOpts, err := server.GetPruningOptionsFromFlags(appOpts) - if err != nil { - panic(err) - } - - snapshotDir := filepath.Join(cast.ToString(appOpts.Get(flags.FlagHome)), "data", "snapshots") - snapshotDB, err := sdk.NewLevelDB("metadata", snapshotDir) - if err != nil { - panic(err) - } - snapshotStore, err := snapshots.NewStore(snapshotDB, snapshotDir) - if err != nil { - panic(err) - } - - return simapp.New( - logger, db, traceStore, true, skipUpgradeHeights, - cast.ToString(appOpts.Get(flags.FlagHome)), - cast.ToUint(appOpts.Get(server.FlagInvCheckPeriod)), - a.encCfg, - appOpts, - baseapp.SetPruning(pruningOpts), - baseapp.SetMinGasPrices(cast.ToString(appOpts.Get(server.FlagMinGasPrices))), - baseapp.SetHaltHeight(cast.ToUint64(appOpts.Get(server.FlagHaltHeight))), - baseapp.SetHaltTime(cast.ToUint64(appOpts.Get(server.FlagHaltTime))), - baseapp.SetMinRetainBlocks(cast.ToUint64(appOpts.Get(server.FlagMinRetainBlocks))), - baseapp.SetInterBlockCache(cache), - baseapp.SetTrace(cast.ToBool(appOpts.Get(server.FlagTrace))), - baseapp.SetIndexEvents(cast.ToStringSlice(appOpts.Get(server.FlagIndexEvents))), - baseapp.SetSnapshotStore(snapshotStore), - baseapp.SetSnapshotInterval(cast.ToUint64(appOpts.Get(server.FlagStateSyncSnapshotInterval))), - baseapp.SetSnapshotKeepRecent(cast.ToUint32(appOpts.Get(server.FlagStateSyncSnapshotKeepRecent))), - baseapp.SetIAVLCacheSize(cast.ToInt(appOpts.Get(server.FlagIAVLCacheSize))), - baseapp.SetIAVLDisableFastNode(cast.ToBool(appOpts.Get(server.FlagDisableIAVLFastNode))), - ) -} - -// appExport creates a new simapp (optionally at a given height) -// and exports state. -func (a appCreator) appExport( - logger log.Logger, db dbm.DB, traceStore io.Writer, height int64, forZeroHeight bool, jailAllowedAddrs []string, - appOpts servertypes.AppOptions, -) (servertypes.ExportedApp, error) { - var simApp *simapp.App - homePath, ok := appOpts.Get(flags.FlagHome).(string) - if !ok || homePath == "" { - return servertypes.ExportedApp{}, errors.New("application home not set") - } - - if height != -1 { - simApp = simapp.New(logger, db, traceStore, false, map[int64]bool{}, homePath, uint(1), a.encCfg, appOpts) - - if err := simApp.LoadHeight(height); err != nil { - return servertypes.ExportedApp{}, err - } - } else { - simApp = simapp.New(logger, db, traceStore, true, map[int64]bool{}, homePath, uint(1), a.encCfg, appOpts) - } - - return simApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs) -} diff --git a/cmd/interchain-security-cdd/main.go b/cmd/interchain-security-cdd/main.go index 427fa3ae7d..f209f0046a 100644 --- a/cmd/interchain-security-cdd/main.go +++ b/cmd/interchain-security-cdd/main.go @@ -10,9 +10,9 @@ import ( ) func main() { - rootCmd, _ := cmd.NewRootCmd() + rootCmd := cmd.NewRootCmd() - if err := svrcmd.Execute(rootCmd, app.DefaultNodeHome); err != nil { + if err := svrcmd.Execute(rootCmd, "", app.DefaultNodeHome); err != nil { switch e := err.(type) { case server.ErrorCode: os.Exit(e.Code) diff --git a/cmd/interchain-security-pd/cmd/genaccounts.go b/cmd/interchain-security-pd/cmd/genaccounts.go deleted file mode 100644 index c3340dccad..0000000000 --- a/cmd/interchain-security-pd/cmd/genaccounts.go +++ /dev/null @@ -1,180 +0,0 @@ -package cmd - -import ( - "bufio" - "encoding/json" - "errors" - "fmt" - - "github.com/spf13/cobra" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/crypto/keyring" - "github.com/cosmos/cosmos-sdk/server" - sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - authvesting "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/cosmos/cosmos-sdk/x/genutil" - genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" -) - -const ( - flagVestingStart = "vesting-start-time" - flagVestingEnd = "vesting-end-time" - flagVestingAmt = "vesting-amount" -) - -// AddGenesisAccountCmd returns add-genesis-account cobra Command. -func AddGenesisAccountCmd(defaultNodeHome string) *cobra.Command { - cmd := &cobra.Command{ - Use: "add-genesis-account [address_or_key_name] [coin][,[coin]]", - Short: "Add a genesis account to genesis.json", - Long: `Add a genesis account to genesis.json. The provided account must specify -the account address or key name and a list of initial coins. If a key name is given, -the address will be looked up in the local Keybase. The list of initial tokens must -contain valid denominations. Accounts may optionally be supplied with vesting parameters. -`, - Args: cobra.ExactArgs(2), - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) - serverCtx := server.GetServerContextFromCmd(cmd) - config := serverCtx.Config - - config.SetRoot(clientCtx.HomeDir) - - var kr keyring.Keyring - addr, err := sdk.AccAddressFromBech32(args[0]) - if err != nil { - inBuf := bufio.NewReader(cmd.InOrStdin()) - keyringBackend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend) - if keyringBackend != "" && clientCtx.Keyring == nil { - var err error - kr, err = keyring.New(sdk.KeyringServiceName(), keyringBackend, clientCtx.HomeDir, inBuf) - if err != nil { - return err - } - } else { - kr = clientCtx.Keyring - } - - info, err := kr.Key(args[0]) - if err != nil { - return fmt.Errorf("failed to get address from Keyring: %w", err) - } - addr = info.GetAddress() - } - - coins, err := sdk.ParseCoinsNormalized(args[1]) - if err != nil { - return fmt.Errorf("failed to parse coins: %w", err) - } - - vestingStart, _ := cmd.Flags().GetInt64(flagVestingStart) - vestingEnd, _ := cmd.Flags().GetInt64(flagVestingEnd) - vestingAmtStr, _ := cmd.Flags().GetString(flagVestingAmt) - - vestingAmt, err := sdk.ParseCoinsNormalized(vestingAmtStr) - if err != nil { - return fmt.Errorf("failed to parse vesting amount: %w", err) - } - - // create concrete account type based on input parameters - var genAccount authtypes.GenesisAccount - - balances := banktypes.Balance{Address: addr.String(), Coins: coins.Sort()} - baseAccount := authtypes.NewBaseAccount(addr, nil, 0, 0) - - if !vestingAmt.IsZero() { - baseVestingAccount := authvesting.NewBaseVestingAccount(baseAccount, vestingAmt.Sort(), vestingEnd) - - if (balances.Coins.IsZero() && !baseVestingAccount.OriginalVesting.IsZero()) || - baseVestingAccount.OriginalVesting.IsAnyGT(balances.Coins) { - return errors.New("vesting amount cannot be greater than total amount") - } - - switch { - case vestingStart != 0 && vestingEnd != 0: - genAccount = authvesting.NewContinuousVestingAccountRaw(baseVestingAccount, vestingStart) - - case vestingEnd != 0: - genAccount = authvesting.NewDelayedVestingAccountRaw(baseVestingAccount) - - default: - return errors.New("invalid vesting parameters; must supply start and end time or end time") - } - } else { - genAccount = baseAccount - } - - if err := genAccount.Validate(); err != nil { - return fmt.Errorf("failed to validate new genesis account: %w", err) - } - - genFile := config.GenesisFile() - appState, genDoc, err := genutiltypes.GenesisStateFromGenFile(genFile) - if err != nil { - return fmt.Errorf("failed to unmarshal genesis state: %w", err) - } - - authGenState := authtypes.GetGenesisStateFromAppState(clientCtx.Codec, appState) - - accs, err := authtypes.UnpackAccounts(authGenState.Accounts) - if err != nil { - return fmt.Errorf("failed to get accounts from any: %w", err) - } - - if accs.Contains(addr) { - return fmt.Errorf("cannot add account at existing address %s", addr) - } - - // Add the new account to the set of genesis accounts and sanitize the - // accounts afterwards. - accs = append(accs, genAccount) - accs = authtypes.SanitizeGenesisAccounts(accs) - - genAccs, err := authtypes.PackAccounts(accs) - if err != nil { - return fmt.Errorf("failed to convert accounts into any's: %w", err) - } - authGenState.Accounts = genAccs - - authGenStateBz, err := clientCtx.Codec.MarshalJSON(&authGenState) - if err != nil { - return fmt.Errorf("failed to marshal auth genesis state: %w", err) - } - - appState[authtypes.ModuleName] = authGenStateBz - - bankGenState := banktypes.GetGenesisStateFromAppState(clientCtx.Codec, appState) - bankGenState.Balances = append(bankGenState.Balances, balances) - bankGenState.Balances = banktypes.SanitizeGenesisBalances(bankGenState.Balances) - bankGenState.Supply = bankGenState.Supply.Add(balances.Coins...) - - bankGenStateBz, err := clientCtx.Codec.MarshalJSON(bankGenState) - if err != nil { - return fmt.Errorf("failed to marshal bank genesis state: %w", err) - } - - appState[banktypes.ModuleName] = bankGenStateBz - - appStateJSON, err := json.Marshal(appState) - if err != nil { - return fmt.Errorf("failed to marshal application genesis state: %w", err) - } - - genDoc.AppState = appStateJSON - return genutil.ExportGenesisFile(genDoc, genFile) - }, - } - - cmd.Flags().String(flags.FlagHome, defaultNodeHome, "The application home directory") - cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|kwallet|pass|test)") - cmd.Flags().String(flagVestingAmt, "", "amount of coins for vesting accounts") - cmd.Flags().Int64(flagVestingStart, 0, "schedule start time (unix epoch) for vesting accounts") - cmd.Flags().Int64(flagVestingEnd, 0, "schedule end time (unix epoch) for vesting accounts") - flags.AddQueryFlagsToCmd(cmd) - - return cmd -} diff --git a/cmd/interchain-security-pd/cmd/root.go b/cmd/interchain-security-pd/cmd/root.go index 69341b917b..e480acfc34 100644 --- a/cmd/interchain-security-pd/cmd/root.go +++ b/cmd/interchain-security-pd/cmd/root.go @@ -4,16 +4,15 @@ import ( "errors" "io" "os" - "path/filepath" + dbm "github.com/cometbft/cometbft-db" + "github.com/cometbft/cometbft/libs/log" serverconfig "github.com/cosmos/cosmos-sdk/server/config" - "github.com/spf13/cast" "github.com/spf13/cobra" - tmcli "github.com/tendermint/tendermint/libs/cli" - "github.com/tendermint/tendermint/libs/log" - dbm "github.com/tendermint/tm-db" + "github.com/spf13/viper" - "github.com/cosmos/cosmos-sdk/baseapp" + rosettaCmd "cosmossdk.io/tools/rosetta/cmd" + tmcfg "github.com/cometbft/cometbft/config" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/config" "github.com/cosmos/cosmos-sdk/client/debug" @@ -23,30 +22,36 @@ import ( "github.com/cosmos/cosmos-sdk/client/rpc" "github.com/cosmos/cosmos-sdk/server" servertypes "github.com/cosmos/cosmos-sdk/server/types" - "github.com/cosmos/cosmos-sdk/snapshots" - "github.com/cosmos/cosmos-sdk/store" + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" sdk "github.com/cosmos/cosmos-sdk/types" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" "github.com/cosmos/cosmos-sdk/x/auth/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/cosmos/cosmos-sdk/x/crisis" genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" "github.com/cosmos/interchain-security/v2/app/params" - simapp "github.com/cosmos/interchain-security/v2/app/provider" + providerApp "github.com/cosmos/interchain-security/v2/app/provider" ) // NewRootCmd creates a new root command for simd. It is called once in the // main function. -func NewRootCmd() (*cobra.Command, params.EncodingConfig) { - encodingConfig := simapp.MakeTestEncodingConfig() +func NewRootCmd() *cobra.Command { + // we "pre"-instantiate the application for getting the injected/configured encoding configuration + tempApp := providerApp.New(log.NewNopLogger(), dbm.NewMemDB(), nil, true, simtestutil.NewAppOptionsWithFlagHome(providerApp.DefaultNodeHome)) + encodingConfig := params.EncodingConfig{ + InterfaceRegistry: tempApp.InterfaceRegistry(), + Codec: tempApp.AppCodec(), + TxConfig: tempApp.TxConfig(), + Amino: tempApp.LegacyAmino(), + } + initClientCtx := client.Context{}. - WithCodec(encodingConfig.Marshaler). + WithCodec(encodingConfig.Codec). WithInterfaceRegistry(encodingConfig.InterfaceRegistry). WithTxConfig(encodingConfig.TxConfig). WithLegacyAmino(encodingConfig.Amino). WithInput(os.Stdin). WithAccountRetriever(types.AccountRetriever{}). - WithHomeDir(simapp.DefaultNodeHome). + WithHomeDir(providerApp.DefaultNodeHome). WithViper("") // In simapp, we don't use any prefix for env variables. rootCmd := &cobra.Command{ @@ -72,14 +77,53 @@ func NewRootCmd() (*cobra.Command, params.EncodingConfig) { } customAppTemplate, customAppConfig := initAppConfig() + customTMConfig := initTendermintConfig() - return server.InterceptConfigsPreRunHandler(cmd, customAppTemplate, customAppConfig) + return server.InterceptConfigsPreRunHandler(cmd, customAppTemplate, customAppConfig, customTMConfig) }, } initRootCmd(rootCmd, encodingConfig) - return rootCmd, encodingConfig + return rootCmd +} + +// initTendermintConfig helps to override default Tendermint Config values. +// return tmcfg.DefaultConfig if no custom configuration is required for the application. +func initTendermintConfig() *tmcfg.Config { + cfg := tmcfg.DefaultConfig() + + // these values put a higher strain on node memory + // cfg.P2P.MaxNumInboundPeers = 100 + // cfg.P2P.MaxNumOutboundPeers = 40 + + return cfg +} + +func txCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "tx", + Short: "Transactions subcommands", + DisableFlagParsing: false, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand( + authcmd.GetSignCommand(), + authcmd.GetSignBatchCommand(), + authcmd.GetMultiSignCommand(), + authcmd.GetMultiSignBatchCmd(), + authcmd.GetValidateSignaturesCommand(), + authcmd.GetBroadcastCommand(), + authcmd.GetEncodeCommand(), + authcmd.GetDecodeCommand(), + authcmd.GetAuxToFeeCommand(), + ) + + providerApp.ModuleBasics.AddTxCommands(cmd) + + return cmd } // initAppConfig helps to override default appConfig template and configs. @@ -143,44 +187,106 @@ func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) { cfg := sdk.GetConfig() cfg.Seal() - a := appCreator{encodingConfig} rootCmd.AddCommand( - genutilcli.InitCmd(simapp.ModuleBasics, simapp.DefaultNodeHome), - genutilcli.CollectGenTxsCmd(banktypes.GenesisBalancesIterator{}, simapp.DefaultNodeHome), - genutilcli.MigrateGenesisCmd(), - genutilcli.GenTxCmd(simapp.ModuleBasics, encodingConfig.TxConfig, banktypes.GenesisBalancesIterator{}, simapp.DefaultNodeHome), - genutilcli.ValidateGenesisCmd(simapp.ModuleBasics), - AddGenesisAccountCmd(simapp.DefaultNodeHome), - tmcli.NewCompletionCmd(rootCmd, true), + genutilcli.InitCmd(providerApp.ModuleBasics, providerApp.DefaultNodeHome), debug.Cmd(), config.Cmd(), - pruning.PruningCmd(a.newApp), + pruning.PruningCmd(newApp), ) - server.AddCommands(rootCmd, simapp.DefaultNodeHome, a.newApp, a.appExport, addModuleInitFlags) + server.AddCommands(rootCmd, providerApp.DefaultNodeHome, newApp, appExport, addModuleInitFlags) - // add keybase, auxiliary RPC, query, and tx child commands + // add keybase, auxiliary RPC, query, genesis, and tx child commands rootCmd.AddCommand( rpc.StatusCommand(), + genesisCommand(encodingConfig), queryCommand(), txCommand(), - keys.Commands(simapp.DefaultNodeHome), + keys.Commands(providerApp.DefaultNodeHome), ) // add rosetta - rootCmd.AddCommand(server.RosettaCommand(encodingConfig.InterfaceRegistry, encodingConfig.Marshaler)) + rootCmd.AddCommand(rosettaCmd.RosettaCommand(encodingConfig.InterfaceRegistry, encodingConfig.Codec)) +} + +// newApp is an appCreator +// newApp creates the application +func newApp( + logger log.Logger, + db dbm.DB, + traceStore io.Writer, + appOpts servertypes.AppOptions, +) servertypes.Application { + baseappOptions := server.DefaultBaseappOptions(appOpts) + + return providerApp.New( + logger, db, traceStore, true, + appOpts, + baseappOptions..., + ) +} + +// appExport creates a new simapp (optionally at a given height) and exports state. +func appExport( + logger log.Logger, + db dbm.DB, + traceStore io.Writer, + height int64, + forZeroHeight bool, + jailAllowedAddrs []string, + appOpts servertypes.AppOptions, + modulesToExport []string, +) (servertypes.ExportedApp, error) { + var simApp *providerApp.App + + // this check is necessary as we use the flag in x/upgrade. + // we can exit more gracefully by checking the flag here. + homePath, ok := appOpts.Get(flags.FlagHome).(string) + if !ok || homePath == "" { + return servertypes.ExportedApp{}, errors.New("application home not set") + } + + viperAppOpts, ok := appOpts.(*viper.Viper) + if !ok { + return servertypes.ExportedApp{}, errors.New("appOpts is not viper.Viper") + } + + // overwrite the FlagInvCheckPeriod + viperAppOpts.Set(server.FlagInvCheckPeriod, 1) + appOpts = viperAppOpts + + if height != -1 { + simApp = providerApp.New(logger, db, traceStore, false, appOpts) + + if err := simApp.LoadHeight(height); err != nil { + return servertypes.ExportedApp{}, err + } + } else { + simApp = providerApp.New(logger, db, traceStore, true, appOpts) + } + + return simApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs, modulesToExport) } func addModuleInitFlags(startCmd *cobra.Command) { crisis.AddModuleInitFlags(startCmd) } +// genesisCommand builds genesis-related `simd genesis` command. Users may provide application specific commands as a parameter +func genesisCommand(encodingConfig params.EncodingConfig, cmds ...*cobra.Command) *cobra.Command { + cmd := genutilcli.GenesisCoreCommand(encodingConfig.TxConfig, providerApp.ModuleBasics, providerApp.DefaultNodeHome) + for _, sub_cmd := range cmds { + cmd.AddCommand(sub_cmd) + } + return cmd +} + func queryCommand() *cobra.Command { cmd := &cobra.Command{ Use: "query", Aliases: []string{"q"}, Short: "Querying subcommands", - DisableFlagParsing: true, + DisableFlagParsing: false, SuggestionsMinimumDistance: 2, RunE: client.ValidateCmd, } @@ -191,115 +297,11 @@ func queryCommand() *cobra.Command { rpc.BlockCommand(), authcmd.QueryTxsByEventsCmd(), authcmd.QueryTxCmd(), - ) - - simapp.ModuleBasics.AddQueryCommands(cmd) - cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID") - - return cmd -} - -func txCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "tx", - Short: "Transactions subcommands", - DisableFlagParsing: true, - SuggestionsMinimumDistance: 2, - RunE: client.ValidateCmd, - } - - cmd.AddCommand( - authcmd.GetSignCommand(), - authcmd.GetSignBatchCommand(), - authcmd.GetMultiSignCommand(), - authcmd.GetMultiSignBatchCmd(), - authcmd.GetValidateSignaturesCommand(), - authcmd.GetBroadcastCommand(), authcmd.GetEncodeCommand(), authcmd.GetDecodeCommand(), ) - simapp.ModuleBasics.AddTxCommands(cmd) - cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID") + providerApp.ModuleBasics.AddQueryCommands(cmd) return cmd } - -type appCreator struct { - encCfg params.EncodingConfig -} - -// newApp is an appCreator -func (a appCreator) newApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts servertypes.AppOptions) servertypes.Application { - var cache sdk.MultiStorePersistentCache - - if cast.ToBool(appOpts.Get(server.FlagInterBlockCache)) { - cache = store.NewCommitKVStoreCacheManager() - } - - skipUpgradeHeights := make(map[int64]bool) - for _, h := range cast.ToIntSlice(appOpts.Get(server.FlagUnsafeSkipUpgrades)) { - skipUpgradeHeights[int64(h)] = true - } - - pruningOpts, err := server.GetPruningOptionsFromFlags(appOpts) - if err != nil { - panic(err) - } - - snapshotDir := filepath.Join(cast.ToString(appOpts.Get(flags.FlagHome)), "data", "snapshots") - snapshotDB, err := sdk.NewLevelDB("metadata", snapshotDir) - if err != nil { - panic(err) - } - snapshotStore, err := snapshots.NewStore(snapshotDB, snapshotDir) - if err != nil { - panic(err) - } - - return simapp.New( - logger, db, traceStore, true, skipUpgradeHeights, - cast.ToString(appOpts.Get(flags.FlagHome)), - cast.ToUint(appOpts.Get(server.FlagInvCheckPeriod)), - a.encCfg, - appOpts, - baseapp.SetPruning(pruningOpts), - baseapp.SetMinGasPrices(cast.ToString(appOpts.Get(server.FlagMinGasPrices))), - baseapp.SetHaltHeight(cast.ToUint64(appOpts.Get(server.FlagHaltHeight))), - baseapp.SetHaltTime(cast.ToUint64(appOpts.Get(server.FlagHaltTime))), - baseapp.SetMinRetainBlocks(cast.ToUint64(appOpts.Get(server.FlagMinRetainBlocks))), - baseapp.SetInterBlockCache(cache), - baseapp.SetTrace(cast.ToBool(appOpts.Get(server.FlagTrace))), - baseapp.SetIndexEvents(cast.ToStringSlice(appOpts.Get(server.FlagIndexEvents))), - baseapp.SetSnapshotStore(snapshotStore), - baseapp.SetSnapshotInterval(cast.ToUint64(appOpts.Get(server.FlagStateSyncSnapshotInterval))), - baseapp.SetSnapshotKeepRecent(cast.ToUint32(appOpts.Get(server.FlagStateSyncSnapshotKeepRecent))), - baseapp.SetIAVLCacheSize(cast.ToInt(appOpts.Get(server.FlagIAVLCacheSize))), - baseapp.SetIAVLDisableFastNode(cast.ToBool(appOpts.Get(server.FlagDisableIAVLFastNode))), - ) -} - -// appExport creates a new simapp (optionally at a given height) -// and exports state. -func (a appCreator) appExport( - logger log.Logger, db dbm.DB, traceStore io.Writer, height int64, forZeroHeight bool, jailAllowedAddrs []string, - appOpts servertypes.AppOptions, -) (servertypes.ExportedApp, error) { - var simApp *simapp.App - homePath, ok := appOpts.Get(flags.FlagHome).(string) - if !ok || homePath == "" { - return servertypes.ExportedApp{}, errors.New("application home not set") - } - - if height != -1 { - simApp = simapp.New(logger, db, traceStore, false, map[int64]bool{}, homePath, uint(1), a.encCfg, appOpts) - - if err := simApp.LoadHeight(height); err != nil { - return servertypes.ExportedApp{}, err - } - } else { - simApp = simapp.New(logger, db, traceStore, true, map[int64]bool{}, homePath, uint(1), a.encCfg, appOpts) - } - - return simApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs) -} diff --git a/cmd/interchain-security-pd/main.go b/cmd/interchain-security-pd/main.go index 09e145206a..d39371adc1 100644 --- a/cmd/interchain-security-pd/main.go +++ b/cmd/interchain-security-pd/main.go @@ -10,9 +10,9 @@ import ( ) func main() { - rootCmd, _ := cmd.NewRootCmd() + rootCmd := cmd.NewRootCmd() - if err := svrcmd.Execute(rootCmd, app.DefaultNodeHome); err != nil { + if err := svrcmd.Execute(rootCmd, "", app.DefaultNodeHome); err != nil { switch e := err.(type) { case server.ErrorCode: os.Exit(e.Code) diff --git a/cmd/interchain-security-sd/cmd/genaccounts.go b/cmd/interchain-security-sd/cmd/genaccounts.go deleted file mode 100644 index c3340dccad..0000000000 --- a/cmd/interchain-security-sd/cmd/genaccounts.go +++ /dev/null @@ -1,180 +0,0 @@ -package cmd - -import ( - "bufio" - "encoding/json" - "errors" - "fmt" - - "github.com/spf13/cobra" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/crypto/keyring" - "github.com/cosmos/cosmos-sdk/server" - sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - authvesting "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/cosmos/cosmos-sdk/x/genutil" - genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" -) - -const ( - flagVestingStart = "vesting-start-time" - flagVestingEnd = "vesting-end-time" - flagVestingAmt = "vesting-amount" -) - -// AddGenesisAccountCmd returns add-genesis-account cobra Command. -func AddGenesisAccountCmd(defaultNodeHome string) *cobra.Command { - cmd := &cobra.Command{ - Use: "add-genesis-account [address_or_key_name] [coin][,[coin]]", - Short: "Add a genesis account to genesis.json", - Long: `Add a genesis account to genesis.json. The provided account must specify -the account address or key name and a list of initial coins. If a key name is given, -the address will be looked up in the local Keybase. The list of initial tokens must -contain valid denominations. Accounts may optionally be supplied with vesting parameters. -`, - Args: cobra.ExactArgs(2), - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) - serverCtx := server.GetServerContextFromCmd(cmd) - config := serverCtx.Config - - config.SetRoot(clientCtx.HomeDir) - - var kr keyring.Keyring - addr, err := sdk.AccAddressFromBech32(args[0]) - if err != nil { - inBuf := bufio.NewReader(cmd.InOrStdin()) - keyringBackend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend) - if keyringBackend != "" && clientCtx.Keyring == nil { - var err error - kr, err = keyring.New(sdk.KeyringServiceName(), keyringBackend, clientCtx.HomeDir, inBuf) - if err != nil { - return err - } - } else { - kr = clientCtx.Keyring - } - - info, err := kr.Key(args[0]) - if err != nil { - return fmt.Errorf("failed to get address from Keyring: %w", err) - } - addr = info.GetAddress() - } - - coins, err := sdk.ParseCoinsNormalized(args[1]) - if err != nil { - return fmt.Errorf("failed to parse coins: %w", err) - } - - vestingStart, _ := cmd.Flags().GetInt64(flagVestingStart) - vestingEnd, _ := cmd.Flags().GetInt64(flagVestingEnd) - vestingAmtStr, _ := cmd.Flags().GetString(flagVestingAmt) - - vestingAmt, err := sdk.ParseCoinsNormalized(vestingAmtStr) - if err != nil { - return fmt.Errorf("failed to parse vesting amount: %w", err) - } - - // create concrete account type based on input parameters - var genAccount authtypes.GenesisAccount - - balances := banktypes.Balance{Address: addr.String(), Coins: coins.Sort()} - baseAccount := authtypes.NewBaseAccount(addr, nil, 0, 0) - - if !vestingAmt.IsZero() { - baseVestingAccount := authvesting.NewBaseVestingAccount(baseAccount, vestingAmt.Sort(), vestingEnd) - - if (balances.Coins.IsZero() && !baseVestingAccount.OriginalVesting.IsZero()) || - baseVestingAccount.OriginalVesting.IsAnyGT(balances.Coins) { - return errors.New("vesting amount cannot be greater than total amount") - } - - switch { - case vestingStart != 0 && vestingEnd != 0: - genAccount = authvesting.NewContinuousVestingAccountRaw(baseVestingAccount, vestingStart) - - case vestingEnd != 0: - genAccount = authvesting.NewDelayedVestingAccountRaw(baseVestingAccount) - - default: - return errors.New("invalid vesting parameters; must supply start and end time or end time") - } - } else { - genAccount = baseAccount - } - - if err := genAccount.Validate(); err != nil { - return fmt.Errorf("failed to validate new genesis account: %w", err) - } - - genFile := config.GenesisFile() - appState, genDoc, err := genutiltypes.GenesisStateFromGenFile(genFile) - if err != nil { - return fmt.Errorf("failed to unmarshal genesis state: %w", err) - } - - authGenState := authtypes.GetGenesisStateFromAppState(clientCtx.Codec, appState) - - accs, err := authtypes.UnpackAccounts(authGenState.Accounts) - if err != nil { - return fmt.Errorf("failed to get accounts from any: %w", err) - } - - if accs.Contains(addr) { - return fmt.Errorf("cannot add account at existing address %s", addr) - } - - // Add the new account to the set of genesis accounts and sanitize the - // accounts afterwards. - accs = append(accs, genAccount) - accs = authtypes.SanitizeGenesisAccounts(accs) - - genAccs, err := authtypes.PackAccounts(accs) - if err != nil { - return fmt.Errorf("failed to convert accounts into any's: %w", err) - } - authGenState.Accounts = genAccs - - authGenStateBz, err := clientCtx.Codec.MarshalJSON(&authGenState) - if err != nil { - return fmt.Errorf("failed to marshal auth genesis state: %w", err) - } - - appState[authtypes.ModuleName] = authGenStateBz - - bankGenState := banktypes.GetGenesisStateFromAppState(clientCtx.Codec, appState) - bankGenState.Balances = append(bankGenState.Balances, balances) - bankGenState.Balances = banktypes.SanitizeGenesisBalances(bankGenState.Balances) - bankGenState.Supply = bankGenState.Supply.Add(balances.Coins...) - - bankGenStateBz, err := clientCtx.Codec.MarshalJSON(bankGenState) - if err != nil { - return fmt.Errorf("failed to marshal bank genesis state: %w", err) - } - - appState[banktypes.ModuleName] = bankGenStateBz - - appStateJSON, err := json.Marshal(appState) - if err != nil { - return fmt.Errorf("failed to marshal application genesis state: %w", err) - } - - genDoc.AppState = appStateJSON - return genutil.ExportGenesisFile(genDoc, genFile) - }, - } - - cmd.Flags().String(flags.FlagHome, defaultNodeHome, "The application home directory") - cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|kwallet|pass|test)") - cmd.Flags().String(flagVestingAmt, "", "amount of coins for vesting accounts") - cmd.Flags().Int64(flagVestingStart, 0, "schedule start time (unix epoch) for vesting accounts") - cmd.Flags().Int64(flagVestingEnd, 0, "schedule end time (unix epoch) for vesting accounts") - flags.AddQueryFlagsToCmd(cmd) - - return cmd -} diff --git a/cmd/interchain-security-sd/cmd/root.go b/cmd/interchain-security-sd/cmd/root.go index 56f9ad667b..955da62464 100644 --- a/cmd/interchain-security-sd/cmd/root.go +++ b/cmd/interchain-security-sd/cmd/root.go @@ -4,16 +4,15 @@ import ( "errors" "io" "os" - "path/filepath" + dbm "github.com/cometbft/cometbft-db" + "github.com/cometbft/cometbft/libs/log" serverconfig "github.com/cosmos/cosmos-sdk/server/config" - "github.com/spf13/cast" "github.com/spf13/cobra" - tmcli "github.com/tendermint/tendermint/libs/cli" - "github.com/tendermint/tendermint/libs/log" - dbm "github.com/tendermint/tm-db" + "github.com/spf13/viper" - "github.com/cosmos/cosmos-sdk/baseapp" + rosettaCmd "cosmossdk.io/tools/rosetta/cmd" + tmcfg "github.com/cometbft/cometbft/config" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/config" "github.com/cosmos/cosmos-sdk/client/debug" @@ -23,34 +22,40 @@ import ( "github.com/cosmos/cosmos-sdk/client/rpc" "github.com/cosmos/cosmos-sdk/server" servertypes "github.com/cosmos/cosmos-sdk/server/types" - "github.com/cosmos/cosmos-sdk/snapshots" - "github.com/cosmos/cosmos-sdk/store" + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" sdk "github.com/cosmos/cosmos-sdk/types" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" "github.com/cosmos/cosmos-sdk/x/auth/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/cosmos/cosmos-sdk/x/crisis" genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" "github.com/cosmos/interchain-security/v2/app/params" - simapp "github.com/cosmos/interchain-security/v2/app/sovereign" + sovereignApp "github.com/cosmos/interchain-security/v2/app/sovereign" ) // NewRootCmd creates a new root command for simd. It is called once in the // main function. -func NewRootCmd() (*cobra.Command, params.EncodingConfig) { - encodingConfig := simapp.MakeTestEncodingConfig() +func NewRootCmd() *cobra.Command { + // we "pre"-instantiate the application for getting the injected/configured encoding configuration + tempApp := sovereignApp.New(log.NewNopLogger(), dbm.NewMemDB(), nil, true, simtestutil.NewAppOptionsWithFlagHome(sovereignApp.DefaultNodeHome)) + encodingConfig := params.EncodingConfig{ + InterfaceRegistry: tempApp.InterfaceRegistry(), + Codec: tempApp.AppCodec(), + TxConfig: tempApp.TxConfig(), + Amino: tempApp.LegacyAmino(), + } + initClientCtx := client.Context{}. - WithCodec(encodingConfig.Marshaler). + WithCodec(encodingConfig.Codec). WithInterfaceRegistry(encodingConfig.InterfaceRegistry). WithTxConfig(encodingConfig.TxConfig). WithLegacyAmino(encodingConfig.Amino). WithInput(os.Stdin). WithAccountRetriever(types.AccountRetriever{}). - WithHomeDir(simapp.DefaultNodeHome). + WithHomeDir(sovereignApp.DefaultNodeHome). WithViper("") // In simapp, we don't use any prefix for env variables. rootCmd := &cobra.Command{ - Use: "interchain-security-sd", + Use: "simd", Short: "simulation app", PersistentPreRunE: func(cmd *cobra.Command, _ []string) error { // set the default command outputs @@ -72,14 +77,53 @@ func NewRootCmd() (*cobra.Command, params.EncodingConfig) { } customAppTemplate, customAppConfig := initAppConfig() + customTMConfig := initTendermintConfig() - return server.InterceptConfigsPreRunHandler(cmd, customAppTemplate, customAppConfig) + return server.InterceptConfigsPreRunHandler(cmd, customAppTemplate, customAppConfig, customTMConfig) }, } initRootCmd(rootCmd, encodingConfig) - return rootCmd, encodingConfig + return rootCmd +} + +// initTendermintConfig helps to override default Tendermint Config values. +// return tmcfg.DefaultConfig if no custom configuration is required for the application. +func initTendermintConfig() *tmcfg.Config { + cfg := tmcfg.DefaultConfig() + + // these values put a higher strain on node memory + // cfg.P2P.MaxNumInboundPeers = 100 + // cfg.P2P.MaxNumOutboundPeers = 40 + + return cfg +} + +func txCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "tx", + Short: "Transactions subcommands", + DisableFlagParsing: false, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand( + authcmd.GetSignCommand(), + authcmd.GetSignBatchCommand(), + authcmd.GetMultiSignCommand(), + authcmd.GetMultiSignBatchCmd(), + authcmd.GetValidateSignaturesCommand(), + authcmd.GetBroadcastCommand(), + authcmd.GetEncodeCommand(), + authcmd.GetDecodeCommand(), + authcmd.GetAuxToFeeCommand(), + ) + + sovereignApp.ModuleBasics.AddTxCommands(cmd) + + return cmd } // initAppConfig helps to override default appConfig template and configs. @@ -143,44 +187,106 @@ func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) { cfg := sdk.GetConfig() cfg.Seal() - a := appCreator{encodingConfig} rootCmd.AddCommand( - genutilcli.InitCmd(simapp.ModuleBasics, simapp.DefaultNodeHome), - genutilcli.CollectGenTxsCmd(banktypes.GenesisBalancesIterator{}, simapp.DefaultNodeHome), - genutilcli.MigrateGenesisCmd(), - genutilcli.GenTxCmd(simapp.ModuleBasics, encodingConfig.TxConfig, banktypes.GenesisBalancesIterator{}, simapp.DefaultNodeHome), - genutilcli.ValidateGenesisCmd(simapp.ModuleBasics), - AddGenesisAccountCmd(simapp.DefaultNodeHome), - tmcli.NewCompletionCmd(rootCmd, true), + genutilcli.InitCmd(sovereignApp.ModuleBasics, sovereignApp.DefaultNodeHome), debug.Cmd(), config.Cmd(), - pruning.PruningCmd(a.newApp), + pruning.PruningCmd(newApp), ) - server.AddCommands(rootCmd, simapp.DefaultNodeHome, a.newApp, a.appExport, addModuleInitFlags) + server.AddCommands(rootCmd, sovereignApp.DefaultNodeHome, newApp, appExport, addModuleInitFlags) - // add keybase, auxiliary RPC, query, and tx child commands + // add keybase, auxiliary RPC, query, genesis, and tx child commands rootCmd.AddCommand( rpc.StatusCommand(), + genesisCommand(encodingConfig), queryCommand(), txCommand(), - keys.Commands(simapp.DefaultNodeHome), + keys.Commands(sovereignApp.DefaultNodeHome), ) // add rosetta - rootCmd.AddCommand(server.RosettaCommand(encodingConfig.InterfaceRegistry, encodingConfig.Marshaler)) + rootCmd.AddCommand(rosettaCmd.RosettaCommand(encodingConfig.InterfaceRegistry, encodingConfig.Codec)) +} + +// newApp is an appCreator +// newApp creates the application +func newApp( + logger log.Logger, + db dbm.DB, + traceStore io.Writer, + appOpts servertypes.AppOptions, +) servertypes.Application { + baseappOptions := server.DefaultBaseappOptions(appOpts) + + return sovereignApp.New( + logger, db, traceStore, true, + appOpts, + baseappOptions..., + ) +} + +// appExport creates a new simapp (optionally at a given height) and exports state. +func appExport( + logger log.Logger, + db dbm.DB, + traceStore io.Writer, + height int64, + forZeroHeight bool, + jailAllowedAddrs []string, + appOpts servertypes.AppOptions, + modulesToExport []string, +) (servertypes.ExportedApp, error) { + var simApp *sovereignApp.App + + // this check is necessary as we use the flag in x/upgrade. + // we can exit more gracefully by checking the flag here. + homePath, ok := appOpts.Get(flags.FlagHome).(string) + if !ok || homePath == "" { + return servertypes.ExportedApp{}, errors.New("application home not set") + } + + viperAppOpts, ok := appOpts.(*viper.Viper) + if !ok { + return servertypes.ExportedApp{}, errors.New("appOpts is not viper.Viper") + } + + // overwrite the FlagInvCheckPeriod + viperAppOpts.Set(server.FlagInvCheckPeriod, 1) + appOpts = viperAppOpts + + if height != -1 { + simApp = sovereignApp.New(logger, db, traceStore, false, appOpts) + + if err := simApp.LoadHeight(height); err != nil { + return servertypes.ExportedApp{}, err + } + } else { + simApp = sovereignApp.New(logger, db, traceStore, true, appOpts) + } + + return simApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs, modulesToExport) } func addModuleInitFlags(startCmd *cobra.Command) { crisis.AddModuleInitFlags(startCmd) } +// genesisCommand builds genesis-related `simd genesis` command. Users may provide application specific commands as a parameter +func genesisCommand(encodingConfig params.EncodingConfig, cmds ...*cobra.Command) *cobra.Command { + cmd := genutilcli.GenesisCoreCommand(encodingConfig.TxConfig, sovereignApp.ModuleBasics, sovereignApp.DefaultNodeHome) + for _, sub_cmd := range cmds { + cmd.AddCommand(sub_cmd) + } + return cmd +} + func queryCommand() *cobra.Command { cmd := &cobra.Command{ Use: "query", Aliases: []string{"q"}, Short: "Querying subcommands", - DisableFlagParsing: true, + DisableFlagParsing: false, SuggestionsMinimumDistance: 2, RunE: client.ValidateCmd, } @@ -191,115 +297,11 @@ func queryCommand() *cobra.Command { rpc.BlockCommand(), authcmd.QueryTxsByEventsCmd(), authcmd.QueryTxCmd(), - ) - - simapp.ModuleBasics.AddQueryCommands(cmd) - cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID") - - return cmd -} - -func txCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "tx", - Short: "Transactions subcommands", - DisableFlagParsing: true, - SuggestionsMinimumDistance: 2, - RunE: client.ValidateCmd, - } - - cmd.AddCommand( - authcmd.GetSignCommand(), - authcmd.GetSignBatchCommand(), - authcmd.GetMultiSignCommand(), - authcmd.GetMultiSignBatchCmd(), - authcmd.GetValidateSignaturesCommand(), - authcmd.GetBroadcastCommand(), authcmd.GetEncodeCommand(), authcmd.GetDecodeCommand(), ) - simapp.ModuleBasics.AddTxCommands(cmd) - cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID") + sovereignApp.ModuleBasics.AddQueryCommands(cmd) return cmd } - -type appCreator struct { - encCfg params.EncodingConfig -} - -// newApp is an appCreator -func (a appCreator) newApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts servertypes.AppOptions) servertypes.Application { - var cache sdk.MultiStorePersistentCache - - if cast.ToBool(appOpts.Get(server.FlagInterBlockCache)) { - cache = store.NewCommitKVStoreCacheManager() - } - - skipUpgradeHeights := make(map[int64]bool) - for _, h := range cast.ToIntSlice(appOpts.Get(server.FlagUnsafeSkipUpgrades)) { - skipUpgradeHeights[int64(h)] = true - } - - pruningOpts, err := server.GetPruningOptionsFromFlags(appOpts) - if err != nil { - panic(err) - } - - snapshotDir := filepath.Join(cast.ToString(appOpts.Get(flags.FlagHome)), "data", "snapshots") - snapshotDB, err := sdk.NewLevelDB("metadata", snapshotDir) - if err != nil { - panic(err) - } - snapshotStore, err := snapshots.NewStore(snapshotDB, snapshotDir) - if err != nil { - panic(err) - } - - return simapp.New( - logger, db, traceStore, true, skipUpgradeHeights, - cast.ToString(appOpts.Get(flags.FlagHome)), - cast.ToUint(appOpts.Get(server.FlagInvCheckPeriod)), - a.encCfg, - appOpts, - baseapp.SetPruning(pruningOpts), - baseapp.SetMinGasPrices(cast.ToString(appOpts.Get(server.FlagMinGasPrices))), - baseapp.SetHaltHeight(cast.ToUint64(appOpts.Get(server.FlagHaltHeight))), - baseapp.SetHaltTime(cast.ToUint64(appOpts.Get(server.FlagHaltTime))), - baseapp.SetMinRetainBlocks(cast.ToUint64(appOpts.Get(server.FlagMinRetainBlocks))), - baseapp.SetInterBlockCache(cache), - baseapp.SetTrace(cast.ToBool(appOpts.Get(server.FlagTrace))), - baseapp.SetIndexEvents(cast.ToStringSlice(appOpts.Get(server.FlagIndexEvents))), - baseapp.SetSnapshotStore(snapshotStore), - baseapp.SetSnapshotInterval(cast.ToUint64(appOpts.Get(server.FlagStateSyncSnapshotInterval))), - baseapp.SetSnapshotKeepRecent(cast.ToUint32(appOpts.Get(server.FlagStateSyncSnapshotKeepRecent))), - baseapp.SetIAVLCacheSize(cast.ToInt(appOpts.Get(server.FlagIAVLCacheSize))), - baseapp.SetIAVLDisableFastNode(cast.ToBool(appOpts.Get(server.FlagDisableIAVLFastNode))), - ) -} - -// appExport creates a new simapp (optionally at a given height) -// and exports state. -func (a appCreator) appExport( - logger log.Logger, db dbm.DB, traceStore io.Writer, height int64, forZeroHeight bool, jailAllowedAddrs []string, - appOpts servertypes.AppOptions, -) (servertypes.ExportedApp, error) { - var simApp *simapp.App - homePath, ok := appOpts.Get(flags.FlagHome).(string) - if !ok || homePath == "" { - return servertypes.ExportedApp{}, errors.New("application home not set") - } - - if height != -1 { - simApp = simapp.New(logger, db, traceStore, false, map[int64]bool{}, homePath, uint(1), a.encCfg, appOpts) - - if err := simApp.LoadHeight(height); err != nil { - return servertypes.ExportedApp{}, err - } - } else { - simApp = simapp.New(logger, db, traceStore, true, map[int64]bool{}, homePath, uint(1), a.encCfg, appOpts) - } - - return simApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs) -} diff --git a/cmd/interchain-security-sd/main.go b/cmd/interchain-security-sd/main.go index 6b43e7b396..42675b10d2 100644 --- a/cmd/interchain-security-sd/main.go +++ b/cmd/interchain-security-sd/main.go @@ -10,9 +10,9 @@ import ( ) func main() { - rootCmd, _ := cmd.NewRootCmd() + rootCmd := cmd.NewRootCmd() - if err := svrcmd.Execute(rootCmd, app.DefaultNodeHome); err != nil { + if err := svrcmd.Execute(rootCmd, "", app.DefaultNodeHome); err != nil { switch e := err.(type) { case server.ErrorCode: os.Exit(e.Code) diff --git a/docs/docs/features/key-assignment.md b/docs/docs/features/key-assignment.md index 54d93359a7..c68343255c 100644 --- a/docs/docs/features/key-assignment.md +++ b/docs/docs/features/key-assignment.md @@ -3,6 +3,7 @@ sidebar_position: 1 --- # Key Assignment + Key Assignment (aka. as key delegation) allows validator operators to use different consensus keys for each consumer chain validator node that they operate. There are various reasons to use different consensus keys on different chains, but the main benefit is that validator's provider chain consensus key cannot be compromised if their consumer chain node (or other infrastructure) gets compromised. Interchain security module adds queries and transactions for assigning keys on consumer chains. @@ -14,40 +15,42 @@ By sending an `AssignConsumerKey` transaction, validators are able to indicate w Key assignment is handled only by the provider chain - the consumer chains are not aware of the fact that different consensus keys represent the same validator entity. ::: - ## Rules + - a key can be assigned before the consumer addition proposal passes on the provider - validator A cannot assign consumer key K to consumer chain X if there is already a validator B (B!=A) using K on the provider - validator A cannot assign consumer key K to consumer chain X if there is already a validator B using K on X - a new validator on the provider cannot use a consensus key K if K is already used by any validator on any consumer chain :::tip -Validators can use a different key for each consumer chain. +Validators can use a different key for each consumer chain. ::: - ## Adding a key First, create a new node on the consumer chain using the equivalent: + ```bash consumerd init ``` Then query your node for the consensus key. + ```bash consumerd tendermint show-validator # {"@type":"/cosmos.crypto.ed25519.PubKey","key":""} ``` Then, make an `assign-consensus-key` transaction on the provider chain in order to inform the provider chain about the consensus key you will be using for a specific consumer chain. -``` -gaiad tx provider assign-consensus-key '' --from --home --gas 900000 -b block -y -o json +```bash +gaiad tx provider assign-consensus-key '' --from --home --gas 900000 -b sync -y -o json ``` - `consumer-chain-id` is the string identifier of the consumer chain, as assigned on the provider chain - `consumer-pub-key` has the following format `{"@type":"/cosmos.crypto.ed25519.PubKey","key":""}` Check that the key was assigned correcly by querying the provider: + ```bash gaiad query provider validator-consumer-key cosmosvalcons1e....3xsj3ayzf4uv6 ``` @@ -63,8 +66,9 @@ gaiad query provider validator-provider-key consumervalcons1 You must use a `valcons` address. You can obtain it by querying your node on the consumer `consumerd tendermint show-address` ## Changing a key -To change your key, simply repeat all of the steps listed above. Take note that your old key will be remembered for at least the unbonding period of the consumer chain so any slashes can be correctly applied +To change your key, simply repeat all of the steps listed above. Take note that your old key will be remembered for at least the unbonding period of the consumer chain so any slashes can be correctly applied ## Removing a key + To remove a key, simply switch it back to the consensus key you have assigned on the provider chain by following steps in the `Adding a key` section and using your provider consensus key. diff --git a/docs/docs/validators/joining-testnet.md b/docs/docs/validators/joining-testnet.md index b9d9f8f9da..0e99c3710b 100644 --- a/docs/docs/validators/joining-testnet.md +++ b/docs/docs/validators/joining-testnet.md @@ -3,7 +3,8 @@ sidebar_position: 2 title: Joining Replicated Security testnet --- -# Introduction +## Introduction + This short guide will teach you how to join the [Replicated Security testnet](https://github.com/cosmos/testnets/tree/master/replicated-security). The experience gained in the testnet will prepare you for validating interchain secured chains. @@ -14,14 +15,14 @@ Provider and consumer chain represent distinct networks and infrastructures oper For general information about running cosmos-sdk based chains check out the [validator basics](https://hub.cosmos.network/main/validators/validator-setup.html) and [Running a Node section](https://docs.cosmos.network/main/run-node/run-node) of Cosmos SDK docs ::: -# Joining the provider chain +## Joining the provider chain + :::info At present, all validators of the provider chain must also validate all governance approved consumer chains. The consumer chains cannot have a validator set different than the provider, which means they cannot introduce validators that are not also validating the provider chain. ::: A comprehensive guide is available [here](https://github.com/cosmos/testnets/tree/master/replicated-security/provider). - ## Initialization First, initialize your `$NODE_HOME` using the `provider` chain binary. @@ -37,14 +38,16 @@ gaiad init $NODE_MONIKER --chain-id $CHAIN_ID --home $NODE_HOME Add your key to the keyring - more details available [here](https://docs.cosmos.network/main/run-node/keyring). In this example we will use the `test` keyring-backend. This option is not safe to use in production. + ```bash gaiad keys add --keyring-backend test # save the address as variable for later use MY_VALIDATOR_ADDRESS=$(gaiad keys show my_validator -a --keyring-backend test) -``` +``` Before issuing any transactions, use the `provider` testnet faucet to add funds to your address. + ```bash curl https://faucet.rs-testnet.polypore.xyz/request?address=$MY_VALIDATOR_ADDRESS&chain=provider @@ -82,6 +85,7 @@ Check this [guide](https://hub.cosmos.network/main/validators/validator-setup.ht After this step, your validator is created and you can start your node and catch up to the rest of the network. It is recommended that you use `statesync` to catch up to the rest of the network. You can use this script to modify your `config.toml` with the required statesync parameters. + ```bash # create the statesync script $: cd $NODE_HOME @@ -107,11 +111,13 @@ s|^(trust_hash[[:space:]]+=[[:space:]]+).*$|\1\"$TRUST_HASH\"|" $NODE_HOME/confi ``` Then, you can execute the script: + ```bash $: ./statesync.sh # setup config.toml for statesync ``` Finally, copy the provider genesis and start your node: + ```bash $: GENESIS_URL=https://github.com/cosmos/testnets/raw/master/replicated-security/provider/provider-genesis.json $: wget $GENESIS_URL -O genesis.json @@ -122,7 +128,8 @@ $: gaiad start --x-crisis-skip-assert-invariants --home $NODE_HOME --p2p.seeds=" Additional scripts to setup your nodes are available [here](https://github.com/cosmos/testnets/blob/master/replicated-security/provider/join-rs-provider.sh) and [here](https://github.com/cosmos/testnets/blob/master/replicated-security/provider/join-rs-provider-cv.sh). The scripts will configure your node and create the required services - the scripts only work in linux environments. -# Joining consumer chains +## Joining consumer chains + :::tip Once you reach the active set on the provider chain, you will be required to validate all available consumer chains. @@ -136,6 +143,7 @@ To join consumer chains, simply replicate the steps above for each consumer usin When running the provider chain and consumers on the same machine please update the `PORT` numbers for each of them and make sure they do not overlap (otherwise the binaries will not start). Important ports to re-configure: + - `--rpc.laddr` - `--p2p.laddr` - `--api.address` @@ -144,11 +152,13 @@ Important ports to re-configure: ::: ## Re-using consensus key + To reuse the key on the provider and consumer chains, simply initialize your consumer chain and place the `priv_validator_key.json` into the home directory of your consumer chain (`/config/priv_validator_key.json`). When you start the chain, the consensus key will be the same on the provider and the consumer chain. ## Assigning consensus keys + Whenever you initialize a new node, it will be configured with a consensus key you can use. ```bash @@ -161,16 +171,18 @@ consumerd tendermint show-validator ``` Then, let the provider know which key you will be using for the consumer chain: + ```bash # machine running the provider chain -gaiad tx provider assign-consensus-key consumer-1 '' --from --home $NODE_HOME --gas 900000 -b block -y -o json +gaiad tx provider assign-consensus-key consumer-1 '' --from --home $NODE_HOME --gas 900000 -b sync -y -o json ``` After this step, you are ready to copy the consumer genesis into your nodes's `/config` folder, start your consumer chain node and catch up to the network. ## Baryon -You can find the onboarding repo instructions for the Baryon chain [here](https://github.com/cosmos/testnets/blob/master/replicated-security/baryon-1/README.md) +You can find the onboarding repo instructions for the Baryon chain [here](https://github.com/cosmos/testnets/blob/master/replicated-security/baryon-1/README.md) ## Noble + You can find the onboarding repo instructions for the Noble chain [here](https://github.com/cosmos/testnets/blob/master/replicated-security/noble-1/README.md) diff --git a/go.mod b/go.mod index 58b8eaa667..b199160aa2 100644 --- a/go.mod +++ b/go.mod @@ -3,158 +3,178 @@ module github.com/cosmos/interchain-security/v2 go 1.19 require ( - github.com/confio/ics23/go v0.9.0 - github.com/cosmos/cosmos-sdk v0.45.15 - github.com/cosmos/ibc-go/v4 v4.4.2 - github.com/gogo/protobuf v1.3.3 + cosmossdk.io/errors v1.0.0-beta.7 + cosmossdk.io/math v1.0.1 + github.com/cometbft/cometbft v0.37.1 + github.com/cometbft/cometbft-db v0.8.0 + github.com/cosmos/cosmos-sdk v0.47.3 + github.com/cosmos/gogoproto v1.4.10 + github.com/cosmos/ibc-go/v7 v7.0.0 + github.com/cosmos/ics23/go v0.10.0 github.com/golang/mock v1.6.0 github.com/golang/protobuf v1.5.3 - github.com/gorilla/mux v1.8.0 + github.com/gorilla/mux v1.8.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/kylelemons/godebug v1.1.0 github.com/oxyno-zeta/gomock-extra-matcher v1.1.0 - github.com/rakyll/statik v0.1.7 - github.com/regen-network/cosmos-proto v0.3.1 - github.com/spf13/cast v1.5.1 - github.com/spf13/cobra v1.7.0 - github.com/stretchr/testify v1.8.4 - github.com/tendermint/tendermint v0.34.27 - github.com/tendermint/tm-db v0.6.7 + github.com/rakyll/statik v0.1.7 // indirect + github.com/spf13/cast v1.5.0 + github.com/spf13/cobra v1.6.1 + github.com/stretchr/testify v1.8.2 github.com/tidwall/gjson v1.14.4 - golang.org/x/crypto v0.5.0 // indirect - golang.org/x/exp v0.0.0-20221019170559-20944726eadf - golang.org/x/net v0.7.0 // indirect - golang.org/x/sys v0.5.0 // indirect - google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa - google.golang.org/grpc v1.52.3 + golang.org/x/crypto v0.7.0 // indirect + golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc + golang.org/x/net v0.9.0 // indirect + golang.org/x/sys v0.7.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 + google.golang.org/grpc v1.55.0 google.golang.org/protobuf v1.30.0 gopkg.in/yaml.v2 v2.4.0 ) -require cosmossdk.io/errors v1.0.0-beta.7 - require ( - cosmossdk.io/api v0.2.6 // indirect + cloud.google.com/go v0.110.0 // indirect + cloud.google.com/go/compute v1.18.0 // indirect + cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go/iam v0.12.0 // indirect + cloud.google.com/go/storage v1.29.0 // indirect + cosmossdk.io/api v0.3.1 cosmossdk.io/core v0.5.1 // indirect cosmossdk.io/depinject v1.0.0-alpha.3 // indirect - filippo.io/edwards25519 v1.0.0-rc.1 // indirect + cosmossdk.io/tools/rosetta v0.2.1 + filippo.io/edwards25519 v1.0.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.1 // indirect - github.com/ChainSafe/go-schnorrkel v1.0.0 // indirect - github.com/DataDog/zstd v1.5.0 // indirect - github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect - github.com/Workiva/go-datastructures v1.0.53 // indirect + github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect github.com/armon/go-metrics v0.4.1 // indirect + github.com/aws/aws-sdk-go v1.44.203 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/cenkalti/backoff/v4 v4.1.3 // indirect github.com/cespare/xxhash v1.1.0 // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect - github.com/cockroachdb/errors v1.9.1 // indirect - github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect - github.com/cockroachdb/pebble v0.0.0-20220817183557-09c6e030a677 // indirect - github.com/cockroachdb/redact v1.1.3 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/chzyer/readline v1.5.1 // indirect + github.com/cockroachdb/apd/v2 v2.0.2 // indirect github.com/coinbase/rosetta-sdk-go v0.7.9 // indirect - github.com/cometbft/cometbft-db v0.7.0 // indirect - github.com/cosmos/btcutil v1.0.4 // indirect - github.com/cosmos/cosmos-db v0.0.0-20221226095112-f3c38ecb5e32 // indirect - github.com/cosmos/cosmos-proto v1.0.0-beta.1 // indirect + github.com/confio/ics23/go v0.9.0 // indirect + github.com/cosmos/btcutil v1.0.5 // indirect + github.com/cosmos/cosmos-proto v1.0.0-beta.2 github.com/cosmos/go-bip39 v1.0.0 // indirect - github.com/cosmos/gorocksdb v1.2.0 // indirect - github.com/cosmos/iavl v0.19.5 // indirect + github.com/cosmos/gogogateway v1.2.0 // indirect + github.com/cosmos/iavl v0.20.0 // indirect github.com/cosmos/ledger-cosmos-go v0.12.2 // indirect - github.com/creachadair/taskgroup v0.3.2 // indirect + github.com/cosmos/rosetta-sdk-go v0.10.0 // indirect + github.com/creachadair/taskgroup v0.4.2 // indirect github.com/danieljoos/wincred v1.1.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect github.com/dgraph-io/badger/v2 v2.2007.4 // indirect - github.com/dgraph-io/ristretto v0.1.0 // indirect + github.com/dgraph-io/ristretto v0.1.1 // indirect github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect - github.com/dustin/go-humanize v1.0.0 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.5.0 // indirect github.com/felixge/httpsnoop v1.0.2 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/getsentry/sentry-go v0.17.0 // indirect github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.1 // indirect - github.com/go-logfmt/logfmt v0.5.1 // indirect + github.com/go-logfmt/logfmt v0.6.0 // indirect + github.com/go-playground/universal-translator v0.18.0 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect - github.com/gogo/gateway v1.1.0 // indirect - github.com/golang/glog v1.0.0 // indirect + github.com/gogo/googleapis v1.4.1 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/glog v1.1.0 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/btree v1.1.2 // indirect - github.com/google/gofuzz v1.2.0 // indirect + github.com/google/go-cmp v0.5.9 // indirect github.com/google/orderedcode v0.0.1 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect + github.com/googleapis/gax-go/v2 v2.7.0 // indirect github.com/gorilla/handlers v1.5.1 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/gtank/merlin v0.1.1 // indirect github.com/gtank/ristretto255 v0.1.2 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-getter v1.7.1 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-safetemp v1.0.0 // indirect github.com/hashicorp/go-uuid v1.0.2 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3 // indirect + github.com/hdevalence/ed25519consensus v0.1.0 // indirect + github.com/huandu/skiplist v1.2.0 // indirect github.com/improbable-eng/grpc-web v0.15.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect - github.com/klauspost/compress v1.15.11 // indirect - github.com/kr/pretty v0.3.1 // indirect - github.com/kr/text v0.2.0 // indirect - github.com/lib/pq v1.10.6 // indirect + github.com/klauspost/compress v1.16.3 // indirect + github.com/leodido/go-urn v1.2.1 // indirect + github.com/lib/pq v1.10.7 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect - github.com/linxGnu/grocksdb v1.7.10 // indirect - github.com/magiconair/properties v1.8.6 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.16 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect + github.com/linxGnu/grocksdb v1.7.16 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/manifoldco/promptui v0.9.0 // indirect + github.com/mattn/go-isatty v0.0.18 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect github.com/minio/highwayhash v1.0.2 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mtibben/percent v0.2.1 // indirect - github.com/onsi/ginkgo v1.16.4 // indirect - github.com/onsi/gomega v1.20.0 // indirect - github.com/pelletier/go-toml v1.9.5 // indirect - github.com/pelletier/go-toml/v2 v2.0.5 // indirect - github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect + github.com/pelletier/go-toml/v2 v2.0.7 // indirect + github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.14.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.37.0 // indirect - github.com/prometheus/procfs v0.8.0 // indirect + github.com/prometheus/common v0.42.0 // indirect + github.com/prometheus/procfs v0.9.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect - github.com/rogpeppe/go-internal v1.9.0 // indirect - github.com/rs/cors v1.8.2 // indirect - github.com/rs/zerolog v1.27.0 // indirect + github.com/rs/cors v1.8.3 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect - github.com/spf13/afero v1.9.2 // indirect + github.com/spf13/afero v1.9.3 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.14.0 // indirect - github.com/subosito/gotenv v1.4.1 // indirect - github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect - github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect + github.com/subosito/gotenv v1.4.2 // indirect + github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tendermint/go-amino v0.16.0 // indirect - github.com/tidwall/btree v1.5.0 // indirect + github.com/tidwall/btree v1.6.0 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect + github.com/ugorji/go/codec v1.2.7 // indirect + github.com/ulikunitz/xz v0.5.11 // indirect github.com/zondax/hid v0.9.1 // indirect github.com/zondax/ledger-go v0.14.1 // indirect - go.etcd.io/bbolt v1.3.6 // indirect - golang.org/x/term v0.5.0 // indirect - golang.org/x/text v0.7.0 // indirect + go.etcd.io/bbolt v1.3.7 // indirect + go.opencensus.io v0.24.0 // indirect + golang.org/x/oauth2 v0.6.0 // indirect + golang.org/x/term v0.7.0 // indirect + golang.org/x/text v0.9.0 // indirect + golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect + google.golang.org/api v0.110.0 // indirect + google.golang.org/appengine v1.6.7 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect nhooyr.io/websocket v1.8.6 // indirect + pgregory.net/rapid v0.5.5 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect ) -replace ( - github.com/cosmos/cosmos-sdk => github.com/cosmos/cosmos-sdk v0.45.15-ics - github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 - github.com/tendermint/tendermint => github.com/cometbft/cometbft v0.34.28 - google.golang.org/grpc => google.golang.org/grpc v1.33.2 +require github.com/spf13/viper v1.15.0 + +require ( + cosmossdk.io/log v1.1.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/rs/zerolog v1.29.1 // indirect ) + +// following versions might cause unexpected behavior +replace github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 diff --git a/go.sum b/go.sum index ed38bf1bab..d175ed9849 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg= @@ -18,84 +19,229 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= +cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= +cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= +cloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys= +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= +cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= +cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= +cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= +cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= +cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= +cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= +cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= +cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= +cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= +cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= +cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= +cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= +cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= +cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= +cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o= +cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= +cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= +cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= +cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= +cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= +cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= +cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= +cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= +cloud.google.com/go/compute v1.18.0 h1:FEigFqoDbys2cvFkZ9Fjq4gnHBP55anJ0yQyau2f9oY= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= +cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= +cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= +cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= +cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= +cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= +cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= +cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= +cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= +cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= +cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= +cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= +cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= +cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= +cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= +cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= +cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= +cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= +cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= +cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= +cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= +cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= +cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= +cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= +cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= +cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= +cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= +cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= +cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= +cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= +cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= +cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= +cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= +cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= +cloud.google.com/go/iam v0.12.0 h1:DRtTY29b75ciH6Ov1PHb4/iat2CLCvrOm40Q0a6DFpE= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= +cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= +cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= +cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= +cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM= +cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= +cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= +cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= +cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= +cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= +cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= +cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= +cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= +cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= +cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= +cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= +cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= +cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= +cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= +cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= +cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= +cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= +cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= +cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= +cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= +cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= +cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= +cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= +cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= +cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= +cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= +cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= +cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= +cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= +cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= +cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= +cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= +cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= +cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= +cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= +cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= +cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= +cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= +cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= +cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= +cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= +cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= +cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= +cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= +cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= +cloud.google.com/go/storage v1.29.0 h1:6weCgzRvMg7lzuUurI4697AqIRPU1SvzHhynwpW31jI= +cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= +cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= +cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= +cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= +cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= +cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= +cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= +cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= +cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= +cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= +cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= +cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE= -cosmossdk.io/api v0.2.6 h1:AoNwaLLapcLsphhMK6+o0kZl+D6MMUaHVqSdwinASGU= -cosmossdk.io/api v0.2.6/go.mod h1:u/d+GAxil0nWpl1XnQL8nkziQDIWuBDhv8VnDm/s6dI= +cosmossdk.io/api v0.3.1 h1:NNiOclKRR0AOlO4KIqeaG6PS6kswOMhHD0ir0SscNXE= +cosmossdk.io/api v0.3.1/go.mod h1:DfHfMkiNA2Uhy8fj0JJlOCYOBp4eWUUJ1te5zBGNyIw= cosmossdk.io/core v0.5.1 h1:vQVtFrIYOQJDV3f7rw4pjjVqc1id4+mE0L9hHP66pyI= cosmossdk.io/core v0.5.1/go.mod h1:KZtwHCLjcFuo0nmDc24Xy6CRNEL9Vl/MeimQ2aC7NLE= cosmossdk.io/depinject v1.0.0-alpha.3 h1:6evFIgj//Y3w09bqOUOzEpFj5tsxBqdc5CfkO7z+zfw= cosmossdk.io/depinject v1.0.0-alpha.3/go.mod h1:eRbcdQ7MRpIPEM5YUJh8k97nxHpYbc3sMUnEtt8HPWU= cosmossdk.io/errors v1.0.0-beta.7 h1:gypHW76pTQGVnHKo6QBkb4yFOJjC+sUGRc5Al3Odj1w= cosmossdk.io/errors v1.0.0-beta.7/go.mod h1:mz6FQMJRku4bY7aqS/Gwfcmr/ue91roMEKAmDUDpBfE= +cosmossdk.io/log v1.1.0 h1:v0ogPHYeTzPcBTcPR1A3j1hkei4pZama8kz8LKlCMv0= +cosmossdk.io/log v1.1.0/go.mod h1:6zjroETlcDs+mm62gd8Ig7mZ+N+fVOZS91V17H+M4N4= +cosmossdk.io/math v1.0.1 h1:Qx3ifyOPaMLNH/89WeZFH268yCvU4xEcnPLu3sJqPPg= +cosmossdk.io/math v1.0.1/go.mod h1:Ygz4wBHrgc7g0N+8+MrnTfS9LLn9aaTGa9hKopuym5k= +cosmossdk.io/tools/rosetta v0.2.1 h1:ddOMatOH+pbxWbrGJKRAawdBkPYLfKXutK9IETnjYxw= +cosmossdk.io/tools/rosetta v0.2.1/go.mod h1:Pqdc1FdvkNV3LcNIkYWt2RQY6IP1ge6YWZk8MhhO9Hw= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU= filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= +filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= +filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= git.sr.ht/~sircmpwn/getopt v0.0.0-20191230200459-23622cc906b3/go.mod h1:wMEGFFFNuPos7vHmWXfszqImLppbc0wEhh6JBfJIUgw= git.sr.ht/~sircmpwn/go-bare v0.0.0-20210406120253-ab86bc2846d9/go.mod h1:BVJwbDfVjCjoFiKrhkei6NdGcZYpkDkdyCdg1ukytRA= github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs= github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= github.com/99designs/keyring v1.2.1 h1:tYLp1ULvO7i3fI5vE21ReQuj99QFSs7lGm0xWyJo87o= github.com/99designs/keyring v1.2.1/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStKOQ5vOA= -github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1/go.mod h1:fBF9PQNqB8scdgpZ3ufzaLntG0AG7C1WjPMsiFOmfHM= github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSuH8w8yEK6DpFl3LP5rhdvAb7Yz5I= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/ChainSafe/go-schnorrkel v1.0.0 h1:3aDA67lAykLaG1y3AOjs88dMxC88PgUuHRrLeDnvGIM= -github.com/ChainSafe/go-schnorrkel v1.0.0/go.mod h1:dpzHYVxLZcp8pjlV+O+UR8K0Hp/z7vcchBSbMBEhCw4= -github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= -github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= -github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= -github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= +github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= +github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= -github.com/DataDog/zstd v1.5.0 h1:+K/VEwIAaPcHiMtQvpLD4lqW7f0Gk3xdYZmI1hD+CXo= github.com/DataDog/zstd v1.5.0/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= -github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= -github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= -github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= -github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= -github.com/Workiva/go-datastructures v1.0.53 h1:J6Y/52yX10Xc5JjXmGtWoSSxs3mZnGSaq37xZZh7Yig= -github.com/Workiva/go-datastructures v1.0.53/go.mod h1:1yZL+zfsztete+ePzZz/Zb1/t5BnDuE2Ya2MMGhzP6A= github.com/Zilliqa/gozilliqa-sdk v1.2.1-0.20201201074141-dd0ecada1be6/go.mod h1:eSYp2T6f0apnuW8TzhV3f6Aff2SE8Dwio++U4ha4yEM= github.com/adlio/schema v1.3.3 h1:oBJn8I02PyTB466pZO1UZEn1TV5XLlifBSyMrmHl/1I= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= -github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/alecthomas/participle/v2 v2.0.0-alpha7 h1:cK4vjj0VSgb3lN1nuKA5F7dw+1s1pWBe5bx7nNCnN+c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -118,6 +264,9 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/aws/aws-sdk-go v1.44.203 h1:pcsP805b9acL3wUqa4JR2vg1k2wnItkDYNvfmcy6F+U= +github.com/aws/aws-sdk-go v1.44.203/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/aws/aws-sdk-go-v2 v1.2.0/go.mod h1:zEQs02YRBw1DjK0PoJv3ygDYOFTre1ejlJWl8FwAuQo= github.com/aws/aws-sdk-go-v2/config v1.1.1/go.mod h1:0XsVy9lBI/BCXm+2Tuvt39YmdHwS5unDQmxZOYe8F5Y= @@ -128,11 +277,12 @@ github.com/aws/aws-sdk-go-v2/service/route53 v1.1.1/go.mod h1:rLiOUrPLW/Er5kRcQ7 github.com/aws/aws-sdk-go-v2/service/sso v1.1.1/go.mod h1:SuZJxklHxLAXgLTc1iFXbEWkXs7QRTQpCLGaKIprQW0= github.com/aws/aws-sdk-go-v2/service/sts v1.1.1/go.mod h1:Wi0EBZwiz/K44YliU0EKxqTCJGUfYTWXrrBwkq736bM= github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw= -github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 h1:41iFGWnSlI2gVpmOtVTJZNodLdLQLn/KsJqFvXwnd/s= github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= @@ -162,6 +312,7 @@ github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= @@ -175,43 +326,44 @@ github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= +github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= +github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= +github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b8034E= +github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw= github.com/cockroachdb/apd/v3 v3.1.0 h1:MK3Ow7LH0W8zkd5GMKA1PvS9qG3bWFI95WaVNfyZJ/w= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/cockroachdb/datadriven v1.0.0/go.mod h1:5Ib8Meh+jk1RlHIXej6Pzevx/NLlNvQB9pmSBZErGA4= -github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= -github.com/cockroachdb/errors v1.6.1/go.mod h1:tm6FTP5G81vwJ5lC0SizQo374JNCOPrHyXGitRJoDqM= -github.com/cockroachdb/errors v1.8.1/go.mod h1:qGwQn6JmZ+oMjuLwjWzUNqblqk0xl4CVV3SQbGwK7Ac= -github.com/cockroachdb/errors v1.9.1 h1:yFVvsI0VxmRShfawbt/laCIDy/mtTqqnvoNgiy5bEV8= -github.com/cockroachdb/errors v1.9.1/go.mod h1:2sxOtL2WIc096WSZqZ5h8fa17rdDq9HZOZLBCor4mBk= -github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= -github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= -github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/pebble v0.0.0-20220817183557-09c6e030a677 h1:qbb/AE938DFhOajUYh9+OXELpSF9KZw2ZivtmW6eX1Q= -github.com/cockroachdb/pebble v0.0.0-20220817183557-09c6e030a677/go.mod h1:890yq1fUb9b6dGNwssgeUO5vQV9qfXnCPxAJhBQfXw0= -github.com/cockroachdb/redact v1.0.8/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= -github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= -github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= -github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/coinbase/kryptology v1.8.0/go.mod h1:RYXOAPdzOGUe3qlSFkMGn58i3xUA8hmxYHksuq+8ciI= github.com/coinbase/rosetta-sdk-go v0.7.9 h1:lqllBjMnazTjIqYrOGv8h8jxjg9+hJazIGZr9ZvoCcA= github.com/coinbase/rosetta-sdk-go v0.7.9/go.mod h1:0/knutI7XGVqXmmH4OQD8OckFrbQ8yMsUZTG7FXCR2M= -github.com/cometbft/cometbft v0.34.28 h1:gwryf55P1SWMUP4nOXpRVI2D0yPoYEzN+IBqmRBOsDc= -github.com/cometbft/cometbft v0.34.28/go.mod h1:L9shMfbkZ8B+7JlwANEr+NZbBcn+hBpwdbeYvA5rLCw= -github.com/cometbft/cometbft-db v0.7.0 h1:uBjbrBx4QzU0zOEnU8KxoDl18dMNgDh+zZRUE0ucsbo= -github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= +github.com/cometbft/cometbft v0.37.1 h1:KLxkQTK2hICXYq21U2hn1W5hOVYUdQgDQ1uB+90xPIg= +github.com/cometbft/cometbft v0.37.1/go.mod h1:Y2MMMN//O5K4YKd8ze4r9jmk4Y7h0ajqILXbH5JQFVs= +github.com/cometbft/cometbft-db v0.8.0 h1:vUMDaH3ApkX8m0KZvOFFy9b5DZHBAjsnEuo9AKVZpjo= +github.com/cometbft/cometbft-db v0.8.0/go.mod h1:6ASCP4pfhmrCBpfk01/9E1SI29nD3HfVHrY4PG8x5c0= github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4= github.com/confio/ics23/go v0.9.0/go.mod h1:4LPZ2NYqnYIVRklaozjNR1FScgDJ2s5Xrp+e/mYVRak= github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ= @@ -223,32 +375,37 @@ github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cosmos/btcutil v1.0.4 h1:n7C2ngKXo7UC9gNyMNLbzqz7Asuf+7Qv4gnX/rOdQ44= -github.com/cosmos/btcutil v1.0.4/go.mod h1:Ffqc8Hn6TJUdDgHBwIZLtrLQC1KdJ9jGJl/TvgUaxbU= -github.com/cosmos/cosmos-db v0.0.0-20221226095112-f3c38ecb5e32 h1:zlCp9n3uwQieELltZWHRmwPmPaZ8+XoL2Sj+A2YJlr8= -github.com/cosmos/cosmos-db v0.0.0-20221226095112-f3c38ecb5e32/go.mod h1:kwMlEC4wWvB48zAShGKVqboJL6w4zCLesaNQ3YLU2BQ= -github.com/cosmos/cosmos-proto v1.0.0-beta.1 h1:iDL5qh++NoXxG8hSy93FdYJut4XfgbShIocllGaXx/0= -github.com/cosmos/cosmos-proto v1.0.0-beta.1/go.mod h1:8k2GNZghi5sDRFw/scPL8gMSowT1vDA+5ouxL8GjaUE= -github.com/cosmos/cosmos-sdk v0.45.15-ics h1:ujrXsulYGwggLCC0oD7CizvlAerqMQHfCHHjHqIamfY= -github.com/cosmos/cosmos-sdk v0.45.15-ics/go.mod h1:bScuNwWAP0TZJpUf+SHXRU3xGoUPp+X9nAzfeIXts40= +github.com/cosmos/btcutil v1.0.5 h1:t+ZFcX77LpKtDBhjucvnOH8C2l2ioGsBNEQ3jef8xFk= +github.com/cosmos/btcutil v1.0.5/go.mod h1:IyB7iuqZMJlthe2tkIFL33xPyzbFYP0XVdS8P5lUPis= +github.com/cosmos/cosmos-proto v1.0.0-beta.2 h1:X3OKvWgK9Gsejo0F1qs5l8Qn6xJV/AzgIWR2wZ8Nua8= +github.com/cosmos/cosmos-proto v1.0.0-beta.2/go.mod h1:+XRCLJ14pr5HFEHIUcn51IKXD1Fy3rkEQqt4WqmN4V0= +github.com/cosmos/cosmos-sdk v0.47.3 h1:r0hGmZoAzP2D+MaPaFGHwAaTdFQq3pNpHaUp1BsffbM= +github.com/cosmos/cosmos-sdk v0.47.3/go.mod h1:c4OfLdAykA9zsj1CqrxBRqXzVz48I++JSvIMPSPcEmk= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= -github.com/cosmos/gorocksdb v1.2.0 h1:d0l3jJG8M4hBouIZq0mDUHZ+zjOx044J3nGRskwTb4Y= -github.com/cosmos/gorocksdb v1.2.0/go.mod h1:aaKvKItm514hKfNJpUJXnnOWeBnk2GL4+Qw9NHizILw= -github.com/cosmos/iavl v0.19.5 h1:rGA3hOrgNxgRM5wYcSCxgQBap7fW82WZgY78V9po/iY= -github.com/cosmos/iavl v0.19.5/go.mod h1:X9PKD3J0iFxdmgNLa7b2LYWdsGd90ToV5cAONApkEPw= -github.com/cosmos/ibc-go/v4 v4.4.2 h1:PG4Yy0/bw6Hvmha3RZbc53KYzaCwuB07Ot4GLyzcBvo= -github.com/cosmos/ibc-go/v4 v4.4.2/go.mod h1:j/kD2JCIaV5ozvJvaEkWhLxM2zva7/KTM++EtKFYcB8= +github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= +github.com/cosmos/gogogateway v1.2.0/go.mod h1:iQpLkGWxYcnCdz5iAdLcRBSw3h7NXeOkZ4GUkT+tbFI= +github.com/cosmos/gogoproto v1.4.2/go.mod h1:cLxOsn1ljAHSV527CHOtaIP91kK6cCrZETRBrkzItWU= +github.com/cosmos/gogoproto v1.4.10 h1:QH/yT8X+c0F4ZDacDv3z+xE3WU1P1Z3wQoLMBRJoKuI= +github.com/cosmos/gogoproto v1.4.10/go.mod h1:3aAZzeRWpAwr+SS/LLkICX2/kDFyaYVzckBDzygIxek= +github.com/cosmos/iavl v0.20.0 h1:fTVznVlepH0KK8NyKq8w+U7c2L6jofa27aFX6YGlm38= +github.com/cosmos/iavl v0.20.0/go.mod h1:WO7FyvaZJoH65+HFOsDir7xU9FWk2w9cHXNW1XHcl7A= +github.com/cosmos/ibc-go/v7 v7.0.0 h1:j4kyywlG0hhDmT9FmSaR5iCIka7Pz7kJTxGWY1nlV9Q= +github.com/cosmos/ibc-go/v7 v7.0.0/go.mod h1:BFh8nKWjr5zeR2OZfhkzdgDzj1+KjRn3aJLpwapStj8= +github.com/cosmos/ics23/go v0.10.0 h1:iXqLLgp2Lp+EdpIuwXTYIQU+AiHj9mOC2X9ab++bZDM= +github.com/cosmos/ics23/go v0.10.0/go.mod h1:ZfJSmng/TBNTBkFemHHHj5YY7VAU/MBU980F4VU1NG0= github.com/cosmos/ledger-cosmos-go v0.12.2 h1:/XYaBlE2BJxtvpkHiBm97gFGSGmYGKunKyF3nNqAXZA= github.com/cosmos/ledger-cosmos-go v0.12.2/go.mod h1:ZcqYgnfNJ6lAXe4HPtWgarNEY+B74i+2/8MhZw4ziiI= +github.com/cosmos/rosetta-sdk-go v0.10.0 h1:E5RhTruuoA7KTIXUcMicL76cffyeoyvNybzUGSKFTcM= +github.com/cosmos/rosetta-sdk-go v0.10.0/go.mod h1:SImAZkb96YbwvoRkzSMQB6noNJXFgWl/ENIznEoYQI4= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creachadair/taskgroup v0.3.2 h1:zlfutDS+5XG40AOxcHDSThxKzns8Tnr9jnr6VqkYlkM= -github.com/creachadair/taskgroup v0.3.2/go.mod h1:wieWwecHVzsidg2CsUnFinW1faVN4+kq+TDlRJQ0Wbk= +github.com/creachadair/taskgroup v0.4.2 h1:jsBLdAJE42asreGss2xZGZ8fJra7WtwnHWeJFxv2Li8= +github.com/creachadair/taskgroup v0.4.2/go.mod h1:qiXUOSrbwAY3u0JPGTzObbE3yf9hcXHDKBZ2ZjpCbgM= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cucumber/common/gherkin/go/v22 v22.0.0 h1:4K8NqptbvdOrjL9DEea6HFjSpbdT9+Q5kgLpmmsHYl0= @@ -264,20 +421,20 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo= github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M= github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= -github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.0.3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= -github.com/dgraph-io/ristretto v0.1.0 h1:Jv3CGQHp9OjuMBSne1485aDpUkTKEcUqF+jm/LuerPI= -github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug= +github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= +github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= @@ -293,8 +450,9 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4 github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/dvsekhvalnov/jose2go v1.5.0 h1:3j8ya4Z4kMCwT5nXIKFSV84YS+HdqSSO0VsTQxaLAeM= github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= @@ -302,53 +460,44 @@ github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1 github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= +github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/ethereum/go-ethereum v1.10.17/go.mod h1:Lt5WzjM07XlXc95YzrhosmR4J9Ahd6X2wyEV2SvGhk0= -github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0= -github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= -github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpmbhCOZJ293Lz68O7PYrF2EzeiFMwCLk= -github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o= github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= -github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= -github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= -github.com/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TBdRL1M71JZW2c= -github.com/getsentry/sentry-go v0.17.0 h1:UustVWnOoDFHBS7IJUB2QK/nB5pap748ZEp0swnQJak= -github.com/getsentry/sentry-go v0.17.0/go.mod h1:B82dxtBvxG0KaPD8/hfSV+VcHD+Lg/xUS4JuQn1P4cM= -github.com/ghemawat/stream v0.0.0-20171120220530-696b145b53b9/go.mod h1:106OIgooyS7OzLDOpUGgm9fA3bQENb/cFSyyBmMoJDs= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8= github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= -github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= -github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -357,31 +506,29 @@ github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= -github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= +github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= +github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= @@ -394,28 +541,36 @@ github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6 github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.3.0+incompatible h1:CaSVZxm5B+7o45rtab4jC2G37WGYX1zQfuU2i6DSvnc= -github.com/gogo/gateway v1.1.0 h1:u0SuhL9+Il+UbjM9VIE3ntfRujKbvVpFvNB4HbjeVQ0= -github.com/gogo/gateway v1.1.0/go.mod h1:S7rR8FRQyG3QFESeSv4l2WnsyzlCLG0CzBbUUo/mbic= -github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/googleapis v1.4.1-0.20201022092350-68b0159b7869/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= +github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0= github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= -github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= -github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= -github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= +github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -434,6 +589,7 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= @@ -442,7 +598,6 @@ github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= -github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= @@ -456,18 +611,24 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= -github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= github.com/google/orderedcode v0.0.1 h1:UzfcAexk9Vhv8+9pNOgRu41f16lHq725vPwnSeiG/Us= github.com/google/orderedcode v0.0.1/go.mod h1:iVyU4/qPKHY5h/wSd6rZZCDcLJNxiWO6dvsYES2Sb20= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -480,13 +641,35 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= +github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k= +github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= +github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= +github.com/googleapis/gax-go/v2 v2.7.0 h1:IcsPKeInNvYi7eqSaDjiZqDDKu5rsmunY0Y1YupQSSQ= +github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= +github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= @@ -497,7 +680,6 @@ github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= @@ -508,7 +690,6 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaD github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= @@ -525,6 +706,10 @@ github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brv github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-getter v1.7.1 h1:SWiSWN/42qdpR0MdhaOc/bLR48PLuP1ZQtYLRlM69uY= +github.com/hashicorp/go-getter v1.7.1/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= @@ -532,6 +717,8 @@ github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iP github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= +github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= @@ -539,6 +726,7 @@ github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -551,22 +739,24 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3 h1:aSVUgRRRtOrZOC1fYmY9gV0e9z/Iu+xNVSASWjsuyGU= -github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3/go.mod h1:5PC6ZNPde8bBqU/ewGZig35+UIZtw9Ytxez8/q5ZyFE= +github.com/hdevalence/ed25519consensus v0.1.0 h1:jtBwzzcHuTmFrQN6xQZn6CQEO/V9f7HsjsjeEZ6auqU= +github.com/hdevalence/ed25519consensus v0.1.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c= +github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U= +github.com/huandu/skiplist v1.2.0 h1:gox56QD77HzSC0w+Ws3MH3iie755GBJU1OER3h5VsYw= +github.com/huandu/skiplist v1.2.0/go.mod h1:7v3iFjLcSAzO4fN5B8dvebvo/qsfumiLiDXMrPiHF9w= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/huin/goupnp v1.0.3-0.20220313090229-ca81a64b4204/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= -github.com/hydrogen18/memlistener v0.0.0-20141126152155-54553eb933fb/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= -github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/improbable-eng/grpc-web v0.15.0 h1:BN+7z6uNXZ1tQGcNAuaU1YjsLTApzkjt2tzCixLaUPQ= github.com/improbable-eng/grpc-web v0.15.0/go.mod h1:1sy9HKV4Jt9aEs9JSnkWlRJPuPtwNr0l57L4f878wP8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY= @@ -581,19 +771,15 @@ github.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19y github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE= github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0= github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po= -github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= -github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= -github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI= -github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= -github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g= -github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jhump/protoreflect v1.13.1-0.20220928232736-101791cb1b4c h1:XImQJfpJLmGEEd8ll5yPVyL/aEvmgGHW4WYTyNseLOM= +github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= @@ -605,45 +791,29 @@ github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= -github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= -github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0= -github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= -github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk= -github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8= -github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U= -github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE= -github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw= -github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE= -github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0= -github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro= -github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c= github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY= +github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg= github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -652,69 +822,64 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= -github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs= -github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= +github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= -github.com/linxGnu/grocksdb v1.7.10 h1:dz7RY7GnFUA+GJO6jodyxgkUeGMEkPp3ikt9hAcNGEw= -github.com/linxGnu/grocksdb v1.7.10/go.mod h1:0hTf+iA+GOr0jDX4CgIYyJZxqOH9XlBh6KVj8+zmF34= +github.com/linxGnu/grocksdb v1.7.16 h1:Q2co1xrpdkr5Hx3Fp+f+f7fRGhQFQhvi/+226dtLmA8= +github.com/linxGnu/grocksdb v1.7.16/go.mod h1:JkS7pl5qWpGpuVb3bPqTz8nC12X3YtPZT+Xq7+QfQo4= github.com/lucasjones/reggen v0.0.0-20180717132126-cdb49ff09d77/go.mod h1:5ELEyG+X8f+meRWHuqUOewBOhvHkl7M76pdGEansxW4= +github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= -github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= +github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= +github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= -github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= -github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg= -github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ= -github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= -github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 h1:QRUSJEgZn2Snx0EmT/QLXibWjSUDjKWvXIT19NBVp94= @@ -723,8 +888,11 @@ github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= @@ -740,9 +908,7 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= -github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= @@ -755,9 +921,7 @@ github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= -github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= -github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= @@ -765,7 +929,6 @@ github.com/neilotoole/errgroup v0.1.6/go.mod h1:Q2nLGf+594h0CLBs/Mbg6qOr7GtqDK7C github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= @@ -773,18 +936,14 @@ github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:v github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.20.0 h1:8W0cWlwFkflGPLltQvLRB7ZVD5HuP6ng320w2IS245Q= -github.com/onsi/gomega v1.20.0/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034= @@ -799,7 +958,6 @@ github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJ github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= -github.com/otiai10/copy v1.6.0 h1:IinKAryFFuPONZ7cm6T6E2QX/vcJwSnlaA5lfoaXIiQ= github.com/oxyno-zeta/gomock-extra-matcher v1.1.0 h1:Yyk5ov0ZPKBXtVEeIWtc4J2XVrHuNoIK+0F2BUJgtsc= github.com/oxyno-zeta/gomock-extra-matcher v1.1.0/go.mod h1:UMGTHYEmJ1dRq8LDZ7VTAYO4nqM3GD1UGC3RJEUxEz0= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= @@ -809,22 +967,17 @@ github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144T github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= -github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= -github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= +github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us= +github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= -github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= +github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 h1:hDSdbBuw3Lefr6R18ax0tZ2BJeNB3NehB3trOwYBsdU= +github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= -github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= -github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -841,8 +994,6 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -861,62 +1012,47 @@ github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt2 github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= +github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= +github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ= github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Unghqrcc= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/regen-network/cosmos-proto v0.3.1 h1:rV7iM4SSFAagvy8RiyhiACbWEGotmqzywPxOvwMdxcg= -github.com/regen-network/cosmos-proto v0.3.1/go.mod h1:jO0sVX6a1B36nmE8C9xBFXpNwWejXC7QqCOnH3O0+YM= github.com/regen-network/gocuke v0.6.2 h1:pHviZ0kKAq2U2hN2q3smKNxct6hS0mGByFMHGnWA97M= -github.com/regen-network/protobuf v1.3.3-alpha.regen.1 h1:OHEc+q5iIAXpqiqFKeLpu5NwTIkVXUs48vFMwzqpqY4= -github.com/regen-network/protobuf v1.3.3-alpha.regen.1/go.mod h1:2DjTFR1HhMQhiWC5sZ4OhQ3+NtdbZ6oBDKQwq5Ou+FI= github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= -github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= -github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= -github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.27.0 h1:1T7qCieN22GVc8S4Q2yuexzBb1EqjbgjSH9RohbMjKs= -github.com/rs/zerolog v1.27.0/go.mod h1:7frBqO0oezxmnO7GF86FY++uy8I0Tk/If5ni1G9Qc0U= +github.com/rs/cors v1.8.3 h1:O+qNyWn7Z+F9M0ILBHgMVPuB1xTOucVd5gtaYyXBpRo= +github.com/rs/cors v1.8.3/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc= +github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= -github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= -github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY= github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -932,15 +1068,15 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw= -github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= +github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= -github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= +github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= +github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= -github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= +github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= @@ -949,8 +1085,8 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.14.0 h1:Rg7d3Lo706X9tHsJMUjdiwMpHB7W8WnSVOssIY+JElU= -github.com/spf13/viper v1.14.0/go.mod h1:WT//axPky3FdvXHzGw33dNdXXXfFQqmEalje+egj8As= +github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= +github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA= github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= @@ -959,6 +1095,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -968,20 +1105,17 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= -github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= +github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= -github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= -github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= -github.com/tendermint/tm-db v0.6.7 h1:fE00Cbl0jayAoqlExN6oyQJ7fR/ZtoVOmvPJ//+shu8= -github.com/tendermint/tm-db v0.6.7/go.mod h1:byQDzFkZV1syXr/ReXS808NxA2xvyuuVgXOJ/088L6I= -github.com/tidwall/btree v1.5.0 h1:iV0yVY/frd7r6qGBXfEYs7DH0gTDgrKTrDjS7xt/IyQ= -github.com/tidwall/btree v1.5.0/go.mod h1:LGm8L/DZjPLmeWGjv5kFrY8dL4uVhMmzmmLYmsObdKE= +github.com/tidwall/btree v1.6.0 h1:LDZfKfQIBHGHWSwckhXI0RPSXzlo+KYdjK7FWSqOzzg= +github.com/tidwall/btree v1.6.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.14.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= @@ -992,55 +1126,47 @@ github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/sjson v1.2.4/go.mod h1:098SZ494YoMWPmMO6ct4dcFnqxwj9r/gF0Etp19pSNM= github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= -github.com/tinylib/msgp v1.1.5/go.mod h1:eQsjooMTnV42mHu917E26IogZ2930nFyBQdofk10Udg= github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI= github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/tyler-smith/go-bip39 v1.0.2/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= +github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= +github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= +github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= -github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= github.com/ybbus/jsonrpc v2.1.2+incompatible/go.mod h1:XJrh1eMSzdIYFbM08flv0wp5G35eRniyeGut1z+LSiE= -github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= -github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= -github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zondax/hid v0.9.1 h1:gQe66rtmyZ8VeGFcOpbuH3r7erYtNEAezCAYu8LdkJo= github.com/zondax/hid v0.9.1/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= github.com/zondax/ledger-go v0.14.1 h1:Pip65OOl4iJ84WTpA4BKChvOufMhhbxED3BaihoZN4c= github.com/zondax/ledger-go v0.14.1/go.mod h1:fZ3Dqg6qcdXWSOJFKMG8GCTnD7slO/RL2feOQv8K320= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= -go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= +go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= +go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= @@ -1050,6 +1176,10 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -1071,7 +1201,6 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -1083,8 +1212,8 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= -golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= +golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1099,12 +1228,12 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= -golang.org/x/exp v0.0.0-20200513190911-00229845015e/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= -golang.org/x/exp v0.0.0-20221019170559-20944726eadf h1:nFVjjKDgNY37+ZSYCJmtYf7tOlfQswHqplG2eosjOMg= -golang.org/x/exp v0.0.0-20221019170559-20944726eadf/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= +golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc h1:mCRnTeVUjcrhlRmO0VK8a6k6Rrf6TF9htwo2pJVSjIU= +golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -1127,9 +1256,11 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1139,7 +1270,6 @@ golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -1149,7 +1279,6 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1170,21 +1299,32 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1194,8 +1334,24 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= +golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= +golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1207,8 +1363,11 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1261,45 +1420,68 @@ golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210909193231-528a39cd75f3/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1309,23 +1491,26 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -1367,28 +1552,32 @@ golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.4.0 h1:7mTAgkunk3fr4GAloyyCasadO6h9zSsQZbwvcaIciV4= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= -gonum.org/v1/gonum v0.8.2 h1:CCXrcPKiGGotvnN6jfUsKk4rRqm7q09/YbKb5xCEvtM= -gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= @@ -1412,14 +1601,46 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513 google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= +google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= +google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= +google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= +google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= +google.golang.org/api v0.110.0 h1:l+rh0KYUooe9JGbGVx71tbFo4SMbMTXK3I3ia2QSEeU= +google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1444,7 +1665,6 @@ google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200324203455-a04cca1dde73/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= @@ -1463,12 +1683,120 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa h1:qQPhfbPO23fwm/9lQr91L1u62Zo6cm+zI+slZT+uf+o= -google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= +google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= +google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= +google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= +google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= +google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1481,26 +1809,25 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= -gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= -gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= -gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= @@ -1518,7 +1845,6 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= @@ -1526,6 +1852,7 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1536,11 +1863,14 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= -pgregory.net/rapid v0.5.3 h1:163N50IHFqr1phZens4FQOdPgfJscR7a562mjQqeo4M= +pgregory.net/rapid v0.5.5 h1:jkgx1TjbQPD/feRoK+S/mXw9e1uj6WilpHrXJowi6oA= +pgregory.net/rapid v0.5.5/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/legacy_ibc_testing/core/events.go b/legacy_ibc_testing/core/events.go index fdf14c50f6..daabc92d54 100644 --- a/legacy_ibc_testing/core/events.go +++ b/legacy_ibc_testing/core/events.go @@ -3,10 +3,10 @@ package core import ( "strconv" - abci "github.com/tendermint/tendermint/abci/types" + abci "github.com/cometbft/cometbft/abci/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" ) /* @@ -20,7 +20,7 @@ These files will be deprecated once ICS is able to upgrade to ibc-go v5. func ReconstructPacketFromEvent(event abci.Event) (packet types.Packet, err error) { attrMap := make(map[string][]byte) for _, attr := range event.Attributes { - attrMap[string(attr.Key)] = attr.Value + attrMap[string(attr.Key)] = []byte(attr.Value) } sequence, err := strconv.Atoi(string(attrMap[string(types.AttributeKeySequence)])) diff --git a/legacy_ibc_testing/simapp/test_helpers.go b/legacy_ibc_testing/simapp/test_helpers.go index fb680aa082..2d11af5790 100644 --- a/legacy_ibc_testing/simapp/test_helpers.go +++ b/legacy_ibc_testing/simapp/test_helpers.go @@ -8,6 +8,8 @@ import ( "testing" "time" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + tmtypes "github.com/cometbft/cometbft/types" bam "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" @@ -15,9 +17,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/errors" "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - tmtypes "github.com/tendermint/tendermint/types" "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/simapp/helpers" ) @@ -31,8 +30,8 @@ These files will be deprecated once ICS is able to upgrade to ibc-go v5. // DefaultConsensusParams defines the default Tendermint consensus params used in // SimApp testing. -var DefaultConsensusParams = &abci.ConsensusParams{ - Block: &abci.BlockParams{ +var DefaultConsensusParams = &tmproto.ConsensusParams{ + Block: &tmproto.BlockParams{ MaxBytes: 200000, MaxGas: 2000000, }, @@ -62,7 +61,7 @@ func ConvertAddrsToValAddrs(addrs []sdk.AccAddress) []sdk.ValAddress { } func TestAddr(addr string, bech string) (sdk.AccAddress, error) { - res, err := sdk.AccAddressFromHex(addr) + res, err := sdk.AccAddressFromHexUnsafe(addr) if err != nil { return nil, err } @@ -104,7 +103,7 @@ func SignAndDeliver( require.NoError(t, err) // Simulate a sending a transaction - gInfo, res, err := app.Deliver(txCfg.TxEncoder(), tx) + gInfo, res, err := app.SimDeliver(txCfg.TxEncoder(), tx) if expPass { require.NoError(t, err) diff --git a/legacy_ibc_testing/testing/app.go b/legacy_ibc_testing/testing/app.go index 45d5248773..ce4e32c90f 100644 --- a/legacy_ibc_testing/testing/app.go +++ b/legacy_ibc_testing/testing/app.go @@ -5,26 +5,29 @@ import ( "testing" "time" + "cosmossdk.io/math" "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/core" + abci "github.com/cometbft/cometbft/abci/types" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + tmtypes "github.com/cometbft/cometbft/types" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + storetypes "github.com/cosmos/cosmos-sdk/store/types" 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" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - tmtypes "github.com/tendermint/tendermint/types" - "github.com/cosmos/ibc-go/v4/modules/core/keeper" + "github.com/cosmos/ibc-go/v7/modules/core/keeper" "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/simapp" + consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" ) /* @@ -52,7 +55,7 @@ type TestingApp interface { AppCodec() codec.Codec // Implemented by BaseApp - LastCommitID() sdk.CommitID + LastCommitID() storetypes.CommitID LastBlockHeight() int64 } @@ -60,9 +63,10 @@ type TestingApp interface { // that also act as delegators. For simplicity, each validator is bonded with a delegation // of one consensus engine unit (10^6) in the default token of the simapp from first genesis // account. A Nop logger is set in SimApp. -func SetupWithGenesisValSet(t *testing.T, appIniter AppIniter, valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount, chainID string, powerReduction sdk.Int, balances ...banktypes.Balance) TestingApp { +func SetupWithGenesisValSet(t *testing.T, appIniter AppIniter, valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount, chainID string, powerReduction math.Int, balances ...banktypes.Balance) TestingApp { t.Helper() app, genesisState := appIniter() + baseapp.SetChainID(chainID)(app.GetBaseApp()) // set genesis accounts authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs) @@ -73,6 +77,7 @@ func SetupWithGenesisValSet(t *testing.T, appIniter AppIniter, valSet *tmtypes.V bondAmt := sdk.TokensFromConsensusPower(1, powerReduction) + initValPowers := []abci.ValidatorUpdate{} for _, val := range valSet.Validators { pk, err := cryptocodec.FromTmPubKeyInterface(val.PubKey) require.NoError(t, err) @@ -94,14 +99,20 @@ func SetupWithGenesisValSet(t *testing.T, appIniter AppIniter, valSet *tmtypes.V validators = append(validators, validator) delegations = append(delegations, stakingtypes.NewDelegation(genAccs[0].GetAddress(), val.Address.Bytes(), sdk.OneDec())) + + pub, _ := val.ToProto() + initValPowers = append(initValPowers, abci.ValidatorUpdate{ + Power: val.VotingPower, + PubKey: pub.PubKey, + }) } // set validators and delegations var ( - stakingGenesis stakingtypes.GenesisState - bondDenom string + stakingGenesis stakingtypes.GenesisState + consumerGenesis consumertypes.GenesisState + bondDenom string ) - if genesisState[stakingtypes.ModuleName] != nil { app.AppCodec().MustUnmarshalJSON(genesisState[stakingtypes.ModuleName], &stakingGenesis) bondDenom = stakingGenesis.Params.BondDenom @@ -120,9 +131,16 @@ func SetupWithGenesisValSet(t *testing.T, appIniter AppIniter, valSet *tmtypes.V genesisState[stakingtypes.ModuleName] = app.AppCodec().MustMarshalJSON(&stakingGenesis) // update total supply - bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, sdk.NewCoins(), []banktypes.Metadata{}) + bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, sdk.NewCoins(), []banktypes.Metadata{}, []banktypes.SendEnabled{}) genesisState[banktypes.ModuleName] = app.AppCodec().MustMarshalJSON(bankGenesis) + if genesisState[consumertypes.ModuleName] != nil { + app.AppCodec().MustUnmarshalJSON(genesisState[consumertypes.ModuleName], &consumerGenesis) + consumerGenesis.InitialValSet = initValPowers + consumerGenesis.Params.Enabled = true + genesisState[consumertypes.ModuleName] = app.AppCodec().MustMarshalJSON(&consumerGenesis) + } + stateBytes, err := json.MarshalIndent(genesisState, "", " ") require.NoError(t, err) @@ -138,6 +156,7 @@ func SetupWithGenesisValSet(t *testing.T, appIniter AppIniter, valSet *tmtypes.V // commit genesis changes app.Commit() + app.BeginBlock( abci.RequestBeginBlock{ Header: tmproto.Header{ diff --git a/legacy_ibc_testing/testing/chain.go b/legacy_ibc_testing/testing/chain.go index f86bdda905..c037ca43c8 100644 --- a/legacy_ibc_testing/testing/chain.go +++ b/legacy_ibc_testing/testing/chain.go @@ -7,6 +7,12 @@ import ( "time" errorsmod "cosmossdk.io/errors" + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/crypto/tmhash" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + tmprotoversion "github.com/cometbft/cometbft/proto/tendermint/version" + tmtypes "github.com/cometbft/cometbft/types" + tmversion "github.com/cometbft/cometbft/version" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" @@ -16,24 +22,19 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - "github.com/cosmos/cosmos-sdk/x/staking/teststaking" + teststaking "github.com/cosmos/cosmos-sdk/x/staking/testutil" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/crypto/tmhash" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - tmprotoversion "github.com/tendermint/tendermint/proto/tendermint/version" - tmtypes "github.com/tendermint/tendermint/types" - tmversion "github.com/tendermint/tendermint/version" - - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" - commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v4/modules/core/24-host" - "github.com/cosmos/ibc-go/v4/modules/core/exported" - "github.com/cosmos/ibc-go/v4/modules/core/types" - ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" - "github.com/cosmos/ibc-go/v4/testing/mock" + + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v7/modules/core/24-host" + "github.com/cosmos/ibc-go/v7/modules/core/exported" + "github.com/cosmos/ibc-go/v7/modules/core/types" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + "github.com/cosmos/ibc-go/v7/testing/mock" + ibctestingcore "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/core" "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/simapp" ) @@ -211,7 +212,7 @@ func (chain *TestChain) QueryProof(key []byte) ([]byte, clienttypes.Height) { // for the query and the height at which the proof will succeed on a tendermint verifier. func (chain *TestChain) QueryProofAtHeight(key []byte, height int64) ([]byte, clienttypes.Height) { res := chain.App.Query(abci.RequestQuery{ - Path: fmt.Sprintf("store/%s/key", host.StoreKey), + Path: fmt.Sprintf("store/%s/key", exported.StoreKey), Height: height - 1, Data: key, Prove: true, diff --git a/legacy_ibc_testing/testing/config.go b/legacy_ibc_testing/testing/config.go index 5e94c8c4c3..dffe01053f 100644 --- a/legacy_ibc_testing/testing/config.go +++ b/legacy_ibc_testing/testing/config.go @@ -3,11 +3,11 @@ package testing import ( "time" - connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" - "github.com/cosmos/ibc-go/v4/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" - "github.com/cosmos/ibc-go/v4/testing/mock" + connectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v7/modules/core/exported" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + "github.com/cosmos/ibc-go/v7/testing/mock" ) /* diff --git a/legacy_ibc_testing/testing/coordinator.go b/legacy_ibc_testing/testing/coordinator.go index c56a505da0..4aee8f8923 100644 --- a/legacy_ibc_testing/testing/coordinator.go +++ b/legacy_ibc_testing/testing/coordinator.go @@ -6,8 +6,8 @@ import ( "testing" "time" + abci "github.com/cometbft/cometbft/abci/types" "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" ) /* diff --git a/legacy_ibc_testing/testing/endpoint.go b/legacy_ibc_testing/testing/endpoint.go index 0929942511..c3f2ac9abb 100644 --- a/legacy_ibc_testing/testing/endpoint.go +++ b/legacy_ibc_testing/testing/endpoint.go @@ -6,13 +6,13 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" - commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v4/modules/core/24-host" - "github.com/cosmos/ibc-go/v4/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v7/modules/core/24-host" + "github.com/cosmos/ibc-go/v7/modules/core/exported" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" ) /* @@ -86,7 +86,7 @@ func (endpoint *Endpoint) CreateClient() (err error) { height := endpoint.Counterparty.Chain.LastHeader.GetHeight().(clienttypes.Height) clientState = ibctmtypes.NewClientState( endpoint.Counterparty.Chain.ChainID, tmConfig.TrustLevel, tmConfig.TrustingPeriod, tmConfig.UnbondingPeriod, tmConfig.MaxClockDrift, - height, commitmenttypes.GetSDKSpecs(), UpgradePath, tmConfig.AllowUpdateAfterExpiry, tmConfig.AllowUpdateAfterMisbehaviour, + height, commitmenttypes.GetSDKSpecs(), UpgradePath, ) consensusState = endpoint.Counterparty.Chain.LastHeader.ConsensusState() case exported.Solomachine: @@ -124,7 +124,7 @@ func (endpoint *Endpoint) UpdateClient() (err error) { // ensure counterparty has committed state endpoint.Chain.Coordinator.CommitBlock(endpoint.Counterparty.Chain) - var header exported.Header + var header *ibctmtypes.Header switch endpoint.ClientConfig.GetClientType() { case exported.Tendermint: @@ -364,8 +364,18 @@ func (endpoint *Endpoint) ChanCloseInit() error { func (endpoint *Endpoint) SendPacket(packet exported.PacketI) error { channelCap := endpoint.Chain.GetChannelCapability(packet.GetSourcePort(), packet.GetSourceChannel()) + timeoutHeight := clienttypes.Height{ + RevisionNumber: packet.GetTimeoutHeight().GetRevisionNumber(), + RevisionHeight: packet.GetTimeoutHeight().GetRevisionHeight(), + } + // no need to send message, acting as a module - err := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.SendPacket(endpoint.Chain.GetContext(), channelCap, packet) + _, err := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.SendPacket(endpoint.Chain.GetContext(), + channelCap, packet.GetSourcePort(), + packet.GetSourceChannel(), + timeoutHeight, + packet.GetTimeoutTimestamp(), + packet.GetData()) if err != nil { return err } diff --git a/legacy_ibc_testing/testing/events.go b/legacy_ibc_testing/testing/events.go index 7d60e69799..763199a695 100644 --- a/legacy_ibc_testing/testing/events.go +++ b/legacy_ibc_testing/testing/events.go @@ -5,9 +5,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" ) /* @@ -70,7 +70,7 @@ func ParseAckFromEvents(events sdk.Events) ([]byte, error) { if ev.Type == channeltypes.EventTypeWriteAck { for _, attr := range ev.Attributes { if string(attr.Key) == channeltypes.AttributeKeyAck { - return attr.Value, nil + return []byte(attr.Value), nil } } } diff --git a/legacy_ibc_testing/testing/path.go b/legacy_ibc_testing/testing/path.go index 78aa4bacfa..31efe8215d 100644 --- a/legacy_ibc_testing/testing/path.go +++ b/legacy_ibc_testing/testing/path.go @@ -4,7 +4,7 @@ import ( "bytes" "fmt" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" ) /* diff --git a/legacy_ibc_testing/testing/utils.go b/legacy_ibc_testing/testing/utils.go index 3887f99352..885958f25e 100644 --- a/legacy_ibc_testing/testing/utils.go +++ b/legacy_ibc_testing/testing/utils.go @@ -3,9 +3,9 @@ package testing import ( "testing" + abci "github.com/cometbft/cometbft/abci/types" + tmtypes "github.com/cometbft/cometbft/types" "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" - tmtypes "github.com/tendermint/tendermint/types" ) /* diff --git a/legacy_ibc_testing/testing/values.go b/legacy_ibc_testing/testing/values.go index ebc5f31fa4..579d00cea4 100644 --- a/legacy_ibc_testing/testing/values.go +++ b/legacy_ibc_testing/testing/values.go @@ -3,10 +3,10 @@ package testing import ( "time" - ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" - connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" - ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" - "github.com/cosmos/ibc-go/v4/testing/mock" + ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + connectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + "github.com/cosmos/ibc-go/v7/testing/mock" ) /* diff --git a/proto/buf.lock b/proto/buf.lock index 68c709a8d9..1c8fbbc13a 100644 --- a/proto/buf.lock +++ b/proto/buf.lock @@ -1,11 +1,27 @@ # Generated by buf. DO NOT EDIT. version: v1 deps: + - remote: buf.build + owner: cosmos + repository: cosmos-proto + commit: 1935555c206d4afb9e94615dfd0fad31 + - remote: buf.build + owner: cosmos + repository: cosmos-sdk + commit: 954f7b05f38440fc8250134b15adec47 - remote: buf.build owner: cosmos repository: gogo-proto - commit: bee5511075b7499da6178d9e4aaa628b + commit: 34d970b699f84aa382f3c29773a60836 + - remote: buf.build + owner: cosmos + repository: ibc + commit: fbb44f5ad3194450af479a615fa715d9 + - remote: buf.build + owner: cosmos + repository: ics23 + commit: 55085f7c710a45f58fa09947208eb70b - remote: buf.build owner: googleapis repository: googleapis - commit: 62f35d8aed1149c291d606d958a7ce32 + commit: 5ae7f88519b04fe1965da0f8a375a088 diff --git a/proto/buf.yaml b/proto/buf.yaml index 5208a19c81..5ef6b4b743 100644 --- a/proto/buf.yaml +++ b/proto/buf.yaml @@ -7,7 +7,11 @@ version: v1 name: buf.build/cosmos/interchain-security deps: - buf.build/cosmos/gogo-proto + - buf.build/cosmos/cosmos-sdk:v0.47.0 + - buf.build/cosmos/ibc:fbb44f5ad3194450af479a615fa715d9 - buf.build/googleapis/googleapis + - buf.build/cosmos/ics23:b1abd8678aab07165efd453c96796a179eb3131f + breaking: use: - FILE diff --git a/proto/interchain_security/ccv/consumer/v1/consumer.proto b/proto/interchain_security/ccv/consumer/v1/consumer.proto index 92602eee4c..1487e579a8 100644 --- a/proto/interchain_security/ccv/consumer/v1/consumer.proto +++ b/proto/interchain_security/ccv/consumer/v1/consumer.proto @@ -32,11 +32,11 @@ message Params { string provider_fee_pool_addr_str = 4; // Sent CCV related IBC packets will timeout after this duration google.protobuf.Duration ccv_timeout_period = 5 - [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; + [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; // Sent transfer related IBC packets will timeout after this duration google.protobuf.Duration transfer_timeout_period = 6 - [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; + [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; // The fraction of tokens allocated to the consumer redistribution address // during distribution events. The fraction is a string representing a @@ -44,25 +44,27 @@ message Params { string consumer_redistribution_fraction = 7; // The number of historical info entries to persist in store. - // This param is a part of the cosmos sdk staking module. In the case of + // This param is a part of the cosmos sdk staking module. In the case of // a ccv enabled consumer chain, the ccv module acts as the staking module. int64 historical_entries = 8; // Unbonding period for the consumer, // which should be smaller than that of the provider in general. google.protobuf.Duration unbonding_period = 9 - [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; + [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; // The threshold for the percentage of validators at the bottom of the set who - // can opt out of running the consumer chain without being punished. For example, a - // value of 0.05 means that the validators in the bottom 5% of the set can opt out + // can opt out of running the consumer chain without being punished. For + // example, a value of 0.05 means that the validators in the bottom 5% of the + // set can opt out string soft_opt_out_threshold = 10; - // Reward denoms. These are the denominations which are allowed to be sent to the provider as rewards. + // Reward denoms. These are the denominations which are allowed to be sent to + // the provider as rewards. repeated string reward_denoms = 11; - // Provider-originated reward denoms. These are denoms coming from the provider - // which are allowed to be used as rewards. e.g. "uatom" + // Provider-originated reward denoms. These are denoms coming from the + // provider which are allowed to be used as rewards. e.g. "uatom" repeated string provider_reward_denoms = 12; } @@ -84,5 +86,6 @@ message CrossChainValidator { // MaturingVSCPacket contains the maturing time of a received VSCPacket message MaturingVSCPacket { uint64 vscId = 1; - google.protobuf.Timestamp maturity_time = 2 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; + google.protobuf.Timestamp maturity_time = 2 + [ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ]; } diff --git a/proto/interchain_security/ccv/consumer/v1/genesis.proto b/proto/interchain_security/ccv/consumer/v1/genesis.proto index 578518086c..739ac2798e 100644 --- a/proto/interchain_security/ccv/consumer/v1/genesis.proto +++ b/proto/interchain_security/ccv/consumer/v1/genesis.proto @@ -15,16 +15,18 @@ import "gogoproto/gogo.proto"; // GenesisState defines the CCV consumer chain genesis state message GenesisState { Params params = 1 [ (gogoproto.nullable) = false ]; - string provider_client_id = 2; // empty for a new chain, filled in on restart. - string provider_channel_id = 3; // empty for a new chain, filled in on restart. - bool new_chain = 4; // true for new chain GenesisState, false for chain restart. + string provider_client_id = 2; // empty for a new chain, filled in on restart. + string provider_channel_id = + 3; // empty for a new chain, filled in on restart. + bool new_chain = + 4; // true for new chain GenesisState, false for chain restart. // ProviderClientState filled in on new chain, nil on restart. ibc.lightclients.tendermint.v1.ClientState provider_client_state = 5; // ProviderConsensusState filled in on new chain, nil on restart. ibc.lightclients.tendermint.v1.ConsensusState provider_consensus_state = 6; // MaturingPackets nil on new chain, filled in on restart. - repeated interchain_security.ccv.consumer.v1.MaturingVSCPacket maturing_packets = 7 - [ (gogoproto.nullable) = false ]; + repeated interchain_security.ccv.consumer.v1.MaturingVSCPacket + maturing_packets = 7 [ (gogoproto.nullable) = false ]; // InitialValset filled in on new chain and on restart. repeated .tendermint.abci.ValidatorUpdate initial_val_set = 8 [ (gogoproto.nullable) = false ]; @@ -35,15 +37,16 @@ message GenesisState { repeated OutstandingDowntime outstanding_downtime_slashing = 10 [ (gogoproto.nullable) = false ]; // PendingConsumerPackets nil on new chain, filled in on restart. - interchain_security.ccv.v1.ConsumerPacketDataList pending_consumer_packets = 11 - [ (gogoproto.nullable) = false ]; + interchain_security.ccv.v1.ConsumerPacketDataList pending_consumer_packets = + 11 [ (gogoproto.nullable) = false ]; // LastTransmissionBlockHeight nil on new chain, filled in on restart. - interchain_security.ccv.consumer.v1.LastTransmissionBlockHeight last_transmission_block_height = 12 - [ (gogoproto.nullable) = false ]; - bool preCCV = 13; // flag indicating whether the consumer CCV module starts in pre-CCV state + interchain_security.ccv.consumer.v1.LastTransmissionBlockHeight + last_transmission_block_height = 12 [ (gogoproto.nullable) = false ]; + bool preCCV = 13; // flag indicating whether the consumer CCV module starts in + // pre-CCV state } -// HeightValsetUpdateID defines the genesis information for the mapping +// HeightValsetUpdateID defines the genesis information for the mapping // of each block height to a valset update id message HeightToValsetUpdateID { uint64 height = 1; diff --git a/proto/interchain_security/ccv/consumer/v1/query.proto b/proto/interchain_security/ccv/consumer/v1/query.proto index 8efbfa2f8b..b5576b57fe 100644 --- a/proto/interchain_security/ccv/consumer/v1/query.proto +++ b/proto/interchain_security/ccv/consumer/v1/query.proto @@ -39,10 +39,10 @@ message NextFeeDistributionEstimate { string toConsumer = 7; } -message QueryNextFeeDistributionEstimateRequest { } +message QueryNextFeeDistributionEstimateRequest {} message QueryNextFeeDistributionEstimateResponse { - NextFeeDistributionEstimate data = 1; + NextFeeDistributionEstimate data = 1; } message QueryParamsRequest {} @@ -50,5 +50,5 @@ message QueryParamsRequest {} // QueryParamsResponse is response type for the Query/Params RPC method. message QueryParamsResponse { // params holds all the parameters of this module. - Params params = 1 [(gogoproto.nullable) = false]; + Params params = 1 [ (gogoproto.nullable) = false ]; } diff --git a/proto/interchain_security/ccv/provider/v1/genesis.proto b/proto/interchain_security/ccv/provider/v1/genesis.proto index bf7fe58d15..e1c241413b 100644 --- a/proto/interchain_security/ccv/provider/v1/genesis.proto +++ b/proto/interchain_security/ccv/provider/v1/genesis.proto @@ -11,41 +11,39 @@ import "interchain_security/ccv/consumer/v1/consumer.proto"; import "interchain_security/ccv/consumer/v1/genesis.proto"; import "tendermint/crypto/keys.proto"; - // GenesisState defines the CCV provider chain genesis state message GenesisState { // strictly positive and set to 1 (DefaultValsetUpdateID) for a new chain - uint64 valset_update_id = 1; + uint64 valset_update_id = 1; // empty for a new chain - repeated ConsumerState consumer_states = 2 [ + repeated ConsumerState consumer_states = 2 [ (gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"consumer_states\"" ]; // empty for a new chain repeated interchain_security.ccv.provider.v1.UnbondingOp unbonding_ops = 3 - [ (gogoproto.nullable) = false ]; + [ (gogoproto.nullable) = false ]; // empty for a new chain interchain_security.ccv.v1.MaturedUnbondingOps mature_unbonding_ops = 4; - // empty for a new chain + // empty for a new chain repeated ValsetUpdateIdToHeight valset_update_id_to_height = 5 - [ (gogoproto.nullable) = false ]; + [ (gogoproto.nullable) = false ]; // empty for a new chain repeated ConsumerAdditionProposal consumer_addition_proposals = 6 - [ (gogoproto.nullable) = false ]; + [ (gogoproto.nullable) = false ]; // empty for a new chain repeated ConsumerRemovalProposal consumer_removal_proposals = 7 - [ (gogoproto.nullable) = false ]; - Params params = 8 - [ (gogoproto.nullable) = false ]; + [ (gogoproto.nullable) = false ]; + Params params = 8 [ (gogoproto.nullable) = false ]; // empty for a new chain repeated ValidatorConsumerPubKey validator_consumer_pubkeys = 9 - [ (gogoproto.nullable) = false ]; + [ (gogoproto.nullable) = false ]; // empty for a new chain repeated ValidatorByConsumerAddr validators_by_consumer_addr = 10 - [ (gogoproto.nullable) = false ]; + [ (gogoproto.nullable) = false ]; // empty for a new chain repeated ConsumerAddrsToPrune consumer_addrs_to_prune = 11 - [ (gogoproto.nullable) = false ]; + [ (gogoproto.nullable) = false ]; } // consumer chain @@ -60,19 +58,21 @@ message ConsumerState { uint64 initial_height = 4; // ConsumerGenesis defines the initial consumer chain genesis states interchain_security.ccv.consumer.v1.GenesisState consumer_genesis = 5 - [ (gogoproto.nullable) = false ]; - // PendingValsetChanges defines the pending validator set changes for the consumer chain - repeated interchain_security.ccv.v1.ValidatorSetChangePacketData pending_valset_changes = 6 - [ (gogoproto.nullable) = false ]; + [ (gogoproto.nullable) = false ]; + // PendingValsetChanges defines the pending validator set changes for the + // consumer chain + repeated interchain_security.ccv.v1.ValidatorSetChangePacketData + pending_valset_changes = 6 [ (gogoproto.nullable) = false ]; repeated string slash_downtime_ack = 7; - // UnbondingOpsIndex defines the unbonding operations waiting on this consumer chain - repeated interchain_security.ccv.provider.v1.VscUnbondingOps unbonding_ops_index = 8 - [ (gogoproto.nullable) = false ]; + // UnbondingOpsIndex defines the unbonding operations waiting on this consumer + // chain + repeated interchain_security.ccv.provider.v1.VscUnbondingOps + unbonding_ops_index = 8 [ (gogoproto.nullable) = false ]; } -// ValsetUpdateIdToHeight defines the genesis information for the mapping +// ValsetUpdateIdToHeight defines the genesis information for the mapping // of each valset udpate id to a block height message ValsetUpdateIdToHeight { - uint64 valset_update_id = 1; - uint64 height = 2; + uint64 valset_update_id = 1; + uint64 height = 2; } diff --git a/proto/interchain_security/ccv/provider/v1/provider.proto b/proto/interchain_security/ccv/provider/v1/provider.proto index d190b3a6ca..f235f0831a 100644 --- a/proto/interchain_security/ccv/provider/v1/provider.proto +++ b/proto/interchain_security/ccv/provider/v1/provider.proto @@ -13,141 +13,155 @@ import "tendermint/crypto/keys.proto"; import "cosmos/evidence/v1beta1/evidence.proto"; import "cosmos/base/v1beta1/coin.proto"; -// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain. -// If it passes, then all validators on the provider chain are expected to validate the consumer chain at spawn time -// or get slashed. It is recommended that spawn time occurs after the proposal end time. +// ConsumerAdditionProposal is a governance proposal on the provider chain to +// spawn a new consumer chain. If it passes, then all validators on the provider +// chain are expected to validate the consumer chain at spawn time or get +// slashed. It is recommended that spawn time occurs after the proposal end +// time. message ConsumerAdditionProposal { - option (gogoproto.goproto_getters) = false; - option (gogoproto.goproto_stringer) = false; - - // the title of the proposal - string title = 1; - // the description of the proposal - string description = 2; - // the proposed chain-id of the new consumer chain, must be different from all other consumer chain ids of the executing - // provider chain. - string chain_id = 3 ; - // the proposed initial height of new consumer chain. - // For a completely new chain, this will be {0,1}. However, it may be different if this is a chain that is converting to a consumer chain. - ibc.core.client.v1.Height initial_height = 4 [(gogoproto.nullable) = false]; - // The hash of the consumer chain genesis state without the consumer CCV module genesis params. - // It is used for off-chain confirmation of genesis.json validity by validators and other parties. - bytes genesis_hash = 5 ; - // The hash of the consumer chain binary that should be run by validators on chain initialization. - // It is used for off-chain confirmation of binary validity by validators and other parties. - bytes binary_hash = 6 ; - // spawn time is the time on the provider chain at which the consumer chain genesis is finalized and all validators - // will be responsible for starting their consumer chain validator node. - google.protobuf.Timestamp spawn_time = 7 - [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; - - // Unbonding period for the consumer, - // which should be smaller than that of the provider in general. - google.protobuf.Duration unbonding_period = 8 - [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; - // Sent CCV related IBC packets will timeout after this duration - google.protobuf.Duration ccv_timeout_period = 9 - [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; - // Sent transfer related IBC packets will timeout after this duration - google.protobuf.Duration transfer_timeout_period = 10 - [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; - // The fraction of tokens allocated to the consumer redistribution address - // during distribution events. The fraction is a string representing a - // decimal number. For example "0.75" would represent 75%. - string consumer_redistribution_fraction = 11; - // BlocksPerDistributionTransmission is the number of blocks between ibc-token-transfers from the consumer chain to the provider chain. - // On sending transmission event, `consumer_redistribution_fraction` of the accumulated tokens are sent to the consumer redistribution address. - int64 blocks_per_distribution_transmission = 12; - // The number of historical info entries to persist in store. - // This param is a part of the cosmos sdk staking module. In the case of - // a ccv enabled consumer chain, the ccv module acts as the staking module. - int64 historical_entries = 13; - // The ID of a token transfer channel used for the Reward Distribution - // sub-protocol. If DistributionTransmissionChannel == "", a new transfer - // channel is created on top of the same connection as the CCV channel. - // Note that transfer_channel_id is the ID of the channel end on the consumer chain. - // it is most relevant for chains performing a sovereign to consumer changeover - // in order to maintan the existing ibc transfer channel - string distribution_transmission_channel = 14; -} - -// ConsumerRemovalProposal is a governance proposal on the provider chain to remove (and stop) a consumer chain. -// If it passes, all the consumer chain's state is removed from the provider chain. The outstanding unbonding -// operation funds are released. + option (gogoproto.goproto_getters) = false; + option (gogoproto.goproto_stringer) = false; + + // the title of the proposal + string title = 1; + // the description of the proposal + string description = 2; + // the proposed chain-id of the new consumer chain, must be different from all + // other consumer chain ids of the executing provider chain. + string chain_id = 3; + // the proposed initial height of new consumer chain. + // For a completely new chain, this will be {0,1}. However, it may be + // different if this is a chain that is converting to a consumer chain. + ibc.core.client.v1.Height initial_height = 4 [ (gogoproto.nullable) = false ]; + // The hash of the consumer chain genesis state without the consumer CCV + // module genesis params. It is used for off-chain confirmation of + // genesis.json validity by validators and other parties. + bytes genesis_hash = 5; + // The hash of the consumer chain binary that should be run by validators on + // chain initialization. It is used for off-chain confirmation of binary + // validity by validators and other parties. + bytes binary_hash = 6; + // spawn time is the time on the provider chain at which the consumer chain + // genesis is finalized and all validators will be responsible for starting + // their consumer chain validator node. + google.protobuf.Timestamp spawn_time = 7 + [ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ]; + + // Unbonding period for the consumer, + // which should be smaller than that of the provider in general. + google.protobuf.Duration unbonding_period = 8 + [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; + // Sent CCV related IBC packets will timeout after this duration + google.protobuf.Duration ccv_timeout_period = 9 + [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; + // Sent transfer related IBC packets will timeout after this duration + google.protobuf.Duration transfer_timeout_period = 10 + [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; + // The fraction of tokens allocated to the consumer redistribution address + // during distribution events. The fraction is a string representing a + // decimal number. For example "0.75" would represent 75%. + string consumer_redistribution_fraction = 11; + // BlocksPerDistributionTransmission is the number of blocks between + // ibc-token-transfers from the consumer chain to the provider chain. On + // sending transmission event, `consumer_redistribution_fraction` of the + // accumulated tokens are sent to the consumer redistribution address. + int64 blocks_per_distribution_transmission = 12; + // The number of historical info entries to persist in store. + // This param is a part of the cosmos sdk staking module. In the case of + // a ccv enabled consumer chain, the ccv module acts as the staking module. + int64 historical_entries = 13; + // The ID of a token transfer channel used for the Reward Distribution + // sub-protocol. If DistributionTransmissionChannel == "", a new transfer + // channel is created on top of the same connection as the CCV channel. + // Note that transfer_channel_id is the ID of the channel end on the consumer + // chain. it is most relevant for chains performing a sovereign to consumer + // changeover in order to maintan the existing ibc transfer channel + string distribution_transmission_channel = 14; +} + +// ConsumerRemovalProposal is a governance proposal on the provider chain to +// remove (and stop) a consumer chain. If it passes, all the consumer chain's +// state is removed from the provider chain. The outstanding unbonding operation +// funds are released. message ConsumerRemovalProposal { - // the title of the proposal - string title = 1; - // the description of the proposal - string description = 2; - // the chain-id of the consumer chain to be stopped - string chain_id = 3; - // the time on the provider chain at which all validators are responsible to stop their consumer chain validator node - google.protobuf.Timestamp stop_time = 4 - [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; - } + // the title of the proposal + string title = 1; + // the description of the proposal + string description = 2; + // the chain-id of the consumer chain to be stopped + string chain_id = 3; + // the time on the provider chain at which all validators are responsible to + // stop their consumer chain validator node + google.protobuf.Timestamp stop_time = 4 + [ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ]; +} message EquivocationProposal { // the title of the proposal string title = 1; // the description of the proposal string description = 2; - // the list of equivocations that will be processed + // the list of equivocations that will be processed repeated cosmos.evidence.v1beta1.Equivocation equivocations = 3; } -// A persisted queue entry indicating that a slash packet data instance needs to be handled. -// This type belongs in the "global" queue, to coordinate slash packet handling times between consumers. +// A persisted queue entry indicating that a slash packet data instance needs to +// be handled. This type belongs in the "global" queue, to coordinate slash +// packet handling times between consumers. message GlobalSlashEntry { // Block time that slash packet was received by provider chain. // This field is used for store key iteration ordering. google.protobuf.Timestamp recv_time = 1 - [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; + [ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ]; // The consumer that sent a slash packet. - string consumer_chain_id = 2 - [(gogoproto.customname) = "ConsumerChainID"]; - // The IBC sequence number of the recv packet. + string consumer_chain_id = 2 [ (gogoproto.customname) = "ConsumerChainID" ]; + // The IBC sequence number of the recv packet. // This field is used in the store key to ensure uniqueness. - uint64 ibc_seq_num = 3; - // The provider's consensus address of the validator being slashed. + uint64 ibc_seq_num = 3; + // The provider's consensus address of the validator being slashed. // This field is used to obtain validator power in HandleThrottleQueues. - // - // This field is not used in the store key, but is persisted in value bytes, see QueueGlobalSlashEntry. + // + // This field is not used in the store key, but is persisted in value bytes, + // see QueueGlobalSlashEntry. bytes provider_val_cons_addr = 4; } - + // Params defines the parameters for CCV Provider module message Params { ibc.lightclients.tendermint.v1.ClientState template_client = 1; - // TrustingPeriodFraction is used to compute the consumer and provider IBC client's TrustingPeriod from the chain defined UnbondingPeriod + // TrustingPeriodFraction is used to compute the consumer and provider IBC + // client's TrustingPeriod from the chain defined UnbondingPeriod string trusting_period_fraction = 2; // Sent IBC packets will timeout after this duration google.protobuf.Duration ccv_timeout_period = 3 - [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; - // The channel initialization (IBC channel opening handshake) will timeout after this duration + [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; + // The channel initialization (IBC channel opening handshake) will timeout + // after this duration google.protobuf.Duration init_timeout_period = 4 - [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; + [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; // The VSC packets sent by the provider will timeout after this duration. - // Note that unlike ccv_timeout_period which is an IBC param, - // the vsc_timeout_period is a provider-side param that enables the provider - // to timeout VSC packets even when a consumer chain is not live. + // Note that unlike ccv_timeout_period which is an IBC param, + // the vsc_timeout_period is a provider-side param that enables the provider + // to timeout VSC packets even when a consumer chain is not live. google.protobuf.Duration vsc_timeout_period = 5 - [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; + [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; // The period for which the slash meter is replenished google.protobuf.Duration slash_meter_replenish_period = 6 - [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; + [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; - // The fraction of total voting power that is replenished to the slash meter every replenish period. - // This param also serves as a maximum fraction of total voting power that the slash meter can hold. + // The fraction of total voting power that is replenished to the slash meter + // every replenish period. This param also serves as a maximum fraction of + // total voting power that the slash meter can hold. string slash_meter_replenish_fraction = 7; - // The maximum amount of throttled slash or vsc matured packets + // The maximum amount of throttled slash or vsc matured packets // that can be queued for a single consumer before the provider chain halts. int64 max_throttled_packets = 8; // The fee required to be paid to add a reward denom cosmos.base.v1beta1.Coin consumer_reward_denom_registration_fee = 9 - [(gogoproto.nullable) = false]; + [ (gogoproto.nullable) = false ]; } message HandshakeMetadata { @@ -157,26 +171,24 @@ message HandshakeMetadata { // SlashAcks contains cons addresses of consumer chain validators // successfully slashed on the provider chain -message SlashAcks { - repeated string addresses = 1; -} +message SlashAcks { repeated string addresses = 1; } -// ConsumerAdditionProposals holds pending governance proposals on the provider chain to spawn a new chain. +// ConsumerAdditionProposals holds pending governance proposals on the provider +// chain to spawn a new chain. message ConsumerAdditionProposals { // proposals waiting for spawn_time to pass repeated ConsumerAdditionProposal pending = 1; } -// ConsumerRemovalProposals holds pending governance proposals on the provider chain to remove (and stop) a consumer chain. +// ConsumerRemovalProposals holds pending governance proposals on the provider +// chain to remove (and stop) a consumer chain. message ConsumerRemovalProposals { // proposals waiting for stop_time to pass repeated ConsumerRemovalProposal pending = 1; } // AddressList contains a list of consensus addresses -message AddressList { - repeated bytes addresses = 1; -} +message AddressList { repeated bytes addresses = 1; } message ChannelToChain { string channel_id = 1; @@ -184,13 +196,13 @@ message ChannelToChain { } // VscUnbondingOps contains the IDs of unbonding operations that are waiting for -// at least one VSCMaturedPacket with vscID from a consumer chain +// at least one VSCMaturedPacket with vscID from a consumer chain message VscUnbondingOps { uint64 vsc_id = 1; repeated uint64 unbonding_op_ids = 2; } -// UnbondingOp contains the ids of consumer chains that need to unbond before +// UnbondingOp contains the ids of consumer chains that need to unbond before // the unbonding operation with the given ID can unbond message UnbondingOp { uint64 id = 1; @@ -205,7 +217,8 @@ message InitTimeoutTimestamp { message VscSendTimestamp { uint64 vsc_id = 1; - google.protobuf.Timestamp timestamp = 2 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; + google.protobuf.Timestamp timestamp = 2 + [ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ]; } // @@ -219,7 +232,8 @@ message KeyAssignmentReplacement { } // Used to serialize the ValidatorConsumerPubKey index from key assignment -// ValidatorConsumerPubKey: (chainID, providerAddr consAddr) -> consumerKey tmprotocrypto.PublicKey +// ValidatorConsumerPubKey: (chainID, providerAddr consAddr) -> consumerKey +// tmprotocrypto.PublicKey message ValidatorConsumerPubKey { string chain_id = 1; bytes provider_addr = 2; @@ -227,7 +241,8 @@ message ValidatorConsumerPubKey { } // Used to serialize the ValidatorConsumerAddr index from key assignment -// ValidatorByConsumerAddr: (chainID, consumerAddr consAddr) -> providerAddr consAddr +// ValidatorByConsumerAddr: (chainID, consumerAddr consAddr) -> providerAddr +// consAddr message ValidatorByConsumerAddr { string chain_id = 1; bytes consumer_addr = 2; diff --git a/proto/interchain_security/ccv/provider/v1/query.proto b/proto/interchain_security/ccv/provider/v1/query.proto index c98a8cba1e..4709b287dd 100644 --- a/proto/interchain_security/ccv/provider/v1/query.proto +++ b/proto/interchain_security/ccv/provider/v1/query.proto @@ -10,7 +10,6 @@ import "interchain_security/ccv/v1/ccv.proto"; import "interchain_security/ccv/consumer/v1/genesis.proto"; import "interchain_security/ccv/provider/v1/provider.proto"; - service Query { // ConsumerGenesis queries the genesis state needed to start a consumer chain // whose proposal has been accepted @@ -46,33 +45,41 @@ service Query { // assigned by a validator for a consumer chain. rpc QueryValidatorConsumerAddr(QueryValidatorConsumerAddrRequest) returns (QueryValidatorConsumerAddrResponse) { - option (google.api.http).get = "/interchain_security/ccv/provider/validator_consumer_addr"; + option (google.api.http).get = + "/interchain_security/ccv/provider/validator_consumer_addr"; } // QueryProviderAddr returns the provider chain validator // given a consumer chain validator address rpc QueryValidatorProviderAddr(QueryValidatorProviderAddrRequest) returns (QueryValidatorProviderAddrResponse) { - option (google.api.http).get = "/interchain_security/ccv/provider/validator_provider_addr"; + option (google.api.http).get = + "/interchain_security/ccv/provider/validator_provider_addr"; } - // QueryThrottleState returns the main on-chain state relevant to currently throttled slash packets + // QueryThrottleState returns the main on-chain state relevant to currently + // throttled slash packets rpc QueryThrottleState(QueryThrottleStateRequest) returns (QueryThrottleStateResponse) { - option (google.api.http).get = "/interchain_security/ccv/provider/throttle_state"; + option (google.api.http).get = + "/interchain_security/ccv/provider/throttle_state"; } - // QueryThrottledConsumerPacketData returns a list of pending packet data instances - // (slash packet and vsc matured) for a single consumer chain + // QueryThrottledConsumerPacketData returns a list of pending packet data + // instances (slash packet and vsc matured) for a single consumer chain rpc QueryThrottledConsumerPacketData(QueryThrottledConsumerPacketDataRequest) returns (QueryThrottledConsumerPacketDataResponse) { - option (google.api.http).get = "/interchain_security/ccv/provider/pending_consumer_packets"; + option (google.api.http).get = + "/interchain_security/ccv/provider/pending_consumer_packets"; } - // QueryRegisteredConsumerRewardDenoms returns a list of consumer reward denoms that are registered - rpc QueryRegisteredConsumerRewardDenoms(QueryRegisteredConsumerRewardDenomsRequest) + // QueryRegisteredConsumerRewardDenoms returns a list of consumer reward + // denoms that are registered + rpc QueryRegisteredConsumerRewardDenoms( + QueryRegisteredConsumerRewardDenomsRequest) returns (QueryRegisteredConsumerRewardDenomsResponse) { - option (google.api.http).get = "/interchain_security/ccv/provider/registered_consumer_reward_denoms"; + option (google.api.http).get = + "/interchain_security/ccv/provider/registered_consumer_reward_denoms"; } } @@ -89,13 +96,13 @@ message QueryConsumerChainsResponse { repeated Chain chains = 1; } message QueryConsumerChainStartProposalsRequest {} -message QueryConsumerChainStartProposalsResponse { +message QueryConsumerChainStartProposalsResponse { ConsumerAdditionProposals proposals = 1; } message QueryConsumerChainStopProposalsRequest {} -message QueryConsumerChainStopProposalsResponse { +message QueryConsumerChainStopProposalsResponse { ConsumerRemovalProposals proposals = 1; } @@ -110,8 +117,7 @@ message QueryValidatorConsumerAddrRequest { // The id of the consumer chain string chain_id = 1; // The consensus address of the validator on the provider chain - string provider_address = 2 - [ (gogoproto.moretags) = "yaml:\"address\"" ]; + string provider_address = 2 [ (gogoproto.moretags) = "yaml:\"address\"" ]; } message QueryValidatorConsumerAddrResponse { @@ -125,8 +131,7 @@ message QueryValidatorProviderAddrRequest { // The id of the provider chain string chain_id = 1; // The consensus address of the validator on the consumer chain - string consumer_address = 2 - [ (gogoproto.moretags) = "yaml:\"address\"" ]; + string consumer_address = 2 [ (gogoproto.moretags) = "yaml:\"address\"" ]; } message QueryValidatorProviderAddrResponse { @@ -139,36 +144,37 @@ message QueryThrottleStateRequest {} message QueryThrottleStateResponse { // current slash_meter state int64 slash_meter = 1; - // allowance of voting power units (int) that the slash meter is given per replenish period - // this also serves as the max value for the meter. + // allowance of voting power units (int) that the slash meter is given per + // replenish period this also serves as the max value for the meter. int64 slash_meter_allowance = 2; - // next time the slash meter could potentially be replenished, iff it's not full + // next time the slash meter could potentially be replenished, iff it's not + // full google.protobuf.Timestamp next_replenish_candidate = 3 - [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; + [ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ]; // data relevant to currently throttled slash packets repeated ThrottledSlashPacket packets = 4; } -message QueryThrottledConsumerPacketDataRequest { - string chain_id = 1; -} +message QueryThrottledConsumerPacketDataRequest { string chain_id = 1; } message QueryThrottledConsumerPacketDataResponse { string chain_id = 1; uint64 size = 2; repeated ThrottledPacketDataWrapper packetDataInstances = 3 - [(gogoproto.nullable) = false]; + [ (gogoproto.nullable) = false ]; } -// A query wrapper type for the global entry and data relevant to a throttled slash packet. +// A query wrapper type for the global entry and data relevant to a throttled +// slash packet. message ThrottledSlashPacket { interchain_security.ccv.provider.v1.GlobalSlashEntry global_entry = 1 - [(gogoproto.nullable) = false]; + [ (gogoproto.nullable) = false ]; interchain_security.ccv.v1.SlashPacketData data = 2 - [(gogoproto.nullable) = false]; + [ (gogoproto.nullable) = false ]; } -// ThrottledPacketDataWrapper contains either SlashPacketData or VSCMaturedPacketData +// ThrottledPacketDataWrapper contains either SlashPacketData or +// VSCMaturedPacketData message ThrottledPacketDataWrapper { oneof data { interchain_security.ccv.v1.SlashPacketData slash_packet = 1; diff --git a/proto/interchain_security/ccv/provider/v1/tx.proto b/proto/interchain_security/ccv/provider/v1/tx.proto index 705e155317..3093132727 100644 --- a/proto/interchain_security/ccv/provider/v1/tx.proto +++ b/proto/interchain_security/ccv/provider/v1/tx.proto @@ -10,8 +10,10 @@ import "google/protobuf/any.proto"; // Msg defines the Msg service. service Msg { - rpc AssignConsumerKey(MsgAssignConsumerKey) returns (MsgAssignConsumerKeyResponse); - rpc RegisterConsumerRewardDenom(MsgRegisterConsumerRewardDenom) returns (MsgRegisterConsumerRewardDenomResponse); + rpc AssignConsumerKey(MsgAssignConsumerKey) + returns (MsgAssignConsumerKeyResponse); + rpc RegisterConsumerRewardDenom(MsgRegisterConsumerRewardDenom) + returns (MsgRegisterConsumerRewardDenomResponse); } message MsgAssignConsumerKey { @@ -20,26 +22,26 @@ message MsgAssignConsumerKey { // The chain id of the consumer chain to assign a consensus public key to string chain_id = 1; // The validator address on the provider - string provider_addr = 2 - [ (gogoproto.moretags) = "yaml:\"address\"" ]; + string provider_addr = 2 [ (gogoproto.moretags) = "yaml:\"address\"" ]; // The consensus public key to use on the consumer. - // in json string format corresponding to proto-any, ex: + // in json string format corresponding to proto-any, ex: // `{"@type":"/cosmos.crypto.ed25519.PubKey","key":"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is="}` string consumer_key = 3; } message MsgAssignConsumerKeyResponse {} -// MsgRegisterConsumerRewardDenom allows an account to register -// a consumer reward denom, i.e., add it to the list of denoms +// MsgRegisterConsumerRewardDenom allows an account to register +// a consumer reward denom, i.e., add it to the list of denoms // accepted by the provider as rewards. message MsgRegisterConsumerRewardDenom { - option (gogoproto.equal) = false; + option (gogoproto.equal) = false; option (gogoproto.goproto_getters) = false; string denom = 1; string depositor = 2; } -// MsgRegisterConsumerRewardDenomResponse defines the Msg/RegisterConsumerRewardDenom response type. +// MsgRegisterConsumerRewardDenomResponse defines the +// Msg/RegisterConsumerRewardDenom response type. message MsgRegisterConsumerRewardDenomResponse {} \ No newline at end of file diff --git a/proto/interchain_security/ccv/v1/ccv.proto b/proto/interchain_security/ccv/v1/ccv.proto index f13951f4d6..730366ea7f 100644 --- a/proto/interchain_security/ccv/v1/ccv.proto +++ b/proto/interchain_security/ccv/v1/ccv.proto @@ -27,9 +27,8 @@ message ValidatorSetChangePacketData { // List of ccv.ValidatorSetChangePacketData. message ValidatorSetChangePackets { - repeated ValidatorSetChangePacketData list = 1 [ - (gogoproto.nullable) = false - ]; + repeated ValidatorSetChangePacketData list = 1 + [ (gogoproto.nullable) = false ]; } // This packet is sent from the consumer chain to the provider chain @@ -50,17 +49,16 @@ message SlashPacketData { // map to the infraction block height on the provider uint64 valset_update_id = 2; // tell if the slashing is for a downtime or a double-signing infraction - cosmos.staking.v1beta1.InfractionType infraction = 3; + cosmos.staking.v1beta1.Infraction infraction = 3; } -// MaturedUnbondingOps defines a list of ids corresponding to ids of matured unbonding operations. -message MaturedUnbondingOps { - repeated uint64 ids = 1; -} +// MaturedUnbondingOps defines a list of ids corresponding to ids of matured +// unbonding operations. +message MaturedUnbondingOps { repeated uint64 ids = 1; } // ConsumerPacketData contains a consumer packet data and a type tag message ConsumerPacketData { - ConsumerPacketDataType type = 1; + ConsumerPacketDataType type = 1; oneof data { SlashPacketData slashPacketData = 2; @@ -68,22 +66,22 @@ message ConsumerPacketData { } } - // ConsumerPacketDataList is a list of consumer packet data packets. message ConsumerPacketDataList { - repeated ConsumerPacketData list = 1 - [ (gogoproto.nullable) = false ]; + repeated ConsumerPacketData list = 1 [ (gogoproto.nullable) = false ]; } - // ConsumerPacketType indicates interchain security specific packet types. enum ConsumerPacketDataType { option (gogoproto.goproto_enum_prefix) = false; // UNSPECIFIED packet type - CONSUMER_PACKET_TYPE_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "UnspecifiedPacket"]; + CONSUMER_PACKET_TYPE_UNSPECIFIED = 0 + [ (gogoproto.enumvalue_customname) = "UnspecifiedPacket" ]; // Slash packet - CONSUMER_PACKET_TYPE_SLASH = 1 [(gogoproto.enumvalue_customname) = "SlashPacket"]; + CONSUMER_PACKET_TYPE_SLASH = 1 + [ (gogoproto.enumvalue_customname) = "SlashPacket" ]; // VSCMatured packet - CONSUMER_PACKET_TYPE_VSCM = 2 [(gogoproto.enumvalue_customname) = "VscMaturedPacket"]; + CONSUMER_PACKET_TYPE_VSCM = 2 + [ (gogoproto.enumvalue_customname) = "VscMaturedPacket" ]; } \ No newline at end of file diff --git a/scripts/protocgen.sh b/scripts/protocgen.sh index 530b0fc24d..a6ca6098e4 100644 --- a/scripts/protocgen.sh +++ b/scripts/protocgen.sh @@ -19,4 +19,3 @@ cd .. cp -r github.com/cosmos/interchain-security/v2/* ./ rm -rf github.com -go mod tidy -compat=1.19 diff --git a/tests/difference/core/driver/common.go b/tests/difference/core/driver/common.go index b05b794203..bff271e235 100644 --- a/tests/difference/core/driver/common.go +++ b/tests/difference/core/driver/common.go @@ -3,11 +3,10 @@ package core import ( "time" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + tmtypes "github.com/cometbft/cometbft/types" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - abci "github.com/tendermint/tendermint/abci/types" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - tmtypes "github.com/tendermint/tendermint/types" ) const ( @@ -36,7 +35,7 @@ type InitState struct { Trusting time.Duration MaxClockDrift time.Duration BlockInterval time.Duration - ConsensusParams *abci.ConsensusParams + ConsensusParams *tmproto.ConsensusParams ValStates ValStates MaxEntries int } @@ -76,8 +75,8 @@ func init() { }, }, MaxEntries: 1000000, - ConsensusParams: &abci.ConsensusParams{ - Block: &abci.BlockParams{ + ConsensusParams: &tmproto.ConsensusParams{ + Block: &tmproto.BlockParams{ MaxBytes: 9223372036854775807, MaxGas: 9223372036854775807, }, diff --git a/tests/difference/core/driver/core_test.go b/tests/difference/core/driver/core_test.go index 389935e2bc..df20aef074 100644 --- a/tests/difference/core/driver/core_test.go +++ b/tests/difference/core/driver/core_test.go @@ -8,7 +8,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/suite" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" ibctestingcore "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/core" ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" @@ -66,7 +66,7 @@ func (s *CoreSuite) consumerChain() *ibctesting.TestChain { } func (b *CoreSuite) providerStakingKeeper() stakingkeeper.Keeper { - return b.providerChain().App.(*appProvider.App).StakingKeeper + return *b.providerChain().App.(*appProvider.App).StakingKeeper } func (b *CoreSuite) providerSlashingKeeper() slashingkeeper.Keeper { @@ -152,7 +152,8 @@ func (s *CoreSuite) delegatorBalance() int64 { // delegate delegates amt tokens to validator val func (s *CoreSuite) delegate(val, amt int64) { - server := stakingkeeper.NewMsgServerImpl(s.providerStakingKeeper()) + providerStaking := s.providerStakingKeeper() + server := stakingkeeper.NewMsgServerImpl(&providerStaking) coin := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(amt)) d := s.delegator() v := s.validator(val) @@ -164,7 +165,8 @@ func (s *CoreSuite) delegate(val, amt int64) { // undelegate undelegates amt tokens from validator val func (s *CoreSuite) undelegate(val, amt int64) { - server := stakingkeeper.NewMsgServerImpl(s.providerStakingKeeper()) + providerStaking := s.providerStakingKeeper() + server := stakingkeeper.NewMsgServerImpl(&providerStaking) coin := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(amt)) d := s.delegator() v := s.validator(val) @@ -177,13 +179,13 @@ func (s *CoreSuite) undelegate(val, amt int64) { // consumerSlash simulates a slash event occurring on the consumer chain. // It can be for a downtime or doublesign. func (s *CoreSuite) consumerSlash(val sdk.ConsAddress, h int64, isDowntime bool) { - kind := stakingtypes.DoubleSign + kind := stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN if isDowntime { - kind = stakingtypes.Downtime + kind = stakingtypes.Infraction_INFRACTION_DOWNTIME } ctx := s.ctx(C) before := len(ctx.EventManager().Events()) - s.consumerKeeper().Slash(ctx, val, h, 0, sdk.Dec{}, kind) + s.consumerKeeper().SlashWithInfractionReason(ctx, val, h, 0, sdk.Dec{}, kind) // consumer module emits packets on slash, so these must be collected. evts := ctx.EventManager().ABCIEvents() for _, e := range evts[before:] { diff --git a/tests/difference/core/driver/seed_gen_fuzzy_test.go b/tests/difference/core/driver/seed_gen_fuzzy_test.go index 5843cf9f04..0ea051c63b 100644 --- a/tests/difference/core/driver/seed_gen_fuzzy_test.go +++ b/tests/difference/core/driver/seed_gen_fuzzy_test.go @@ -6,11 +6,11 @@ import ( cryptoEd25519 "crypto/ed25519" + tmtypes "github.com/cometbft/cometbft/types" cosmosEd25519 "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - mock "github.com/cosmos/ibc-go/v4/testing/mock" - tmtypes "github.com/tendermint/tendermint/types" + mock "github.com/cosmos/ibc-go/v7/testing/mock" ) func GetPV(seed []byte) mock.PV { diff --git a/tests/difference/core/driver/setup.go b/tests/difference/core/driver/setup.go index 4798c2e3ca..1e77588c64 100644 --- a/tests/difference/core/driver/setup.go +++ b/tests/difference/core/driver/setup.go @@ -6,6 +6,10 @@ import ( "encoding/json" "time" + abci "github.com/cometbft/cometbft/abci/types" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + tmtypes "github.com/cometbft/cometbft/types" + "github.com/cosmos/cosmos-sdk/baseapp" codectypes "github.com/cosmos/cosmos-sdk/codec/types" cosmosEd25519 "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" @@ -14,20 +18,17 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" - abci "github.com/tendermint/tendermint/abci/types" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - tmtypes "github.com/tendermint/tendermint/types" ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" - commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" - ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" - "github.com/cosmos/ibc-go/v4/testing/mock" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + "github.com/cosmos/ibc-go/v7/testing/mock" slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" @@ -68,7 +69,7 @@ func (b *Builder) consumerCtx() sdk.Context { } func (b *Builder) providerStakingKeeper() stakingkeeper.Keeper { - return b.provider().App.(*appProvider.App).StakingKeeper + return *b.provider().App.(*appProvider.App).StakingKeeper } func (b *Builder) providerSlashingKeeper() slashingkeeper.Keeper { @@ -156,6 +157,7 @@ func (b *Builder) getAppBytesAndSenders( // Sum bonded is needed for BondedPool account sumBonded := sdk.NewInt(0) + initValPowers := []abci.ValidatorUpdate{} for i, val := range validators.Validators { status := b.initState.ValStates.Status[i] @@ -195,10 +197,18 @@ func (b *Builder) getAppBytesAndSenders( delegations = append(delegations, stakingtypes.NewDelegation(accounts[0].GetAddress(), val.Address.Bytes(), delShares)) // Remaining delegation is from extra account delegations = append(delegations, stakingtypes.NewDelegation(accounts[1].GetAddress(), val.Address.Bytes(), sumShares.Sub(delShares))) + + // add initial validator powers so consumer InitGenesis runs correctly + pub, _ := val.ToProto() + initValPowers = append(initValPowers, abci.ValidatorUpdate{ + Power: val.VotingPower, + PubKey: pub.PubKey, + }) } bondDenom := sdk.DefaultBondDenom genesisStaking := stakingtypes.GenesisState{} + genesisConsumer := consumertypes.GenesisState{} if genesis[stakingtypes.ModuleName] != nil { // If staking module genesis already exists @@ -206,6 +216,13 @@ func (b *Builder) getAppBytesAndSenders( bondDenom = genesisStaking.Params.BondDenom } + if genesis[consumertypes.ModuleName] != nil { + app.AppCodec().MustUnmarshalJSON(genesis[consumertypes.ModuleName], &genesisConsumer) + genesisConsumer.InitialValSet = initValPowers + genesisConsumer.Params.Enabled = true + genesis[consumertypes.ModuleName] = app.AppCodec().MustMarshalJSON(&genesisConsumer) + } + // Set model parameters genesisStaking.Params.MaxEntries = uint32(b.initState.MaxEntries) genesisStaking.Params.MaxValidators = uint32(b.initState.MaxValidators) @@ -226,7 +243,7 @@ func (b *Builder) getAppBytesAndSenders( }) // update total funds supply - genesisBank := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, sdk.NewCoins(), []banktypes.Metadata{}) + genesisBank := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, sdk.NewCoins(), []banktypes.Metadata{}, []banktypes.SendEnabled{}) genesis[banktypes.ModuleName] = app.AppCodec().MustMarshalJSON(genesisBank) stateBytes, err := json.MarshalIndent(genesis, "", " ") @@ -244,6 +261,8 @@ func (b *Builder) newChain( ) *ibctesting.TestChain { app, genesis := appInit() + baseapp.SetChainID(chainID)(app.GetBaseApp()) + stateBytes, senderAccounts := b.getAppBytesAndSenders(chainID, app, genesis, validators) app.InitChain( @@ -387,7 +406,8 @@ func (b *Builder) delegate(del int, val sdk.ValAddress, amt int64) { d := b.provider().SenderAccounts[del].SenderAccount.GetAddress() coins := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(amt)) msg := stakingtypes.NewMsgDelegate(d, val, coins) - pskServer := stakingkeeper.NewMsgServerImpl(b.providerStakingKeeper()) + providerStaking := b.providerStakingKeeper() + pskServer := stakingkeeper.NewMsgServerImpl(&providerStaking) _, err := pskServer.Delegate(sdk.WrapSDKContext(b.providerCtx()), msg) b.suite.Require().NoError(err) } @@ -415,7 +435,8 @@ func (b *Builder) addValidatorToStakingModule(privVal mock.PV) { stakingtypes.NewCommissionRates(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()), sdk.ZeroInt()) b.suite.Require().NoError(err) - pskServer := stakingkeeper.NewMsgServerImpl(b.providerStakingKeeper()) + providerStaking := b.providerStakingKeeper() + pskServer := stakingkeeper.NewMsgServerImpl(&providerStaking) _, _ = pskServer.CreateValidator(sdk.WrapSDKContext(b.providerCtx()), msg) } @@ -455,8 +476,10 @@ func (b *Builder) setProviderParams() { slash := b.providerSlashingKeeper().GetParams(b.providerCtx()) slash.SlashFractionDoubleSign = b.initState.SlashDoublesign slash.SlashFractionDowntime = b.initState.SlashDowntime - b.providerSlashingKeeper().SetParams(b.providerCtx(), slash) - + err := b.providerSlashingKeeper().SetParams(b.providerCtx(), slash) + if err != nil { + panic(err) + } // Set the throttle factors throttle := b.providerKeeper().GetParams(b.providerCtx()) throttle.SlashMeterReplenishFraction = "1.0" @@ -495,7 +518,7 @@ func (b *Builder) createConsumersLocalClientGenesis() *ibctmtypes.ClientState { return ibctmtypes.NewClientState( b.provider().ChainID, tmCfg.TrustLevel, tmCfg.TrustingPeriod, tmCfg.UnbondingPeriod, tmCfg.MaxClockDrift, b.provider().LastHeader.GetHeight().(clienttypes.Height), commitmenttypes.GetSDKSpecs(), - []string{"upgrade", "upgradedIBCState"}, tmCfg.AllowUpdateAfterExpiry, tmCfg.AllowUpdateAfterMisbehaviour, + []string{"upgrade", "upgradedIBCState"}, ) } diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index ecad541290..a16f6b3bd4 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -13,9 +13,9 @@ import ( "time" evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" "github.com/cosmos/interchain-security/v2/x/ccv/provider/client" "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" "github.com/tidwall/gjson" @@ -47,7 +47,6 @@ func (tr TestRun) sendTokens( `--home`, tr.getValidatorHome(action.chain, action.from), `--node`, tr.getValidatorNode(action.chain, action.from), `--keyring-backend`, `test`, - `-b`, `block`, `-y`, ) if verbose { @@ -57,6 +56,9 @@ func (tr TestRun) sendTokens( if err != nil { log.Fatal(err, "\n", string(bz)) } + + // wait for inclusion in a block -> '--broadcast-mode block' is deprecated + tr.waitBlocks(action.chain, 2, 30*time.Second) } type StartChainAction struct { @@ -186,7 +188,6 @@ type submitTextProposalAction struct { chain chainID from validatorID deposit uint - propType string title string description string } @@ -195,26 +196,26 @@ func (tr TestRun) submitTextProposal( action submitTextProposalAction, verbose bool, ) { + // TEXT PROPOSAL //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. bz, err := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[action.chain].binaryName, - - "tx", "gov", "submit-proposal", + "tx", "gov", "submit-legacy-proposal", `--title`, action.title, `--description`, action.description, - `--type`, action.propType, `--deposit`, fmt.Sprint(action.deposit)+`stake`, - `--from`, `validator`+fmt.Sprint(action.from), `--chain-id`, string(tr.chainConfigs[action.chain].chainId), `--home`, tr.getValidatorHome(action.chain, action.from), `--node`, tr.getValidatorNode(action.chain, action.from), `--keyring-backend`, `test`, - `-b`, `block`, `-y`, ).CombinedOutput() if err != nil { log.Fatal(err, "\n", string(bz)) } + + // wait for inclusion in a block -> '--broadcast-mode block' is deprecated + tr.waitBlocks(action.chain, 1, 10*time.Second) } type submitConsumerAdditionProposalAction struct { @@ -236,7 +237,7 @@ func (tr TestRun) submitConsumerAdditionProposal( params := consumertypes.DefaultParams() prop := client.ConsumerAdditionProposalJSON{ Title: "Propose the addition of a new chain", - Description: "Gonna be a great chain", + Summary: "Gonna be a great chain", ChainId: string(tr.chainConfigs[action.consumerChain].chainId), InitialHeight: action.initialHeight, GenesisHash: []byte("gen_hash"), @@ -271,24 +272,24 @@ func (tr TestRun) submitConsumerAdditionProposal( } //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + // CONSUMER ADDITION PROPOSAL bz, err = exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[action.chain].binaryName, - - "tx", "gov", "submit-proposal", "consumer-addition", - "/temp-proposal.json", - + "tx", "gov", "submit-legacy-proposal", "consumer-addition", "/temp-proposal.json", `--from`, `validator`+fmt.Sprint(action.from), `--chain-id`, string(tr.chainConfigs[action.chain].chainId), `--home`, tr.getValidatorHome(action.chain, action.from), `--gas`, `900000`, `--node`, tr.getValidatorNode(action.chain, action.from), `--keyring-backend`, `test`, - `-b`, `block`, `-y`, ).CombinedOutput() if err != nil { log.Fatal(err, "\n", string(bz)) } + + // wait for inclusion in a block -> '--broadcast-mode block' is deprecated + tr.waitBlocks(chainID("provi"), 2, 10*time.Second) } type submitConsumerRemovalProposalAction struct { @@ -305,11 +306,11 @@ func (tr TestRun) submitConsumerRemovalProposal( ) { stopTime := tr.containerConfig.now.Add(action.stopTimeOffset) prop := client.ConsumerRemovalProposalJSON{ - Title: fmt.Sprintf("Stop the %v chain", action.consumerChain), - Description: "It was a great chain", - ChainId: string(tr.chainConfigs[action.consumerChain].chainId), - StopTime: stopTime, - Deposit: fmt.Sprint(action.deposit) + `stake`, + Title: fmt.Sprintf("Stop the %v chain", action.consumerChain), + Summary: "It was a great chain", + ChainId: string(tr.chainConfigs[action.consumerChain].chainId), + StopTime: stopTime, + Deposit: fmt.Sprint(action.deposit) + `stake`, } bz, err := json.Marshal(prop) @@ -331,26 +332,27 @@ func (tr TestRun) submitConsumerRemovalProposal( } //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + // CONSUMER REMOVAL PROPOSAL bz, err = exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[action.chain].binaryName, - - "tx", "gov", "submit-proposal", "consumer-removal", - "/temp-proposal.json", - + "tx", "gov", "submit-legacy-proposal", "consumer-removal", "/temp-proposal.json", `--from`, `validator`+fmt.Sprint(action.from), `--chain-id`, string(tr.chainConfigs[action.chain].chainId), `--home`, tr.getValidatorHome(action.chain, action.from), `--node`, tr.getValidatorNode(action.chain, action.from), + `--gas`, "900000", `--keyring-backend`, `test`, - `-b`, `block`, `-y`, ).CombinedOutput() if err != nil { log.Fatal(err, "\n", string(bz)) } + + // wait for inclusion in a block -> '--broadcast-mode block' is deprecated + tr.waitBlocks(chainID("provi"), 2, 20*time.Second) } -type submitParamChangeProposalAction struct { +type submitParamChangeLegacyProposalAction struct { chain chainID from validatorID deposit uint @@ -361,6 +363,7 @@ type submitParamChangeProposalAction struct { type paramChangeProposalJSON struct { Title string `json:"title"` + Summary string `json:"summary"` Description string `json:"description"` Changes []paramChangeJSON `json:"changes"` Deposit string `json:"deposit"` @@ -373,12 +376,13 @@ type paramChangeJSON struct { } func (tr TestRun) submitParamChangeProposal( - action submitParamChangeProposalAction, + action submitParamChangeLegacyProposalAction, verbose bool, ) { prop := paramChangeProposalJSON{ - Title: "Param change", - Description: "Changing module params", + Title: "Legacy Param change", + Summary: "Changing legacy module params", + Description: "Changing legacy module params", Changes: []paramChangeJSON{{Subspace: action.subspace, Key: action.key, Value: action.value}}, Deposit: fmt.Sprint(action.deposit) + `stake`, } @@ -402,24 +406,25 @@ func (tr TestRun) submitParamChangeProposal( } //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - bz, err = exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[action.chain].binaryName, - - "tx", "gov", "submit-proposal", "param-change", - "/params-proposal.json", - + // PARAM CHANGE PROPOSAL // we should be able to make these all one command which will be cool + cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[action.chain].binaryName, + "tx", "gov", "submit-legacy-proposal", "param-change", "/params-proposal.json", `--from`, `validator`+fmt.Sprint(action.from), `--chain-id`, string(tr.chainConfigs[action.chain].chainId), `--home`, tr.getValidatorHome(action.chain, action.from), `--node`, tr.getValidatorNode(action.chain, action.from), `--gas`, "900000", `--keyring-backend`, `test`, - `-b`, `block`, `-y`, - ).CombinedOutput() + ) + bz, err = cmd.CombinedOutput() if err != nil { log.Fatal(err, "\n", string(bz)) } + + // wait for inclusion in a block -> '--broadcast-mode block' is deprecated + tr.waitBlocks(action.chain, 2, 60*time.Second) } type submitEquivocationProposalAction struct { @@ -437,6 +442,7 @@ func (tr TestRun) submitEquivocationProposal(action submitEquivocationProposalAc providerChain := tr.chainConfigs[chainID("provi")] prop := client.EquivocationProposalJSON{ + Summary: "Validator equivocation!", EquivocationProposal: types.EquivocationProposal{ Title: "Validator equivocation!", Description: fmt.Sprintf("Validator: %s has committed an equivocation infraction on chainID: %s", action.validator, action.chain), @@ -471,24 +477,24 @@ func (tr TestRun) submitEquivocationProposal(action submitEquivocationProposalAc } //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + // EQUIVOCATION PROPOSAL bz, err = exec.Command("docker", "exec", tr.containerConfig.instanceName, providerChain.binaryName, - - "tx", "gov", "submit-proposal", "equivocation", - "/equivocation-proposal.json", - + "tx", "gov", "submit-legacy-proposal", "equivocation", "/equivocation-proposal.json", `--from`, `validator`+fmt.Sprint(action.from), `--chain-id`, string(providerChain.chainId), `--home`, tr.getValidatorHome(providerChain.chainId, action.from), `--node`, tr.getValidatorNode(providerChain.chainId, action.from), `--gas`, "9000000", `--keyring-backend`, `test`, - `-b`, `block`, `-y`, ).CombinedOutput() if err != nil { log.Fatal(err, "\n", string(bz)) } + + // wait for inclusion in a block -> '--broadcast-mode block' is deprecated + tr.waitBlocks(chainID("provi"), 2, 30*time.Second) } type voteGovProposalAction struct { @@ -520,7 +526,6 @@ func (tr *TestRun) voteGovProposal( `--node`, tr.getValidatorNode(action.chain, val), `--keyring-backend`, `test`, `--gas`, "900000", - `-b`, `block`, `-y`, ).CombinedOutput() if err != nil { @@ -530,7 +535,9 @@ func (tr *TestRun) voteGovProposal( } wg.Wait() - tr.WaitTime(time.Duration(tr.chainConfigs[action.chain].votingWaitTime) * time.Second) + // wait for inclusion in a block -> '--broadcast-mode block' is deprecated + tr.waitBlocks(action.chain, 1, 10*time.Second) + time.Sleep(time.Duration(tr.chainConfigs[action.chain].votingWaitTime) * time.Second) } type startConsumerChainAction struct { @@ -727,7 +734,7 @@ websocket_addr = "%s" [chains.gas_price] denom = "stake" - price = 0.00 + price = 0.000 [chains.trust_threshold] denominator = "3" @@ -1212,6 +1219,7 @@ func (tr TestRun) transferChannelComplete( "--dst-channel", "channel-"+fmt.Sprint(action.channelA), "--src-channel", "channel-"+fmt.Sprint(action.channelB), ) + executeCommand(chanOpenAckCmd, "transferChanOpenAck") //#nosec G204 -- Bypass linter warning for spawning subprocess with chanOpenConfirmCmd arguments. @@ -1374,9 +1382,9 @@ func (tr TestRun) delegateTokens( `--home`, tr.getValidatorHome(action.chain, action.from), `--node`, tr.getValidatorNode(action.chain, action.from), `--keyring-backend`, `test`, - `-b`, `block`, `-y`, ) + if verbose { fmt.Println("delegate cmd:", cmd.String()) } @@ -1386,6 +1394,7 @@ func (tr TestRun) delegateTokens( log.Fatal(err, "\n", string(bz)) } + // wait for inclusion in a block -> '--broadcast-mode block' is deprecated tr.waitBlocks(action.chain, 1, 10*time.Second) } @@ -1418,9 +1427,9 @@ func (tr TestRun) unbondTokens( `--node`, tr.getValidatorNode(action.chain, action.sender), `--gas`, "900000", `--keyring-backend`, `test`, - `-b`, `block`, `-y`, ) + if verbose { fmt.Println("unbond cmd:", cmd.String()) } @@ -1430,7 +1439,76 @@ func (tr TestRun) unbondTokens( log.Fatal(err, "\n", string(bz)) } - tr.waitBlocks(action.chain, 1, 10*time.Second) + // wait for inclusion in a block -> '--broadcast-mode block' is deprecated + tr.waitBlocks(action.chain, 2, 20*time.Second) +} + +type cancelUnbondTokensAction struct { + chain chainID + delegator validatorID + validator validatorID + amount uint +} + +func (tr TestRun) cancelUnbondTokens( + action cancelUnbondTokensAction, + verbose bool, +) { + validator := tr.validatorConfigs[action.validator].valoperAddress + if tr.validatorConfigs[action.validator].useConsumerKey { + validator = tr.validatorConfigs[action.validator].consumerValoperAddress + } + + // get creation-height from state + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[action.chain].binaryName, + "q", "staking", "unbonding-delegation", + tr.validatorConfigs[action.delegator].delAddress, + validator, + `--home`, tr.getValidatorHome(action.chain, action.delegator), + `--node`, tr.getValidatorNode(action.chain, action.delegator), + `-o`, `json`, + ) + if verbose { + fmt.Println("get unbonding delegations cmd:", cmd.String()) + } + + bz, err := cmd.CombinedOutput() + if err != nil { + log.Fatal(err, "\n", string(bz)) + } + creationHeight := gjson.Get(string(bz), "entries.0.creation_height").Int() + if creationHeight == 0 { + log.Fatal("invalid creation height") + } + + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + cmd = exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[action.chain].binaryName, + "tx", "staking", "cancel-unbond", + validator, + fmt.Sprint(action.amount)+`stake`, + fmt.Sprint(creationHeight), + `--from`, `validator`+fmt.Sprint(action.delegator), + `--chain-id`, string(tr.chainConfigs[action.chain].chainId), + `--home`, tr.getValidatorHome(action.chain, action.delegator), + `--node`, tr.getValidatorNode(action.chain, action.delegator), + `--gas`, "900000", + `--keyring-backend`, `test`, + `-o`, `json`, + `-y`, + ) + + if verbose { + fmt.Println("unbond cmd:", cmd.String()) + } + + bz, err = cmd.CombinedOutput() + if err != nil { + log.Fatal(err, "\n", string(bz)) + } + + // wait for inclusion in a block -> '--broadcast-mode block' is deprecated + tr.waitBlocks(action.chain, 2, 20*time.Second) } type redelegateTokensAction struct { @@ -1470,7 +1548,6 @@ func (tr TestRun) redelegateTokens(action redelegateTokensAction, verbose bool) // Need to manually set gas limit past default (200000), since redelegate has a lot of operations `--gas`, "900000", `--keyring-backend`, `test`, - `-b`, `block`, `-y`, ) @@ -1483,7 +1560,8 @@ func (tr TestRun) redelegateTokens(action redelegateTokensAction, verbose bool) log.Fatal(err, "\n", string(bz)) } - tr.waitBlocks(action.chain, 1, 10*time.Second) + // wait for inclusion in a block -> '--broadcast-mode block' is deprecated + tr.waitBlocks(action.chain, 2, 10*time.Second) } type downtimeSlashAction struct { @@ -1509,7 +1587,7 @@ func (tr TestRun) invokeDowntimeSlash(action downtimeSlashAction, verbose bool) // Bring validator down tr.setValidatorDowntime(action.chain, action.validator, true, verbose) // Wait appropriate amount of blocks for validator to be slashed - tr.waitBlocks(action.chain, 12, 2*time.Minute) + tr.waitBlocks(action.chain, 10, 3*time.Minute) // Bring validator back up tr.setValidatorDowntime(action.chain, action.validator, false, verbose) } @@ -1577,7 +1655,7 @@ type unjailValidatorAction struct { // Sends an unjail transaction to the provider chain func (tr TestRun) unjailValidator(action unjailValidatorAction, verbose bool) { // wait a block to be sure downtime_jail_duration has elapsed - tr.waitBlocks(action.provider, 1, time.Minute) + time.Sleep(61 * time.Second) //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. cmd := exec.Command("docker", "exec", @@ -1591,9 +1669,9 @@ func (tr TestRun) unjailValidator(action unjailValidatorAction, verbose bool) { `--node`, tr.getValidatorNode(action.provider, action.validator), `--gas`, "900000", `--keyring-backend`, `test`, - `-b`, `block`, `-y`, ) + if verbose { fmt.Println("unjail cmd:", cmd.String()) } @@ -1605,7 +1683,7 @@ func (tr TestRun) unjailValidator(action unjailValidatorAction, verbose bool) { // wait for 1 blocks to make sure that tx got included // in a block and packets committed before proceeding - tr.waitBlocks(action.provider, 1, time.Minute) + tr.waitBlocks(action.provider, 2, time.Minute) } type registerRepresentativeAction struct { @@ -1651,12 +1729,14 @@ func (tr TestRun) registerRepresentative( `--home`, tr.getValidatorHome(action.chain, val), `--node`, tr.getValidatorNode(action.chain, val), `--keyring-backend`, `test`, - `-b`, `block`, `-y`, ).CombinedOutput() if err != nil { log.Fatal(err, "\n", string(bz)) } + + // wait for inclusion in a block -> '--broadcast-mode block' is deprecated + tr.waitBlocks(action.chain, 1, 10*time.Second) }(val, stake) } @@ -1738,7 +1818,7 @@ func (tr TestRun) assignConsumerPubKey(action assignConsumerPubKeyAction, verbos valCfg := tr.validatorConfigs[action.validator] assignKey := fmt.Sprintf( - `%s tx provider assign-consensus-key %s '%s' --from validator%s --chain-id %s --home %s --node %s --gas 900000 --keyring-backend test -b block -y -o json`, + `%s tx provider assign-consensus-key %s '%s' --from validator%s --chain-id %s --home %s --node %s --gas 90000 --keyring-backend test -y -o json`, tr.chainConfigs[chainID("provi")].binaryName, string(tr.chainConfigs[action.chain].chainId), action.consumerPubkey, @@ -1747,6 +1827,7 @@ func (tr TestRun) assignConsumerPubKey(action assignConsumerPubKeyAction, verbos tr.getValidatorHome(chainID("provi"), action.validator), tr.getValidatorNode(chainID("provi"), action.validator), ) + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, @@ -1759,21 +1840,13 @@ func (tr TestRun) assignConsumerPubKey(action assignConsumerPubKeyAction, verbos } bz, err := cmd.CombinedOutput() - if err != nil { - log.Fatal(err, "\n", string(bz)) - } - - jsonStr := string(bz) - code := gjson.Get(jsonStr, "code") - rawLog := gjson.Get(jsonStr, "raw_log") - if !action.expectError && code.Int() != 0 { - log.Fatalf("unexpected error during key assignment - code: %s, output: %s", code, jsonStr) + if err != nil && !action.expectError { + log.Fatalf("unexpected error during key assignment - output: %s, err: %s", string(bz), err) } if action.expectError { - if code.Int() == 0 { - } else if verbose { - fmt.Printf("got expected error during key assignment | code: %v | log: %s\n", code, rawLog) + if verbose { + fmt.Printf("got expected error during key assignment | err: %s \n", err.Error()) } } @@ -1825,6 +1898,9 @@ func (tr TestRun) assignConsumerPubKey(action assignConsumerPubKeyAction, verbos valCfg.useConsumerKey = true tr.validatorConfigs[action.validator] = valCfg } + + // wait for inclusion in a block -> '--broadcast-mode block' is deprecated + tr.waitBlocks(chainID("provi"), 2, 30*time.Second) } // slashThrottleDequeue polls slash queue sizes until nextQueueSize is achieved diff --git a/tests/e2e/config.go b/tests/e2e/config.go index 94fae8438f..df54cbd4f4 100644 --- a/tests/e2e/config.go +++ b/tests/e2e/config.go @@ -44,7 +44,7 @@ type ChainConfig struct { ipPrefix string votingWaitTime uint // Any transformations to apply to the genesis file of all chains instantiated with this chain config, as a jq string. - // Example: ".app_state.gov.voting_params.voting_period = \"5s\" | .app_state.slashing.params.signed_blocks_window = \"2\" | .app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\"" + // Example: ".app_state.gov.params.voting_period = \"5s\" | .app_state.slashing.params.signed_blocks_window = \"2\" | .app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\"" genesisChanges string binaryName string @@ -167,12 +167,12 @@ func SlashThrottleTestRun() TestRun { binaryName: "interchain-security-pd", ipPrefix: "7.7.7", votingWaitTime: 20, - genesisChanges: ".app_state.gov.voting_params.voting_period = \"20s\" | " + + genesisChanges: ".app_state.gov.params.voting_period = \"20s\" | " + // Custom slashing parameters for testing validator downtime functionality // See https://docs.cosmos.network/main/modules/slashing/04_begin_block.html#uptime-tracking ".app_state.slashing.params.signed_blocks_window = \"10\" | " + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + - ".app_state.slashing.params.downtime_jail_duration = \"2s\" | " + + ".app_state.slashing.params.downtime_jail_duration = \"60s\" | " + ".app_state.slashing.params.slash_fraction_downtime = \"0.010000000000000000\" | " + ".app_state.provider.params.slash_meter_replenish_fraction = \"0.10\" | " + ".app_state.provider.params.slash_meter_replenish_period = \"20s\"", @@ -182,10 +182,10 @@ func SlashThrottleTestRun() TestRun { binaryName: "interchain-security-cd", ipPrefix: "7.7.8", votingWaitTime: 20, - genesisChanges: ".app_state.gov.voting_params.voting_period = \"20s\" | " + + genesisChanges: ".app_state.gov.params.voting_period = \"20s\" | " + ".app_state.slashing.params.signed_blocks_window = \"15\" | " + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + - ".app_state.slashing.params.downtime_jail_duration = \"2s\" | " + + ".app_state.slashing.params.downtime_jail_duration = \"60s\" | " + ".app_state.slashing.params.slash_fraction_downtime = \"0.010000000000000000\"", }, }, @@ -212,12 +212,12 @@ func DefaultTestRun() TestRun { binaryName: "interchain-security-pd", ipPrefix: "7.7.7", votingWaitTime: 20, - genesisChanges: ".app_state.gov.voting_params.voting_period = \"20s\" | " + + genesisChanges: ".app_state.gov.params.voting_period = \"20s\" | " + // Custom slashing parameters for testing validator downtime functionality // See https://docs.cosmos.network/main/modules/slashing/04_begin_block.html#uptime-tracking ".app_state.slashing.params.signed_blocks_window = \"10\" | " + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + - ".app_state.slashing.params.downtime_jail_duration = \"2s\" | " + + ".app_state.slashing.params.downtime_jail_duration = \"60s\" | " + ".app_state.slashing.params.slash_fraction_downtime = \"0.010000000000000000\" | " + ".app_state.provider.params.slash_meter_replenish_fraction = \"1.0\" | " + // This disables slash packet throttling ".app_state.provider.params.slash_meter_replenish_period = \"3s\"", @@ -227,10 +227,10 @@ func DefaultTestRun() TestRun { binaryName: "interchain-security-cd", ipPrefix: "7.7.8", votingWaitTime: 20, - genesisChanges: ".app_state.gov.voting_params.voting_period = \"20s\" | " + + genesisChanges: ".app_state.gov.params.voting_period = \"20s\" | " + ".app_state.slashing.params.signed_blocks_window = \"15\" | " + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + - ".app_state.slashing.params.downtime_jail_duration = \"2s\" | " + + ".app_state.slashing.params.downtime_jail_duration = \"60s\" | " + ".app_state.slashing.params.slash_fraction_downtime = \"0.010000000000000000\"", }, }, @@ -246,7 +246,7 @@ func DemocracyTestRun(allowReward bool) TestRun { ".app_state.gov.voting_params.voting_period = \"10s\" | " + ".app_state.slashing.params.signed_blocks_window = \"10\" | " + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + - ".app_state.slashing.params.downtime_jail_duration = \"2s\" | " + + ".app_state.slashing.params.downtime_jail_duration = \"60s\" | " + ".app_state.slashing.params.slash_fraction_downtime = \"0.010000000000000000\"" if allowReward { @@ -269,12 +269,12 @@ func DemocracyTestRun(allowReward bool) TestRun { binaryName: "interchain-security-pd", ipPrefix: "7.7.7", votingWaitTime: 20, - genesisChanges: ".app_state.gov.voting_params.voting_period = \"20s\" | " + + genesisChanges: ".app_state.gov.params.voting_period = \"20s\" | " + // Custom slashing parameters for testing validator downtime functionality // See https://docs.cosmos.network/main/modules/slashing/04_begin_block.html#uptime-tracking ".app_state.slashing.params.signed_blocks_window = \"10\" | " + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + - ".app_state.slashing.params.downtime_jail_duration = \"2s\" | " + + ".app_state.slashing.params.downtime_jail_duration = \"60s\" | " + ".app_state.slashing.params.slash_fraction_downtime = \"0.010000000000000000\" | " + ".app_state.provider.params.slash_meter_replenish_fraction = \"1.0\"", // This disables slash packet throttling }, @@ -309,12 +309,12 @@ func MultiConsumerTestRun() TestRun { binaryName: "interchain-security-pd", ipPrefix: "7.7.7", votingWaitTime: 20, - genesisChanges: ".app_state.gov.voting_params.voting_period = \"20s\" | " + + genesisChanges: ".app_state.gov.params.voting_period = \"30s\" | " + // Custom slashing parameters for testing validator downtime functionality // See https://docs.cosmos.network/main/modules/slashing/04_begin_block.html#uptime-tracking ".app_state.slashing.params.signed_blocks_window = \"10\" | " + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + - ".app_state.slashing.params.downtime_jail_duration = \"2s\" | " + + ".app_state.slashing.params.downtime_jail_duration = \"60s\" | " + ".app_state.slashing.params.slash_fraction_downtime = \"0.010000000000000000\" | " + ".app_state.provider.params.slash_meter_replenish_fraction = \"1.0\"", // This disables slash packet throttling }, @@ -323,10 +323,10 @@ func MultiConsumerTestRun() TestRun { binaryName: "interchain-security-cd", ipPrefix: "7.7.8", votingWaitTime: 20, - genesisChanges: ".app_state.gov.voting_params.voting_period = \"20s\" | " + + genesisChanges: ".app_state.gov.params.voting_period = \"20s\" | " + ".app_state.slashing.params.signed_blocks_window = \"10\" | " + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + - ".app_state.slashing.params.downtime_jail_duration = \"2s\" | " + + ".app_state.slashing.params.downtime_jail_duration = \"60s\" | " + ".app_state.slashing.params.slash_fraction_downtime = \"0.010000000000000000\"", }, chainID("densu"): { @@ -334,10 +334,10 @@ func MultiConsumerTestRun() TestRun { binaryName: "interchain-security-cd", ipPrefix: "7.7.9", votingWaitTime: 20, - genesisChanges: ".app_state.gov.voting_params.voting_period = \"20s\" | " + + genesisChanges: ".app_state.gov.params.voting_period = \"20s\" | " + ".app_state.slashing.params.signed_blocks_window = \"10\" | " + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + - ".app_state.slashing.params.downtime_jail_duration = \"2s\" | " + + ".app_state.slashing.params.downtime_jail_duration = \"60s\" | " + ".app_state.slashing.params.slash_fraction_downtime = \"0.010000000000000000\"", }, }, diff --git a/tests/e2e/main.go b/tests/e2e/main.go index 737a318de2..00967dfcac 100644 --- a/tests/e2e/main.go +++ b/tests/e2e/main.go @@ -131,7 +131,7 @@ func (tr *TestRun) runStep(step Step, verbose bool) { tr.submitConsumerRemovalProposal(action, verbose) case submitEquivocationProposalAction: tr.submitEquivocationProposal(action, verbose) - case submitParamChangeProposalAction: + case submitParamChangeLegacyProposalAction: tr.submitParamChangeProposal(action, verbose) case voteGovProposalAction: tr.voteGovProposal(action, verbose) @@ -155,6 +155,8 @@ func (tr *TestRun) runStep(step Step, verbose bool) { tr.delegateTokens(action, verbose) case unbondTokensAction: tr.unbondTokens(action, verbose) + case cancelUnbondTokensAction: + tr.cancelUnbondTokens(action, verbose) case redelegateTokensAction: tr.redelegateTokens(action, verbose) case downtimeSlashAction: diff --git a/tests/e2e/state.go b/tests/e2e/state.go index 4de28277d2..0c2573574f 100644 --- a/tests/e2e/state.go +++ b/tests/e2e/state.go @@ -8,7 +8,7 @@ import ( "strconv" "time" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" "github.com/tidwall/gjson" "gopkg.in/yaml.v2" ) @@ -231,7 +231,7 @@ func (tr TestRun) waitBlocks(chain chainID, blocks uint, timeout time.Duration) if time.Since(start) > timeout { panic(fmt.Sprintf("\n\n\nwaitBlocks method has timed out after: %s\n\n", timeout)) } - time.Sleep(500 * time.Millisecond) + time.Sleep(time.Second) } } @@ -388,7 +388,7 @@ func (tr TestRun) getProposal(chain chainID, proposal uint) Proposal { log.Fatal(err, "\n", string(bz)) } - propType := gjson.Get(string(bz), `content.@type`).String() + propType := gjson.Get(string(bz), `messages.0.content.@type`).String() deposit := gjson.Get(string(bz), `total_deposit.#(denom=="stake").amount`).Uint() status := gjson.Get(string(bz), `status`).String() @@ -404,8 +404,8 @@ func (tr TestRun) getProposal(chain chainID, proposal uint) Proposal { Description: description, } case "/interchain_security.ccv.provider.v1.ConsumerAdditionProposal": - chainId := gjson.Get(string(bz), `content.chain_id`).String() - spawnTime := gjson.Get(string(bz), `content.spawn_time`).Time().Sub(tr.containerConfig.now) + chainId := gjson.Get(string(bz), `messages.0.content.chain_id`).String() + spawnTime := gjson.Get(string(bz), `messages.0.content.spawn_time`).Time().Sub(tr.containerConfig.now) var chain chainID for i, conf := range tr.chainConfigs { @@ -421,8 +421,8 @@ func (tr TestRun) getProposal(chain chainID, proposal uint) Proposal { Chain: chain, SpawnTime: int(spawnTime.Milliseconds()), InitialHeight: clienttypes.Height{ - RevisionNumber: gjson.Get(string(bz), `content.initial_height.revision_number`).Uint(), - RevisionHeight: gjson.Get(string(bz), `content.initial_height.revision_height`).Uint(), + RevisionNumber: gjson.Get(string(bz), `messages.0.content.initial_height.revision_number`).Uint(), + RevisionHeight: gjson.Get(string(bz), `messages.0.content.initial_height.revision_height`).Uint(), }, } case "/cosmos.upgrade.v1beta1.SoftwareUpgradeProposal": @@ -436,8 +436,8 @@ func (tr TestRun) getProposal(chain chainID, proposal uint) Proposal { Type: "/cosmos.upgrade.v1beta1.SoftwareUpgradeProposal", } case "/interchain_security.ccv.provider.v1.ConsumerRemovalProposal": - chainId := gjson.Get(string(bz), `content.chain_id`).String() - stopTime := gjson.Get(string(bz), `content.stop_time`).Time().Sub(tr.containerConfig.now) + chainId := gjson.Get(string(bz), `messages.0.content.chain_id`).String() + stopTime := gjson.Get(string(bz), `messages.0.content.stop_time`).Time().Sub(tr.containerConfig.now) var chain chainID for i, conf := range tr.chainConfigs { @@ -458,18 +458,18 @@ func (tr TestRun) getProposal(chain chainID, proposal uint) Proposal { return EquivocationProposal{ Deposit: uint(deposit), Status: status, - Height: uint(gjson.Get(string(bz), `content.equivocations.0.height`).Uint()), - Power: uint(gjson.Get(string(bz), `content.equivocations.0.power`).Uint()), - ConsensusAddress: gjson.Get(string(bz), `content.equivocations.0.consensus_address`).String(), + Height: uint(gjson.Get(string(bz), `messages.0.content.equivocations.0.height`).Uint()), + Power: uint(gjson.Get(string(bz), `messages.0.content.equivocations.0.power`).Uint()), + ConsensusAddress: gjson.Get(string(bz), `messages.0.content.equivocations.0.consensus_address`).String(), } case "/cosmos.params.v1beta1.ParameterChangeProposal": return ParamsProposal{ Deposit: uint(deposit), Status: status, - Subspace: gjson.Get(string(bz), `content.changes.0.subspace`).String(), - Key: gjson.Get(string(bz), `content.changes.0.key`).String(), - Value: gjson.Get(string(bz), `content.changes.0.value`).String(), + Subspace: gjson.Get(string(bz), `messages.0.content.changes.0.subspace`).String(), + Key: gjson.Get(string(bz), `messages.0.content.changes.0.key`).String(), + Value: gjson.Get(string(bz), `messages.0.content.changes.0.value`).String(), } } @@ -647,6 +647,7 @@ func (tr TestRun) getProviderAddressFromConsumer(consumerChain chainID, validato `--node`, tr.getQueryNode(chainID("provi")), `-o`, `json`, ) + bz, err := cmd.CombinedOutput() if err != nil { log.Fatal(err, "\n", string(bz)) diff --git a/tests/e2e/step_delegation.go b/tests/e2e/step_delegation.go index f33fc136d4..b6e7c8ad76 100644 --- a/tests/e2e/step_delegation.go +++ b/tests/e2e/step_delegation.go @@ -129,6 +129,97 @@ func stepsUnbond(consumerName string) []Step { } } +// stepsCancelUnbond canceling unbonding operation for delegator and validator combination +// the steps perform a full unbonding where the unbonding delegation is removed from the unbonding queue +func stepsCancelUnbond(consumerName string) []Step { + return []Step{ + { + action: unbondTokensAction{ + chain: chainID("provi"), + unbondFrom: validatorID("alice"), + sender: validatorID("alice"), + amount: 1000000, + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + chainID("consu"): ChainState{ + ValPowers: &map[validatorID]uint{ + // Voting power on consumer should not be affected yet + validatorID("alice"): 510, + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + }, + }, + { + action: relayPacketsAction{ + chainA: chainID("provi"), + chainB: chainID(consumerName), + port: "provider", + channel: 0, + }, + state: State{ + chainID("consu"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + }, + }, + { + action: cancelUnbondTokensAction{ + chain: chainID("provi"), + delegator: validatorID("alice"), + validator: validatorID("alice"), + amount: 1000000, // cancel unbonding the full amount + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 510, // power restored + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + chainID("consu"): ChainState{ + ValPowers: &map[validatorID]uint{ + // Voting power on consumer should not be affected yet + validatorID("alice"): 509, + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + }, + }, + { + action: relayPacketsAction{ + chainA: chainID("provi"), + chainB: chainID(consumerName), + port: "provider", + channel: 0, + }, + state: State{ + chainID("consu"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 510, // power restored on consumer + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + }, + }, + } +} + // stepsRedelegateForOptOut tests redelegation, and sets up voting powers s.t // alice will have less than 5% of the total voting power. This is needed to // test opt-out functionality. diff --git a/tests/e2e/steps.go b/tests/e2e/steps.go index ee53e9fd2a..aa08426103 100644 --- a/tests/e2e/steps.go +++ b/tests/e2e/steps.go @@ -18,6 +18,7 @@ var happyPathSteps = concatSteps( stepsDelegate("consu"), stepsAssignConsumerKeyOnStartedChain("consu", "bob"), stepsUnbond("consu"), + stepsCancelUnbond("consu"), stepsRedelegateForOptOut("consu"), stepsDowntimeWithOptOut("consu"), stepsRedelegate("consu"), diff --git a/tests/e2e/steps_democracy.go b/tests/e2e/steps_democracy.go index 686fbf1c49..3c80818a24 100644 --- a/tests/e2e/steps_democracy.go +++ b/tests/e2e/steps_democracy.go @@ -62,13 +62,14 @@ func stepsDemocracy(consumerName string) []Step { }, }, { - action: submitParamChangeProposalAction{ + // whitelisted legacy proposal can only handle ibctransfer.SendEnabled/ReceiveEnabled + action: submitParamChangeLegacyProposalAction{ chain: chainID(consumerName), from: validatorID("alice"), deposit: 10000001, - subspace: "staking", - key: "MaxValidators", - value: 105, + subspace: "transfer", + key: "SendEnabled", + value: true, }, state: State{ chainID(consumerName): ChainState{ @@ -80,9 +81,9 @@ func stepsDemocracy(consumerName string) []Step { 1: ParamsProposal{ Deposit: 10000001, Status: "PROPOSAL_STATUS_VOTING_PERIOD", - Subspace: "staking", - Key: "MaxValidators", - Value: "105", + Subspace: "transfer", + Key: "SendEnabled", + Value: "true", }, }, }, @@ -103,7 +104,7 @@ func stepsDemocracy(consumerName string) []Step { validatorID("bob"): 9960000001, }, // Check that the parameter is changed on gov-consumer chain - Params: &([]Param{{Subspace: "staking", Key: "MaxValidators", Value: "105"}}), + Params: &([]Param{{Subspace: "transfer", Key: "SendEnabled", Value: "true"}}), }, }, }, diff --git a/tests/e2e/steps_reward_denom.go b/tests/e2e/steps_reward_denom.go index dc10ccb7c6..cb557f0471 100644 --- a/tests/e2e/steps_reward_denom.go +++ b/tests/e2e/steps_reward_denom.go @@ -60,13 +60,14 @@ func stepsRewardDenomConsumer(consumerName string) []Step { }, }, { - action: submitParamChangeProposalAction{ + // whitelisted legacy proposal can only handle ibctransfer.SendEnabled/ReceiveEnabled + action: submitParamChangeLegacyProposalAction{ chain: chainID(consumerName), from: validatorID("alice"), deposit: 10000001, - subspace: "staking", - key: "MaxValidators", - value: 105, + subspace: "transfer", + key: "SendEnabled", + value: true, }, state: State{ chainID(consumerName): ChainState{ @@ -78,9 +79,9 @@ func stepsRewardDenomConsumer(consumerName string) []Step { 1: ParamsProposal{ Deposit: 10000001, Status: "PROPOSAL_STATUS_VOTING_PERIOD", - Subspace: "staking", - Key: "MaxValidators", - Value: "105", + Subspace: "transfer", + Key: "SendEnabled", + Value: "true", }, }, }, diff --git a/tests/e2e/steps_sovereign_changeover.go b/tests/e2e/steps_sovereign_changeover.go index e122c1fb2a..71daad684b 100644 --- a/tests/e2e/steps_sovereign_changeover.go +++ b/tests/e2e/steps_sovereign_changeover.go @@ -1,6 +1,6 @@ package main -import clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" +import clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" // this creates new clients on both chains and a connection (connection-0) between them // connection-0 is used to create a transfer channel between the chains diff --git a/tests/e2e/steps_start_chains.go b/tests/e2e/steps_start_chains.go index c51042e8c8..15d0045760 100644 --- a/tests/e2e/steps_start_chains.go +++ b/tests/e2e/steps_start_chains.go @@ -1,7 +1,7 @@ package main import ( - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" ) func stepStartProviderChain() []Step { diff --git a/tests/e2e/testnet-scripts/sovereign-genesis.json b/tests/e2e/testnet-scripts/sovereign-genesis.json index 94a279840e..6c34a0ec1c 100644 --- a/tests/e2e/testnet-scripts/sovereign-genesis.json +++ b/tests/e2e/testnet-scripts/sovereign-genesis.json @@ -1,279 +1,281 @@ { - "genesis_time": "2023-06-13T11:19:05.998449459Z", - "chain_id": "sover", - "initial_height": "1", - "consensus_params": { - "block": { - "max_bytes": "22020096", - "max_gas": "-1", - "time_iota_ms": "1000" - }, - "evidence": { - "max_age_num_blocks": "100000", - "max_age_duration": "172800000000000", - "max_bytes": "1048576" - }, - "validator": { - "pub_key_types": [ - "ed25519" - ] - }, - "version": {} + "genesis_time": "2023-06-19T21:06:09.696739416Z", + "chain_id": "sover", + "initial_height": "1", + "consensus_params": { + "block": { + "max_bytes": "22020096", + "max_gas": "-1" }, - "app_hash": "", - "app_state": { - "auth": { - "params": { - "max_memo_characters": "256", - "tx_sig_limit": "7", - "tx_size_cost_per_byte": "10", - "sig_verify_cost_ed25519": "590", - "sig_verify_cost_secp256k1": "1000" - }, - "accounts": [ - { - "@type": "/cosmos.auth.v1beta1.BaseAccount", - "address": "cosmos19pe9pg5dv9k5fzgzmsrgnw9rl9asf7ddwhu7lm", - "pub_key": null, - "account_number": "0", - "sequence": "0" - } - ] - }, - "authz": { - "authorization": [] - }, - "bank": { - "params": { - "send_enabled": [], - "default_send_enabled": true - }, - "balances": [ - { - "address": "cosmos19pe9pg5dv9k5fzgzmsrgnw9rl9asf7ddwhu7lm", - "coins": [ - { - "denom": "stake", - "amount": "10000000000" - } - ] - } - ], - "supply": [ - { - "denom": "stake", - "amount": "10000000000" - } - ], - "denom_metadata": [] + "evidence": { + "max_age_num_blocks": "100000", + "max_age_duration": "172800000000000", + "max_bytes": "1048576" + }, + "validator": { + "pub_key_types": [ + "ed25519" + ] + }, + "version": { + "app": "0" + } + }, + "app_hash": "", + "app_state": { + "07-tendermint": null, + "auth": { + "params": { + "max_memo_characters": "256", + "tx_sig_limit": "7", + "tx_size_cost_per_byte": "10", + "sig_verify_cost_ed25519": "590", + "sig_verify_cost_secp256k1": "1000" }, - "capability": { - "index": "1", - "owners": [] + "accounts": [ + { + "@type": "/cosmos.auth.v1beta1.BaseAccount", + "address": "cosmos1dkas8mu4kyhl5jrh4nzvm65qz588hy9qcz08la", + "pub_key": null, + "account_number": "0", + "sequence": "0" + } + ] + }, + "bank": { + "params": { + "send_enabled": [], + "default_send_enabled": true }, - "crisis": { - "constant_fee": { + "balances": [ + { + "address": "cosmos19pe9pg5dv9k5fzgzmsrgnw9rl9asf7ddwhu7lm", + "coins": [ + { + "denom": "stake", + "amount": "10000000000" + } + ] + } + ], + "supply": [ + { "denom": "stake", - "amount": "1000" + "amount": "10000000000" } + ], + "denom_metadata": [], + "send_enabled": [] + }, + "capability": { + "index": "1", + "owners": [] + }, + "crisis": { + "constant_fee": { + "denom": "stake", + "amount": "1000" + } + }, + "distribution": { + "params": { + "community_tax": "0.020000000000000000", + "base_proposer_reward": "0.000000000000000000", + "bonus_proposer_reward": "0.000000000000000000", + "withdraw_addr_enabled": true }, - "distribution": { - "params": { - "community_tax": "0.020000000000000000", - "base_proposer_reward": "0.010000000000000000", - "bonus_proposer_reward": "0.040000000000000000", - "withdraw_addr_enabled": true - }, - "fee_pool": { - "community_pool": [] - }, - "delegator_withdraw_infos": [], - "previous_proposer": "", - "outstanding_rewards": [], - "validator_accumulated_commissions": [], - "validator_historical_rewards": [], - "validator_current_rewards": [], - "delegator_starting_infos": [], - "validator_slash_events": [] - }, - "evidence": { - "evidence": [] - }, - "feegrant": { - "allowances": [] + "fee_pool": { + "community_pool": [] }, - "genutil": { - "gen_txs": [ - { - "body": { - "messages": [ - { - "@type": "/cosmos.staking.v1beta1.MsgCreateValidator", - "description": { - "moniker": "validatoralice", - "identity": "", - "website": "", - "security_contact": "", - "details": "" - }, - "commission": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "min_self_delegation": "1", - "delegator_address": "cosmos19pe9pg5dv9k5fzgzmsrgnw9rl9asf7ddwhu7lm", - "validator_address": "cosmosvaloper19pe9pg5dv9k5fzgzmsrgnw9rl9asf7ddtrgtng", - "pubkey": { - "@type": "/cosmos.crypto.ed25519.PubKey", - "key": "RrclQz9bIhkIy/gfL485g3PYMeiIku4qeo495787X10=" - }, - "value": { - "denom": "stake", - "amount": "500000000" - } - } - ], - "memo": "8339e14baab81c2a2350e261962263397a8d7fb0@7.7.8.254:26656", - "timeout_height": "0", - "extension_options": [], - "non_critical_extension_options": [] - }, - "auth_info": { - "signer_infos": [ - { - "public_key": { - "@type": "/cosmos.crypto.secp256k1.PubKey", - "key": "AsFC8tmbGGQSHthsVStbsQ13/+Yza9IT8KCSXXEN7y9f" - }, - "mode_info": { - "single": { - "mode": "SIGN_MODE_DIRECT" - } - }, - "sequence": "0" + "delegator_withdraw_infos": [], + "previous_proposer": "", + "outstanding_rewards": [], + "validator_accumulated_commissions": [], + "validator_historical_rewards": [], + "validator_current_rewards": [], + "delegator_starting_infos": [], + "validator_slash_events": [] + }, + "evidence": { + "evidence": [] + }, + "genutil": { + "gen_txs": [ + { + "body": { + "messages": [ + { + "@type": "/cosmos.staking.v1beta1.MsgCreateValidator", + "description": { + "moniker": "validatoralice", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "commission": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "min_self_delegation": "1", + "delegator_address": "cosmos19pe9pg5dv9k5fzgzmsrgnw9rl9asf7ddwhu7lm", + "validator_address": "cosmosvaloper19pe9pg5dv9k5fzgzmsrgnw9rl9asf7ddtrgtng", + "pubkey": { + "@type": "/cosmos.crypto.ed25519.PubKey", + "key": "RrclQz9bIhkIy/gfL485g3PYMeiIku4qeo495787X10=" + }, + "value": { + "denom": "stake", + "amount": "500000000" } - ], - "fee": { - "amount": [], - "gas_limit": "200000", - "payer": "", - "granter": "" } + ], + "memo": "8339e14baab81c2a2350e261962263397a8d7fb0@7.7.7.254:26656", + "timeout_height": "0", + "extension_options": [], + "non_critical_extension_options": [] + }, + "auth_info": { + "signer_infos": [ + { + "public_key": { + "@type": "/cosmos.crypto.secp256k1.PubKey", + "key": "AsFC8tmbGGQSHthsVStbsQ13/+Yza9IT8KCSXXEN7y9f" + }, + "mode_info": { + "single": { + "mode": "SIGN_MODE_DIRECT" + } + }, + "sequence": "0" + } + ], + "fee": { + "amount": [], + "gas_limit": "200000", + "payer": "", + "granter": "" }, - "signatures": [ - "rZuml3RLgrrZkUoNHw90FuHF/Orxzs0uiwflCkUOcvoA4bzohisjdQhkPWCn5aRw30mqZJGj1IxgXS15XleMvQ==" - ] - } - ] - }, - "gov": { - "starting_proposal_id": "1", - "deposits": [], - "votes": [], - "proposals": [], - "deposit_params": { - "min_deposit": [ - { - "denom": "stake", - "amount": "10000000" - } - ], - "max_deposit_period": "172800s" - }, - "voting_params": { - "voting_period": "20s" - }, - "tally_params": { - "quorum": "0.334000000000000000", - "threshold": "0.500000000000000000", - "veto_threshold": "0.334000000000000000" - } - }, - "ibc": { - "client_genesis": { - "clients": [], - "clients_consensus": [], - "clients_metadata": [], - "params": { - "allowed_clients": [ - "06-solomachine", - "07-tendermint" - ] + "tip": null }, - "create_localhost": false, - "next_client_sequence": "0" - }, - "connection_genesis": { - "connections": [], - "client_connection_paths": [], - "next_connection_sequence": "0", - "params": { - "max_expected_time_per_block": "30000000000" + "signatures": [ + "D06i2qqq2HathlT7cy+PDLTDuYKAmzw5Ne+Ehvzr9bVy3jpm2h8deDGeSXTSrhdP04UpFXerSn+zIPth5TKNrg==" + ] + } + ] + }, + "gov": { + "starting_proposal_id": "1", + "deposits": [], + "votes": [], + "proposals": [], + "deposit_params": null, + "voting_params": null, + "tally_params": null, + "params": { + "min_deposit": [ + { + "denom": "stake", + "amount": "10000000" } + ], + "max_deposit_period": "172800s", + "voting_period": "20s", + "quorum": "0.334000000000000000", + "threshold": "0.500000000000000000", + "veto_threshold": "0.334000000000000000", + "min_initial_deposit_ratio": "0.000000000000000000", + "burn_vote_quorum": false, + "burn_proposal_deposit_prevote": false, + "burn_vote_veto": true + } + }, + "ibc": { + "client_genesis": { + "clients": [], + "clients_consensus": [], + "clients_metadata": [], + "params": { + "allowed_clients": [ + "06-solomachine", + "07-tendermint" + ] }, - "channel_genesis": { - "channels": [], - "acknowledgements": [], - "commitments": [], - "receipts": [], - "send_sequences": [], - "recv_sequences": [], - "ack_sequences": [], - "next_channel_sequence": "0" - } + "create_localhost": false, + "next_client_sequence": "0" }, - "mint": { - "minter": { - "inflation": "0.130000000000000000", - "annual_provisions": "0.000000000000000000" - }, + "connection_genesis": { + "connections": [], + "client_connection_paths": [], + "next_connection_sequence": "0", "params": { - "mint_denom": "stake", - "inflation_rate_change": "0.130000000000000000", - "inflation_max": "0.200000000000000000", - "inflation_min": "0.070000000000000000", - "goal_bonded": "0.670000000000000000", - "blocks_per_year": "6311520" + "max_expected_time_per_block": "30000000000" } }, - "params": null, - "slashing": { - "params": { - "signed_blocks_window": "15", - "min_signed_per_window": "0.500000000000000000", - "downtime_jail_duration": "2s", - "slash_fraction_double_sign": "0.050000000000000000", - "slash_fraction_downtime": "0.010000000000000000" - }, - "signing_infos": [], - "missed_blocks": [] + "channel_genesis": { + "channels": [], + "acknowledgements": [], + "commitments": [], + "receipts": [], + "send_sequences": [], + "recv_sequences": [], + "ack_sequences": [], + "next_channel_sequence": "0" + } + }, + "mint": { + "minter": { + "inflation": "0.130000000000000000", + "annual_provisions": "0.000000000000000000" }, - "staking": { - "params": { - "unbonding_time": "1814400s", - "max_validators": 100, - "max_entries": 7, - "historical_entries": 10000, - "bond_denom": "stake" - }, - "last_total_power": "0", - "last_validator_powers": [], - "validators": [], - "delegations": [], - "unbonding_delegations": [], - "redelegations": [], - "exported": false + "params": { + "mint_denom": "stake", + "inflation_rate_change": "0.130000000000000000", + "inflation_max": "0.200000000000000000", + "inflation_min": "0.070000000000000000", + "goal_bonded": "0.670000000000000000", + "blocks_per_year": "6311520" + } + }, + "params": null, + "slashing": { + "params": { + "signed_blocks_window": "10", + "min_signed_per_window": "0.500000000000000000", + "downtime_jail_duration": "60s", + "slash_fraction_double_sign": "0.050000000000000000", + "slash_fraction_downtime": "0.010000000000000000" }, - "transfer": { - "port_id": "transfer", - "denom_traces": [], - "params": { - "send_enabled": true, - "receive_enabled": true - } + "signing_infos": [], + "missed_blocks": [] + }, + "staking": { + "params": { + "unbonding_time": "1814400s", + "max_validators": 100, + "max_entries": 7, + "historical_entries": 10000, + "bond_denom": "stake", + "min_commission_rate": "0.000000000000000000" }, - "upgrade": {}, - "vesting": {} - } - } \ No newline at end of file + "last_total_power": "0", + "last_validator_powers": [], + "validators": [], + "delegations": [], + "unbonding_delegations": [], + "redelegations": [], + "exported": false + }, + "transfer": { + "port_id": "transfer", + "denom_traces": [], + "params": { + "send_enabled": true, + "receive_enabled": true + } + }, + "upgrade": {}, + "vesting": {} + } +} \ No newline at end of file diff --git a/tests/e2e/testnet-scripts/start-chain.sh b/tests/e2e/testnet-scripts/start-chain.sh index 9d6e73fdbb..a3609acf73 100644 --- a/tests/e2e/testnet-scripts/start-chain.sh +++ b/tests/e2e/testnet-scripts/start-chain.sh @@ -136,7 +136,7 @@ do # give this validator some money ALLOCATION=$(echo "$VALIDATORS" | jq -r ".[$i].allocation") - $BIN add-genesis-account validator$VAL_ID $ALLOCATION \ + $BIN genesis add-genesis-account validator$VAL_ID $ALLOCATION \ --home /$CHAIN_ID/validator$VAL_ID \ --keyring-backend test @@ -180,7 +180,7 @@ do # Make a gentx (this command also sets up validator state on disk even if we are not going to use the gentx for anything) if [ "$SKIP_GENTX" = "false" ] ; then STAKE_AMOUNT=$(echo "$VALIDATORS" | jq -r ".[$i].stake") - $BIN gentx validator$VAL_ID "$STAKE_AMOUNT" \ + $BIN genesis gentx validator$VAL_ID "$STAKE_AMOUNT" \ --home /$CHAIN_ID/validator$VAL_ID \ --keyring-backend test \ --moniker validator$VAL_ID \ @@ -207,7 +207,7 @@ done if [ "$SKIP_GENTX" = "false" ] ; then # make the final genesis.json - $BIN collect-gentxs --home /$CHAIN_ID/validator$FIRST_VAL_ID + $BIN genesis collect-gentxs --home /$CHAIN_ID/validator$FIRST_VAL_ID # and copy it to the root cp /$CHAIN_ID/validator$FIRST_VAL_ID/config/genesis.json /$CHAIN_ID/genesis.json diff --git a/tests/integration/changeover.go b/tests/integration/changeover.go index 13d18a4026..bd94857598 100644 --- a/tests/integration/changeover.go +++ b/tests/integration/changeover.go @@ -1,8 +1,8 @@ package integration import ( - transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" ) func (suite *CCVTestSuite) TestRecycleTransferChannel() { diff --git a/tests/integration/common.go b/tests/integration/common.go index 00ad6536cf..8f32193206 100644 --- a/tests/integration/common.go +++ b/tests/integration/common.go @@ -4,23 +4,24 @@ import ( "fmt" "time" + "cosmossdk.io/math" + abci "github.com/cometbft/cometbft/abci/types" + tmtypes "github.com/cometbft/cometbft/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" sdk "github.com/cosmos/cosmos-sdk/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" - commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" - "github.com/cosmos/ibc-go/v4/modules/core/exported" - ibctm "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/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" + commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" + "github.com/cosmos/ibc-go/v7/modules/core/exported" + ibctm "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" icstestingutils "github.com/cosmos/interchain-security/v2/testutil/ibc_testing" testutil "github.com/cosmos/interchain-security/v2/testutil/integration" providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" - tmtypes "github.com/tendermint/tendermint/types" ) // ChainType defines the type of chain (either provider or consumer) @@ -84,13 +85,13 @@ func (s *CCVTestSuite) setDefaultValSigningInfo(tmVal tmtypes.Validator) { s.providerApp.GetTestSlashingKeeper().SetValidatorSigningInfo(s.providerCtx(), consAddr, valInfo) } -func getBalance(s *CCVTestSuite, providerCtx sdk.Context, delAddr sdk.AccAddress) sdk.Int { +func getBalance(s *CCVTestSuite, providerCtx sdk.Context, delAddr sdk.AccAddress) math.Int { return s.providerApp.GetTestBankKeeper().GetBalance(providerCtx, delAddr, s.providerBondDenom()).Amount } // delegateAndUndelegate delegates bondAmt from delAddr to the first validator // and then immediately undelegates 1/shareDiv of that delegation -func delegateAndUndelegate(s *CCVTestSuite, delAddr sdk.AccAddress, bondAmt sdk.Int, shareDiv int64) (initBalance sdk.Int, valsetUpdateId uint64) { +func delegateAndUndelegate(s *CCVTestSuite, delAddr sdk.AccAddress, bondAmt math.Int, shareDiv int64) (initBalance math.Int, valsetUpdateId uint64) { // delegate initBalance, shares, valAddr := delegate(s, delAddr, bondAmt) @@ -112,7 +113,7 @@ func delegateAndUndelegate(s *CCVTestSuite, delAddr sdk.AccAddress, bondAmt sdk. // Note: This function advances blocks in-between operations, where validator powers are // not checked, since they are checked in integration tests. func delegateAndRedelegate(s *CCVTestSuite, delAddr sdk.AccAddress, - srcValAddr, dstValAddr sdk.ValAddress, amount sdk.Int, + srcValAddr, dstValAddr sdk.ValAddress, amount math.Int, ) { // Delegate to src validator srcValTokensBefore := s.getVal(s.providerCtx(), srcValAddr).GetBondedTokens() @@ -142,12 +143,12 @@ func delegateAndRedelegate(s *CCVTestSuite, delAddr sdk.AccAddress, } // delegate delegates bondAmt to the first validator -func delegate(s *CCVTestSuite, delAddr sdk.AccAddress, bondAmt sdk.Int) (initBalance sdk.Int, shares sdk.Dec, valAddr sdk.ValAddress) { +func delegate(s *CCVTestSuite, delAddr sdk.AccAddress, bondAmt math.Int) (initBalance math.Int, shares sdk.Dec, valAddr sdk.ValAddress) { return delegateByIdx(s, delAddr, bondAmt, 0) } // delegateByIdx delegates bondAmt to the validator at specified index in provider val set -func delegateByIdx(s *CCVTestSuite, delAddr sdk.AccAddress, bondAmt sdk.Int, idx int) (initBalance sdk.Int, shares sdk.Dec, valAddr sdk.ValAddress) { +func delegateByIdx(s *CCVTestSuite, delAddr sdk.AccAddress, bondAmt math.Int, idx int) (initBalance math.Int, shares sdk.Dec, valAddr sdk.ValAddress) { initBalance = getBalance(s, s.providerCtx(), delAddr) // choose a validator validator, valAddr := s.getValByIdx(idx) @@ -407,7 +408,7 @@ func (suite *CCVTestSuite) commitConsumerPacket(ctx sdk.Context, packetData ccv. // constructSlashPacketFromConsumer constructs an IBC packet embedding // slash packet data to be sent from consumer to provider func (s *CCVTestSuite) constructSlashPacketFromConsumer(bundle icstestingutils.ConsumerBundle, - tmVal tmtypes.Validator, infractionType stakingtypes.InfractionType, ibcSeqNum uint64, + tmVal tmtypes.Validator, infractionType stakingtypes.Infraction, ibcSeqNum uint64, ) channeltypes.Packet { valsetUpdateId := bundle.GetKeeper().GetHeightValsetUpdateID( bundle.GetCtx(), uint64(bundle.GetCtx().BlockHeight())) @@ -556,7 +557,7 @@ func (suite *CCVTestSuite) CreateCustomClient(endpoint *ibctesting.Endpoint, unb UpgradePath := []string{"upgrade", "upgradedIBCState"} clientState := ibctm.NewClientState( endpoint.Counterparty.Chain.ChainID, tmConfig.TrustLevel, tmConfig.TrustingPeriod, tmConfig.UnbondingPeriod, tmConfig.MaxClockDrift, - height, commitmenttypes.GetSDKSpecs(), UpgradePath, tmConfig.AllowUpdateAfterExpiry, tmConfig.AllowUpdateAfterMisbehaviour, + height, commitmenttypes.GetSDKSpecs(), UpgradePath, ) consensusState := endpoint.Counterparty.Chain.LastHeader.ConsensusState() diff --git a/tests/integration/democracy.go b/tests/integration/democracy.go index f13398aa91..c1262b31c1 100644 --- a/tests/integration/democracy.go +++ b/tests/integration/democracy.go @@ -1,19 +1,18 @@ package integration import ( - "fmt" - "strconv" "testing" "time" + "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" icstestingutils "github.com/cosmos/interchain-security/v2/testutil/ibc_testing" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" - proposaltypes "github.com/cosmos/cosmos-sdk/x/params/types/proposal" testutil "github.com/cosmos/interchain-security/v2/testutil/integration" consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" "github.com/stretchr/testify/suite" @@ -78,7 +77,7 @@ func (s *ConsumerDemocracyTestSuite) TestDemocracyRewardsDistribution() { currentRepresentativesRewards := map[string]sdk.Dec{} nextRepresentativesRewards := map[string]sdk.Dec{} - representativesTokens := map[string]sdk.Int{} + representativesTokens := map[string]math.Int{} for _, representative := range stakingKeeper.GetAllValidators(s.consumerCtx()) { currentRepresentativesRewards[representative.OperatorAddress] = sdk.NewDec(0) @@ -148,30 +147,42 @@ func (s *ConsumerDemocracyTestSuite) TestDemocracyRewardsDistribution() { func (s *ConsumerDemocracyTestSuite) TestDemocracyGovernanceWhitelisting() { govKeeper := s.consumerApp.GetTestGovKeeper() + params := govKeeper.GetParams(s.consumerCtx()) stakingKeeper := s.consumerApp.GetTestStakingKeeper() bankKeeper := s.consumerApp.GetTestBankKeeper() accountKeeper := s.consumerApp.GetTestAccountKeeper() mintKeeper := s.consumerApp.GetTestMintKeeper() newAuthParamValue := uint64(128) newMintParamValue := sdk.NewDecWithPrec(1, 1) // "0.100000000000000000" - allowedChange := proposaltypes.ParamChange{Subspace: minttypes.ModuleName, Key: "InflationMax", Value: fmt.Sprintf("\"%s\"", newMintParamValue)} - forbiddenChange := proposaltypes.ParamChange{Subspace: authtypes.ModuleName, Key: "MaxMemoCharacters", Value: fmt.Sprintf("\"%s\"", strconv.FormatUint(newAuthParamValue, 10))} votingAccounts := s.consumerChain.SenderAccounts bondDenom := stakingKeeper.BondDenom(s.consumerCtx()) - depositAmount := govKeeper.GetDepositParams(s.consumerCtx()).MinDeposit - votingParams := govKeeper.GetVotingParams(s.consumerCtx()) - votingParams.VotingPeriod = 3 * time.Second - govKeeper.SetVotingParams(s.consumerCtx(), votingParams) + depositAmount := params.MinDeposit + duration := (3 * time.Second) + params.VotingPeriod = &duration + err := govKeeper.SetParams(s.consumerCtx(), params) + s.Assert().NoError(err) + proposer := s.consumerChain.SenderAccount s.consumerChain.NextBlock() votersOldBalances := getAccountsBalances(s.consumerCtx(), bankKeeper, bondDenom, votingAccounts) // submit proposal with forbidden and allowed changes - paramChange := proposaltypes.ParameterChangeProposal{Changes: []proposaltypes.ParamChange{allowedChange, forbiddenChange}} - err := submitProposalWithDepositAndVote(govKeeper, s.consumerCtx(), paramChange, votingAccounts, depositAmount) + mintParams := mintKeeper.GetParams(s.consumerCtx()) + mintParams.InflationMax = newMintParamValue + msg_1 := &minttypes.MsgUpdateParams{ + Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), + Params: mintParams, + } + authParams := accountKeeper.GetParams(s.consumerCtx()) + authParams.MaxMemoCharacters = newAuthParamValue + msg_2 := &authtypes.MsgUpdateParams{ + Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), + Params: authParams, + } + err = submitProposalWithDepositAndVote(govKeeper, s.consumerCtx(), []sdk.Msg{msg_1, msg_2}, votingAccounts, proposer.GetAddress(), depositAmount) s.Assert().NoError(err) // set current header time to be equal or later than voting end time in order to process proposal from active queue, // once the proposal is added to the chain - s.consumerChain.CurrentHeader.Time = s.consumerChain.CurrentHeader.Time.Add(votingParams.VotingPeriod) + s.consumerChain.CurrentHeader.Time = s.consumerChain.CurrentHeader.Time.Add(*params.VotingPeriod) s.consumerChain.NextBlock() // at this moment, proposal is added, but not yet executed. we are saving old param values for comparison oldAuthParamValue := accountKeeper.GetParams(s.consumerCtx()).MaxMemoCharacters @@ -189,10 +200,9 @@ func (s *ConsumerDemocracyTestSuite) TestDemocracyGovernanceWhitelisting() { s.Assert().Equal(votersOldBalances, getAccountsBalances(s.consumerCtx(), bankKeeper, bondDenom, votingAccounts)) // submit proposal with allowed changes - paramChange = proposaltypes.ParameterChangeProposal{Changes: []proposaltypes.ParamChange{allowedChange}} - err = submitProposalWithDepositAndVote(govKeeper, s.consumerCtx(), paramChange, votingAccounts, depositAmount) + err = submitProposalWithDepositAndVote(govKeeper, s.consumerCtx(), []sdk.Msg{msg_1}, votingAccounts, proposer.GetAddress(), depositAmount) s.Assert().NoError(err) - s.consumerChain.CurrentHeader.Time = s.consumerChain.CurrentHeader.Time.Add(votingParams.VotingPeriod) + s.consumerChain.CurrentHeader.Time = s.consumerChain.CurrentHeader.Time.Add(*params.VotingPeriod) s.consumerChain.NextBlock() oldMintParamValue = mintKeeper.GetParams(s.consumerCtx()).InflationMax s.consumerChain.NextBlock() @@ -204,10 +214,10 @@ func (s *ConsumerDemocracyTestSuite) TestDemocracyGovernanceWhitelisting() { s.Assert().Equal(votersOldBalances, getAccountsBalances(s.consumerCtx(), bankKeeper, bondDenom, votingAccounts)) // submit proposal with forbidden changes - paramChange = proposaltypes.ParameterChangeProposal{Changes: []proposaltypes.ParamChange{forbiddenChange}} - err = submitProposalWithDepositAndVote(govKeeper, s.consumerCtx(), paramChange, votingAccounts, depositAmount) + + err = submitProposalWithDepositAndVote(govKeeper, s.consumerCtx(), []sdk.Msg{msg_2}, votingAccounts, proposer.GetAddress(), depositAmount) s.Assert().NoError(err) - s.consumerChain.CurrentHeader.Time = s.consumerChain.CurrentHeader.Time.Add(votingParams.VotingPeriod) + s.consumerChain.CurrentHeader.Time = s.consumerChain.CurrentHeader.Time.Add(*params.VotingPeriod) s.consumerChain.NextBlock() oldAuthParamValue = accountKeeper.GetParams(s.consumerCtx()).MaxMemoCharacters s.consumerChain.NextBlock() @@ -219,20 +229,20 @@ func (s *ConsumerDemocracyTestSuite) TestDemocracyGovernanceWhitelisting() { s.Assert().Equal(votersOldBalances, getAccountsBalances(s.consumerCtx(), bankKeeper, bondDenom, votingAccounts)) } -func submitProposalWithDepositAndVote(govKeeper testutil.TestGovKeeper, ctx sdk.Context, paramChange proposaltypes.ParameterChangeProposal, - accounts []ibctesting.SenderAccount, depositAmount sdk.Coins, +func submitProposalWithDepositAndVote(govKeeper testutil.TestGovKeeper, ctx sdk.Context, msgs []sdk.Msg, + accounts []ibctesting.SenderAccount, proposer sdk.AccAddress, depositAmount sdk.Coins, ) error { - proposal, err := govKeeper.SubmitProposal(ctx, ¶mChange) + proposal, err := govKeeper.SubmitProposal(ctx, msgs, "", "title", "summary", proposer) if err != nil { return err } - _, err = govKeeper.AddDeposit(ctx, proposal.ProposalId, accounts[0].SenderAccount.GetAddress(), depositAmount) // proposal becomes active + _, err = govKeeper.AddDeposit(ctx, proposal.Id, accounts[0].SenderAccount.GetAddress(), depositAmount) // proposal becomes active if err != nil { return err } for _, account := range accounts { - err = govKeeper.AddVote(ctx, proposal.ProposalId, account.SenderAccount.GetAddress(), govtypes.NewNonSplitVoteOption(govtypes.OptionYes)) + err = govKeeper.AddVote(ctx, proposal.Id, account.SenderAccount.GetAddress(), govv1.NewNonSplitVoteOption(govv1.OptionYes), "") if err != nil { return err } @@ -240,8 +250,8 @@ func submitProposalWithDepositAndVote(govKeeper testutil.TestGovKeeper, ctx sdk. return nil } -func getAccountsBalances(ctx sdk.Context, bankKeeper testutil.TestBankKeeper, bondDenom string, accounts []ibctesting.SenderAccount) map[string]sdk.Int { - accountsBalances := map[string]sdk.Int{} +func getAccountsBalances(ctx sdk.Context, bankKeeper testutil.TestBankKeeper, bondDenom string, accounts []ibctesting.SenderAccount) map[string]math.Int { + accountsBalances := map[string]math.Int{} for _, acc := range accounts { accountsBalances[string(acc.SenderAccount.GetAddress())] = bankKeeper.GetBalance(ctx, acc.SenderAccount.GetAddress(), bondDenom).Amount } diff --git a/tests/integration/distribution.go b/tests/integration/distribution.go index b9e3b9975e..58132fcc62 100644 --- a/tests/integration/distribution.go +++ b/tests/integration/distribution.go @@ -6,7 +6,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" @@ -23,7 +24,7 @@ func (s *CCVTestSuite) TestRewardsDistribution() { s.providerChain.NextBlock() // register a consumer reward denom - params := s.consumerApp.GetConsumerKeeper().GetParams(s.consumerCtx()) + params := s.consumerApp.GetConsumerKeeper().GetConsumerParams(s.consumerCtx()) params.RewardDenoms = []string{sdk.DefaultBondDenom} s.consumerApp.GetConsumerKeeper().SetParams(s.consumerCtx(), params) @@ -53,7 +54,7 @@ func (s *CCVTestSuite) TestRewardsDistribution() { frac, err := sdk.NewDecFromStr(s.consumerApp.GetConsumerKeeper().GetConsumerRedistributionFrac(s.consumerCtx())) s.Require().NoError(err) consumerExpectedRewards, _ := sdk.NewDecCoinsFromCoins(feePoolTokens...).MulDec(frac).TruncateDecimal() - providerExpectedRewards := feePoolTokens.Sub(consumerExpectedRewards) + providerExpectedRewards := feePoolTokens.Sub(consumerExpectedRewards...) s.consumerChain.NextBlock() // amount from the fee pool is divided between consumer redistribute address and address reserved for provider chain @@ -126,7 +127,7 @@ func (s *CCVTestSuite) TestRewardsDistribution() { // Check that the delAddr has the right amount less money in it after paying the fee senderCoins2 := providerBankKeeper.GetAllBalances(s.providerCtx(), delAddr) consumerRewardDenomRegistrationFee := s.providerApp.GetProviderKeeper().GetConsumerRewardDenomRegistrationFee(s.providerCtx()) - s.Require().Equal(senderCoins1.Sub(senderCoins2), sdk.NewCoins(consumerRewardDenomRegistrationFee)) + s.Require().Equal(senderCoins1.Sub(senderCoins2...), sdk.NewCoins(consumerRewardDenomRegistrationFee)) s.providerChain.NextBlock() @@ -152,7 +153,7 @@ func (s *CCVTestSuite) TestSendRewardsRetries() { s.providerChain.NextBlock() // Register denom on consumer chain - params := s.consumerApp.GetConsumerKeeper().GetParams(s.consumerCtx()) + params := s.consumerApp.GetConsumerKeeper().GetConsumerParams(s.consumerCtx()) params.RewardDenoms = []string{sdk.DefaultBondDenom} s.consumerApp.GetConsumerKeeper().SetParams(s.consumerCtx(), params) @@ -281,7 +282,7 @@ func (s *CCVTestSuite) TestEndBlockRD() { s.providerChain.NextBlock() if tc.denomRegistered { - params := s.consumerApp.GetConsumerKeeper().GetParams(s.consumerCtx()) + params := s.consumerApp.GetConsumerKeeper().GetConsumerParams(s.consumerCtx()) params.RewardDenoms = []string{sdk.DefaultBondDenom} s.consumerApp.GetConsumerKeeper().SetParams(s.consumerCtx(), params) } diff --git a/tests/integration/expired_client.go b/tests/integration/expired_client.go index 16abe75c35..ae7570a57f 100644 --- a/tests/integration/expired_client.go +++ b/tests/integration/expired_client.go @@ -3,15 +3,16 @@ package integration import ( "time" + abci "github.com/cometbft/cometbft/abci/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" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - ibcexported "github.com/cosmos/ibc-go/v4/modules/core/exported" - ibctm "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" + ibctm "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" - abci "github.com/tendermint/tendermint/abci/types" ) // TestVSCPacketSendWithExpiredClient tests queueing of VSCPackets when the consumer client is expired. @@ -127,11 +128,11 @@ func (s *CCVTestSuite) TestConsumerPacketSendExpiredClient() { // try to send slash packet for downtime infraction addr := ed25519.GenPrivKey().PubKey().Address() val := abci.Validator{Address: addr} - consumerKeeper.QueueSlashPacket(s.consumerCtx(), val, 2, stakingtypes.Downtime) + consumerKeeper.QueueSlashPacket(s.consumerCtx(), val, 2, stakingtypes.Infraction_INFRACTION_DOWNTIME) // try to send slash packet for the same downtime infraction - consumerKeeper.QueueSlashPacket(s.consumerCtx(), val, 3, stakingtypes.Downtime) + consumerKeeper.QueueSlashPacket(s.consumerCtx(), val, 3, stakingtypes.Infraction_INFRACTION_DOWNTIME) // try to send slash packet for the double-sign infraction - consumerKeeper.QueueSlashPacket(s.consumerCtx(), val, 3, stakingtypes.DoubleSign) + consumerKeeper.QueueSlashPacket(s.consumerCtx(), val, 3, stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN) // check that the packets were added to the list of pending data packets consumerPackets = consumerKeeper.GetPendingPackets(s.consumerCtx()) diff --git a/tests/integration/key_assignment.go b/tests/integration/key_assignment.go index bf0cc394c3..e6a794fedf 100644 --- a/tests/integration/key_assignment.go +++ b/tests/integration/key_assignment.go @@ -1,13 +1,14 @@ package integration import ( + tmencoding "github.com/cometbft/cometbft/crypto/encoding" + tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/cosmos/ibc-go/v4/testing/mock" + "github.com/cosmos/ibc-go/v7/testing/mock" + providerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/provider/keeper" ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" - tmencoding "github.com/tendermint/tendermint/crypto/encoding" - tmprotocrypto "github.com/tendermint/tendermint/proto/tendermint/crypto" ) func (s *CCVTestSuite) TestKeyAssignment() { diff --git a/tests/integration/normal_operations.go b/tests/integration/normal_operations.go index e752d783a4..3318e29940 100644 --- a/tests/integration/normal_operations.go +++ b/tests/integration/normal_operations.go @@ -1,9 +1,9 @@ package integration import ( + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" - tmproto "github.com/tendermint/tendermint/proto/tendermint/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 ef1b85f3f7..86084545c6 100644 --- a/tests/integration/setup.go +++ b/tests/integration/setup.go @@ -3,18 +3,18 @@ package integration import ( "testing" + tmencoding "github.com/cometbft/cometbft/crypto/encoding" sdk "github.com/cosmos/cosmos-sdk/types" - ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" - "github.com/cosmos/ibc-go/v4/testing/mock" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + "github.com/cosmos/ibc-go/v7/testing/mock" testutil "github.com/cosmos/interchain-security/v2/testutil/integration" - tmencoding "github.com/tendermint/tendermint/crypto/encoding" icstestingutils "github.com/cosmos/interchain-security/v2/testutil/ibc_testing" consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" - transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" "github.com/stretchr/testify/suite" @@ -160,6 +160,7 @@ func initConsumerChain( // run CCV module init genesis s.NotPanics(func() { consumerKeeper := bundle.GetKeeper() + // this will set the initial valset on consumer consumerKeeper.InitGenesis(bundle.GetCtx(), genesisState) }) diff --git a/tests/integration/slashing.go b/tests/integration/slashing.go index 6e60bc5df3..8b4cb80547 100644 --- a/tests/integration/slashing.go +++ b/tests/integration/slashing.go @@ -4,6 +4,8 @@ import ( "fmt" "time" + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/crypto/ed25519" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" sdk "github.com/cosmos/cosmos-sdk/types" evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" @@ -11,14 +13,11 @@ import ( stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + tmtypes "github.com/cometbft/cometbft/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" keepertestutil "github.com/cosmos/interchain-security/v2/testutil/keeper" providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - tmtypes "github.com/tendermint/tendermint/types" - - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/crypto/ed25519" ) // TestRelayAndApplyDowntimePacket tests that downtime slash packets can be properly relayed @@ -67,7 +66,7 @@ func (s *CCVTestSuite) TestRelayAndApplyDowntimePacket() { s.setDefaultValSigningInfo(*tmtypes.NewValidator(tmPk, stakingVal.ConsensusPower(sdk.DefaultPowerReduction))) // Send slash packet from the first consumer chain - packet := s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmVal, stakingtypes.Downtime, 1) + packet := s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmVal, stakingtypes.Infraction_INFRACTION_DOWNTIME, 1) err = s.getFirstBundle().Path.EndpointA.SendPacket(packet) s.Require().NoError(err) @@ -195,7 +194,7 @@ func (s *CCVTestSuite) TestRelayAndApplyDoubleSignPacket() { s.setDefaultValSigningInfo(*tmtypes.NewValidator(tmPk, stakingVal.ConsensusPower(sdk.DefaultPowerReduction))) // Send slash packet from the first consumer chain - packet := s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmVal, stakingtypes.DoubleSign, 1) + packet := s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmVal, stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN, 1) err = s.getFirstBundle().Path.EndpointA.SendPacket(packet) s.Require().NoError(err) @@ -289,7 +288,7 @@ func (suite *CCVTestSuite) TestHandleSlashPacketDowntime() { *ccv.NewSlashPacketData( abci.Validator{Address: tmVal.Address, Power: 0}, uint64(0), - stakingtypes.Downtime, + stakingtypes.Infraction_INFRACTION_DOWNTIME, ), ) @@ -338,7 +337,7 @@ func (suite *CCVTestSuite) TestOnRecvSlashPacketErrors() { providerKeeper.SetInitChainHeight(ctx, consumerChainID, initChainHeight) // now the method will fail at infraction height check. - packetData.Infraction = stakingtypes.InfractionEmpty + packetData.Infraction = stakingtypes.Infraction_INFRACTION_UNSPECIFIED errAck = providerKeeper.OnRecvSlashPacket(ctx, packet, packetData) suite.Require().False(errAck.Success()) errAckCast = errAck.(channeltypes.Acknowledgement) @@ -366,7 +365,7 @@ func (suite *CCVTestSuite) TestOnRecvSlashPacketErrors() { abci.Validator{ Address: ed25519.GenPrivKey().PubKey().Address(), Power: int64(0), - }, uint64(0), stakingtypes.Downtime, + }, uint64(0), stakingtypes.Infraction_INFRACTION_DOWNTIME, ) // Set initial block height for consumer chain @@ -398,7 +397,7 @@ func (suite *CCVTestSuite) TestOnRecvSlashPacketErrors() { // expect error ack when infraction type in unspecified tmAddr := suite.providerChain.Vals.Validators[1].Address slashingPkt.Validator.Address = tmAddr - slashingPkt.Infraction = stakingtypes.InfractionEmpty + slashingPkt.Infraction = stakingtypes.Infraction_INFRACTION_UNSPECIFIED valInfo.Address = sdk.ConsAddress(tmAddr).String() providerSlashingKeeper.SetValidatorSigningInfo(ctx, sdk.ConsAddress(tmAddr), valInfo) @@ -411,7 +410,7 @@ func (suite *CCVTestSuite) TestOnRecvSlashPacketErrors() { suite.Require().Equal(uint64(0), (providerKeeper.GetThrottledPacketDataSize(ctx, consumerChainID))) // expect to queue entries for the slash request - slashingPkt.Infraction = stakingtypes.Downtime + slashingPkt.Infraction = stakingtypes.Infraction_INFRACTION_DOWNTIME ack = providerKeeper.OnRecvSlashPacket(ctx, packet, *slashingPkt) suite.Require().True(ack.Success()) suite.Require().Equal(1, len(providerKeeper.GetAllGlobalSlashEntries(ctx))) @@ -460,7 +459,7 @@ func (suite *CCVTestSuite) TestValidatorDowntime() { abci.Validator{Address: vals[0].Address, Power: valPower}, // get the VSC ID mapping the infraction height consumerKeeper.GetHeightValsetUpdateID(ctx, uint64(missedBlockThreshold-sdk.ValidatorUpdateDelay-1)), - stakingtypes.Downtime, + stakingtypes.Infraction_INFRACTION_DOWNTIME, ) expCommit := suite.commitSlashPacket(ctx, *packetData) @@ -564,7 +563,7 @@ func (suite *CCVTestSuite) TestValidatorDoubleSigning() { abci.Validator{Address: consAddr.Bytes(), Power: power}, // get VSC ID mapping to the infraction height with the TM delay subtracted suite.consumerApp.GetConsumerKeeper().GetHeightValsetUpdateID(ctx, uint64(infractionHeight-sdk.ValidatorUpdateDelay)), - stakingtypes.DoubleSign, + stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN, ) expCommit := suite.commitSlashPacket(ctx, *packetData) @@ -609,11 +608,11 @@ func (suite *CCVTestSuite) TestQueueAndSendSlashPacket() { // and 4 slash request for double-signing type slashedVal struct { validator abci.Validator - infraction stakingtypes.InfractionType + infraction stakingtypes.Infraction } slashedVals := []slashedVal{} - infraction := stakingtypes.Downtime + infraction := stakingtypes.Infraction_INFRACTION_DOWNTIME for j := 0; j < 2; j++ { for i := 0; i < 4; i++ { addr := ed25519.GenPrivKey().PubKey().Address() @@ -623,7 +622,7 @@ func (suite *CCVTestSuite) TestQueueAndSendSlashPacket() { consumerKeeper.QueueSlashPacket(ctx, val, 0, infraction) slashedVals = append(slashedVals, slashedVal{validator: val, infraction: infraction}) } - infraction = stakingtypes.DoubleSign + infraction = stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN } // expect to store a duplicate for each slash request @@ -676,8 +675,8 @@ func (suite *CCVTestSuite) TestCISBeforeCCVEstablished() { pendingPackets := consumerKeeper.GetPendingPackets(suite.consumerCtx()) suite.Require().Len(pendingPackets.List, 0) - consumerKeeper.Slash(suite.consumerCtx(), []byte{0x01, 0x02, 0x3}, - 66, 4324, sdk.MustNewDecFromStr("0.05"), stakingtypes.Downtime) + consumerKeeper.SlashWithInfractionReason(suite.consumerCtx(), []byte{0x01, 0x02, 0x3}, + 66, 4324, sdk.MustNewDecFromStr("0.05"), stakingtypes.Infraction_INFRACTION_DOWNTIME) // Check slash packet was queued pendingPackets = consumerKeeper.GetPendingPackets(suite.consumerCtx()) diff --git a/tests/integration/stop_consumer.go b/tests/integration/stop_consumer.go index 39da4eabe4..fda0aeb441 100644 --- a/tests/integration/stop_consumer.go +++ b/tests/integration/stop_consumer.go @@ -1,12 +1,13 @@ package integration import ( + abci "github.com/cometbft/cometbft/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" - abci "github.com/tendermint/tendermint/abci/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 b2dc390ea1..289c57e9d0 100644 --- a/tests/integration/throttle.go +++ b/tests/integration/throttle.go @@ -3,13 +3,14 @@ package integration import ( "time" + tmtypes "github.com/cometbft/cometbft/types" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + icstestingutils "github.com/cosmos/interchain-security/v2/testutil/ibc_testing" providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" - tmtypes "github.com/tendermint/tendermint/types" ) const fullSlashMeterString = "1.0" @@ -59,7 +60,7 @@ func (s *CCVTestSuite) TestBasicSlashPacketThrottling() { // Send a slash packet from consumer to provider s.setDefaultValSigningInfo(*s.providerChain.Vals.Validators[0]) tmVal := s.providerChain.Vals.Validators[0] - packet := s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmVal, stakingtypes.Downtime, 1) + packet := s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmVal, stakingtypes.Infraction_INFRACTION_DOWNTIME, 1) sendOnConsumerRecvOnProvider(s, s.getFirstBundle().Path, packet) // Assert validator 0 is jailed and has no power @@ -78,7 +79,7 @@ func (s *CCVTestSuite) TestBasicSlashPacketThrottling() { // Now send a second slash packet from consumer to provider for a different validator. s.setDefaultValSigningInfo(*s.providerChain.Vals.Validators[2]) tmVal = s.providerChain.Vals.Validators[2] - packet = s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmVal, stakingtypes.Downtime, 2) + packet = s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmVal, stakingtypes.Infraction_INFRACTION_DOWNTIME, 2) sendOnConsumerRecvOnProvider(s, s.getFirstBundle().Path, packet) // Require that slash packet has not been handled @@ -195,7 +196,7 @@ func (s *CCVTestSuite) TestMultiConsumerSlashPacketThrottling() { packet := s.constructSlashPacketFromConsumer( *bundle, *tmVal, - stakingtypes.Downtime, + stakingtypes.Infraction_INFRACTION_DOWNTIME, 3, // use sequence 3, 1 and 2 are used above. ) sendOnConsumerRecvOnProvider(s, bundle.Path, packet) @@ -301,11 +302,11 @@ func (s *CCVTestSuite) TestPacketSpam() { // Increment ibc seq num for each packet (starting at 1) ibcSeqNum++ // Set infraction type based on even/odd index. - var infractionType stakingtypes.InfractionType + var infractionType stakingtypes.Infraction if ibcSeqNum%2 == 0 { - infractionType = stakingtypes.Downtime + infractionType = stakingtypes.Infraction_INFRACTION_DOWNTIME } else { - infractionType = stakingtypes.DoubleSign + infractionType = stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN } valToJail := s.providerChain.Vals.Validators[ibcSeqNum%3] packets = append(packets, s.constructSlashPacketFromConsumer(firstBundle, *valToJail, infractionType, ibcSeqNum)) @@ -362,7 +363,7 @@ func (s *CCVTestSuite) TestDoubleSignDoesNotAffectThrottling() { // Increment ibc seq num for each packet (starting at 1) ibcSeqNum++ valToJail := s.providerChain.Vals.Validators[ibcSeqNum%3] - packets = append(packets, s.constructSlashPacketFromConsumer(firstBundle, *valToJail, stakingtypes.DoubleSign, ibcSeqNum)) + packets = append(packets, s.constructSlashPacketFromConsumer(firstBundle, *valToJail, stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN, ibcSeqNum)) } // Recv 500 packets from consumer to provider in same block @@ -458,7 +459,7 @@ func (s *CCVTestSuite) TestQueueOrdering() { // Else instantiate a slash packet valToJail := s.providerChain.Vals.Validators[ibcSeqNum%3] - packets = append(packets, s.constructSlashPacketFromConsumer(firstBundle, *valToJail, stakingtypes.Downtime, ibcSeqNum)) + packets = append(packets, s.constructSlashPacketFromConsumer(firstBundle, *valToJail, stakingtypes.Infraction_INFRACTION_DOWNTIME, ibcSeqNum)) } // Recv 500 packets from consumer to provider in same block @@ -592,9 +593,9 @@ func (s *CCVTestSuite) TestSlashingSmallValidators() { tmval1 := s.providerChain.Vals.Validators[1] tmval2 := s.providerChain.Vals.Validators[2] tmval3 := s.providerChain.Vals.Validators[3] - packet1 := s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval1, stakingtypes.Downtime, 1) - packet2 := s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval2, stakingtypes.Downtime, 2) - packet3 := s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval3, stakingtypes.Downtime, 3) + packet1 := s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval1, stakingtypes.Infraction_INFRACTION_DOWNTIME, 1) + packet2 := s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval2, stakingtypes.Infraction_INFRACTION_DOWNTIME, 2) + packet3 := s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval3, stakingtypes.Infraction_INFRACTION_DOWNTIME, 3) sendOnConsumerRecvOnProvider(s, s.getFirstBundle().Path, packet1) sendOnConsumerRecvOnProvider(s, s.getFirstBundle().Path, packet2) sendOnConsumerRecvOnProvider(s, s.getFirstBundle().Path, packet3) @@ -667,12 +668,12 @@ func (s *CCVTestSuite) TestSlashSameValidator() { s.setDefaultValSigningInfo(*tmval3) packets := []channeltypes.Packet{ - s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval1, stakingtypes.Downtime, 1), - s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval2, stakingtypes.Downtime, 2), - s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval3, stakingtypes.Downtime, 3), - s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval1, stakingtypes.Downtime, 4), - s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval2, stakingtypes.Downtime, 5), - s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval3, stakingtypes.Downtime, 6), + s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval1, stakingtypes.Infraction_INFRACTION_DOWNTIME, 1), + s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval2, stakingtypes.Infraction_INFRACTION_DOWNTIME, 2), + s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval3, stakingtypes.Infraction_INFRACTION_DOWNTIME, 3), + s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval1, stakingtypes.Infraction_INFRACTION_DOWNTIME, 4), + s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval2, stakingtypes.Infraction_INFRACTION_DOWNTIME, 5), + s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval3, stakingtypes.Infraction_INFRACTION_DOWNTIME, 6), } // Recv and queue all slash packets. @@ -723,7 +724,7 @@ func (s CCVTestSuite) TestSlashAllValidators() { //nolint:govet // this is a tes for _, val := range s.providerChain.Vals.Validators { s.setDefaultValSigningInfo(*val) packets = append(packets, s.constructSlashPacketFromConsumer( - s.getFirstBundle(), *val, stakingtypes.Downtime, ibcSeqNum)) + s.getFirstBundle(), *val, stakingtypes.Infraction_INFRACTION_DOWNTIME, ibcSeqNum)) ibcSeqNum++ } @@ -731,7 +732,7 @@ func (s CCVTestSuite) TestSlashAllValidators() { //nolint:govet // this is a tes for _, val := range s.providerChain.Vals.Validators { for i := 0; i < 5; i++ { packets = append(packets, s.constructSlashPacketFromConsumer( - s.getFirstBundle(), *val, stakingtypes.Downtime, ibcSeqNum)) + s.getFirstBundle(), *val, stakingtypes.Infraction_INFRACTION_DOWNTIME, ibcSeqNum)) ibcSeqNum++ } } @@ -784,7 +785,7 @@ func (s *CCVTestSuite) TestLeadingVSCMaturedAreDequeued() { for i := 50; i < 100; i++ { ibcSeqNum := uint64(i) packet := s.constructSlashPacketFromConsumer(*bundle, - *s.providerChain.Vals.Validators[0], stakingtypes.Downtime, ibcSeqNum) + *s.providerChain.Vals.Validators[0], stakingtypes.Infraction_INFRACTION_DOWNTIME, ibcSeqNum) packetData := ccvtypes.ConsumerPacketData{} ccvtypes.ModuleCdc.MustUnmarshalJSON(packet.GetData(), &packetData) providerKeeper.OnRecvSlashPacket(s.providerCtx(), @@ -875,7 +876,7 @@ func (s *CCVTestSuite) TestVscMaturedHandledPerBlockLimit() { for i := 100; i < 150; i++ { ibcSeqNum := uint64(i) packet := s.constructSlashPacketFromConsumer(*bundle, - *s.providerChain.Vals.Validators[0], stakingtypes.Downtime, ibcSeqNum) + *s.providerChain.Vals.Validators[0], stakingtypes.Infraction_INFRACTION_DOWNTIME, ibcSeqNum) packetData := ccvtypes.ConsumerPacketData{} ccvtypes.ModuleCdc.MustUnmarshalJSON(packet.GetData(), &packetData) providerKeeper.OnRecvSlashPacket(s.providerCtx(), diff --git a/tests/integration/unbonding.go b/tests/integration/unbonding.go index fdb3e3af13..6b14099d45 100644 --- a/tests/integration/unbonding.go +++ b/tests/integration/unbonding.go @@ -3,6 +3,7 @@ package integration import ( "time" + "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" providerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/provider/keeper" @@ -25,10 +26,10 @@ func (s *CCVTestSuite) TestUndelegationNormalOperation() { testCases := []struct { name string shareDiv int64 - unbond func(expBalance, balance sdk.Int) + unbond func(expBalance, balance math.Int) }{ { - "provider unbonding period elapses first", 2, func(expBalance, balance sdk.Int) { + "provider unbonding period elapses first", 2, func(expBalance, balance math.Int) { // increment time so that the unbonding period ends on the provider incrementTimeByUnbondingPeriod(s, Provider) @@ -43,7 +44,7 @@ func (s *CCVTestSuite) TestUndelegationNormalOperation() { }, }, { - "consumer unbonding period elapses first", 2, func(expBalance, balance sdk.Int) { + "consumer unbonding period elapses first", 2, func(expBalance, balance math.Int) { // undelegation complete on consumer unbondConsumer(1) @@ -58,7 +59,7 @@ func (s *CCVTestSuite) TestUndelegationNormalOperation() { }, }, { - "no valset changes", 1, func(expBalance, balance sdk.Int) { + "no valset changes", 1, func(expBalance, balance math.Int) { // undelegation complete on consumer unbondConsumer(1) diff --git a/tests/integration/valset_update.go b/tests/integration/valset_update.go index d255c7f18d..6e231976c4 100644 --- a/tests/integration/valset_update.go +++ b/tests/integration/valset_update.go @@ -3,12 +3,12 @@ package integration import ( "time" + abci "github.com/cometbft/cometbft/abci/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" sdk "github.com/cosmos/cosmos-sdk/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/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" ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" - abci "github.com/tendermint/tendermint/abci/types" ) // TestPacketRoundtrip tests a CCV packet roundtrip when tokens are bonded on provider diff --git a/testutil/crypto/crypto.go b/testutil/crypto/crypto.go index 891f357c9a..1becc4248e 100644 --- a/testutil/crypto/crypto.go +++ b/testutil/crypto/crypto.go @@ -13,9 +13,9 @@ import ( sdkstakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - tmcrypto "github.com/tendermint/tendermint/crypto" - tmprotocrypto "github.com/tendermint/tendermint/proto/tendermint/crypto" - tmtypes "github.com/tendermint/tendermint/types" + tmcrypto "github.com/cometbft/cometbft/crypto" + tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" + tmtypes "github.com/cometbft/cometbft/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 9a1bbdd48b..67e169af98 100644 --- a/testutil/ibc_testing/generic_setup.go +++ b/testutil/ibc_testing/generic_setup.go @@ -5,7 +5,7 @@ import ( "testing" sdk "github.com/cosmos/cosmos-sdk/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" testutil "github.com/cosmos/interchain-security/v2/testutil/integration" testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" @@ -13,8 +13,8 @@ import ( "github.com/stretchr/testify/suite" - tmencoding "github.com/tendermint/tendermint/crypto/encoding" - tmtypes "github.com/tendermint/tendermint/types" + tmencoding "github.com/cometbft/cometbft/crypto/encoding" + tmtypes "github.com/cometbft/cometbft/types" ) // Contains generic setup code for running integration tests against a provider, consumer, diff --git a/testutil/ibc_testing/specific_setup.go b/testutil/ibc_testing/specific_setup.go index 3e3886c818..ab9715ebd9 100644 --- a/testutil/ibc_testing/specific_setup.go +++ b/testutil/ibc_testing/specific_setup.go @@ -7,12 +7,11 @@ package ibc_testing import ( "encoding/json" - "github.com/cosmos/cosmos-sdk/simapp" - + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" - "github.com/tendermint/tendermint/libs/log" - tmdb "github.com/tendermint/tm-db" + tmdb "github.com/cometbft/cometbft-db" + "github.com/cometbft/cometbft/libs/log" appConsumer "github.com/cosmos/interchain-security/v2/app/consumer" appConsumerDemocracy "github.com/cosmos/interchain-security/v2/app/consumer-democracy" @@ -22,23 +21,20 @@ import ( // ProviderAppIniter implements ibctesting.AppIniter for a provider app func ProviderAppIniter() (ibctesting.TestingApp, map[string]json.RawMessage) { encoding := appProvider.MakeTestEncodingConfig() - testApp := appProvider.New(log.NewNopLogger(), tmdb.NewMemDB(), nil, true, map[int64]bool{}, - simapp.DefaultNodeHome, 5, encoding, simapp.EmptyAppOptions{}) - return testApp, appProvider.NewDefaultGenesisState(encoding.Marshaler) + testApp := appProvider.New(log.NewNopLogger(), tmdb.NewMemDB(), nil, true, simtestutil.EmptyAppOptions{}) + return testApp, appProvider.NewDefaultGenesisState(encoding.Codec) } // ConsumerAppIniter implements ibctesting.AppIniter for a consumer app func ConsumerAppIniter() (ibctesting.TestingApp, map[string]json.RawMessage) { encoding := appConsumer.MakeTestEncodingConfig() - testApp := appConsumer.New(log.NewNopLogger(), tmdb.NewMemDB(), nil, true, map[int64]bool{}, - simapp.DefaultNodeHome, 5, encoding, simapp.EmptyAppOptions{}) - return testApp, appConsumer.NewDefaultGenesisState(encoding.Marshaler) + testApp := appConsumer.New(log.NewNopLogger(), tmdb.NewMemDB(), nil, true, simtestutil.EmptyAppOptions{}) + return testApp, appConsumer.NewDefaultGenesisState(encoding.Codec) } // DemocracyConsumerAppIniter implements ibctesting.AppIniter for a democracy consumer app func DemocracyConsumerAppIniter() (ibctesting.TestingApp, map[string]json.RawMessage) { encoding := appConsumerDemocracy.MakeTestEncodingConfig() - testApp := appConsumerDemocracy.New(log.NewNopLogger(), tmdb.NewMemDB(), nil, true, map[int64]bool{}, - simapp.DefaultNodeHome, 5, encoding, simapp.EmptyAppOptions{}) - return testApp, appConsumerDemocracy.NewDefaultGenesisState(encoding.Marshaler) + testApp := appConsumerDemocracy.New(log.NewNopLogger(), tmdb.NewMemDB(), nil, true, simtestutil.EmptyAppOptions{}) + return testApp, appConsumerDemocracy.NewDefaultGenesisState(encoding.Codec) } diff --git a/testutil/integration/interfaces.go b/testutil/integration/interfaces.go index 51ffe51154..6fe667c2fa 100644 --- a/testutil/integration/interfaces.go +++ b/testutil/integration/interfaces.go @@ -3,21 +3,23 @@ package integration import ( "time" + "cosmossdk.io/math" + abci "github.com/cometbft/cometbft/abci/types" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" "github.com/cosmos/cosmos-sdk/x/staking/types" + ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" consumerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/consumer/keeper" providerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/provider/keeper" ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" - abci "github.com/tendermint/tendermint/abci/types" ) // The interface that any provider app must implement to be compatible with ccv integration tests. @@ -85,7 +87,7 @@ type DemocConsumerApp interface { type TestStakingKeeper interface { ccvtypes.StakingKeeper - Delegate(ctx sdk.Context, delAddr sdk.AccAddress, bondAmt sdk.Int, tokenSrc types.BondStatus, + Delegate(ctx sdk.Context, delAddr sdk.AccAddress, bondAmt math.Int, tokenSrc types.BondStatus, validator types.Validator, subtractAccount bool) (newShares sdk.Dec, err error) Undelegate(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress, sharesAmount sdk.Dec, ) (time.Time, error) @@ -144,10 +146,9 @@ type TestMintKeeper interface { } type TestGovKeeper interface { - GetDepositParams(ctx sdk.Context) govtypes.DepositParams - GetVotingParams(ctx sdk.Context) govtypes.VotingParams - SetVotingParams(ctx sdk.Context, votingParams govtypes.VotingParams) - SubmitProposal(ctx sdk.Context, content govtypes.Content) (govtypes.Proposal, error) + GetParams(ctx sdk.Context) govv1.Params + SetParams(ctx sdk.Context, params govv1.Params) error + SubmitProposal(ctx sdk.Context, messages []sdk.Msg, metadata, title, summary string, proposer sdk.AccAddress) (govv1.Proposal, error) AddDeposit(ctx sdk.Context, proposalID uint64, depositorAddr sdk.AccAddress, depositAmount sdk.Coins) (bool, error) - AddVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress, options govtypes.WeightedVoteOptions) error + AddVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress, options govv1.WeightedVoteOptions, metadata string) error } diff --git a/testutil/keeper/expectations.go b/testutil/keeper/expectations.go index 6377bf5613..06b5008750 100644 --- a/testutil/keeper/expectations.go +++ b/testutil/keeper/expectations.go @@ -6,14 +6,16 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - conntypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" - ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" - providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" + "github.com/golang/mock/gomock" - host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + 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" + providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" + + host "github.com/cosmos/ibc-go/v7/modules/core/24-host" ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" extra "github.com/oxyno-zeta/gomock-extra-matcher" diff --git a/testutil/keeper/mocks.go b/testutil/keeper/mocks.go index 4f931d8152..fea83079d3 100644 --- a/testutil/keeper/mocks.go +++ b/testutil/keeper/mocks.go @@ -9,18 +9,20 @@ import ( reflect "reflect" time "time" - types "github.com/cosmos/cosmos-sdk/types" - types0 "github.com/cosmos/cosmos-sdk/x/auth/types" - types1 "github.com/cosmos/cosmos-sdk/x/capability/types" - types2 "github.com/cosmos/cosmos-sdk/x/evidence/types" - types3 "github.com/cosmos/cosmos-sdk/x/slashing/types" - types4 "github.com/cosmos/cosmos-sdk/x/staking/types" - types5 "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - types6 "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" - types7 "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" - exported "github.com/cosmos/ibc-go/v4/modules/core/exported" + math "cosmossdk.io/math" + types "github.com/cometbft/cometbft/abci/types" + 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/evidence/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" - types8 "github.com/tendermint/tendermint/abci/types" ) // MockStakingKeeper is a mock of StakingKeeper interface. @@ -47,7 +49,7 @@ func (m *MockStakingKeeper) EXPECT() *MockStakingKeeperMockRecorder { } // BondDenom mocks base method. -func (m *MockStakingKeeper) BondDenom(ctx types.Context) string { +func (m *MockStakingKeeper) BondDenom(ctx types0.Context) string { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "BondDenom", ctx) ret0, _ := ret[0].(string) @@ -61,10 +63,10 @@ func (mr *MockStakingKeeperMockRecorder) BondDenom(ctx interface{}) *gomock.Call } // Delegation mocks base method. -func (m *MockStakingKeeper) Delegation(ctx types.Context, addr types.AccAddress, valAddr types.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 } @@ -75,10 +77,10 @@ func (mr *MockStakingKeeperMockRecorder) Delegation(ctx, addr, valAddr interface } // GetLastTotalPower mocks base method. -func (m *MockStakingKeeper) GetLastTotalPower(ctx types.Context) types.Int { +func (m *MockStakingKeeper) GetLastTotalPower(ctx types0.Context) math.Int { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetLastTotalPower", ctx) - ret0, _ := ret[0].(types.Int) + ret0, _ := ret[0].(math.Int) return ret0 } @@ -89,7 +91,7 @@ func (mr *MockStakingKeeperMockRecorder) GetLastTotalPower(ctx interface{}) *gom } // GetLastValidatorPower mocks base method. -func (m *MockStakingKeeper) GetLastValidatorPower(ctx types.Context, operator types.ValAddress) int64 { +func (m *MockStakingKeeper) GetLastValidatorPower(ctx types0.Context, operator types0.ValAddress) int64 { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetLastValidatorPower", ctx, operator) ret0, _ := ret[0].(int64) @@ -103,10 +105,10 @@ func (mr *MockStakingKeeperMockRecorder) GetLastValidatorPower(ctx, operator int } // GetLastValidators mocks base method. -func (m *MockStakingKeeper) GetLastValidators(ctx types.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 } @@ -116,11 +118,26 @@ func (mr *MockStakingKeeperMockRecorder) GetLastValidators(ctx interface{}) *gom return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLastValidators", reflect.TypeOf((*MockStakingKeeper)(nil).GetLastValidators), ctx) } +// GetUnbondingType mocks base method. +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].(types5.UnbondingType) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// GetUnbondingType indicates an expected call of GetUnbondingType. +func (mr *MockStakingKeeperMockRecorder) GetUnbondingType(ctx, id interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUnbondingType", reflect.TypeOf((*MockStakingKeeper)(nil).GetUnbondingType), ctx, id) +} + // GetValidator mocks base method. -func (m *MockStakingKeeper) GetValidator(ctx types.Context, addr types.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 } @@ -132,10 +149,10 @@ func (mr *MockStakingKeeperMockRecorder) GetValidator(ctx, addr interface{}) *go } // GetValidatorByConsAddr mocks base method. -func (m *MockStakingKeeper) GetValidatorByConsAddr(ctx types.Context, consAddr types.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 } @@ -147,10 +164,10 @@ func (mr *MockStakingKeeperMockRecorder) GetValidatorByConsAddr(ctx, consAddr in } // GetValidatorUpdates mocks base method. -func (m *MockStakingKeeper) GetValidatorUpdates(ctx types.Context) []types8.ValidatorUpdate { +func (m *MockStakingKeeper) GetValidatorUpdates(ctx types0.Context) []types.ValidatorUpdate { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetValidatorUpdates", ctx) - ret0, _ := ret[0].([]types8.ValidatorUpdate) + ret0, _ := ret[0].([]types.ValidatorUpdate) return ret0 } @@ -161,7 +178,7 @@ func (mr *MockStakingKeeperMockRecorder) GetValidatorUpdates(ctx interface{}) *g } // IsValidatorJailed mocks base method. -func (m *MockStakingKeeper) IsValidatorJailed(ctx types.Context, addr types.ConsAddress) bool { +func (m *MockStakingKeeper) IsValidatorJailed(ctx types0.Context, addr types0.ConsAddress) bool { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "IsValidatorJailed", ctx, addr) ret0, _ := ret[0].(bool) @@ -175,7 +192,7 @@ func (mr *MockStakingKeeperMockRecorder) IsValidatorJailed(ctx, addr interface{} } // IterateLastValidatorPowers mocks base method. -func (m *MockStakingKeeper) IterateLastValidatorPowers(ctx types.Context, cb func(types.ValAddress, int64) bool) { +func (m *MockStakingKeeper) IterateLastValidatorPowers(ctx types0.Context, cb func(types0.ValAddress, int64) bool) { m.ctrl.T.Helper() m.ctrl.Call(m, "IterateLastValidatorPowers", ctx, cb) } @@ -187,7 +204,7 @@ func (mr *MockStakingKeeperMockRecorder) IterateLastValidatorPowers(ctx, cb inte } // IterateValidators mocks base method. -func (m *MockStakingKeeper) IterateValidators(ctx types.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) } @@ -199,7 +216,7 @@ func (mr *MockStakingKeeperMockRecorder) IterateValidators(ctx, f interface{}) * } // Jail mocks base method. -func (m *MockStakingKeeper) Jail(arg0 types.Context, arg1 types.ConsAddress) { +func (m *MockStakingKeeper) Jail(arg0 types0.Context, arg1 types0.ConsAddress) { m.ctrl.T.Helper() m.ctrl.Call(m, "Jail", arg0, arg1) } @@ -211,7 +228,7 @@ func (mr *MockStakingKeeperMockRecorder) Jail(arg0, arg1 interface{}) *gomock.Ca } // MaxValidators mocks base method. -func (m *MockStakingKeeper) MaxValidators(ctx types.Context) uint32 { +func (m *MockStakingKeeper) MaxValidators(ctx types0.Context) uint32 { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "MaxValidators", ctx) ret0, _ := ret[0].(uint32) @@ -225,10 +242,10 @@ func (mr *MockStakingKeeperMockRecorder) MaxValidators(ctx interface{}) *gomock. } // PowerReduction mocks base method. -func (m *MockStakingKeeper) PowerReduction(ctx types.Context) types.Int { +func (m *MockStakingKeeper) PowerReduction(ctx types0.Context) math.Int { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "PowerReduction", ctx) - ret0, _ := ret[0].(types.Int) + ret0, _ := ret[0].(math.Int) return ret0 } @@ -239,7 +256,7 @@ func (mr *MockStakingKeeperMockRecorder) PowerReduction(ctx interface{}) *gomock } // PutUnbondingOnHold mocks base method. -func (m *MockStakingKeeper) PutUnbondingOnHold(ctx types.Context, id uint64) error { +func (m *MockStakingKeeper) PutUnbondingOnHold(ctx types0.Context, id uint64) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "PutUnbondingOnHold", ctx, id) ret0, _ := ret[0].(error) @@ -253,19 +270,35 @@ func (mr *MockStakingKeeperMockRecorder) PutUnbondingOnHold(ctx, id interface{}) } // Slash mocks base method. -func (m *MockStakingKeeper) Slash(arg0 types.Context, arg1 types.ConsAddress, arg2, arg3 int64, arg4 types.Dec, arg5 types4.InfractionType) { +func (m *MockStakingKeeper) Slash(arg0 types0.Context, arg1 types0.ConsAddress, arg2, arg3 int64, arg4 types0.Dec) math.Int { m.ctrl.T.Helper() - m.ctrl.Call(m, "Slash", arg0, arg1, arg2, arg3, arg4, arg5) + ret := m.ctrl.Call(m, "Slash", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(math.Int) + return ret0 } // Slash indicates an expected call of Slash. -func (mr *MockStakingKeeperMockRecorder) Slash(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call { +func (mr *MockStakingKeeperMockRecorder) Slash(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Slash", reflect.TypeOf((*MockStakingKeeper)(nil).Slash), arg0, arg1, arg2, arg3, arg4, arg5) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Slash", reflect.TypeOf((*MockStakingKeeper)(nil).Slash), arg0, arg1, arg2, arg3, arg4) +} + +// SlashWithInfractionReason mocks base method. +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) + return ret0 +} + +// SlashWithInfractionReason indicates an expected call of SlashWithInfractionReason. +func (mr *MockStakingKeeperMockRecorder) SlashWithInfractionReason(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SlashWithInfractionReason", reflect.TypeOf((*MockStakingKeeper)(nil).SlashWithInfractionReason), arg0, arg1, arg2, arg3, arg4, arg5) } // UnbondingCanComplete mocks base method. -func (m *MockStakingKeeper) UnbondingCanComplete(ctx types.Context, id uint64) error { +func (m *MockStakingKeeper) UnbondingCanComplete(ctx types0.Context, id uint64) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "UnbondingCanComplete", ctx, id) ret0, _ := ret[0].(error) @@ -279,7 +312,7 @@ func (mr *MockStakingKeeperMockRecorder) UnbondingCanComplete(ctx, id interface{ } // UnbondingTime mocks base method. -func (m *MockStakingKeeper) UnbondingTime(ctx types.Context) time.Duration { +func (m *MockStakingKeeper) UnbondingTime(ctx types0.Context) time.Duration { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "UnbondingTime", ctx) ret0, _ := ret[0].(time.Duration) @@ -293,7 +326,7 @@ func (mr *MockStakingKeeperMockRecorder) UnbondingTime(ctx interface{}) *gomock. } // Unjail mocks base method. -func (m *MockStakingKeeper) Unjail(ctx types.Context, addr types.ConsAddress) { +func (m *MockStakingKeeper) Unjail(ctx types0.Context, addr types0.ConsAddress) { m.ctrl.T.Helper() m.ctrl.Call(m, "Unjail", ctx, addr) } @@ -305,10 +338,10 @@ func (mr *MockStakingKeeperMockRecorder) Unjail(ctx, addr interface{}) *gomock.C } // Validator mocks base method. -func (m *MockStakingKeeper) Validator(ctx types.Context, addr types.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 } @@ -319,10 +352,10 @@ func (mr *MockStakingKeeperMockRecorder) Validator(ctx, addr interface{}) *gomoc } // ValidatorByConsAddr mocks base method. -func (m *MockStakingKeeper) ValidatorByConsAddr(ctx types.Context, consAddr types.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 } @@ -356,7 +389,7 @@ func (m *MockEvidenceKeeper) EXPECT() *MockEvidenceKeeperMockRecorder { } // HandleEquivocationEvidence mocks base method. -func (m *MockEvidenceKeeper) HandleEquivocationEvidence(ctx types.Context, evidence *types2.Equivocation) { +func (m *MockEvidenceKeeper) HandleEquivocationEvidence(ctx types0.Context, evidence *types3.Equivocation) { m.ctrl.T.Helper() m.ctrl.Call(m, "HandleEquivocationEvidence", ctx, evidence) } @@ -391,7 +424,7 @@ func (m *MockSlashingKeeper) EXPECT() *MockSlashingKeeperMockRecorder { } // DowntimeJailDuration mocks base method. -func (m *MockSlashingKeeper) DowntimeJailDuration(arg0 types.Context) time.Duration { +func (m *MockSlashingKeeper) DowntimeJailDuration(arg0 types0.Context) time.Duration { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "DowntimeJailDuration", arg0) ret0, _ := ret[0].(time.Duration) @@ -405,10 +438,10 @@ func (mr *MockSlashingKeeperMockRecorder) DowntimeJailDuration(arg0 interface{}) } // GetValidatorSigningInfo mocks base method. -func (m *MockSlashingKeeper) GetValidatorSigningInfo(ctx types.Context, address types.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 } @@ -420,7 +453,7 @@ func (mr *MockSlashingKeeperMockRecorder) GetValidatorSigningInfo(ctx, address i } // IsTombstoned mocks base method. -func (m *MockSlashingKeeper) IsTombstoned(arg0 types.Context, arg1 types.ConsAddress) bool { +func (m *MockSlashingKeeper) IsTombstoned(arg0 types0.Context, arg1 types0.ConsAddress) bool { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "IsTombstoned", arg0, arg1) ret0, _ := ret[0].(bool) @@ -434,7 +467,7 @@ func (mr *MockSlashingKeeperMockRecorder) IsTombstoned(arg0, arg1 interface{}) * } // JailUntil mocks base method. -func (m *MockSlashingKeeper) JailUntil(arg0 types.Context, arg1 types.ConsAddress, arg2 time.Time) { +func (m *MockSlashingKeeper) JailUntil(arg0 types0.Context, arg1 types0.ConsAddress, arg2 time.Time) { m.ctrl.T.Helper() m.ctrl.Call(m, "JailUntil", arg0, arg1, arg2) } @@ -446,10 +479,10 @@ func (mr *MockSlashingKeeperMockRecorder) JailUntil(arg0, arg1, arg2 interface{} } // SlashFractionDoubleSign mocks base method. -func (m *MockSlashingKeeper) SlashFractionDoubleSign(ctx types.Context) types.Dec { +func (m *MockSlashingKeeper) SlashFractionDoubleSign(ctx types0.Context) types0.Dec { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SlashFractionDoubleSign", ctx) - ret0, _ := ret[0].(types.Dec) + ret0, _ := ret[0].(types0.Dec) return ret0 } @@ -460,10 +493,10 @@ func (mr *MockSlashingKeeperMockRecorder) SlashFractionDoubleSign(ctx interface{ } // SlashFractionDowntime mocks base method. -func (m *MockSlashingKeeper) SlashFractionDowntime(arg0 types.Context) types.Dec { +func (m *MockSlashingKeeper) SlashFractionDowntime(arg0 types0.Context) types0.Dec { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SlashFractionDowntime", arg0) - ret0, _ := ret[0].(types.Dec) + ret0, _ := ret[0].(types0.Dec) return ret0 } @@ -474,7 +507,7 @@ func (mr *MockSlashingKeeperMockRecorder) SlashFractionDowntime(arg0 interface{} } // Tombstone mocks base method. -func (m *MockSlashingKeeper) Tombstone(arg0 types.Context, arg1 types.ConsAddress) { +func (m *MockSlashingKeeper) Tombstone(arg0 types0.Context, arg1 types0.ConsAddress) { m.ctrl.T.Helper() m.ctrl.Call(m, "Tombstone", arg0, arg1) } @@ -509,7 +542,7 @@ func (m *MockChannelKeeper) EXPECT() *MockChannelKeeperMockRecorder { } // ChanCloseInit mocks base method. -func (m *MockChannelKeeper) ChanCloseInit(ctx types.Context, portID, channelID string, chanCap *types1.Capability) error { +func (m *MockChannelKeeper) ChanCloseInit(ctx types0.Context, portID, channelID string, chanCap *types2.Capability) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ChanCloseInit", ctx, portID, channelID, chanCap) ret0, _ := ret[0].(error) @@ -523,10 +556,10 @@ func (mr *MockChannelKeeperMockRecorder) ChanCloseInit(ctx, portID, channelID, c } // GetChannel mocks base method. -func (m *MockChannelKeeper) GetChannel(ctx types.Context, srcPort, srcChan string) (types7.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].(types7.Channel) + ret0, _ := ret[0].(types9.Channel) ret1, _ := ret[1].(bool) return ret0, ret1 } @@ -538,7 +571,7 @@ func (mr *MockChannelKeeperMockRecorder) GetChannel(ctx, srcPort, srcChan interf } // GetNextSequenceSend mocks base method. -func (m *MockChannelKeeper) GetNextSequenceSend(ctx types.Context, portID, channelID string) (uint64, bool) { +func (m *MockChannelKeeper) GetNextSequenceSend(ctx types0.Context, portID, channelID string) (uint64, bool) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetNextSequenceSend", ctx, portID, channelID) ret0, _ := ret[0].(uint64) @@ -553,21 +586,22 @@ func (mr *MockChannelKeeperMockRecorder) GetNextSequenceSend(ctx, portID, channe } // SendPacket mocks base method. -func (m *MockChannelKeeper) SendPacket(ctx types.Context, channelCap *types1.Capability, packet exported.PacketI) 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, channelCap, packet) - ret0, _ := ret[0].(error) - return ret0 + ret := m.ctrl.Call(m, "SendPacket", ctx, chanCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data) + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 } // SendPacket indicates an expected call of SendPacket. -func (mr *MockChannelKeeperMockRecorder) SendPacket(ctx, channelCap, packet interface{}) *gomock.Call { +func (mr *MockChannelKeeperMockRecorder) SendPacket(ctx, chanCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendPacket", reflect.TypeOf((*MockChannelKeeper)(nil).SendPacket), ctx, channelCap, packet) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendPacket", reflect.TypeOf((*MockChannelKeeper)(nil).SendPacket), ctx, chanCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data) } // WriteAcknowledgement mocks base method. -func (m *MockChannelKeeper) WriteAcknowledgement(ctx types.Context, chanCap *types1.Capability, packet exported.PacketI, acknowledgement exported.Acknowledgement) error { +func (m *MockChannelKeeper) WriteAcknowledgement(ctx types0.Context, chanCap *types2.Capability, packet exported.PacketI, acknowledgement exported.Acknowledgement) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "WriteAcknowledgement", ctx, chanCap, packet, acknowledgement) ret0, _ := ret[0].(error) @@ -604,10 +638,10 @@ func (m *MockPortKeeper) EXPECT() *MockPortKeeperMockRecorder { } // BindPort mocks base method. -func (m *MockPortKeeper) BindPort(ctx types.Context, portID string) *types1.Capability { +func (m *MockPortKeeper) BindPort(ctx types0.Context, portID string) *types2.Capability { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "BindPort", ctx, portID) - ret0, _ := ret[0].(*types1.Capability) + ret0, _ := ret[0].(*types2.Capability) return ret0 } @@ -641,10 +675,10 @@ func (m *MockConnectionKeeper) EXPECT() *MockConnectionKeeperMockRecorder { } // GetConnection mocks base method. -func (m *MockConnectionKeeper) GetConnection(ctx types.Context, connectionID string) (types6.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].(types6.ConnectionEnd) + ret0, _ := ret[0].(types8.ConnectionEnd) ret1, _ := ret[1].(bool) return ret0, ret1 } @@ -679,7 +713,7 @@ func (m *MockClientKeeper) EXPECT() *MockClientKeeperMockRecorder { } // CreateClient mocks base method. -func (m *MockClientKeeper) CreateClient(ctx types.Context, clientState exported.ClientState, consensusState exported.ConsensusState) (string, error) { +func (m *MockClientKeeper) CreateClient(ctx types0.Context, clientState exported.ClientState, consensusState exported.ConsensusState) (string, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "CreateClient", ctx, clientState, consensusState) ret0, _ := ret[0].(string) @@ -694,7 +728,7 @@ func (mr *MockClientKeeperMockRecorder) CreateClient(ctx, clientState, consensus } // GetClientState mocks base method. -func (m *MockClientKeeper) GetClientState(ctx types.Context, clientID string) (exported.ClientState, bool) { +func (m *MockClientKeeper) GetClientState(ctx types0.Context, clientID string) (exported.ClientState, bool) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetClientState", ctx, clientID) ret0, _ := ret[0].(exported.ClientState) @@ -709,7 +743,7 @@ func (mr *MockClientKeeperMockRecorder) GetClientState(ctx, clientID interface{} } // GetLatestClientConsensusState mocks base method. -func (m *MockClientKeeper) GetLatestClientConsensusState(ctx types.Context, clientID string) (exported.ConsensusState, bool) { +func (m *MockClientKeeper) GetLatestClientConsensusState(ctx types0.Context, clientID string) (exported.ConsensusState, bool) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetLatestClientConsensusState", ctx, clientID) ret0, _ := ret[0].(exported.ConsensusState) @@ -724,7 +758,7 @@ func (mr *MockClientKeeperMockRecorder) GetLatestClientConsensusState(ctx, clien } // GetSelfConsensusState mocks base method. -func (m *MockClientKeeper) GetSelfConsensusState(ctx types.Context, height exported.Height) (exported.ConsensusState, error) { +func (m *MockClientKeeper) GetSelfConsensusState(ctx types0.Context, height exported.Height) (exported.ConsensusState, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetSelfConsensusState", ctx, height) ret0, _ := ret[0].(exported.ConsensusState) @@ -762,7 +796,7 @@ func (m *MockDistributionKeeper) EXPECT() *MockDistributionKeeperMockRecorder { } // FundCommunityPool mocks base method. -func (m *MockDistributionKeeper) FundCommunityPool(ctx types.Context, amount types.Coins, sender types.AccAddress) error { +func (m *MockDistributionKeeper) FundCommunityPool(ctx types0.Context, amount types0.Coins, sender types0.AccAddress) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "FundCommunityPool", ctx, amount, sender) ret0, _ := ret[0].(error) @@ -799,15 +833,17 @@ func (m *MockConsumerHooks) EXPECT() *MockConsumerHooksMockRecorder { } // AfterValidatorBonded mocks base method. -func (m *MockConsumerHooks) AfterValidatorBonded(ctx types.Context, consAddr types.ConsAddress, arg2 types.ValAddress) { +func (m *MockConsumerHooks) AfterValidatorBonded(ctx types0.Context, consAddr types0.ConsAddress, valAddresses types0.ValAddress) error { m.ctrl.T.Helper() - m.ctrl.Call(m, "AfterValidatorBonded", ctx, consAddr, arg2) + ret := m.ctrl.Call(m, "AfterValidatorBonded", ctx, consAddr, valAddresses) + ret0, _ := ret[0].(error) + return ret0 } // AfterValidatorBonded indicates an expected call of AfterValidatorBonded. -func (mr *MockConsumerHooksMockRecorder) AfterValidatorBonded(ctx, consAddr, arg2 interface{}) *gomock.Call { +func (mr *MockConsumerHooksMockRecorder) AfterValidatorBonded(ctx, consAddr, valAddresses interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AfterValidatorBonded", reflect.TypeOf((*MockConsumerHooks)(nil).AfterValidatorBonded), ctx, consAddr, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AfterValidatorBonded", reflect.TypeOf((*MockConsumerHooks)(nil).AfterValidatorBonded), ctx, consAddr, valAddresses) } // MockBankKeeper is a mock of BankKeeper interface. @@ -834,10 +870,10 @@ func (m *MockBankKeeper) EXPECT() *MockBankKeeperMockRecorder { } // GetAllBalances mocks base method. -func (m *MockBankKeeper) GetAllBalances(ctx types.Context, addr types.AccAddress) types.Coins { +func (m *MockBankKeeper) GetAllBalances(ctx types0.Context, addr types0.AccAddress) types0.Coins { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetAllBalances", ctx, addr) - ret0, _ := ret[0].(types.Coins) + ret0, _ := ret[0].(types0.Coins) return ret0 } @@ -848,10 +884,10 @@ func (mr *MockBankKeeperMockRecorder) GetAllBalances(ctx, addr interface{}) *gom } // GetBalance mocks base method. -func (m *MockBankKeeper) GetBalance(ctx types.Context, addr types.AccAddress, denom string) types.Coin { +func (m *MockBankKeeper) GetBalance(ctx types0.Context, addr types0.AccAddress, denom string) types0.Coin { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetBalance", ctx, addr, denom) - ret0, _ := ret[0].(types.Coin) + ret0, _ := ret[0].(types0.Coin) return ret0 } @@ -862,7 +898,7 @@ func (mr *MockBankKeeperMockRecorder) GetBalance(ctx, addr, denom interface{}) * } // SendCoinsFromModuleToModule mocks base method. -func (m *MockBankKeeper) SendCoinsFromModuleToModule(ctx types.Context, senderModule, recipientModule string, amt types.Coins) error { +func (m *MockBankKeeper) SendCoinsFromModuleToModule(ctx types0.Context, senderModule, recipientModule string, amt types0.Coins) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SendCoinsFromModuleToModule", ctx, senderModule, recipientModule, amt) ret0, _ := ret[0].(error) @@ -899,10 +935,10 @@ func (m *MockAccountKeeper) EXPECT() *MockAccountKeeperMockRecorder { } // GetModuleAccount mocks base method. -func (m *MockAccountKeeper) GetModuleAccount(ctx types.Context, name string) types0.ModuleAccountI { +func (m *MockAccountKeeper) GetModuleAccount(ctx types0.Context, name string) types1.ModuleAccountI { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetModuleAccount", ctx, name) - ret0, _ := ret[0].(types0.ModuleAccountI) + ret0, _ := ret[0].(types1.ModuleAccountI) return ret0 } @@ -935,18 +971,19 @@ func (m *MockIBCTransferKeeper) EXPECT() *MockIBCTransferKeeperMockRecorder { return m.recorder } -// SendTransfer mocks base method. -func (m *MockIBCTransferKeeper) SendTransfer(ctx types.Context, sourcePort, sourceChannel string, token types.Coin, sender types.AccAddress, receiver string, timeoutHeight types5.Height, timeoutTimestamp uint64) error { +// Transfer mocks base method. +func (m *MockIBCTransferKeeper) Transfer(arg0 context.Context, arg1 *types6.MsgTransfer) (*types6.MsgTransferResponse, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SendTransfer", ctx, sourcePort, sourceChannel, token, sender, receiver, timeoutHeight, timeoutTimestamp) - ret0, _ := ret[0].(error) - return ret0 + ret := m.ctrl.Call(m, "Transfer", arg0, arg1) + ret0, _ := ret[0].(*types6.MsgTransferResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 } -// SendTransfer indicates an expected call of SendTransfer. -func (mr *MockIBCTransferKeeperMockRecorder) SendTransfer(ctx, sourcePort, sourceChannel, token, sender, receiver, timeoutHeight, timeoutTimestamp interface{}) *gomock.Call { +// Transfer indicates an expected call of Transfer. +func (mr *MockIBCTransferKeeperMockRecorder) Transfer(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendTransfer", reflect.TypeOf((*MockIBCTransferKeeper)(nil).SendTransfer), ctx, sourcePort, sourceChannel, token, sender, receiver, timeoutHeight, timeoutTimestamp) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Transfer", reflect.TypeOf((*MockIBCTransferKeeper)(nil).Transfer), arg0, arg1) } // MockIBCCoreKeeper is a mock of IBCCoreKeeper interface. @@ -973,10 +1010,10 @@ func (m *MockIBCCoreKeeper) EXPECT() *MockIBCCoreKeeperMockRecorder { } // ChannelOpenInit mocks base method. -func (m *MockIBCCoreKeeper) ChannelOpenInit(goCtx context.Context, msg *types7.MsgChannelOpenInit) (*types7.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].(*types7.MsgChannelOpenInitResponse) + ret0, _ := ret[0].(*types9.MsgChannelOpenInitResponse) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -1011,7 +1048,7 @@ func (m *MockScopedKeeper) EXPECT() *MockScopedKeeperMockRecorder { } // AuthenticateCapability mocks base method. -func (m *MockScopedKeeper) AuthenticateCapability(ctx types.Context, cap *types1.Capability, name string) bool { +func (m *MockScopedKeeper) AuthenticateCapability(ctx types0.Context, cap *types2.Capability, name string) bool { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "AuthenticateCapability", ctx, cap, name) ret0, _ := ret[0].(bool) @@ -1025,7 +1062,7 @@ func (mr *MockScopedKeeperMockRecorder) AuthenticateCapability(ctx, cap, name in } // ClaimCapability mocks base method. -func (m *MockScopedKeeper) ClaimCapability(ctx types.Context, cap *types1.Capability, name string) error { +func (m *MockScopedKeeper) ClaimCapability(ctx types0.Context, cap *types2.Capability, name string) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ClaimCapability", ctx, cap, name) ret0, _ := ret[0].(error) @@ -1039,10 +1076,10 @@ func (mr *MockScopedKeeperMockRecorder) ClaimCapability(ctx, cap, name interface } // GetCapability mocks base method. -func (m *MockScopedKeeper) GetCapability(ctx types.Context, name string) (*types1.Capability, bool) { +func (m *MockScopedKeeper) GetCapability(ctx types0.Context, name string) (*types2.Capability, bool) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetCapability", ctx, name) - ret0, _ := ret[0].(*types1.Capability) + ret0, _ := ret[0].(*types2.Capability) ret1, _ := ret[1].(bool) return ret0, ret1 } diff --git a/testutil/keeper/unit_test_helpers.go b/testutil/keeper/unit_test_helpers.go index 77a597c726..d13ab17a63 100644 --- a/testutil/keeper/unit_test_helpers.go +++ b/testutil/keeper/unit_test_helpers.go @@ -6,9 +6,12 @@ import ( "testing" "time" + abci "github.com/cometbft/cometbft/abci/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - abci "github.com/tendermint/tendermint/abci/types" + tmdb "github.com/cometbft/cometbft-db" + "github.com/cometbft/cometbft/libs/log" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/store" @@ -23,15 +26,12 @@ import ( "github.com/cosmos/interchain-security/v2/x/ccv/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/libs/log" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - tmdb "github.com/tendermint/tm-db" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" ) // Parameters needed to instantiate an in-memory keeper @@ -50,8 +50,8 @@ func NewInMemKeeperParams(tb testing.TB) InMemKeeperParams { db := tmdb.NewMemDB() stateStore := store.NewCommitMultiStore(db) - stateStore.MountStoreWithDB(storeKey, sdk.StoreTypeIAVL, db) - stateStore.MountStoreWithDB(memStoreKey, sdk.StoreTypeMemory, nil) + stateStore.MountStoreWithDB(storeKey, storetypes.StoreTypeIAVL, db) + stateStore.MountStoreWithDB(memStoreKey, storetypes.StoreTypeMemory, nil) require.NoError(tb, stateStore.LoadLatestVersion()) registry := codectypes.NewInterfaceRegistry() @@ -195,7 +195,7 @@ func GetNewSlashPacketData() types.SlashPacketData { Power: int64(binary.BigEndian.Uint64(b1)), }, ValsetUpdateId: binary.BigEndian.Uint64(b2), - Infraction: stakingtypes.InfractionType(binary.BigEndian.Uint64(b2) % 3), + Infraction: stakingtypes.Infraction(binary.BigEndian.Uint64(b2) % 3), } } diff --git a/testutil/simibc/chain_util.go b/testutil/simibc/chain_util.go index 144fca7bf0..50015834e3 100644 --- a/testutil/simibc/chain_util.go +++ b/testutil/simibc/chain_util.go @@ -3,12 +3,12 @@ package simibc import ( "time" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" - ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + abci "github.com/cometbft/cometbft/abci/types" + tmproto "github.com/cometbft/cometbft/proto/tendermint/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" ibctestingcore "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/core" ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" - abci "github.com/tendermint/tendermint/abci/types" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" ) // BeginBlock updates the current header and calls the app.BeginBlock method. diff --git a/testutil/simibc/ordered_outbox.go b/testutil/simibc/ordered_outbox.go index a408b0b9cc..3c969d2a32 100644 --- a/testutil/simibc/ordered_outbox.go +++ b/testutil/simibc/ordered_outbox.go @@ -1,6 +1,6 @@ package simibc -import channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" +import channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" // Ack represents a (sent) ack committed to block state type Ack struct { diff --git a/testutil/simibc/relay_util.go b/testutil/simibc/relay_util.go index 761b1b5512..48e127aa60 100644 --- a/testutil/simibc/relay_util.go +++ b/testutil/simibc/relay_util.go @@ -2,15 +2,15 @@ package simibc import ( errorsmod "cosmossdk.io/errors" + tmtypes "github.com/cometbft/cometbft/types" sdk "github.com/cosmos/cosmos-sdk/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v4/modules/core/24-host" - ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/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" + host "github.com/cosmos/ibc-go/v7/modules/core/24-host" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" simapp "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/simapp" ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" "github.com/stretchr/testify/require" - tmtypes "github.com/tendermint/tendermint/types" ) // UpdateReceiverClient DELIVERs a header to the receiving endpoint diff --git a/testutil/simibc/relayed_path.go b/testutil/simibc/relayed_path.go index d13303009a..b5339b2923 100644 --- a/testutil/simibc/relayed_path.go +++ b/testutil/simibc/relayed_path.go @@ -4,7 +4,7 @@ import ( "testing" "time" - ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" ) diff --git a/third_party/gogoproto/gogo.proto b/third_party/gogoproto/gogo.proto deleted file mode 100644 index 49e78f99fe..0000000000 --- a/third_party/gogoproto/gogo.proto +++ /dev/null @@ -1,145 +0,0 @@ -// Protocol Buffers for Go with Gadgets -// -// Copyright (c) 2013, The GoGo Authors. All rights reserved. -// http://github.com/gogo/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto2"; -package gogoproto; - -import "google/protobuf/descriptor.proto"; - -option java_package = "com.google.protobuf"; -option java_outer_classname = "GoGoProtos"; -option go_package = "github.com/gogo/protobuf/gogoproto"; - -extend google.protobuf.EnumOptions { - optional bool goproto_enum_prefix = 62001; - optional bool goproto_enum_stringer = 62021; - optional bool enum_stringer = 62022; - optional string enum_customname = 62023; - optional bool enumdecl = 62024; -} - -extend google.protobuf.EnumValueOptions { - optional string enumvalue_customname = 66001; -} - -extend google.protobuf.FileOptions { - optional bool goproto_getters_all = 63001; - optional bool goproto_enum_prefix_all = 63002; - optional bool goproto_stringer_all = 63003; - optional bool verbose_equal_all = 63004; - optional bool face_all = 63005; - optional bool gostring_all = 63006; - optional bool populate_all = 63007; - optional bool stringer_all = 63008; - optional bool onlyone_all = 63009; - - optional bool equal_all = 63013; - optional bool description_all = 63014; - optional bool testgen_all = 63015; - optional bool benchgen_all = 63016; - optional bool marshaler_all = 63017; - optional bool unmarshaler_all = 63018; - optional bool stable_marshaler_all = 63019; - - optional bool sizer_all = 63020; - - optional bool goproto_enum_stringer_all = 63021; - optional bool enum_stringer_all = 63022; - - optional bool unsafe_marshaler_all = 63023; - optional bool unsafe_unmarshaler_all = 63024; - - optional bool goproto_extensions_map_all = 63025; - optional bool goproto_unrecognized_all = 63026; - optional bool gogoproto_import = 63027; - optional bool protosizer_all = 63028; - optional bool compare_all = 63029; - optional bool typedecl_all = 63030; - optional bool enumdecl_all = 63031; - - optional bool goproto_registration = 63032; - optional bool messagename_all = 63033; - - optional bool goproto_sizecache_all = 63034; - optional bool goproto_unkeyed_all = 63035; -} - -extend google.protobuf.MessageOptions { - optional bool goproto_getters = 64001; - optional bool goproto_stringer = 64003; - optional bool verbose_equal = 64004; - optional bool face = 64005; - optional bool gostring = 64006; - optional bool populate = 64007; - optional bool stringer = 67008; - optional bool onlyone = 64009; - - optional bool equal = 64013; - optional bool description = 64014; - optional bool testgen = 64015; - optional bool benchgen = 64016; - optional bool marshaler = 64017; - optional bool unmarshaler = 64018; - optional bool stable_marshaler = 64019; - - optional bool sizer = 64020; - - optional bool unsafe_marshaler = 64023; - optional bool unsafe_unmarshaler = 64024; - - optional bool goproto_extensions_map = 64025; - optional bool goproto_unrecognized = 64026; - - optional bool protosizer = 64028; - optional bool compare = 64029; - - optional bool typedecl = 64030; - - optional bool messagename = 64033; - - optional bool goproto_sizecache = 64034; - optional bool goproto_unkeyed = 64035; -} - -extend google.protobuf.FieldOptions { - optional bool nullable = 65001; - optional bool embed = 65002; - optional string customtype = 65003; - optional string customname = 65004; - optional string jsontag = 65005; - optional string moretags = 65006; - optional string casttype = 65007; - optional string castkey = 65008; - optional string castvalue = 65009; - - optional bool stdtime = 65010; - optional bool stdduration = 65011; - optional bool wktpointer = 65012; - - optional string castrepeated = 65013; -} diff --git a/third_party/google/api/annotations.proto b/third_party/google/api/annotations.proto deleted file mode 100644 index 85c361b47f..0000000000 --- a/third_party/google/api/annotations.proto +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2015, Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -package google.api; - -import "google/api/http.proto"; -import "google/protobuf/descriptor.proto"; - -option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; -option java_multiple_files = true; -option java_outer_classname = "AnnotationsProto"; -option java_package = "com.google.api"; -option objc_class_prefix = "GAPI"; - -extend google.protobuf.MethodOptions { - // See `HttpRule`. - HttpRule http = 72295728; -} diff --git a/third_party/google/api/http.proto b/third_party/google/api/http.proto deleted file mode 100644 index 2bd3a19bfa..0000000000 --- a/third_party/google/api/http.proto +++ /dev/null @@ -1,318 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -package google.api; - -option cc_enable_arenas = true; -option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; -option java_multiple_files = true; -option java_outer_classname = "HttpProto"; -option java_package = "com.google.api"; -option objc_class_prefix = "GAPI"; - - -// Defines the HTTP configuration for an API service. It contains a list of -// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method -// to one or more HTTP REST API methods. -message Http { - // A list of HTTP configuration rules that apply to individual API methods. - // - // **NOTE:** All service configuration rules follow "last one wins" order. - repeated HttpRule rules = 1; - - // When set to true, URL path parmeters will be fully URI-decoded except in - // cases of single segment matches in reserved expansion, where "%2F" will be - // left encoded. - // - // The default behavior is to not decode RFC 6570 reserved characters in multi - // segment matches. - bool fully_decode_reserved_expansion = 2; -} - -// `HttpRule` defines the mapping of an RPC method to one or more HTTP -// REST API methods. The mapping specifies how different portions of the RPC -// request message are mapped to URL path, URL query parameters, and -// HTTP request body. The mapping is typically specified as an -// `google.api.http` annotation on the RPC method, -// see "google/api/annotations.proto" for details. -// -// The mapping consists of a field specifying the path template and -// method kind. The path template can refer to fields in the request -// message, as in the example below which describes a REST GET -// operation on a resource collection of messages: -// -// -// service Messaging { -// rpc GetMessage(GetMessageRequest) returns (Message) { -// option (google.api.http).get = "/v1/messages/{message_id}/{sub.subfield}"; -// } -// } -// message GetMessageRequest { -// message SubMessage { -// string subfield = 1; -// } -// string message_id = 1; // mapped to the URL -// SubMessage sub = 2; // `sub.subfield` is url-mapped -// } -// message Message { -// string text = 1; // content of the resource -// } -// -// The same http annotation can alternatively be expressed inside the -// `GRPC API Configuration` YAML file. -// -// http: -// rules: -// - selector: .Messaging.GetMessage -// get: /v1/messages/{message_id}/{sub.subfield} -// -// This definition enables an automatic, bidrectional mapping of HTTP -// JSON to RPC. Example: -// -// HTTP | RPC -// -----|----- -// `GET /v1/messages/123456/foo` | `GetMessage(message_id: "123456" sub: SubMessage(subfield: "foo"))` -// -// In general, not only fields but also field paths can be referenced -// from a path pattern. Fields mapped to the path pattern cannot be -// repeated and must have a primitive (non-message) type. -// -// Any fields in the request message which are not bound by the path -// pattern automatically become (optional) HTTP query -// parameters. Assume the following definition of the request message: -// -// -// service Messaging { -// rpc GetMessage(GetMessageRequest) returns (Message) { -// option (google.api.http).get = "/v1/messages/{message_id}"; -// } -// } -// message GetMessageRequest { -// message SubMessage { -// string subfield = 1; -// } -// string message_id = 1; // mapped to the URL -// int64 revision = 2; // becomes a parameter -// SubMessage sub = 3; // `sub.subfield` becomes a parameter -// } -// -// -// This enables a HTTP JSON to RPC mapping as below: -// -// HTTP | RPC -// -----|----- -// `GET /v1/messages/123456?revision=2&sub.subfield=foo` | `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: "foo"))` -// -// Note that fields which are mapped to HTTP parameters must have a -// primitive type or a repeated primitive type. Message types are not -// allowed. In the case of a repeated type, the parameter can be -// repeated in the URL, as in `...?param=A¶m=B`. -// -// For HTTP method kinds which allow a request body, the `body` field -// specifies the mapping. Consider a REST update method on the -// message resource collection: -// -// -// service Messaging { -// rpc UpdateMessage(UpdateMessageRequest) returns (Message) { -// option (google.api.http) = { -// put: "/v1/messages/{message_id}" -// body: "message" -// }; -// } -// } -// message UpdateMessageRequest { -// string message_id = 1; // mapped to the URL -// Message message = 2; // mapped to the body -// } -// -// -// The following HTTP JSON to RPC mapping is enabled, where the -// representation of the JSON in the request body is determined by -// protos JSON encoding: -// -// HTTP | RPC -// -----|----- -// `PUT /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: "123456" message { text: "Hi!" })` -// -// The special name `*` can be used in the body mapping to define that -// every field not bound by the path template should be mapped to the -// request body. This enables the following alternative definition of -// the update method: -// -// service Messaging { -// rpc UpdateMessage(Message) returns (Message) { -// option (google.api.http) = { -// put: "/v1/messages/{message_id}" -// body: "*" -// }; -// } -// } -// message Message { -// string message_id = 1; -// string text = 2; -// } -// -// -// The following HTTP JSON to RPC mapping is enabled: -// -// HTTP | RPC -// -----|----- -// `PUT /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: "123456" text: "Hi!")` -// -// Note that when using `*` in the body mapping, it is not possible to -// have HTTP parameters, as all fields not bound by the path end in -// the body. This makes this option more rarely used in practice of -// defining REST APIs. The common usage of `*` is in custom methods -// which don't use the URL at all for transferring data. -// -// It is possible to define multiple HTTP methods for one RPC by using -// the `additional_bindings` option. Example: -// -// service Messaging { -// rpc GetMessage(GetMessageRequest) returns (Message) { -// option (google.api.http) = { -// get: "/v1/messages/{message_id}" -// additional_bindings { -// get: "/v1/users/{user_id}/messages/{message_id}" -// } -// }; -// } -// } -// message GetMessageRequest { -// string message_id = 1; -// string user_id = 2; -// } -// -// -// This enables the following two alternative HTTP JSON to RPC -// mappings: -// -// HTTP | RPC -// -----|----- -// `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` -// `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: "123456")` -// -// # Rules for HTTP mapping -// -// The rules for mapping HTTP path, query parameters, and body fields -// to the request message are as follows: -// -// 1. The `body` field specifies either `*` or a field path, or is -// omitted. If omitted, it indicates there is no HTTP request body. -// 2. Leaf fields (recursive expansion of nested messages in the -// request) can be classified into three types: -// (a) Matched in the URL template. -// (b) Covered by body (if body is `*`, everything except (a) fields; -// else everything under the body field) -// (c) All other fields. -// 3. URL query parameters found in the HTTP request are mapped to (c) fields. -// 4. Any body sent with an HTTP request can contain only (b) fields. -// -// The syntax of the path template is as follows: -// -// Template = "/" Segments [ Verb ] ; -// Segments = Segment { "/" Segment } ; -// Segment = "*" | "**" | LITERAL | Variable ; -// Variable = "{" FieldPath [ "=" Segments ] "}" ; -// FieldPath = IDENT { "." IDENT } ; -// Verb = ":" LITERAL ; -// -// The syntax `*` matches a single path segment. The syntax `**` matches zero -// or more path segments, which must be the last part of the path except the -// `Verb`. The syntax `LITERAL` matches literal text in the path. -// -// The syntax `Variable` matches part of the URL path as specified by its -// template. A variable template must not contain other variables. If a variable -// matches a single path segment, its template may be omitted, e.g. `{var}` -// is equivalent to `{var=*}`. -// -// If a variable contains exactly one path segment, such as `"{var}"` or -// `"{var=*}"`, when such a variable is expanded into a URL path, all characters -// except `[-_.~0-9a-zA-Z]` are percent-encoded. Such variables show up in the -// Discovery Document as `{var}`. -// -// If a variable contains one or more path segments, such as `"{var=foo/*}"` -// or `"{var=**}"`, when such a variable is expanded into a URL path, all -// characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. Such variables -// show up in the Discovery Document as `{+var}`. -// -// NOTE: While the single segment variable matches the semantics of -// [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 -// Simple String Expansion, the multi segment variable **does not** match -// RFC 6570 Reserved Expansion. The reason is that the Reserved Expansion -// does not expand special characters like `?` and `#`, which would lead -// to invalid URLs. -// -// NOTE: the field paths in variables and in the `body` must not refer to -// repeated fields or map fields. -message HttpRule { - // Selects methods to which this rule applies. - // - // Refer to [selector][google.api.DocumentationRule.selector] for syntax details. - string selector = 1; - - // Determines the URL pattern is matched by this rules. This pattern can be - // used with any of the {get|put|post|delete|patch} methods. A custom method - // can be defined using the 'custom' field. - oneof pattern { - // Used for listing and getting information about resources. - string get = 2; - - // Used for updating a resource. - string put = 3; - - // Used for creating a resource. - string post = 4; - - // Used for deleting a resource. - string delete = 5; - - // Used for updating a resource. - string patch = 6; - - // The custom pattern is used for specifying an HTTP method that is not - // included in the `pattern` field, such as HEAD, or "*" to leave the - // HTTP method unspecified for this rule. The wild-card rule is useful - // for services that provide content to Web (HTML) clients. - CustomHttpPattern custom = 8; - } - - // The name of the request field whose value is mapped to the HTTP body, or - // `*` for mapping all fields not captured by the path pattern to the HTTP - // body. NOTE: the referred field must not be a repeated field and must be - // present at the top-level of request message type. - string body = 7; - - // Optional. The name of the response field whose value is mapped to the HTTP - // body of response. Other response fields are ignored. When - // not set, the response message will be used as HTTP body of response. - string response_body = 12; - - // Additional HTTP bindings for the selector. Nested bindings must - // not contain an `additional_bindings` field themselves (that is, - // the nesting may only be one level deep). - repeated HttpRule additional_bindings = 11; -} - -// A custom pattern is used for defining custom HTTP verb. -message CustomHttpPattern { - // The name of this custom HTTP verb. - string kind = 1; - - // The path matched by this custom verb. - string path = 2; -} diff --git a/third_party/google/api/httpbody.proto b/third_party/google/api/httpbody.proto deleted file mode 100644 index 4428515c12..0000000000 --- a/third_party/google/api/httpbody.proto +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2018 Google LLC. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -syntax = "proto3"; - -package google.api; - -import "google/protobuf/any.proto"; - -option cc_enable_arenas = true; -option go_package = "google.golang.org/genproto/googleapis/api/httpbody;httpbody"; -option java_multiple_files = true; -option java_outer_classname = "HttpBodyProto"; -option java_package = "com.google.api"; -option objc_class_prefix = "GAPI"; - -// Message that represents an arbitrary HTTP body. It should only be used for -// payload formats that can't be represented as JSON, such as raw binary or -// an HTML page. -// -// -// This message can be used both in streaming and non-streaming API methods in -// the request as well as the response. -// -// It can be used as a top-level request field, which is convenient if one -// wants to extract parameters from either the URL or HTTP template into the -// request fields and also want access to the raw HTTP body. -// -// Example: -// -// message GetResourceRequest { -// // A unique request id. -// string request_id = 1; -// -// // The raw HTTP body is bound to this field. -// google.api.HttpBody http_body = 2; -// } -// -// service ResourceService { -// rpc GetResource(GetResourceRequest) returns (google.api.HttpBody); -// rpc UpdateResource(google.api.HttpBody) returns -// (google.protobuf.Empty); -// } -// -// Example with streaming methods: -// -// service CaldavService { -// rpc GetCalendar(stream google.api.HttpBody) -// returns (stream google.api.HttpBody); -// rpc UpdateCalendar(stream google.api.HttpBody) -// returns (stream google.api.HttpBody); -// } -// -// Use of this type only changes how the request and response bodies are -// handled, all other features will continue to work unchanged. -message HttpBody { - // The HTTP Content-Type header value specifying the content type of the body. - string content_type = 1; - - // The HTTP request/response body as raw binary. - bytes data = 2; - - // Application specific response metadata. Must be set in the first response - // for streaming APIs. - repeated google.protobuf.Any extensions = 3; -} \ No newline at end of file diff --git a/third_party/google/protobuf/any.proto b/third_party/google/protobuf/any.proto deleted file mode 100644 index 58b511583a..0000000000 --- a/third_party/google/protobuf/any.proto +++ /dev/null @@ -1,164 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -import "gogoproto/gogo.proto"; - -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; -option go_package = "types"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "AnyProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; - -// `Any` contains an arbitrary serialized protocol buffer message along with a -// URL that describes the type of the serialized message. -// -// Protobuf library provides support to pack/unpack Any values in the form -// of utility functions or additional generated methods of the Any type. -// -// Example 1: Pack and unpack a message in C++. -// -// Foo foo = ...; -// Any any; -// any.PackFrom(foo); -// ... -// if (any.UnpackTo(&foo)) { -// ... -// } -// -// Example 2: Pack and unpack a message in Java. -// -// Foo foo = ...; -// Any any = Any.pack(foo); -// ... -// if (any.is(Foo.class)) { -// foo = any.unpack(Foo.class); -// } -// -// Example 3: Pack and unpack a message in Python. -// -// foo = Foo(...) -// any = Any() -// any.Pack(foo) -// ... -// if any.Is(Foo.DESCRIPTOR): -// any.Unpack(foo) -// ... -// -// Example 4: Pack and unpack a message in Go -// -// foo := &pb.Foo{...} -// any, err := ptypes.MarshalAny(foo) -// ... -// foo := &pb.Foo{} -// if err := ptypes.UnmarshalAny(any, foo); err != nil { -// ... -// } -// -// The pack methods provided by protobuf library will by default use -// 'type.googleapis.com/full.type.name' as the type URL and the unpack -// methods only use the fully qualified type name after the last '/' -// in the type URL, for example "foo.bar.com/x/y.z" will yield type -// name "y.z". -// -// -// JSON -// ==== -// The JSON representation of an `Any` value uses the regular -// representation of the deserialized, embedded message, with an -// additional field `@type` which contains the type URL. Example: -// -// package google.profile; -// message Person { -// string first_name = 1; -// string last_name = 2; -// } -// -// { -// "@type": "type.googleapis.com/google.profile.Person", -// "firstName": , -// "lastName": -// } -// -// If the embedded message type is well-known and has a custom JSON -// representation, that representation will be embedded adding a field -// `value` which holds the custom JSON in addition to the `@type` -// field. Example (for message [google.protobuf.Duration][]): -// -// { -// "@type": "type.googleapis.com/google.protobuf.Duration", -// "value": "1.212s" -// } -// -message Any { - // A URL/resource name that uniquely identifies the type of the serialized - // protocol buffer message. This string must contain at least - // one "/" character. The last segment of the URL's path must represent - // the fully qualified name of the type (as in - // `path/google.protobuf.Duration`). The name should be in a canonical form - // (e.g., leading "." is not accepted). - // - // In practice, teams usually precompile into the binary all types that they - // expect it to use in the context of Any. However, for URLs which use the - // scheme `http`, `https`, or no scheme, one can optionally set up a type - // server that maps type URLs to message definitions as follows: - // - // * If no scheme is provided, `https` is assumed. - // * An HTTP GET on the URL must yield a [google.protobuf.Type][] - // value in binary format, or produce an error. - // * Applications are allowed to cache lookup results based on the - // URL, or have them precompiled into a binary to avoid any - // lookup. Therefore, binary compatibility needs to be preserved - // on changes to types. (Use versioned type names to manage - // breaking changes.) - // - // Note: this functionality is not currently available in the official - // protobuf release, and it is not used for type URLs beginning with - // type.googleapis.com. - // - // Schemes other than `http`, `https` (or the empty scheme) might be - // used with implementation specific semantics. - // - string type_url = 1; - - // Must be a valid serialized protocol buffer of the above specified type. - bytes value = 2; - - option (gogoproto.typedecl) = false; - option (gogoproto.goproto_stringer) = false; - option (gogoproto.gostring) = false; - option (gogoproto.stringer) = false; -} - -option (gogoproto.goproto_registration) = false; diff --git a/third_party/proto/buf.lock b/third_party/proto/buf.lock deleted file mode 100644 index dff37ae0ae..0000000000 --- a/third_party/proto/buf.lock +++ /dev/null @@ -1,10 +0,0 @@ -# Generated by buf. DO NOT EDIT. -version: v1 -deps: - - remote: buf.build - owner: cosmos - repository: gogo-proto - branch: main - commit: bee5511075b7499da6178d9e4aaa628b - digest: b1-rrBIustouD-S80cVoZ_rM0qJsmei9AgbXy9GPQu6vxg= - create_time: 2021-12-02T20:01:17.069307Z diff --git a/third_party/proto/buf.yaml b/third_party/proto/buf.yaml deleted file mode 100644 index 2aad5fd692..0000000000 --- a/third_party/proto/buf.yaml +++ /dev/null @@ -1,37 +0,0 @@ -# Generated by "buf config migrate-v1beta1". Edit as necessary, and -# remove this comment when you're finished. -# -# This module represents the "third_party/proto" root found in -# the previous configuration. -version: v1 -deps: - - buf.build/cosmos/gogo-proto -build: - excludes: - - google/protobuf -breaking: - use: - - FILE - ignore: - - confio - - cosmos_proto - - gogoproto - - google - - tendermint -lint: - use: - - DEFAULT - - COMMENTS - - FILE_LOWER_SNAKE_CASE - except: - - UNARY_RPC - - COMMENT_FIELD - - SERVICE_SUFFIX - - PACKAGE_VERSION_SUFFIX - - RPC_REQUEST_STANDARD_NAME - ignore: - - confio - - cosmos_proto - - gogoproto - - google - - tendermint diff --git a/third_party/proto/confio/proofs.proto b/third_party/proto/confio/proofs.proto deleted file mode 100644 index a1397dff5f..0000000000 --- a/third_party/proto/confio/proofs.proto +++ /dev/null @@ -1,235 +0,0 @@ -syntax = "proto3"; - -package ics23; -option go_package = "github.com/confio/ics23/go"; - -enum HashOp { - // NO_HASH is the default if no data passed. Note this is an illegal argument some places. - NO_HASH = 0; - SHA256 = 1; - SHA512 = 2; - KECCAK = 3; - RIPEMD160 = 4; - BITCOIN = 5; // ripemd160(sha256(x)) - SHA512_256 = 6; -} - -/** -LengthOp defines how to process the key and value of the LeafOp -to include length information. After encoding the length with the given -algorithm, the length will be prepended to the key and value bytes. -(Each one with it's own encoded length) -*/ -enum LengthOp { - // NO_PREFIX don't include any length info - NO_PREFIX = 0; - // VAR_PROTO uses protobuf (and go-amino) varint encoding of the length - VAR_PROTO = 1; - // VAR_RLP uses rlp int encoding of the length - VAR_RLP = 2; - // FIXED32_BIG uses big-endian encoding of the length as a 32 bit integer - FIXED32_BIG = 3; - // FIXED32_LITTLE uses little-endian encoding of the length as a 32 bit integer - FIXED32_LITTLE = 4; - // FIXED64_BIG uses big-endian encoding of the length as a 64 bit integer - FIXED64_BIG = 5; - // FIXED64_LITTLE uses little-endian encoding of the length as a 64 bit integer - FIXED64_LITTLE = 6; - // REQUIRE_32_BYTES is like NONE, but will fail if the input is not exactly 32 bytes (sha256 output) - REQUIRE_32_BYTES = 7; - // REQUIRE_64_BYTES is like NONE, but will fail if the input is not exactly 64 bytes (sha512 output) - REQUIRE_64_BYTES = 8; -} - -/** -ExistenceProof takes a key and a value and a set of steps to perform on it. -The result of peforming all these steps will provide a "root hash", which can -be compared to the value in a header. - -Since it is computationally infeasible to produce a hash collission for any of the used -cryptographic hash functions, if someone can provide a series of operations to transform -a given key and value into a root hash that matches some trusted root, these key and values -must be in the referenced merkle tree. - -The only possible issue is maliablity in LeafOp, such as providing extra prefix data, -which should be controlled by a spec. Eg. with lengthOp as NONE, - prefix = FOO, key = BAR, value = CHOICE -and - prefix = F, key = OOBAR, value = CHOICE -would produce the same value. - -With LengthOp this is tricker but not impossible. Which is why the "leafPrefixEqual" field -in the ProofSpec is valuable to prevent this mutability. And why all trees should -length-prefix the data before hashing it. -*/ -message ExistenceProof { - bytes key = 1; - bytes value = 2; - LeafOp leaf = 3; - repeated InnerOp path = 4; -} - -/* -NonExistenceProof takes a proof of two neighbors, one left of the desired key, -one right of the desired key. If both proofs are valid AND they are neighbors, -then there is no valid proof for the given key. -*/ -message NonExistenceProof { - bytes key = 1; // TODO: remove this as unnecessary??? we prove a range - ExistenceProof left = 2; - ExistenceProof right = 3; -} - -/* -CommitmentProof is either an ExistenceProof or a NonExistenceProof, or a Batch of such messages -*/ -message CommitmentProof { - oneof proof { - ExistenceProof exist = 1; - NonExistenceProof nonexist = 2; - BatchProof batch = 3; - CompressedBatchProof compressed = 4; - } -} - -/** -LeafOp represents the raw key-value data we wish to prove, and -must be flexible to represent the internal transformation from -the original key-value pairs into the basis hash, for many existing -merkle trees. - -key and value are passed in. So that the signature of this operation is: - leafOp(key, value) -> output - -To process this, first prehash the keys and values if needed (ANY means no hash in this case): - hkey = prehashKey(key) - hvalue = prehashValue(value) - -Then combine the bytes, and hash it - output = hash(prefix || length(hkey) || hkey || length(hvalue) || hvalue) -*/ -message LeafOp { - HashOp hash = 1; - HashOp prehash_key = 2; - HashOp prehash_value = 3; - LengthOp length = 4; - // prefix is a fixed bytes that may optionally be included at the beginning to differentiate - // a leaf node from an inner node. - bytes prefix = 5; -} - -/** -InnerOp represents a merkle-proof step that is not a leaf. -It represents concatenating two children and hashing them to provide the next result. - -The result of the previous step is passed in, so the signature of this op is: - innerOp(child) -> output - -The result of applying InnerOp should be: - output = op.hash(op.prefix || child || op.suffix) - - where the || operator is concatenation of binary data, -and child is the result of hashing all the tree below this step. - -Any special data, like prepending child with the length, or prepending the entire operation with -some value to differentiate from leaf nodes, should be included in prefix and suffix. -If either of prefix or suffix is empty, we just treat it as an empty string -*/ -message InnerOp { - HashOp hash = 1; - bytes prefix = 2; - bytes suffix = 3; -} - - -/** -ProofSpec defines what the expected parameters are for a given proof type. -This can be stored in the client and used to validate any incoming proofs. - - verify(ProofSpec, Proof) -> Proof | Error - -As demonstrated in tests, if we don't fix the algorithm used to calculate the -LeafHash for a given tree, there are many possible key-value pairs that can -generate a given hash (by interpretting the preimage differently). -We need this for proper security, requires client knows a priori what -tree format server uses. But not in code, rather a configuration object. -*/ -message ProofSpec { - // any field in the ExistenceProof must be the same as in this spec. - // except Prefix, which is just the first bytes of prefix (spec can be longer) - LeafOp leaf_spec = 1; - InnerSpec inner_spec = 2; - // max_depth (if > 0) is the maximum number of InnerOps allowed (mainly for fixed-depth tries) - int32 max_depth = 3; - // min_depth (if > 0) is the minimum number of InnerOps allowed (mainly for fixed-depth tries) - int32 min_depth = 4; -} - -/* -InnerSpec contains all store-specific structure info to determine if two proofs from a -given store are neighbors. - -This enables: - - isLeftMost(spec: InnerSpec, op: InnerOp) - isRightMost(spec: InnerSpec, op: InnerOp) - isLeftNeighbor(spec: InnerSpec, left: InnerOp, right: InnerOp) -*/ -message InnerSpec { - // Child order is the ordering of the children node, must count from 0 - // iavl tree is [0, 1] (left then right) - // merk is [0, 2, 1] (left, right, here) - repeated int32 child_order = 1; - int32 child_size = 2; - int32 min_prefix_length = 3; - int32 max_prefix_length = 4; - // empty child is the prehash image that is used when one child is nil (eg. 20 bytes of 0) - bytes empty_child = 5; - // hash is the algorithm that must be used for each InnerOp - HashOp hash = 6; -} - -/* -BatchProof is a group of multiple proof types than can be compressed -*/ -message BatchProof { - repeated BatchEntry entries = 1; -} - -// Use BatchEntry not CommitmentProof, to avoid recursion -message BatchEntry { - oneof proof { - ExistenceProof exist = 1; - NonExistenceProof nonexist = 2; - } -} - - -/****** all items here are compressed forms *******/ - -message CompressedBatchProof { - repeated CompressedBatchEntry entries = 1; - repeated InnerOp lookup_inners = 2; -} - -// Use BatchEntry not CommitmentProof, to avoid recursion -message CompressedBatchEntry { - oneof proof { - CompressedExistenceProof exist = 1; - CompressedNonExistenceProof nonexist = 2; - } -} - -message CompressedExistenceProof { - bytes key = 1; - bytes value = 2; - LeafOp leaf = 3; - // these are indexes into the lookup_inners table in CompressedBatchProof - repeated int32 path = 4; -} - -message CompressedNonExistenceProof { - bytes key = 1; // TODO: remove this as unnecessary??? we prove a range - CompressedExistenceProof left = 2; - CompressedExistenceProof right = 3; -} diff --git a/third_party/proto/cosmos/base/query/v1beta1/pagination.proto b/third_party/proto/cosmos/base/query/v1beta1/pagination.proto deleted file mode 100644 index cd5eb066d3..0000000000 --- a/third_party/proto/cosmos/base/query/v1beta1/pagination.proto +++ /dev/null @@ -1,55 +0,0 @@ -syntax = "proto3"; -package cosmos.base.query.v1beta1; - -option go_package = "github.com/cosmos/cosmos-sdk/types/query"; - -// PageRequest is to be embedded in gRPC request messages for efficient -// pagination. Ex: -// -// message SomeRequest { -// Foo some_parameter = 1; -// PageRequest pagination = 2; -// } -message PageRequest { - // key is a value returned in PageResponse.next_key to begin - // querying the next page most efficiently. Only one of offset or key - // should be set. - bytes key = 1; - - // offset is a numeric offset that can be used when key is unavailable. - // It is less efficient than using key. Only one of offset or key should - // be set. - uint64 offset = 2; - - // limit is the total number of results to be returned in the result page. - // If left empty it will default to a value to be set by each app. - uint64 limit = 3; - - // count_total is set to true to indicate that the result set should include - // a count of the total number of items available for pagination in UIs. - // count_total is only respected when offset is used. It is ignored when key - // is set. - bool count_total = 4; - - // reverse is set to true if results are to be returned in the descending order. - // - // Since: cosmos-sdk 0.43 - bool reverse = 5; -} - -// PageResponse is to be embedded in gRPC response messages where the -// corresponding request message has used PageRequest. -// -// message SomeResponse { -// repeated Bar results = 1; -// PageResponse page = 2; -// } -message PageResponse { - // next_key is the key to be passed to PageRequest.key to - // query the next page most efficiently - bytes next_key = 1; - - // total is total number of results available if PageRequest.count_total - // was set, its value is undefined otherwise - uint64 total = 2; -} diff --git a/third_party/proto/cosmos/base/v1beta1/coin.proto b/third_party/proto/cosmos/base/v1beta1/coin.proto deleted file mode 100644 index fab75284b7..0000000000 --- a/third_party/proto/cosmos/base/v1beta1/coin.proto +++ /dev/null @@ -1,40 +0,0 @@ -syntax = "proto3"; -package cosmos.base.v1beta1; - -import "gogoproto/gogo.proto"; - -option go_package = "github.com/cosmos/cosmos-sdk/types"; -option (gogoproto.goproto_stringer_all) = false; -option (gogoproto.stringer_all) = false; - -// Coin defines a token with a denomination and an amount. -// -// NOTE: The amount field is an Int which implements the custom method -// signatures required by gogoproto. -message Coin { - option (gogoproto.equal) = true; - - string denom = 1; - string amount = 2 [(gogoproto.customtype) = "Int", (gogoproto.nullable) = false]; -} - -// DecCoin defines a token with a denomination and a decimal amount. -// -// NOTE: The amount field is an Dec which implements the custom method -// signatures required by gogoproto. -message DecCoin { - option (gogoproto.equal) = true; - - string denom = 1; - string amount = 2 [(gogoproto.customtype) = "Dec", (gogoproto.nullable) = false]; -} - -// IntProto defines a Protobuf wrapper around an Int object. -message IntProto { - string int = 1 [(gogoproto.customtype) = "Int", (gogoproto.nullable) = false]; -} - -// DecProto defines a Protobuf wrapper around a Dec object. -message DecProto { - string dec = 1 [(gogoproto.customtype) = "Dec", (gogoproto.nullable) = false]; -} diff --git a/third_party/proto/cosmos/evidence/v1beta1/evidence.proto b/third_party/proto/cosmos/evidence/v1beta1/evidence.proto deleted file mode 100644 index 14612c314f..0000000000 --- a/third_party/proto/cosmos/evidence/v1beta1/evidence.proto +++ /dev/null @@ -1,21 +0,0 @@ -syntax = "proto3"; -package cosmos.evidence.v1beta1; - -option go_package = "github.com/cosmos/cosmos-sdk/x/evidence/types"; -option (gogoproto.equal_all) = true; - -import "gogoproto/gogo.proto"; -import "google/protobuf/timestamp.proto"; - -// Equivocation implements the Evidence interface and defines evidence of double -// signing misbehavior. -message Equivocation { - option (gogoproto.goproto_stringer) = false; - option (gogoproto.goproto_getters) = false; - option (gogoproto.equal) = false; - - int64 height = 1; - google.protobuf.Timestamp time = 2 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; - int64 power = 3; - string consensus_address = 4 [(gogoproto.moretags) = "yaml:\"consensus_address\""]; -} \ No newline at end of file diff --git a/third_party/proto/cosmos/staking/v1beta1/staking.proto b/third_party/proto/cosmos/staking/v1beta1/staking.proto deleted file mode 100644 index 27581a12cf..0000000000 --- a/third_party/proto/cosmos/staking/v1beta1/staking.proto +++ /dev/null @@ -1,370 +0,0 @@ -syntax = "proto3"; -package cosmos.staking.v1beta1; - -import "gogoproto/gogo.proto"; -import "google/protobuf/any.proto"; -import "google/protobuf/duration.proto"; -import "google/protobuf/timestamp.proto"; - -import "cosmos_proto/cosmos.proto"; -import "cosmos/base/v1beta1/coin.proto"; -import "tendermint/types/types.proto"; -import "tendermint/abci/types.proto"; - -option go_package = "github.com/cosmos/cosmos-sdk/x/staking/types"; - -// HistoricalInfo contains header and validator information for a given block. -// It is stored as part of staking module's state, which persists the `n` most -// recent HistoricalInfo -// (`n` is set by the staking module's `historical_entries` parameter). -message HistoricalInfo { - tendermint.types.Header header = 1 [(gogoproto.nullable) = false]; - repeated Validator valset = 2 [(gogoproto.nullable) = false]; -} - -// CommissionRates defines the initial commission rates to be used for creating -// a validator. -message CommissionRates { - option (gogoproto.equal) = true; - option (gogoproto.goproto_stringer) = false; - - // rate is the commission rate charged to delegators, as a fraction. - string rate = 1 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false]; - // max_rate defines the maximum commission rate which validator can ever charge, as a fraction. - string max_rate = 2 [ - (gogoproto.moretags) = "yaml:\"max_rate\"", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = false - ]; - // max_change_rate defines the maximum daily increase of the validator commission, as a fraction. - string max_change_rate = 3 [ - (gogoproto.moretags) = "yaml:\"max_change_rate\"", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = false - ]; -} - -// Commission defines commission parameters for a given validator. -message Commission { - option (gogoproto.equal) = true; - option (gogoproto.goproto_stringer) = false; - - // commission_rates defines the initial commission rates to be used for creating a validator. - CommissionRates commission_rates = 1 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; - // update_time is the last time the commission rate was changed. - google.protobuf.Timestamp update_time = 2 - [(gogoproto.nullable) = false, (gogoproto.stdtime) = true, (gogoproto.moretags) = "yaml:\"update_time\""]; -} - -// Description defines a validator description. -message Description { - option (gogoproto.equal) = true; - option (gogoproto.goproto_stringer) = false; - - // moniker defines a human-readable name for the validator. - string moniker = 1; - // identity defines an optional identity signature (ex. UPort or Keybase). - string identity = 2; - // website defines an optional website link. - string website = 3; - // security_contact defines an optional email for security contact. - string security_contact = 4 [(gogoproto.moretags) = "yaml:\"security_contact\""]; - // details define other optional details. - string details = 5; -} - -// Validator defines a validator, together with the total amount of the -// Validator's bond shares and their exchange rate to coins. Slashing results in -// a decrease in the exchange rate, allowing correct calculation of future -// undelegations without iterating over delegators. When coins are delegated to -// this validator, the validator is credited with a delegation whose number of -// bond shares is based on the amount of coins delegated divided by the current -// exchange rate. Voting power can be calculated as total bonded shares -// multiplied by exchange rate. -message Validator { - option (gogoproto.equal) = false; - option (gogoproto.goproto_stringer) = false; - option (gogoproto.goproto_getters) = false; - - // operator_address defines the address of the validator's operator; bech encoded in JSON. - string operator_address = 1 [(gogoproto.moretags) = "yaml:\"operator_address\""]; - // consensus_pubkey is the consensus public key of the validator, as a Protobuf Any. - google.protobuf.Any consensus_pubkey = 2 - [(cosmos_proto.accepts_interface) = "cosmos.crypto.PubKey", (gogoproto.moretags) = "yaml:\"consensus_pubkey\""]; - // jailed defined whether the validator has been jailed from bonded status or not. - bool jailed = 3; - // status is the validator status (bonded/unbonding/unbonded). - BondStatus status = 4; - // tokens define the delegated tokens (incl. self-delegation). - string tokens = 5 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.nullable) = false]; - // delegator_shares defines total shares issued to a validator's delegators. - string delegator_shares = 6 [ - (gogoproto.moretags) = "yaml:\"delegator_shares\"", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = false - ]; - // description defines the description terms for the validator. - Description description = 7 [(gogoproto.nullable) = false]; - // unbonding_height defines, if unbonding, the height at which this validator has begun unbonding. - int64 unbonding_height = 8 [(gogoproto.moretags) = "yaml:\"unbonding_height\""]; - // unbonding_time defines, if unbonding, the min time for the validator to complete unbonding. - google.protobuf.Timestamp unbonding_time = 9 - [(gogoproto.nullable) = false, (gogoproto.stdtime) = true, (gogoproto.moretags) = "yaml:\"unbonding_time\""]; - // commission defines the commission parameters. - Commission commission = 10 [(gogoproto.nullable) = false]; - // min_self_delegation is the validator's self declared minimum self delegation. - string min_self_delegation = 11 [ - (gogoproto.moretags) = "yaml:\"min_self_delegation\"", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", - (gogoproto.nullable) = false - ]; - - // strictly positive if this validator's unbonding has been stopped by external modules - int64 unbonding_on_hold_ref_count = 12; - - // list of unbonding ids, each uniquely identifing an unbonding of this validator - repeated uint64 unbonding_ids = 13; -} - -// BondStatus is the status of a validator. -enum BondStatus { - option (gogoproto.goproto_enum_prefix) = false; - - // UNSPECIFIED defines an invalid validator status. - BOND_STATUS_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "Unspecified"]; - // UNBONDED defines a validator that is not bonded. - BOND_STATUS_UNBONDED = 1 [(gogoproto.enumvalue_customname) = "Unbonded"]; - // UNBONDING defines a validator that is unbonding. - BOND_STATUS_UNBONDING = 2 [(gogoproto.enumvalue_customname) = "Unbonding"]; - // BONDED defines a validator that is bonded. - BOND_STATUS_BONDED = 3 [(gogoproto.enumvalue_customname) = "Bonded"]; -} - -// ValAddresses defines a repeated set of validator addresses. -message ValAddresses { - option (gogoproto.goproto_stringer) = false; - option (gogoproto.stringer) = true; - - repeated string addresses = 1; -} - -// DVPair is struct that just has a delegator-validator pair with no other data. -// It is intended to be used as a marshalable pointer. For example, a DVPair can -// be used to construct the key to getting an UnbondingDelegation from state. -message DVPair { - option (gogoproto.equal) = false; - option (gogoproto.goproto_getters) = false; - option (gogoproto.goproto_stringer) = false; - - string delegator_address = 1 [(gogoproto.moretags) = "yaml:\"delegator_address\""]; - string validator_address = 2 [(gogoproto.moretags) = "yaml:\"validator_address\""]; -} - -// DVPairs defines an array of DVPair objects. -message DVPairs { - repeated DVPair pairs = 1 [(gogoproto.nullable) = false]; -} - -// DVVTriplet is struct that just has a delegator-validator-validator triplet -// with no other data. It is intended to be used as a marshalable pointer. For -// example, a DVVTriplet can be used to construct the key to getting a -// Redelegation from state. -message DVVTriplet { - option (gogoproto.equal) = false; - option (gogoproto.goproto_getters) = false; - option (gogoproto.goproto_stringer) = false; - - string delegator_address = 1 [(gogoproto.moretags) = "yaml:\"delegator_address\""]; - string validator_src_address = 2 [(gogoproto.moretags) = "yaml:\"validator_src_address\""]; - string validator_dst_address = 3 [(gogoproto.moretags) = "yaml:\"validator_dst_address\""]; -} - -// DVVTriplets defines an array of DVVTriplet objects. -message DVVTriplets { - repeated DVVTriplet triplets = 1 [(gogoproto.nullable) = false]; -} - -// Delegation represents the bond with tokens held by an account. It is -// owned by one delegator, and is associated with the voting power of one -// validator. -message Delegation { - option (gogoproto.equal) = false; - option (gogoproto.goproto_getters) = false; - option (gogoproto.goproto_stringer) = false; - - // delegator_address is the bech32-encoded address of the delegator. - string delegator_address = 1 [(gogoproto.moretags) = "yaml:\"delegator_address\""]; - // validator_address is the bech32-encoded address of the validator. - string validator_address = 2 [(gogoproto.moretags) = "yaml:\"validator_address\""]; - // shares define the delegation shares received. - string shares = 3 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false]; -} - -// UnbondingDelegation stores all of a single delegator's unbonding bonds -// for a single validator in an time-ordered list. -message UnbondingDelegation { - option (gogoproto.equal) = false; - option (gogoproto.goproto_getters) = false; - option (gogoproto.goproto_stringer) = false; - - // delegator_address is the bech32-encoded address of the delegator. - string delegator_address = 1 [(gogoproto.moretags) = "yaml:\"delegator_address\""]; - // validator_address is the bech32-encoded address of the validator. - string validator_address = 2 [(gogoproto.moretags) = "yaml:\"validator_address\""]; - // entries are the unbonding delegation entries. - repeated UnbondingDelegationEntry entries = 3 [(gogoproto.nullable) = false]; // unbonding delegation entries -} - -// UnbondingDelegationEntry defines an unbonding object with relevant metadata. -message UnbondingDelegationEntry { - option (gogoproto.equal) = true; - option (gogoproto.goproto_stringer) = false; - - // creation_height is the height which the unbonding took place. - int64 creation_height = 1 [(gogoproto.moretags) = "yaml:\"creation_height\""]; - // completion_time is the unix time for unbonding completion. - google.protobuf.Timestamp completion_time = 2 - [(gogoproto.nullable) = false, (gogoproto.stdtime) = true, (gogoproto.moretags) = "yaml:\"completion_time\""]; - // initial_balance defines the tokens initially scheduled to receive at completion. - string initial_balance = 3 [ - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", - (gogoproto.nullable) = false, - (gogoproto.moretags) = "yaml:\"initial_balance\"" - ]; - // balance defines the tokens to receive at completion. - string balance = 4 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.nullable) = false]; - - // Incrementing id that uniquely identifies this entry - uint64 unbonding_id = 5; - - // Strictly positive if this entry's unbonding has been stopped by external modules - int64 unbonding_on_hold_ref_count = 6; -} - -// RedelegationEntry defines a redelegation object with relevant metadata. -message RedelegationEntry { - option (gogoproto.equal) = true; - option (gogoproto.goproto_stringer) = false; - - // creation_height defines the height which the redelegation took place. - int64 creation_height = 1 [(gogoproto.moretags) = "yaml:\"creation_height\""]; - // completion_time defines the unix time for redelegation completion. - google.protobuf.Timestamp completion_time = 2 - [(gogoproto.nullable) = false, (gogoproto.stdtime) = true, (gogoproto.moretags) = "yaml:\"completion_time\""]; - // initial_balance defines the initial balance when redelegation started. - string initial_balance = 3 [ - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", - (gogoproto.nullable) = false, - (gogoproto.moretags) = "yaml:\"initial_balance\"" - ]; - // shares_dst is the amount of destination-validator shares created by redelegation. - string shares_dst = 4 - [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false]; - - // Incrementing id that uniquely identifies this entry - uint64 unbonding_id = 5; - - // Strictly positive if this entry's unbonding has been stopped by external modules - int64 unbonding_on_hold_ref_count = 6; -} - -// Redelegation contains the list of a particular delegator's redelegating bonds -// from a particular source validator to a particular destination validator. -message Redelegation { - option (gogoproto.equal) = false; - option (gogoproto.goproto_getters) = false; - option (gogoproto.goproto_stringer) = false; - - // delegator_address is the bech32-encoded address of the delegator. - string delegator_address = 1 [(gogoproto.moretags) = "yaml:\"delegator_address\""]; - // validator_src_address is the validator redelegation source operator address. - string validator_src_address = 2 [(gogoproto.moretags) = "yaml:\"validator_src_address\""]; - // validator_dst_address is the validator redelegation destination operator address. - string validator_dst_address = 3 [(gogoproto.moretags) = "yaml:\"validator_dst_address\""]; - // entries are the redelegation entries. - repeated RedelegationEntry entries = 4 [(gogoproto.nullable) = false]; // redelegation entries -} - -// Params defines the parameters for the staking module. -message Params { - option (gogoproto.equal) = true; - option (gogoproto.goproto_stringer) = false; - - // unbonding_time is the time duration of unbonding. - google.protobuf.Duration unbonding_time = 1 - [(gogoproto.nullable) = false, (gogoproto.stdduration) = true, (gogoproto.moretags) = "yaml:\"unbonding_time\""]; - // max_validators is the maximum number of validators. - uint32 max_validators = 2 [(gogoproto.moretags) = "yaml:\"max_validators\""]; - // max_entries is the max entries for either unbonding delegation or redelegation (per pair/trio). - uint32 max_entries = 3 [(gogoproto.moretags) = "yaml:\"max_entries\""]; - // historical_entries is the number of historical entries to persist. - uint32 historical_entries = 4 [(gogoproto.moretags) = "yaml:\"historical_entries\""]; - // bond_denom defines the bondable coin denomination. - string bond_denom = 5 [(gogoproto.moretags) = "yaml:\"bond_denom\""]; -} - -// DelegationResponse is equivalent to Delegation except that it contains a -// balance in addition to shares which is more suitable for client responses. -message DelegationResponse { - option (gogoproto.equal) = false; - option (gogoproto.goproto_stringer) = false; - - Delegation delegation = 1 [(gogoproto.nullable) = false]; - - cosmos.base.v1beta1.Coin balance = 2 [(gogoproto.nullable) = false]; -} - -// RedelegationEntryResponse is equivalent to a RedelegationEntry except that it -// contains a balance in addition to shares which is more suitable for client -// responses. -message RedelegationEntryResponse { - option (gogoproto.equal) = true; - - RedelegationEntry redelegation_entry = 1 [(gogoproto.nullable) = false]; - string balance = 4 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.nullable) = false]; -} - -// RedelegationResponse is equivalent to a Redelegation except that its entries -// contain a balance in addition to shares which is more suitable for client -// responses. -message RedelegationResponse { - option (gogoproto.equal) = false; - - Redelegation redelegation = 1 [(gogoproto.nullable) = false]; - repeated RedelegationEntryResponse entries = 2 [(gogoproto.nullable) = false]; -} - -// Pool is used for tracking bonded and not-bonded token supply of the bond -// denomination. -message Pool { - option (gogoproto.description) = true; - option (gogoproto.equal) = true; - string not_bonded_tokens = 1 [ - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", - (gogoproto.jsontag) = "not_bonded_tokens", - (gogoproto.nullable) = false - ]; - string bonded_tokens = 2 [ - (gogoproto.jsontag) = "bonded_tokens", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", - (gogoproto.nullable) = false, - (gogoproto.moretags) = "yaml:\"bonded_tokens\"" - ]; -} - -// InfractionType indicates the infraction type a validator commited. -enum InfractionType { - option (gogoproto.goproto_enum_prefix) = false; - - // UNSPECIFIED defines an empty infraction type. - INFRACTION_TYPE_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "InfractionEmpty"]; - // DOUBLE_SIGN defines a validator that double-signs a block. - INFRACTION_TYPE_DOUBLE_SIGN = 1 [(gogoproto.enumvalue_customname) = "DoubleSign"]; - // DOWNTIME defines a validator that missed signing too many blocks. - INFRACTION_TYPE_DOWNTIME = 2 [(gogoproto.enumvalue_customname) = "Downtime"]; -} - -// ValidatorUpdates defines an array of abci.ValidatorUpdate objects. -message ValidatorUpdates { - repeated tendermint.abci.ValidatorUpdate updates = 1 [(gogoproto.nullable) = false]; -} \ No newline at end of file diff --git a/third_party/proto/cosmos/upgrade/v1beta1/upgrade.proto b/third_party/proto/cosmos/upgrade/v1beta1/upgrade.proto deleted file mode 100644 index e888b393d6..0000000000 --- a/third_party/proto/cosmos/upgrade/v1beta1/upgrade.proto +++ /dev/null @@ -1,78 +0,0 @@ -syntax = "proto3"; -package cosmos.upgrade.v1beta1; - -import "google/protobuf/any.proto"; -import "gogoproto/gogo.proto"; -import "google/protobuf/timestamp.proto"; - -option go_package = "github.com/cosmos/cosmos-sdk/x/upgrade/types"; -option (gogoproto.goproto_getters_all) = false; - -// Plan specifies information about a planned upgrade and when it should occur. -message Plan { - option (gogoproto.equal) = true; - option (gogoproto.goproto_stringer) = false; - - // Sets the name for the upgrade. This name will be used by the upgraded - // version of the software to apply any special "on-upgrade" commands during - // the first BeginBlock method after the upgrade is applied. It is also used - // to detect whether a software version can handle a given upgrade. If no - // upgrade handler with this name has been set in the software, it will be - // assumed that the software is out-of-date when the upgrade Time or Height is - // reached and the software will exit. - string name = 1; - - // Deprecated: Time based upgrades have been deprecated. Time based upgrade logic - // has been removed from the SDK. - // If this field is not empty, an error will be thrown. - google.protobuf.Timestamp time = 2 [deprecated = true, (gogoproto.stdtime) = true, (gogoproto.nullable) = false]; - - // The height at which the upgrade must be performed. - // Only used if Time is not set. - int64 height = 3; - - // Any application specific upgrade info to be included on-chain - // such as a git commit that validators could automatically upgrade to - string info = 4; - - // Deprecated: UpgradedClientState field has been deprecated. IBC upgrade logic has been - // moved to the IBC module in the sub module 02-client. - // If this field is not empty, an error will be thrown. - google.protobuf.Any upgraded_client_state = 5 - [deprecated = true, (gogoproto.moretags) = "yaml:\"upgraded_client_state\""]; -} - -// SoftwareUpgradeProposal is a gov Content type for initiating a software -// upgrade. -message SoftwareUpgradeProposal { - option (gogoproto.equal) = true; - option (gogoproto.goproto_stringer) = false; - - string title = 1; - string description = 2; - Plan plan = 3 [(gogoproto.nullable) = false]; -} - -// CancelSoftwareUpgradeProposal is a gov Content type for cancelling a software -// upgrade. -message CancelSoftwareUpgradeProposal { - option (gogoproto.equal) = true; - option (gogoproto.goproto_stringer) = false; - - string title = 1; - string description = 2; -} - -// ModuleVersion specifies a module and its consensus version. -// -// Since: cosmos-sdk 0.43 -message ModuleVersion { - option (gogoproto.equal) = true; - option (gogoproto.goproto_stringer) = true; - - // name of the app module - string name = 1; - - // consensus version of the app module - uint64 version = 2; -} diff --git a/third_party/proto/cosmos_proto/cosmos.proto b/third_party/proto/cosmos_proto/cosmos.proto deleted file mode 100644 index 167b170757..0000000000 --- a/third_party/proto/cosmos_proto/cosmos.proto +++ /dev/null @@ -1,16 +0,0 @@ -syntax = "proto3"; -package cosmos_proto; - -import "google/protobuf/descriptor.proto"; - -option go_package = "github.com/regen-network/cosmos-proto"; - -extend google.protobuf.MessageOptions { - string interface_type = 93001; - - string implements_interface = 93002; -} - -extend google.protobuf.FieldOptions { - string accepts_interface = 93001; -} diff --git a/third_party/proto/ibc/core/channel/v1/channel.proto b/third_party/proto/ibc/core/channel/v1/channel.proto deleted file mode 100644 index 87c4324d3c..0000000000 --- a/third_party/proto/ibc/core/channel/v1/channel.proto +++ /dev/null @@ -1,148 +0,0 @@ -syntax = "proto3"; - -package ibc.core.channel.v1; - -option go_package = "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types"; - -import "gogoproto/gogo.proto"; -import "ibc/core/client/v1/client.proto"; - -// Channel defines pipeline for exactly-once packet delivery between specific -// modules on separate blockchains, which has at least one end capable of -// sending packets and one end capable of receiving packets. -message Channel { - option (gogoproto.goproto_getters) = false; - - // current state of the channel end - State state = 1; - // whether the channel is ordered or unordered - Order ordering = 2; - // counterparty channel end - Counterparty counterparty = 3 [(gogoproto.nullable) = false]; - // list of connection identifiers, in order, along which packets sent on - // this channel will travel - repeated string connection_hops = 4 [(gogoproto.moretags) = "yaml:\"connection_hops\""]; - // opaque channel version, which is agreed upon during the handshake - string version = 5; -} - -// IdentifiedChannel defines a channel with additional port and channel -// identifier fields. -message IdentifiedChannel { - option (gogoproto.goproto_getters) = false; - - // current state of the channel end - State state = 1; - // whether the channel is ordered or unordered - Order ordering = 2; - // counterparty channel end - Counterparty counterparty = 3 [(gogoproto.nullable) = false]; - // list of connection identifiers, in order, along which packets sent on - // this channel will travel - repeated string connection_hops = 4 [(gogoproto.moretags) = "yaml:\"connection_hops\""]; - // opaque channel version, which is agreed upon during the handshake - string version = 5; - // port identifier - string port_id = 6; - // channel identifier - string channel_id = 7; -} - -// State defines if a channel is in one of the following states: -// CLOSED, INIT, TRYOPEN, OPEN or UNINITIALIZED. -enum State { - option (gogoproto.goproto_enum_prefix) = false; - - // Default State - STATE_UNINITIALIZED_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "UNINITIALIZED"]; - // A channel has just started the opening handshake. - STATE_INIT = 1 [(gogoproto.enumvalue_customname) = "INIT"]; - // A channel has acknowledged the handshake step on the counterparty chain. - STATE_TRYOPEN = 2 [(gogoproto.enumvalue_customname) = "TRYOPEN"]; - // A channel has completed the handshake. Open channels are - // ready to send and receive packets. - STATE_OPEN = 3 [(gogoproto.enumvalue_customname) = "OPEN"]; - // A channel has been closed and can no longer be used to send or receive - // packets. - STATE_CLOSED = 4 [(gogoproto.enumvalue_customname) = "CLOSED"]; -} - -// Order defines if a channel is ORDERED or UNORDERED -enum Order { - option (gogoproto.goproto_enum_prefix) = false; - - // zero-value for channel ordering - ORDER_NONE_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "NONE"]; - // packets can be delivered in any order, which may differ from the order in - // which they were sent. - ORDER_UNORDERED = 1 [(gogoproto.enumvalue_customname) = "UNORDERED"]; - // packets are delivered exactly in the order which they were sent - ORDER_ORDERED = 2 [(gogoproto.enumvalue_customname) = "ORDERED"]; -} - -// Counterparty defines a channel end counterparty -message Counterparty { - option (gogoproto.goproto_getters) = false; - - // port on the counterparty chain which owns the other end of the channel. - string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; - // channel end on the counterparty chain - string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""]; -} - -// Packet defines a type that carries data across different chains through IBC -message Packet { - option (gogoproto.goproto_getters) = false; - - // number corresponds to the order of sends and receives, where a Packet - // with an earlier sequence number must be sent and received before a Packet - // with a later sequence number. - uint64 sequence = 1; - // identifies the port on the sending chain. - string source_port = 2 [(gogoproto.moretags) = "yaml:\"source_port\""]; - // identifies the channel end on the sending chain. - string source_channel = 3 [(gogoproto.moretags) = "yaml:\"source_channel\""]; - // identifies the port on the receiving chain. - string destination_port = 4 [(gogoproto.moretags) = "yaml:\"destination_port\""]; - // identifies the channel end on the receiving chain. - string destination_channel = 5 [(gogoproto.moretags) = "yaml:\"destination_channel\""]; - // actual opaque bytes transferred directly to the application module - bytes data = 6; - // block height after which the packet times out - ibc.core.client.v1.Height timeout_height = 7 - [(gogoproto.moretags) = "yaml:\"timeout_height\"", (gogoproto.nullable) = false]; - // block timestamp (in nanoseconds) after which the packet times out - uint64 timeout_timestamp = 8 [(gogoproto.moretags) = "yaml:\"timeout_timestamp\""]; -} - -// PacketState defines the generic type necessary to retrieve and store -// packet commitments, acknowledgements, and receipts. -// Caller is responsible for knowing the context necessary to interpret this -// state as a commitment, acknowledgement, or a receipt. -message PacketState { - option (gogoproto.goproto_getters) = false; - - // channel port identifier. - string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; - // channel unique identifier. - string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""]; - // packet sequence. - uint64 sequence = 3; - // embedded data that represents packet state. - bytes data = 4; -} - -// Acknowledgement is the recommended acknowledgement format to be used by -// app-specific protocols. -// NOTE: The field numbers 21 and 22 were explicitly chosen to avoid accidental -// conflicts with other protobuf message formats used for acknowledgements. -// The first byte of any message with this format will be the non-ASCII values -// `0xaa` (result) or `0xb2` (error). Implemented as defined by ICS: -// https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#acknowledgement-envelope -message Acknowledgement { - // response contains either a result or an error and must be non-empty - oneof response { - bytes result = 21; - string error = 22; - } -} diff --git a/third_party/proto/ibc/core/channel/v1/genesis.proto b/third_party/proto/ibc/core/channel/v1/genesis.proto deleted file mode 100644 index 1c0ff6ee88..0000000000 --- a/third_party/proto/ibc/core/channel/v1/genesis.proto +++ /dev/null @@ -1,32 +0,0 @@ -syntax = "proto3"; - -package ibc.core.channel.v1; - -option go_package = "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types"; - -import "gogoproto/gogo.proto"; -import "ibc/core/channel/v1/channel.proto"; - -// GenesisState defines the ibc channel submodule's genesis state. -message GenesisState { - repeated IdentifiedChannel channels = 1 [(gogoproto.casttype) = "IdentifiedChannel", (gogoproto.nullable) = false]; - repeated PacketState acknowledgements = 2 [(gogoproto.nullable) = false]; - repeated PacketState commitments = 3 [(gogoproto.nullable) = false]; - repeated PacketState receipts = 4 [(gogoproto.nullable) = false]; - repeated PacketSequence send_sequences = 5 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"send_sequences\""]; - repeated PacketSequence recv_sequences = 6 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"recv_sequences\""]; - repeated PacketSequence ack_sequences = 7 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"ack_sequences\""]; - // the sequence for the next generated channel identifier - uint64 next_channel_sequence = 8 [(gogoproto.moretags) = "yaml:\"next_channel_sequence\""]; -} - -// PacketSequence defines the genesis type necessary to retrieve and store -// next send and receive sequences. -message PacketSequence { - string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; - string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""]; - uint64 sequence = 3; -} diff --git a/third_party/proto/ibc/core/channel/v1/query.proto b/third_party/proto/ibc/core/channel/v1/query.proto deleted file mode 100644 index 986633173c..0000000000 --- a/third_party/proto/ibc/core/channel/v1/query.proto +++ /dev/null @@ -1,376 +0,0 @@ -syntax = "proto3"; - -package ibc.core.channel.v1; - -option go_package = "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types"; - -import "ibc/core/client/v1/client.proto"; -import "cosmos/base/query/v1beta1/pagination.proto"; -import "ibc/core/channel/v1/channel.proto"; -import "google/api/annotations.proto"; -import "google/protobuf/any.proto"; -import "gogoproto/gogo.proto"; - -// Query provides defines the gRPC querier service -service Query { - // Channel queries an IBC Channel. - rpc Channel(QueryChannelRequest) returns (QueryChannelResponse) { - option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}"; - } - - // Channels queries all the IBC channels of a chain. - rpc Channels(QueryChannelsRequest) returns (QueryChannelsResponse) { - option (google.api.http).get = "/ibc/core/channel/v1/channels"; - } - - // ConnectionChannels queries all the channels associated with a connection - // end. - rpc ConnectionChannels(QueryConnectionChannelsRequest) returns (QueryConnectionChannelsResponse) { - option (google.api.http).get = "/ibc/core/channel/v1/connections/{connection}/channels"; - } - - // ChannelClientState queries for the client state for the channel associated - // with the provided channel identifiers. - rpc ChannelClientState(QueryChannelClientStateRequest) returns (QueryChannelClientStateResponse) { - option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" - "ports/{port_id}/client_state"; - } - - // ChannelConsensusState queries for the consensus state for the channel - // associated with the provided channel identifiers. - rpc ChannelConsensusState(QueryChannelConsensusStateRequest) returns (QueryChannelConsensusStateResponse) { - option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" - "ports/{port_id}/consensus_state/revision/" - "{revision_number}/height/{revision_height}"; - } - - // PacketCommitment queries a stored packet commitment hash. - rpc PacketCommitment(QueryPacketCommitmentRequest) returns (QueryPacketCommitmentResponse) { - option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/" - "packet_commitments/{sequence}"; - } - - // PacketCommitments returns all the packet commitments hashes associated - // with a channel. - rpc PacketCommitments(QueryPacketCommitmentsRequest) returns (QueryPacketCommitmentsResponse) { - option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" - "ports/{port_id}/packet_commitments"; - } - - // PacketReceipt queries if a given packet sequence has been received on the - // queried chain - rpc PacketReceipt(QueryPacketReceiptRequest) returns (QueryPacketReceiptResponse) { - option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" - "ports/{port_id}/packet_receipts/{sequence}"; - } - - // PacketAcknowledgement queries a stored packet acknowledgement hash. - rpc PacketAcknowledgement(QueryPacketAcknowledgementRequest) returns (QueryPacketAcknowledgementResponse) { - option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" - "ports/{port_id}/packet_acks/{sequence}"; - } - - // PacketAcknowledgements returns all the packet acknowledgements associated - // with a channel. - rpc PacketAcknowledgements(QueryPacketAcknowledgementsRequest) returns (QueryPacketAcknowledgementsResponse) { - option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" - "ports/{port_id}/packet_acknowledgements"; - } - - // UnreceivedPackets returns all the unreceived IBC packets associated with a - // channel and sequences. - rpc UnreceivedPackets(QueryUnreceivedPacketsRequest) returns (QueryUnreceivedPacketsResponse) { - option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/" - "packet_commitments/" - "{packet_commitment_sequences}/unreceived_packets"; - } - - // UnreceivedAcks returns all the unreceived IBC acknowledgements associated - // with a channel and sequences. - rpc UnreceivedAcks(QueryUnreceivedAcksRequest) returns (QueryUnreceivedAcksResponse) { - option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" - "ports/{port_id}/packet_commitments/" - "{packet_ack_sequences}/unreceived_acks"; - } - - // NextSequenceReceive returns the next receive sequence for a given channel. - rpc NextSequenceReceive(QueryNextSequenceReceiveRequest) returns (QueryNextSequenceReceiveResponse) { - option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" - "ports/{port_id}/next_sequence"; - } -} - -// QueryChannelRequest is the request type for the Query/Channel RPC method -message QueryChannelRequest { - // port unique identifier - string port_id = 1; - // channel unique identifier - string channel_id = 2; -} - -// QueryChannelResponse is the response type for the Query/Channel RPC method. -// Besides the Channel end, it includes a proof and the height from which the -// proof was retrieved. -message QueryChannelResponse { - // channel associated with the request identifiers - ibc.core.channel.v1.Channel channel = 1; - // merkle proof of existence - bytes proof = 2; - // height at which the proof was retrieved - ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; -} - -// QueryChannelsRequest is the request type for the Query/Channels RPC method -message QueryChannelsRequest { - // pagination request - cosmos.base.query.v1beta1.PageRequest pagination = 1; -} - -// QueryChannelsResponse is the response type for the Query/Channels RPC method. -message QueryChannelsResponse { - // list of stored channels of the chain. - repeated ibc.core.channel.v1.IdentifiedChannel channels = 1; - // pagination response - cosmos.base.query.v1beta1.PageResponse pagination = 2; - // query block height - ibc.core.client.v1.Height height = 3 [(gogoproto.nullable) = false]; -} - -// QueryConnectionChannelsRequest is the request type for the -// Query/QueryConnectionChannels RPC method -message QueryConnectionChannelsRequest { - // connection unique identifier - string connection = 1; - // pagination request - cosmos.base.query.v1beta1.PageRequest pagination = 2; -} - -// QueryConnectionChannelsResponse is the Response type for the -// Query/QueryConnectionChannels RPC method -message QueryConnectionChannelsResponse { - // list of channels associated with a connection. - repeated ibc.core.channel.v1.IdentifiedChannel channels = 1; - // pagination response - cosmos.base.query.v1beta1.PageResponse pagination = 2; - // query block height - ibc.core.client.v1.Height height = 3 [(gogoproto.nullable) = false]; -} - -// QueryChannelClientStateRequest is the request type for the Query/ClientState -// RPC method -message QueryChannelClientStateRequest { - // port unique identifier - string port_id = 1; - // channel unique identifier - string channel_id = 2; -} - -// QueryChannelClientStateResponse is the Response type for the -// Query/QueryChannelClientState RPC method -message QueryChannelClientStateResponse { - // client state associated with the channel - ibc.core.client.v1.IdentifiedClientState identified_client_state = 1; - // merkle proof of existence - bytes proof = 2; - // height at which the proof was retrieved - ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; -} - -// QueryChannelConsensusStateRequest is the request type for the -// Query/ConsensusState RPC method -message QueryChannelConsensusStateRequest { - // port unique identifier - string port_id = 1; - // channel unique identifier - string channel_id = 2; - // revision number of the consensus state - uint64 revision_number = 3; - // revision height of the consensus state - uint64 revision_height = 4; -} - -// QueryChannelClientStateResponse is the Response type for the -// Query/QueryChannelClientState RPC method -message QueryChannelConsensusStateResponse { - // consensus state associated with the channel - google.protobuf.Any consensus_state = 1; - // client ID associated with the consensus state - string client_id = 2; - // merkle proof of existence - bytes proof = 3; - // height at which the proof was retrieved - ibc.core.client.v1.Height proof_height = 4 [(gogoproto.nullable) = false]; -} - -// QueryPacketCommitmentRequest is the request type for the -// Query/PacketCommitment RPC method -message QueryPacketCommitmentRequest { - // port unique identifier - string port_id = 1; - // channel unique identifier - string channel_id = 2; - // packet sequence - uint64 sequence = 3; -} - -// QueryPacketCommitmentResponse defines the client query response for a packet -// which also includes a proof and the height from which the proof was -// retrieved -message QueryPacketCommitmentResponse { - // packet associated with the request fields - bytes commitment = 1; - // merkle proof of existence - bytes proof = 2; - // height at which the proof was retrieved - ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; -} - -// QueryPacketCommitmentsRequest is the request type for the -// Query/QueryPacketCommitments RPC method -message QueryPacketCommitmentsRequest { - // port unique identifier - string port_id = 1; - // channel unique identifier - string channel_id = 2; - // pagination request - cosmos.base.query.v1beta1.PageRequest pagination = 3; -} - -// QueryPacketCommitmentsResponse is the request type for the -// Query/QueryPacketCommitments RPC method -message QueryPacketCommitmentsResponse { - repeated ibc.core.channel.v1.PacketState commitments = 1; - // pagination response - cosmos.base.query.v1beta1.PageResponse pagination = 2; - // query block height - ibc.core.client.v1.Height height = 3 [(gogoproto.nullable) = false]; -} - -// QueryPacketReceiptRequest is the request type for the -// Query/PacketReceipt RPC method -message QueryPacketReceiptRequest { - // port unique identifier - string port_id = 1; - // channel unique identifier - string channel_id = 2; - // packet sequence - uint64 sequence = 3; -} - -// QueryPacketReceiptResponse defines the client query response for a packet -// receipt which also includes a proof, and the height from which the proof was -// retrieved -message QueryPacketReceiptResponse { - // success flag for if receipt exists - bool received = 2; - // merkle proof of existence - bytes proof = 3; - // height at which the proof was retrieved - ibc.core.client.v1.Height proof_height = 4 [(gogoproto.nullable) = false]; -} - -// QueryPacketAcknowledgementRequest is the request type for the -// Query/PacketAcknowledgement RPC method -message QueryPacketAcknowledgementRequest { - // port unique identifier - string port_id = 1; - // channel unique identifier - string channel_id = 2; - // packet sequence - uint64 sequence = 3; -} - -// QueryPacketAcknowledgementResponse defines the client query response for a -// packet which also includes a proof and the height from which the -// proof was retrieved -message QueryPacketAcknowledgementResponse { - // packet associated with the request fields - bytes acknowledgement = 1; - // merkle proof of existence - bytes proof = 2; - // height at which the proof was retrieved - ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; -} - -// QueryPacketAcknowledgementsRequest is the request type for the -// Query/QueryPacketCommitments RPC method -message QueryPacketAcknowledgementsRequest { - // port unique identifier - string port_id = 1; - // channel unique identifier - string channel_id = 2; - // pagination request - cosmos.base.query.v1beta1.PageRequest pagination = 3; - // list of packet sequences - repeated uint64 packet_commitment_sequences = 4; -} - -// QueryPacketAcknowledgemetsResponse is the request type for the -// Query/QueryPacketAcknowledgements RPC method -message QueryPacketAcknowledgementsResponse { - repeated ibc.core.channel.v1.PacketState acknowledgements = 1; - // pagination response - cosmos.base.query.v1beta1.PageResponse pagination = 2; - // query block height - ibc.core.client.v1.Height height = 3 [(gogoproto.nullable) = false]; -} - -// QueryUnreceivedPacketsRequest is the request type for the -// Query/UnreceivedPackets RPC method -message QueryUnreceivedPacketsRequest { - // port unique identifier - string port_id = 1; - // channel unique identifier - string channel_id = 2; - // list of packet sequences - repeated uint64 packet_commitment_sequences = 3; -} - -// QueryUnreceivedPacketsResponse is the response type for the -// Query/UnreceivedPacketCommitments RPC method -message QueryUnreceivedPacketsResponse { - // list of unreceived packet sequences - repeated uint64 sequences = 1; - // query block height - ibc.core.client.v1.Height height = 2 [(gogoproto.nullable) = false]; -} - -// QueryUnreceivedAcks is the request type for the -// Query/UnreceivedAcks RPC method -message QueryUnreceivedAcksRequest { - // port unique identifier - string port_id = 1; - // channel unique identifier - string channel_id = 2; - // list of acknowledgement sequences - repeated uint64 packet_ack_sequences = 3; -} - -// QueryUnreceivedAcksResponse is the response type for the -// Query/UnreceivedAcks RPC method -message QueryUnreceivedAcksResponse { - // list of unreceived acknowledgement sequences - repeated uint64 sequences = 1; - // query block height - ibc.core.client.v1.Height height = 2 [(gogoproto.nullable) = false]; -} - -// QueryNextSequenceReceiveRequest is the request type for the -// Query/QueryNextSequenceReceiveRequest RPC method -message QueryNextSequenceReceiveRequest { - // port unique identifier - string port_id = 1; - // channel unique identifier - string channel_id = 2; -} - -// QuerySequenceResponse is the request type for the -// Query/QueryNextSequenceReceiveResponse RPC method -message QueryNextSequenceReceiveResponse { - // next sequence receive number - uint64 next_sequence_receive = 1; - // merkle proof of existence - bytes proof = 2; - // height at which the proof was retrieved - ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; -} diff --git a/third_party/proto/ibc/core/channel/v1/tx.proto b/third_party/proto/ibc/core/channel/v1/tx.proto deleted file mode 100644 index c1ab67a16b..0000000000 --- a/third_party/proto/ibc/core/channel/v1/tx.proto +++ /dev/null @@ -1,211 +0,0 @@ -syntax = "proto3"; - -package ibc.core.channel.v1; - -option go_package = "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types"; - -import "gogoproto/gogo.proto"; -import "ibc/core/client/v1/client.proto"; -import "ibc/core/channel/v1/channel.proto"; - -// Msg defines the ibc/channel Msg service. -service Msg { - // ChannelOpenInit defines a rpc handler method for MsgChannelOpenInit. - rpc ChannelOpenInit(MsgChannelOpenInit) returns (MsgChannelOpenInitResponse); - - // ChannelOpenTry defines a rpc handler method for MsgChannelOpenTry. - rpc ChannelOpenTry(MsgChannelOpenTry) returns (MsgChannelOpenTryResponse); - - // ChannelOpenAck defines a rpc handler method for MsgChannelOpenAck. - rpc ChannelOpenAck(MsgChannelOpenAck) returns (MsgChannelOpenAckResponse); - - // ChannelOpenConfirm defines a rpc handler method for MsgChannelOpenConfirm. - rpc ChannelOpenConfirm(MsgChannelOpenConfirm) returns (MsgChannelOpenConfirmResponse); - - // ChannelCloseInit defines a rpc handler method for MsgChannelCloseInit. - rpc ChannelCloseInit(MsgChannelCloseInit) returns (MsgChannelCloseInitResponse); - - // ChannelCloseConfirm defines a rpc handler method for - // MsgChannelCloseConfirm. - rpc ChannelCloseConfirm(MsgChannelCloseConfirm) returns (MsgChannelCloseConfirmResponse); - - // RecvPacket defines a rpc handler method for MsgRecvPacket. - rpc RecvPacket(MsgRecvPacket) returns (MsgRecvPacketResponse); - - // Timeout defines a rpc handler method for MsgTimeout. - rpc Timeout(MsgTimeout) returns (MsgTimeoutResponse); - - // TimeoutOnClose defines a rpc handler method for MsgTimeoutOnClose. - rpc TimeoutOnClose(MsgTimeoutOnClose) returns (MsgTimeoutOnCloseResponse); - - // Acknowledgement defines a rpc handler method for MsgAcknowledgement. - rpc Acknowledgement(MsgAcknowledgement) returns (MsgAcknowledgementResponse); -} - -// MsgChannelOpenInit defines an sdk.Msg to initialize a channel handshake. It -// is called by a relayer on Chain A. -message MsgChannelOpenInit { - option (gogoproto.equal) = false; - option (gogoproto.goproto_getters) = false; - - string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; - Channel channel = 2 [(gogoproto.nullable) = false]; - string signer = 3; -} - -// MsgChannelOpenInitResponse defines the Msg/ChannelOpenInit response type. -message MsgChannelOpenInitResponse {} - -// MsgChannelOpenInit defines a msg sent by a Relayer to try to open a channel -// on Chain B. -message MsgChannelOpenTry { - option (gogoproto.equal) = false; - option (gogoproto.goproto_getters) = false; - - string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; - // in the case of crossing hello's, when both chains call OpenInit, we need - // the channel identifier of the previous channel in state INIT - string previous_channel_id = 2 [(gogoproto.moretags) = "yaml:\"previous_channel_id\""]; - Channel channel = 3 [(gogoproto.nullable) = false]; - string counterparty_version = 4 [(gogoproto.moretags) = "yaml:\"counterparty_version\""]; - bytes proof_init = 5 [(gogoproto.moretags) = "yaml:\"proof_init\""]; - ibc.core.client.v1.Height proof_height = 6 - [(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false]; - string signer = 7; -} - -// MsgChannelOpenTryResponse defines the Msg/ChannelOpenTry response type. -message MsgChannelOpenTryResponse {} - -// MsgChannelOpenAck defines a msg sent by a Relayer to Chain A to acknowledge -// the change of channel state to TRYOPEN on Chain B. -message MsgChannelOpenAck { - option (gogoproto.equal) = false; - option (gogoproto.goproto_getters) = false; - - string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; - string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""]; - string counterparty_channel_id = 3 [(gogoproto.moretags) = "yaml:\"counterparty_channel_id\""]; - string counterparty_version = 4 [(gogoproto.moretags) = "yaml:\"counterparty_version\""]; - bytes proof_try = 5 [(gogoproto.moretags) = "yaml:\"proof_try\""]; - ibc.core.client.v1.Height proof_height = 6 - [(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false]; - string signer = 7; -} - -// MsgChannelOpenAckResponse defines the Msg/ChannelOpenAck response type. -message MsgChannelOpenAckResponse {} - -// MsgChannelOpenConfirm defines a msg sent by a Relayer to Chain B to -// acknowledge the change of channel state to OPEN on Chain A. -message MsgChannelOpenConfirm { - option (gogoproto.equal) = false; - option (gogoproto.goproto_getters) = false; - - string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; - string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""]; - bytes proof_ack = 3 [(gogoproto.moretags) = "yaml:\"proof_ack\""]; - ibc.core.client.v1.Height proof_height = 4 - [(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false]; - string signer = 5; -} - -// MsgChannelOpenConfirmResponse defines the Msg/ChannelOpenConfirm response -// type. -message MsgChannelOpenConfirmResponse {} - -// MsgChannelCloseInit defines a msg sent by a Relayer to Chain A -// to close a channel with Chain B. -message MsgChannelCloseInit { - option (gogoproto.equal) = false; - option (gogoproto.goproto_getters) = false; - - string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; - string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""]; - string signer = 3; -} - -// MsgChannelCloseInitResponse defines the Msg/ChannelCloseInit response type. -message MsgChannelCloseInitResponse {} - -// MsgChannelCloseConfirm defines a msg sent by a Relayer to Chain B -// to acknowledge the change of channel state to CLOSED on Chain A. -message MsgChannelCloseConfirm { - option (gogoproto.equal) = false; - option (gogoproto.goproto_getters) = false; - - string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; - string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""]; - bytes proof_init = 3 [(gogoproto.moretags) = "yaml:\"proof_init\""]; - ibc.core.client.v1.Height proof_height = 4 - [(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false]; - string signer = 5; -} - -// MsgChannelCloseConfirmResponse defines the Msg/ChannelCloseConfirm response -// type. -message MsgChannelCloseConfirmResponse {} - -// MsgRecvPacket receives incoming IBC packet -message MsgRecvPacket { - option (gogoproto.equal) = false; - option (gogoproto.goproto_getters) = false; - - Packet packet = 1 [(gogoproto.nullable) = false]; - bytes proof_commitment = 2 [(gogoproto.moretags) = "yaml:\"proof_commitment\""]; - ibc.core.client.v1.Height proof_height = 3 - [(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false]; - string signer = 4; -} - -// MsgRecvPacketResponse defines the Msg/RecvPacket response type. -message MsgRecvPacketResponse {} - -// MsgTimeout receives timed-out packet -message MsgTimeout { - option (gogoproto.equal) = false; - option (gogoproto.goproto_getters) = false; - - Packet packet = 1 [(gogoproto.nullable) = false]; - bytes proof_unreceived = 2 [(gogoproto.moretags) = "yaml:\"proof_unreceived\""]; - ibc.core.client.v1.Height proof_height = 3 - [(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false]; - uint64 next_sequence_recv = 4 [(gogoproto.moretags) = "yaml:\"next_sequence_recv\""]; - string signer = 5; -} - -// MsgTimeoutResponse defines the Msg/Timeout response type. -message MsgTimeoutResponse {} - -// MsgTimeoutOnClose timed-out packet upon counterparty channel closure. -message MsgTimeoutOnClose { - option (gogoproto.equal) = false; - option (gogoproto.goproto_getters) = false; - - Packet packet = 1 [(gogoproto.nullable) = false]; - bytes proof_unreceived = 2 [(gogoproto.moretags) = "yaml:\"proof_unreceived\""]; - bytes proof_close = 3 [(gogoproto.moretags) = "yaml:\"proof_close\""]; - ibc.core.client.v1.Height proof_height = 4 - [(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false]; - uint64 next_sequence_recv = 5 [(gogoproto.moretags) = "yaml:\"next_sequence_recv\""]; - string signer = 6; -} - -// MsgTimeoutOnCloseResponse defines the Msg/TimeoutOnClose response type. -message MsgTimeoutOnCloseResponse {} - -// MsgAcknowledgement receives incoming IBC acknowledgement -message MsgAcknowledgement { - option (gogoproto.equal) = false; - option (gogoproto.goproto_getters) = false; - - Packet packet = 1 [(gogoproto.nullable) = false]; - bytes acknowledgement = 2; - bytes proof_acked = 3 [(gogoproto.moretags) = "yaml:\"proof_acked\""]; - ibc.core.client.v1.Height proof_height = 4 - [(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false]; - string signer = 5; -} - -// MsgAcknowledgementResponse defines the Msg/Acknowledgement response type. -message MsgAcknowledgementResponse {} diff --git a/third_party/proto/ibc/core/client/v1/client.proto b/third_party/proto/ibc/core/client/v1/client.proto deleted file mode 100644 index 11edeeca87..0000000000 --- a/third_party/proto/ibc/core/client/v1/client.proto +++ /dev/null @@ -1,100 +0,0 @@ -syntax = "proto3"; - -package ibc.core.client.v1; - -option go_package = "github.com/cosmos/ibc-go/v4/modules/core/02-client/types"; - -import "gogoproto/gogo.proto"; -import "google/protobuf/any.proto"; -import "cosmos/upgrade/v1beta1/upgrade.proto"; - -// IdentifiedClientState defines a client state with an additional client -// identifier field. -message IdentifiedClientState { - // client identifier - string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; - // client state - google.protobuf.Any client_state = 2 [(gogoproto.moretags) = "yaml:\"client_state\""]; -} - -// ConsensusStateWithHeight defines a consensus state with an additional height -// field. -message ConsensusStateWithHeight { - // consensus state height - Height height = 1 [(gogoproto.nullable) = false]; - // consensus state - google.protobuf.Any consensus_state = 2 [(gogoproto.moretags) = "yaml\"consensus_state\""]; -} - -// ClientConsensusStates defines all the stored consensus states for a given -// client. -message ClientConsensusStates { - // client identifier - string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; - // consensus states and their heights associated with the client - repeated ConsensusStateWithHeight consensus_states = 2 - [(gogoproto.moretags) = "yaml:\"consensus_states\"", (gogoproto.nullable) = false]; -} - -// ClientUpdateProposal is a governance proposal. If it passes, the substitute -// client's latest consensus state is copied over to the subject client. The proposal -// handler may fail if the subject and the substitute do not match in client and -// chain parameters (with exception to latest height, frozen height, and chain-id). -message ClientUpdateProposal { - option (gogoproto.goproto_getters) = false; - // the title of the update proposal - string title = 1; - // the description of the proposal - string description = 2; - // the client identifier for the client to be updated if the proposal passes - string subject_client_id = 3 [(gogoproto.moretags) = "yaml:\"subject_client_id\""]; - // the substitute client identifier for the client standing in for the subject - // client - string substitute_client_id = 4 [(gogoproto.moretags) = "yaml:\"substitute_client_id\""]; -} - -// UpgradeProposal is a gov Content type for initiating an IBC breaking -// upgrade. -message UpgradeProposal { - option (gogoproto.goproto_getters) = false; - option (gogoproto.goproto_stringer) = false; - option (gogoproto.equal) = true; - - string title = 1; - string description = 2; - cosmos.upgrade.v1beta1.Plan plan = 3 [(gogoproto.nullable) = false]; - - // An UpgradedClientState must be provided to perform an IBC breaking upgrade. - // This will make the chain commit to the correct upgraded (self) client state - // before the upgrade occurs, so that connecting chains can verify that the - // new upgraded client is valid by verifying a proof on the previous version - // of the chain. This will allow IBC connections to persist smoothly across - // planned chain upgrades - google.protobuf.Any upgraded_client_state = 4 [(gogoproto.moretags) = "yaml:\"upgraded_client_state\""]; -} - -// Height is a monotonically increasing data type -// that can be compared against another Height for the purposes of updating and -// freezing clients -// -// Normally the RevisionHeight is incremented at each height while keeping -// RevisionNumber the same. However some consensus algorithms may choose to -// reset the height in certain conditions e.g. hard forks, state-machine -// breaking changes In these cases, the RevisionNumber is incremented so that -// height continues to be monitonically increasing even as the RevisionHeight -// gets reset -message Height { - option (gogoproto.goproto_getters) = false; - option (gogoproto.goproto_stringer) = false; - - // the revision that the client is currently on - uint64 revision_number = 1 [(gogoproto.moretags) = "yaml:\"revision_number\""]; - // the height within the given revision - uint64 revision_height = 2 [(gogoproto.moretags) = "yaml:\"revision_height\""]; -} - -// Params defines the set of IBC light client parameters. -message Params { - // allowed_clients defines the list of allowed client state types. - repeated string allowed_clients = 1 [(gogoproto.moretags) = "yaml:\"allowed_clients\""]; -} diff --git a/third_party/proto/ibc/core/client/v1/genesis.proto b/third_party/proto/ibc/core/client/v1/genesis.proto deleted file mode 100644 index b2930c4841..0000000000 --- a/third_party/proto/ibc/core/client/v1/genesis.proto +++ /dev/null @@ -1,48 +0,0 @@ -syntax = "proto3"; - -package ibc.core.client.v1; - -option go_package = "github.com/cosmos/ibc-go/v4/modules/core/02-client/types"; - -import "ibc/core/client/v1/client.proto"; -import "gogoproto/gogo.proto"; - -// GenesisState defines the ibc client submodule's genesis state. -message GenesisState { - // client states with their corresponding identifiers - repeated IdentifiedClientState clients = 1 - [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "IdentifiedClientStates"]; - // consensus states from each client - repeated ClientConsensusStates clients_consensus = 2 [ - (gogoproto.nullable) = false, - (gogoproto.castrepeated) = "ClientsConsensusStates", - (gogoproto.moretags) = "yaml:\"clients_consensus\"" - ]; - // metadata from each client - repeated IdentifiedGenesisMetadata clients_metadata = 3 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"clients_metadata\""]; - Params params = 4 [(gogoproto.nullable) = false]; - // create localhost on initialization - bool create_localhost = 5 [(gogoproto.moretags) = "yaml:\"create_localhost\""]; - // the sequence for the next generated client identifier - uint64 next_client_sequence = 6 [(gogoproto.moretags) = "yaml:\"next_client_sequence\""]; -} - -// GenesisMetadata defines the genesis type for metadata that clients may return -// with ExportMetadata -message GenesisMetadata { - option (gogoproto.goproto_getters) = false; - - // store key of metadata without clientID-prefix - bytes key = 1; - // metadata value - bytes value = 2; -} - -// IdentifiedGenesisMetadata has the client metadata with the corresponding -// client id. -message IdentifiedGenesisMetadata { - string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; - repeated GenesisMetadata client_metadata = 2 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"client_metadata\""]; -} diff --git a/third_party/proto/ibc/core/client/v1/query.proto b/third_party/proto/ibc/core/client/v1/query.proto deleted file mode 100644 index b930569313..0000000000 --- a/third_party/proto/ibc/core/client/v1/query.proto +++ /dev/null @@ -1,184 +0,0 @@ -syntax = "proto3"; - -package ibc.core.client.v1; - -option go_package = "github.com/cosmos/ibc-go/v4/modules/core/02-client/types"; - -import "cosmos/base/query/v1beta1/pagination.proto"; -import "ibc/core/client/v1/client.proto"; -import "google/protobuf/any.proto"; -import "google/api/annotations.proto"; -import "gogoproto/gogo.proto"; - -// Query provides defines the gRPC querier service -service Query { - // ClientState queries an IBC light client. - rpc ClientState(QueryClientStateRequest) returns (QueryClientStateResponse) { - option (google.api.http).get = "/ibc/core/client/v1/client_states/{client_id}"; - } - - // ClientStates queries all the IBC light clients of a chain. - rpc ClientStates(QueryClientStatesRequest) returns (QueryClientStatesResponse) { - option (google.api.http).get = "/ibc/core/client/v1/client_states"; - } - - // ConsensusState queries a consensus state associated with a client state at - // a given height. - rpc ConsensusState(QueryConsensusStateRequest) returns (QueryConsensusStateResponse) { - option (google.api.http).get = "/ibc/core/client/v1/consensus_states/" - "{client_id}/revision/{revision_number}/" - "height/{revision_height}"; - } - - // ConsensusStates queries all the consensus state associated with a given - // client. - rpc ConsensusStates(QueryConsensusStatesRequest) returns (QueryConsensusStatesResponse) { - option (google.api.http).get = "/ibc/core/client/v1/consensus_states/{client_id}"; - } - - // Status queries the status of an IBC client. - rpc ClientStatus(QueryClientStatusRequest) returns (QueryClientStatusResponse) { - option (google.api.http).get = "/ibc/core/client/v1/client_status/{client_id}"; - } - - // ClientParams queries all parameters of the ibc client. - rpc ClientParams(QueryClientParamsRequest) returns (QueryClientParamsResponse) { - option (google.api.http).get = "/ibc/client/v1/params"; - } - - // UpgradedClientState queries an Upgraded IBC light client. - rpc UpgradedClientState(QueryUpgradedClientStateRequest) returns (QueryUpgradedClientStateResponse) { - option (google.api.http).get = "/ibc/core/client/v1/upgraded_client_states"; - } - - // UpgradedConsensusState queries an Upgraded IBC consensus state. - rpc UpgradedConsensusState(QueryUpgradedConsensusStateRequest) returns (QueryUpgradedConsensusStateResponse) { - option (google.api.http).get = "/ibc/core/client/v1/upgraded_consensus_states"; - } -} - -// QueryClientStateRequest is the request type for the Query/ClientState RPC -// method -message QueryClientStateRequest { - // client state unique identifier - string client_id = 1; -} - -// QueryClientStateResponse is the response type for the Query/ClientState RPC -// method. Besides the client state, it includes a proof and the height from -// which the proof was retrieved. -message QueryClientStateResponse { - // client state associated with the request identifier - google.protobuf.Any client_state = 1; - // merkle proof of existence - bytes proof = 2; - // height at which the proof was retrieved - ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; -} - -// QueryClientStatesRequest is the request type for the Query/ClientStates RPC -// method -message QueryClientStatesRequest { - // pagination request - cosmos.base.query.v1beta1.PageRequest pagination = 1; -} - -// QueryClientStatesResponse is the response type for the Query/ClientStates RPC -// method. -message QueryClientStatesResponse { - // list of stored ClientStates of the chain. - repeated IdentifiedClientState client_states = 1 - [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "IdentifiedClientStates"]; - // pagination response - cosmos.base.query.v1beta1.PageResponse pagination = 2; -} - -// QueryConsensusStateRequest is the request type for the Query/ConsensusState -// RPC method. Besides the consensus state, it includes a proof and the height -// from which the proof was retrieved. -message QueryConsensusStateRequest { - // client identifier - string client_id = 1; - // consensus state revision number - uint64 revision_number = 2; - // consensus state revision height - uint64 revision_height = 3; - // latest_height overrrides the height field and queries the latest stored - // ConsensusState - bool latest_height = 4; -} - -// QueryConsensusStateResponse is the response type for the Query/ConsensusState -// RPC method -message QueryConsensusStateResponse { - // consensus state associated with the client identifier at the given height - google.protobuf.Any consensus_state = 1; - // merkle proof of existence - bytes proof = 2; - // height at which the proof was retrieved - ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; -} - -// QueryConsensusStatesRequest is the request type for the Query/ConsensusStates -// RPC method. -message QueryConsensusStatesRequest { - // client identifier - string client_id = 1; - // pagination request - cosmos.base.query.v1beta1.PageRequest pagination = 2; -} - -// QueryConsensusStatesResponse is the response type for the -// Query/ConsensusStates RPC method -message QueryConsensusStatesResponse { - // consensus states associated with the identifier - repeated ConsensusStateWithHeight consensus_states = 1 [(gogoproto.nullable) = false]; - // pagination response - cosmos.base.query.v1beta1.PageResponse pagination = 2; -} - -// QueryClientStatusRequest is the request type for the Query/ClientStatus RPC -// method -message QueryClientStatusRequest { - // client unique identifier - string client_id = 1; -} - -// QueryClientStatusResponse is the response type for the Query/ClientStatus RPC -// method. It returns the current status of the IBC client. -message QueryClientStatusResponse { - string status = 1; -} - -// QueryClientParamsRequest is the request type for the Query/ClientParams RPC -// method. -message QueryClientParamsRequest {} - -// QueryClientParamsResponse is the response type for the Query/ClientParams RPC -// method. -message QueryClientParamsResponse { - // params defines the parameters of the module. - Params params = 1; -} - -// QueryUpgradedClientStateRequest is the request type for the -// Query/UpgradedClientState RPC method -message QueryUpgradedClientStateRequest {} - -// QueryUpgradedClientStateResponse is the response type for the -// Query/UpgradedClientState RPC method. -message QueryUpgradedClientStateResponse { - // client state associated with the request identifier - google.protobuf.Any upgraded_client_state = 1; -} - -// QueryUpgradedConsensusStateRequest is the request type for the -// Query/UpgradedConsensusState RPC method -message QueryUpgradedConsensusStateRequest {} - -// QueryUpgradedConsensusStateResponse is the response type for the -// Query/UpgradedConsensusState RPC method. -message QueryUpgradedConsensusStateResponse { - // Consensus state associated with the request identifier - google.protobuf.Any upgraded_consensus_state = 1; -} diff --git a/third_party/proto/ibc/core/client/v1/tx.proto b/third_party/proto/ibc/core/client/v1/tx.proto deleted file mode 100644 index 4c0e981795..0000000000 --- a/third_party/proto/ibc/core/client/v1/tx.proto +++ /dev/null @@ -1,100 +0,0 @@ -syntax = "proto3"; - -package ibc.core.client.v1; - -option go_package = "github.com/cosmos/ibc-go/v4/modules/core/02-client/types"; - -import "gogoproto/gogo.proto"; -import "google/protobuf/any.proto"; -import "ibc/core/client/v1/client.proto"; - -// Msg defines the ibc/client Msg service. -service Msg { - // CreateClient defines a rpc handler method for MsgCreateClient. - rpc CreateClient(MsgCreateClient) returns (MsgCreateClientResponse); - - // UpdateClient defines a rpc handler method for MsgUpdateClient. - rpc UpdateClient(MsgUpdateClient) returns (MsgUpdateClientResponse); - - // UpgradeClient defines a rpc handler method for MsgUpgradeClient. - rpc UpgradeClient(MsgUpgradeClient) returns (MsgUpgradeClientResponse); - - // SubmitMisbehaviour defines a rpc handler method for MsgSubmitMisbehaviour. - rpc SubmitMisbehaviour(MsgSubmitMisbehaviour) returns (MsgSubmitMisbehaviourResponse); -} - -// MsgCreateClient defines a message to create an IBC client -message MsgCreateClient { - option (gogoproto.equal) = false; - option (gogoproto.goproto_getters) = false; - - // light client state - google.protobuf.Any client_state = 1 [(gogoproto.moretags) = "yaml:\"client_state\""]; - // consensus state associated with the client that corresponds to a given - // height. - google.protobuf.Any consensus_state = 2 [(gogoproto.moretags) = "yaml:\"consensus_state\""]; - // signer address - string signer = 3; -} - -// MsgCreateClientResponse defines the Msg/CreateClient response type. -message MsgCreateClientResponse {} - -// MsgUpdateClient defines an sdk.Msg to update a IBC client state using -// the given header. -message MsgUpdateClient { - option (gogoproto.equal) = false; - option (gogoproto.goproto_getters) = false; - - // client unique identifier - string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; - // header to update the light client - google.protobuf.Any header = 2; - // signer address - string signer = 3; -} - -// MsgUpdateClientResponse defines the Msg/UpdateClient response type. -message MsgUpdateClientResponse {} - -// MsgUpgradeClient defines an sdk.Msg to upgrade an IBC client to a new client -// state -message MsgUpgradeClient { - option (gogoproto.equal) = false; - option (gogoproto.goproto_getters) = false; - - // client unique identifier - string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; - // upgraded client state - google.protobuf.Any client_state = 2 [(gogoproto.moretags) = "yaml:\"client_state\""]; - // upgraded consensus state, only contains enough information to serve as a - // basis of trust in update logic - google.protobuf.Any consensus_state = 3 [(gogoproto.moretags) = "yaml:\"consensus_state\""]; - // proof that old chain committed to new client - bytes proof_upgrade_client = 4 [(gogoproto.moretags) = "yaml:\"proof_upgrade_client\""]; - // proof that old chain committed to new consensus state - bytes proof_upgrade_consensus_state = 5 [(gogoproto.moretags) = "yaml:\"proof_upgrade_consensus_state\""]; - // signer address - string signer = 6; -} - -// MsgUpgradeClientResponse defines the Msg/UpgradeClient response type. -message MsgUpgradeClientResponse {} - -// MsgSubmitMisbehaviour defines an sdk.Msg type that submits Evidence for -// light client misbehaviour. -message MsgSubmitMisbehaviour { - option (gogoproto.equal) = false; - option (gogoproto.goproto_getters) = false; - - // client unique identifier - string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; - // misbehaviour used for freezing the light client - google.protobuf.Any misbehaviour = 2; - // signer address - string signer = 3; -} - -// MsgSubmitMisbehaviourResponse defines the Msg/SubmitMisbehaviour response -// type. -message MsgSubmitMisbehaviourResponse {} diff --git a/third_party/proto/ibc/core/commitment/v1/commitment.proto b/third_party/proto/ibc/core/commitment/v1/commitment.proto deleted file mode 100644 index 1c36fcfbde..0000000000 --- a/third_party/proto/ibc/core/commitment/v1/commitment.proto +++ /dev/null @@ -1,41 +0,0 @@ -syntax = "proto3"; - -package ibc.core.commitment.v1; - -option go_package = "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types"; - -import "gogoproto/gogo.proto"; -import "confio/proofs.proto"; - -// MerkleRoot defines a merkle root hash. -// In the Cosmos SDK, the AppHash of a block header becomes the root. -message MerkleRoot { - option (gogoproto.goproto_getters) = false; - - bytes hash = 1; -} - -// MerklePrefix is merkle path prefixed to the key. -// The constructed key from the Path and the key will be append(Path.KeyPath, -// append(Path.KeyPrefix, key...)) -message MerklePrefix { - bytes key_prefix = 1 [(gogoproto.moretags) = "yaml:\"key_prefix\""]; -} - -// MerklePath is the path used to verify commitment proofs, which can be an -// arbitrary structured object (defined by a commitment type). -// MerklePath is represented from root-to-leaf -message MerklePath { - option (gogoproto.goproto_stringer) = false; - - repeated string key_path = 1 [(gogoproto.moretags) = "yaml:\"key_path\""]; -} - -// MerkleProof is a wrapper type over a chain of CommitmentProofs. -// It demonstrates membership or non-membership for an element or set of -// elements, verifiable in conjunction with a known commitment root. Proofs -// should be succinct. -// MerkleProofs are ordered from leaf-to-root -message MerkleProof { - repeated ics23.CommitmentProof proofs = 1; -} diff --git a/third_party/proto/ibc/core/connection/v1/connection.proto b/third_party/proto/ibc/core/connection/v1/connection.proto deleted file mode 100644 index 29e998568d..0000000000 --- a/third_party/proto/ibc/core/connection/v1/connection.proto +++ /dev/null @@ -1,114 +0,0 @@ -syntax = "proto3"; - -package ibc.core.connection.v1; - -option go_package = "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types"; - -import "gogoproto/gogo.proto"; -import "ibc/core/commitment/v1/commitment.proto"; - -// ICS03 - Connection Data Structures as defined in -// https://github.com/cosmos/ics/tree/master/spec/ics-003-connection-semantics#data-structures - -// ConnectionEnd defines a stateful object on a chain connected to another -// separate one. -// NOTE: there must only be 2 defined ConnectionEnds to establish -// a connection between two chains. -message ConnectionEnd { - option (gogoproto.goproto_getters) = false; - // client associated with this connection. - string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; - // IBC version which can be utilised to determine encodings or protocols for - // channels or packets utilising this connection. - repeated Version versions = 2; - // current state of the connection end. - State state = 3; - // counterparty chain associated with this connection. - Counterparty counterparty = 4 [(gogoproto.nullable) = false]; - // delay period that must pass before a consensus state can be used for - // packet-verification NOTE: delay period logic is only implemented by some - // clients. - uint64 delay_period = 5 [(gogoproto.moretags) = "yaml:\"delay_period\""]; -} - -// IdentifiedConnection defines a connection with additional connection -// identifier field. -message IdentifiedConnection { - option (gogoproto.goproto_getters) = false; - // connection identifier. - string id = 1 [(gogoproto.moretags) = "yaml:\"id\""]; - // client associated with this connection. - string client_id = 2 [(gogoproto.moretags) = "yaml:\"client_id\""]; - // IBC version which can be utilised to determine encodings or protocols for - // channels or packets utilising this connection - repeated Version versions = 3; - // current state of the connection end. - State state = 4; - // counterparty chain associated with this connection. - Counterparty counterparty = 5 [(gogoproto.nullable) = false]; - // delay period associated with this connection. - uint64 delay_period = 6 [(gogoproto.moretags) = "yaml:\"delay_period\""]; -} - -// State defines if a connection is in one of the following states: -// INIT, TRYOPEN, OPEN or UNINITIALIZED. -enum State { - option (gogoproto.goproto_enum_prefix) = false; - - // Default State - STATE_UNINITIALIZED_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "UNINITIALIZED"]; - // A connection end has just started the opening handshake. - STATE_INIT = 1 [(gogoproto.enumvalue_customname) = "INIT"]; - // A connection end has acknowledged the handshake step on the counterparty - // chain. - STATE_TRYOPEN = 2 [(gogoproto.enumvalue_customname) = "TRYOPEN"]; - // A connection end has completed the handshake. - STATE_OPEN = 3 [(gogoproto.enumvalue_customname) = "OPEN"]; -} - -// Counterparty defines the counterparty chain associated with a connection end. -message Counterparty { - option (gogoproto.goproto_getters) = false; - - // identifies the client on the counterparty chain associated with a given - // connection. - string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; - // identifies the connection end on the counterparty chain associated with a - // given connection. - string connection_id = 2 [(gogoproto.moretags) = "yaml:\"connection_id\""]; - // commitment merkle prefix of the counterparty chain. - ibc.core.commitment.v1.MerklePrefix prefix = 3 [(gogoproto.nullable) = false]; -} - -// ClientPaths define all the connection paths for a client state. -message ClientPaths { - // list of connection paths - repeated string paths = 1; -} - -// ConnectionPaths define all the connection paths for a given client state. -message ConnectionPaths { - // client state unique identifier - string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; - // list of connection paths - repeated string paths = 2; -} - -// Version defines the versioning scheme used to negotiate the IBC verison in -// the connection handshake. -message Version { - option (gogoproto.goproto_getters) = false; - - // unique version identifier - string identifier = 1; - // list of features compatible with the specified identifier - repeated string features = 2; -} - -// Params defines the set of Connection parameters. -message Params { - // maximum expected time per block (in nanoseconds), used to enforce block delay. This parameter should reflect the - // largest amount of time that the chain might reasonably take to produce the next block under normal operating - // conditions. A safe choice is 3-5x the expected time per block. - uint64 max_expected_time_per_block = 1 [(gogoproto.moretags) = "yaml:\"max_expected_time_per_block\""]; -} diff --git a/third_party/proto/ibc/core/connection/v1/genesis.proto b/third_party/proto/ibc/core/connection/v1/genesis.proto deleted file mode 100644 index f616ae67e0..0000000000 --- a/third_party/proto/ibc/core/connection/v1/genesis.proto +++ /dev/null @@ -1,18 +0,0 @@ -syntax = "proto3"; - -package ibc.core.connection.v1; - -option go_package = "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types"; - -import "gogoproto/gogo.proto"; -import "ibc/core/connection/v1/connection.proto"; - -// GenesisState defines the ibc connection submodule's genesis state. -message GenesisState { - repeated IdentifiedConnection connections = 1 [(gogoproto.nullable) = false]; - repeated ConnectionPaths client_connection_paths = 2 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"client_connection_paths\""]; - // the sequence for the next generated connection identifier - uint64 next_connection_sequence = 3 [(gogoproto.moretags) = "yaml:\"next_connection_sequence\""]; - Params params = 4 [(gogoproto.nullable) = false]; -} diff --git a/third_party/proto/ibc/core/connection/v1/query.proto b/third_party/proto/ibc/core/connection/v1/query.proto deleted file mode 100644 index 129f30a71a..0000000000 --- a/third_party/proto/ibc/core/connection/v1/query.proto +++ /dev/null @@ -1,138 +0,0 @@ -syntax = "proto3"; - -package ibc.core.connection.v1; - -option go_package = "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types"; - -import "gogoproto/gogo.proto"; -import "cosmos/base/query/v1beta1/pagination.proto"; -import "ibc/core/client/v1/client.proto"; -import "ibc/core/connection/v1/connection.proto"; -import "google/api/annotations.proto"; -import "google/protobuf/any.proto"; - -// Query provides defines the gRPC querier service -service Query { - // Connection queries an IBC connection end. - rpc Connection(QueryConnectionRequest) returns (QueryConnectionResponse) { - option (google.api.http).get = "/ibc/core/connection/v1/connections/{connection_id}"; - } - - // Connections queries all the IBC connections of a chain. - rpc Connections(QueryConnectionsRequest) returns (QueryConnectionsResponse) { - option (google.api.http).get = "/ibc/core/connection/v1/connections"; - } - - // ClientConnections queries the connection paths associated with a client - // state. - rpc ClientConnections(QueryClientConnectionsRequest) returns (QueryClientConnectionsResponse) { - option (google.api.http).get = "/ibc/core/connection/v1/client_connections/{client_id}"; - } - - // ConnectionClientState queries the client state associated with the - // connection. - rpc ConnectionClientState(QueryConnectionClientStateRequest) returns (QueryConnectionClientStateResponse) { - option (google.api.http).get = "/ibc/core/connection/v1/connections/{connection_id}/client_state"; - } - - // ConnectionConsensusState queries the consensus state associated with the - // connection. - rpc ConnectionConsensusState(QueryConnectionConsensusStateRequest) returns (QueryConnectionConsensusStateResponse) { - option (google.api.http).get = "/ibc/core/connection/v1/connections/{connection_id}/consensus_state/" - "revision/{revision_number}/height/{revision_height}"; - } -} - -// QueryConnectionRequest is the request type for the Query/Connection RPC -// method -message QueryConnectionRequest { - // connection unique identifier - string connection_id = 1; -} - -// QueryConnectionResponse is the response type for the Query/Connection RPC -// method. Besides the connection end, it includes a proof and the height from -// which the proof was retrieved. -message QueryConnectionResponse { - // connection associated with the request identifier - ibc.core.connection.v1.ConnectionEnd connection = 1; - // merkle proof of existence - bytes proof = 2; - // height at which the proof was retrieved - ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; -} - -// QueryConnectionsRequest is the request type for the Query/Connections RPC -// method -message QueryConnectionsRequest { - cosmos.base.query.v1beta1.PageRequest pagination = 1; -} - -// QueryConnectionsResponse is the response type for the Query/Connections RPC -// method. -message QueryConnectionsResponse { - // list of stored connections of the chain. - repeated ibc.core.connection.v1.IdentifiedConnection connections = 1; - // pagination response - cosmos.base.query.v1beta1.PageResponse pagination = 2; - // query block height - ibc.core.client.v1.Height height = 3 [(gogoproto.nullable) = false]; -} - -// QueryClientConnectionsRequest is the request type for the -// Query/ClientConnections RPC method -message QueryClientConnectionsRequest { - // client identifier associated with a connection - string client_id = 1; -} - -// QueryClientConnectionsResponse is the response type for the -// Query/ClientConnections RPC method -message QueryClientConnectionsResponse { - // slice of all the connection paths associated with a client. - repeated string connection_paths = 1; - // merkle proof of existence - bytes proof = 2; - // height at which the proof was generated - ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; -} - -// QueryConnectionClientStateRequest is the request type for the -// Query/ConnectionClientState RPC method -message QueryConnectionClientStateRequest { - // connection identifier - string connection_id = 1 [(gogoproto.moretags) = "yaml:\"connection_id\""]; -} - -// QueryConnectionClientStateResponse is the response type for the -// Query/ConnectionClientState RPC method -message QueryConnectionClientStateResponse { - // client state associated with the channel - ibc.core.client.v1.IdentifiedClientState identified_client_state = 1; - // merkle proof of existence - bytes proof = 2; - // height at which the proof was retrieved - ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; -} - -// QueryConnectionConsensusStateRequest is the request type for the -// Query/ConnectionConsensusState RPC method -message QueryConnectionConsensusStateRequest { - // connection identifier - string connection_id = 1 [(gogoproto.moretags) = "yaml:\"connection_id\""]; - uint64 revision_number = 2; - uint64 revision_height = 3; -} - -// QueryConnectionConsensusStateResponse is the response type for the -// Query/ConnectionConsensusState RPC method -message QueryConnectionConsensusStateResponse { - // consensus state associated with the channel - google.protobuf.Any consensus_state = 1; - // client ID associated with the consensus state - string client_id = 2; - // merkle proof of existence - bytes proof = 3; - // height at which the proof was retrieved - ibc.core.client.v1.Height proof_height = 4 [(gogoproto.nullable) = false]; -} diff --git a/third_party/proto/ibc/core/connection/v1/tx.proto b/third_party/proto/ibc/core/connection/v1/tx.proto deleted file mode 100644 index 1ca0b40400..0000000000 --- a/third_party/proto/ibc/core/connection/v1/tx.proto +++ /dev/null @@ -1,119 +0,0 @@ -syntax = "proto3"; - -package ibc.core.connection.v1; - -option go_package = "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types"; - -import "gogoproto/gogo.proto"; -import "google/protobuf/any.proto"; -import "ibc/core/client/v1/client.proto"; -import "ibc/core/connection/v1/connection.proto"; - -// Msg defines the ibc/connection Msg service. -service Msg { - // ConnectionOpenInit defines a rpc handler method for MsgConnectionOpenInit. - rpc ConnectionOpenInit(MsgConnectionOpenInit) returns (MsgConnectionOpenInitResponse); - - // ConnectionOpenTry defines a rpc handler method for MsgConnectionOpenTry. - rpc ConnectionOpenTry(MsgConnectionOpenTry) returns (MsgConnectionOpenTryResponse); - - // ConnectionOpenAck defines a rpc handler method for MsgConnectionOpenAck. - rpc ConnectionOpenAck(MsgConnectionOpenAck) returns (MsgConnectionOpenAckResponse); - - // ConnectionOpenConfirm defines a rpc handler method for - // MsgConnectionOpenConfirm. - rpc ConnectionOpenConfirm(MsgConnectionOpenConfirm) returns (MsgConnectionOpenConfirmResponse); -} - -// MsgConnectionOpenInit defines the msg sent by an account on Chain A to -// initialize a connection with Chain B. -message MsgConnectionOpenInit { - option (gogoproto.equal) = false; - option (gogoproto.goproto_getters) = false; - - string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; - Counterparty counterparty = 2 [(gogoproto.nullable) = false]; - Version version = 3; - uint64 delay_period = 4 [(gogoproto.moretags) = "yaml:\"delay_period\""]; - string signer = 5; -} - -// MsgConnectionOpenInitResponse defines the Msg/ConnectionOpenInit response -// type. -message MsgConnectionOpenInitResponse {} - -// MsgConnectionOpenTry defines a msg sent by a Relayer to try to open a -// connection on Chain B. -message MsgConnectionOpenTry { - option (gogoproto.equal) = false; - option (gogoproto.goproto_getters) = false; - - string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; - // in the case of crossing hello's, when both chains call OpenInit, we need - // the connection identifier of the previous connection in state INIT - string previous_connection_id = 2 [(gogoproto.moretags) = "yaml:\"previous_connection_id\""]; - google.protobuf.Any client_state = 3 [(gogoproto.moretags) = "yaml:\"client_state\""]; - Counterparty counterparty = 4 [(gogoproto.nullable) = false]; - uint64 delay_period = 5 [(gogoproto.moretags) = "yaml:\"delay_period\""]; - repeated Version counterparty_versions = 6 [(gogoproto.moretags) = "yaml:\"counterparty_versions\""]; - ibc.core.client.v1.Height proof_height = 7 - [(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false]; - // proof of the initialization the connection on Chain A: `UNITIALIZED -> - // INIT` - bytes proof_init = 8 [(gogoproto.moretags) = "yaml:\"proof_init\""]; - // proof of client state included in message - bytes proof_client = 9 [(gogoproto.moretags) = "yaml:\"proof_client\""]; - // proof of client consensus state - bytes proof_consensus = 10 [(gogoproto.moretags) = "yaml:\"proof_consensus\""]; - ibc.core.client.v1.Height consensus_height = 11 - [(gogoproto.moretags) = "yaml:\"consensus_height\"", (gogoproto.nullable) = false]; - string signer = 12; -} - -// MsgConnectionOpenTryResponse defines the Msg/ConnectionOpenTry response type. -message MsgConnectionOpenTryResponse {} - -// MsgConnectionOpenAck defines a msg sent by a Relayer to Chain A to -// acknowledge the change of connection state to TRYOPEN on Chain B. -message MsgConnectionOpenAck { - option (gogoproto.equal) = false; - option (gogoproto.goproto_getters) = false; - - string connection_id = 1 [(gogoproto.moretags) = "yaml:\"connection_id\""]; - string counterparty_connection_id = 2 [(gogoproto.moretags) = "yaml:\"counterparty_connection_id\""]; - Version version = 3; - google.protobuf.Any client_state = 4 [(gogoproto.moretags) = "yaml:\"client_state\""]; - ibc.core.client.v1.Height proof_height = 5 - [(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false]; - // proof of the initialization the connection on Chain B: `UNITIALIZED -> - // TRYOPEN` - bytes proof_try = 6 [(gogoproto.moretags) = "yaml:\"proof_try\""]; - // proof of client state included in message - bytes proof_client = 7 [(gogoproto.moretags) = "yaml:\"proof_client\""]; - // proof of client consensus state - bytes proof_consensus = 8 [(gogoproto.moretags) = "yaml:\"proof_consensus\""]; - ibc.core.client.v1.Height consensus_height = 9 - [(gogoproto.moretags) = "yaml:\"consensus_height\"", (gogoproto.nullable) = false]; - string signer = 10; -} - -// MsgConnectionOpenAckResponse defines the Msg/ConnectionOpenAck response type. -message MsgConnectionOpenAckResponse {} - -// MsgConnectionOpenConfirm defines a msg sent by a Relayer to Chain B to -// acknowledge the change of connection state to OPEN on Chain A. -message MsgConnectionOpenConfirm { - option (gogoproto.equal) = false; - option (gogoproto.goproto_getters) = false; - - string connection_id = 1 [(gogoproto.moretags) = "yaml:\"connection_id\""]; - // proof for the change of the connection state on Chain A: `INIT -> OPEN` - bytes proof_ack = 2 [(gogoproto.moretags) = "yaml:\"proof_ack\""]; - ibc.core.client.v1.Height proof_height = 3 - [(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false]; - string signer = 4; -} - -// MsgConnectionOpenConfirmResponse defines the Msg/ConnectionOpenConfirm -// response type. -message MsgConnectionOpenConfirmResponse {} diff --git a/third_party/proto/ibc/core/types/v1/genesis.proto b/third_party/proto/ibc/core/types/v1/genesis.proto deleted file mode 100644 index 4cc931d32f..0000000000 --- a/third_party/proto/ibc/core/types/v1/genesis.proto +++ /dev/null @@ -1,23 +0,0 @@ -syntax = "proto3"; - -package ibc.core.types.v1; - -option go_package = "github.com/cosmos/ibc-go/v4/modules/core/types"; - -import "gogoproto/gogo.proto"; -import "ibc/core/client/v1/genesis.proto"; -import "ibc/core/connection/v1/genesis.proto"; -import "ibc/core/channel/v1/genesis.proto"; - -// GenesisState defines the ibc module's genesis state. -message GenesisState { - // ICS002 - Clients genesis state - ibc.core.client.v1.GenesisState client_genesis = 1 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"client_genesis\""]; - // ICS003 - Connections genesis state - ibc.core.connection.v1.GenesisState connection_genesis = 2 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"connection_genesis\""]; - // ICS004 - Channel genesis state - ibc.core.channel.v1.GenesisState channel_genesis = 3 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"channel_genesis\""]; -} diff --git a/third_party/proto/ibc/lightclients/localhost/v1/localhost.proto b/third_party/proto/ibc/lightclients/localhost/v1/localhost.proto deleted file mode 100644 index 9eda835ebb..0000000000 --- a/third_party/proto/ibc/lightclients/localhost/v1/localhost.proto +++ /dev/null @@ -1,18 +0,0 @@ -syntax = "proto3"; - -package ibc.lightclients.localhost.v1; - -option go_package = "github.com/cosmos/ibc-go/v4/modules/light-clients/09-localhost/types"; - -import "gogoproto/gogo.proto"; -import "ibc/core/client/v1/client.proto"; - -// ClientState defines a loopback (localhost) client. It requires (read-only) -// access to keys outside the client prefix. -message ClientState { - option (gogoproto.goproto_getters) = false; - // self chain ID - string chain_id = 1 [(gogoproto.moretags) = "yaml:\"chain_id\""]; - // self latest block height - ibc.core.client.v1.Height height = 2 [(gogoproto.nullable) = false]; -} diff --git a/third_party/proto/ibc/lightclients/solomachine/v1/solomachine.proto b/third_party/proto/ibc/lightclients/solomachine/v1/solomachine.proto deleted file mode 100644 index 37bd81e923..0000000000 --- a/third_party/proto/ibc/lightclients/solomachine/v1/solomachine.proto +++ /dev/null @@ -1,189 +0,0 @@ -syntax = "proto3"; - -package ibc.lightclients.solomachine.v1; - -option go_package = "github.com/cosmos/ibc-go/v4/modules/core/02-client/legacy/v100"; - -import "ibc/core/connection/v1/connection.proto"; -import "ibc/core/channel/v1/channel.proto"; -import "gogoproto/gogo.proto"; -import "google/protobuf/any.proto"; - -// ClientState defines a solo machine client that tracks the current consensus -// state and if the client is frozen. -message ClientState { - option (gogoproto.goproto_getters) = false; - // latest sequence of the client state - uint64 sequence = 1; - // frozen sequence of the solo machine - uint64 frozen_sequence = 2 [(gogoproto.moretags) = "yaml:\"frozen_sequence\""]; - ConsensusState consensus_state = 3 [(gogoproto.moretags) = "yaml:\"consensus_state\""]; - // when set to true, will allow governance to update a solo machine client. - // The client will be unfrozen if it is frozen. - bool allow_update_after_proposal = 4 [(gogoproto.moretags) = "yaml:\"allow_update_after_proposal\""]; -} - -// ConsensusState defines a solo machine consensus state. The sequence of a -// consensus state is contained in the "height" key used in storing the -// consensus state. -message ConsensusState { - option (gogoproto.goproto_getters) = false; - // public key of the solo machine - google.protobuf.Any public_key = 1 [(gogoproto.moretags) = "yaml:\"public_key\""]; - // diversifier allows the same public key to be re-used across different solo - // machine clients (potentially on different chains) without being considered - // misbehaviour. - string diversifier = 2; - uint64 timestamp = 3; -} - -// Header defines a solo machine consensus header -message Header { - option (gogoproto.goproto_getters) = false; - // sequence to update solo machine public key at - uint64 sequence = 1; - uint64 timestamp = 2; - bytes signature = 3; - google.protobuf.Any new_public_key = 4 [(gogoproto.moretags) = "yaml:\"new_public_key\""]; - string new_diversifier = 5 [(gogoproto.moretags) = "yaml:\"new_diversifier\""]; -} - -// Misbehaviour defines misbehaviour for a solo machine which consists -// of a sequence and two signatures over different messages at that sequence. -message Misbehaviour { - option (gogoproto.goproto_getters) = false; - string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; - uint64 sequence = 2; - SignatureAndData signature_one = 3 [(gogoproto.moretags) = "yaml:\"signature_one\""]; - SignatureAndData signature_two = 4 [(gogoproto.moretags) = "yaml:\"signature_two\""]; -} - -// SignatureAndData contains a signature and the data signed over to create that -// signature. -message SignatureAndData { - option (gogoproto.goproto_getters) = false; - bytes signature = 1; - DataType data_type = 2 [(gogoproto.moretags) = "yaml:\"data_type\""]; - bytes data = 3; - uint64 timestamp = 4; -} - -// TimestampedSignatureData contains the signature data and the timestamp of the -// signature. -message TimestampedSignatureData { - option (gogoproto.goproto_getters) = false; - bytes signature_data = 1 [(gogoproto.moretags) = "yaml:\"signature_data\""]; - uint64 timestamp = 2; -} - -// SignBytes defines the signed bytes used for signature verification. -message SignBytes { - option (gogoproto.goproto_getters) = false; - - uint64 sequence = 1; - uint64 timestamp = 2; - string diversifier = 3; - // type of the data used - DataType data_type = 4 [(gogoproto.moretags) = "yaml:\"data_type\""]; - // marshaled data - bytes data = 5; -} - -// DataType defines the type of solo machine proof being created. This is done -// to preserve uniqueness of different data sign byte encodings. -enum DataType { - option (gogoproto.goproto_enum_prefix) = false; - - // Default State - DATA_TYPE_UNINITIALIZED_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "UNSPECIFIED"]; - // Data type for client state verification - DATA_TYPE_CLIENT_STATE = 1 [(gogoproto.enumvalue_customname) = "CLIENT"]; - // Data type for consensus state verification - DATA_TYPE_CONSENSUS_STATE = 2 [(gogoproto.enumvalue_customname) = "CONSENSUS"]; - // Data type for connection state verification - DATA_TYPE_CONNECTION_STATE = 3 [(gogoproto.enumvalue_customname) = "CONNECTION"]; - // Data type for channel state verification - DATA_TYPE_CHANNEL_STATE = 4 [(gogoproto.enumvalue_customname) = "CHANNEL"]; - // Data type for packet commitment verification - DATA_TYPE_PACKET_COMMITMENT = 5 [(gogoproto.enumvalue_customname) = "PACKETCOMMITMENT"]; - // Data type for packet acknowledgement verification - DATA_TYPE_PACKET_ACKNOWLEDGEMENT = 6 [(gogoproto.enumvalue_customname) = "PACKETACKNOWLEDGEMENT"]; - // Data type for packet receipt absence verification - DATA_TYPE_PACKET_RECEIPT_ABSENCE = 7 [(gogoproto.enumvalue_customname) = "PACKETRECEIPTABSENCE"]; - // Data type for next sequence recv verification - DATA_TYPE_NEXT_SEQUENCE_RECV = 8 [(gogoproto.enumvalue_customname) = "NEXTSEQUENCERECV"]; - // Data type for header verification - DATA_TYPE_HEADER = 9 [(gogoproto.enumvalue_customname) = "HEADER"]; -} - -// HeaderData returns the SignBytes data for update verification. -message HeaderData { - option (gogoproto.goproto_getters) = false; - - // header public key - google.protobuf.Any new_pub_key = 1 [(gogoproto.moretags) = "yaml:\"new_pub_key\""]; - // header diversifier - string new_diversifier = 2 [(gogoproto.moretags) = "yaml:\"new_diversifier\""]; -} - -// ClientStateData returns the SignBytes data for client state verification. -message ClientStateData { - option (gogoproto.goproto_getters) = false; - - bytes path = 1; - google.protobuf.Any client_state = 2 [(gogoproto.moretags) = "yaml:\"client_state\""]; -} - -// ConsensusStateData returns the SignBytes data for consensus state -// verification. -message ConsensusStateData { - option (gogoproto.goproto_getters) = false; - - bytes path = 1; - google.protobuf.Any consensus_state = 2 [(gogoproto.moretags) = "yaml:\"consensus_state\""]; -} - -// ConnectionStateData returns the SignBytes data for connection state -// verification. -message ConnectionStateData { - option (gogoproto.goproto_getters) = false; - - bytes path = 1; - ibc.core.connection.v1.ConnectionEnd connection = 2; -} - -// ChannelStateData returns the SignBytes data for channel state -// verification. -message ChannelStateData { - option (gogoproto.goproto_getters) = false; - - bytes path = 1; - ibc.core.channel.v1.Channel channel = 2; -} - -// PacketCommitmentData returns the SignBytes data for packet commitment -// verification. -message PacketCommitmentData { - bytes path = 1; - bytes commitment = 2; -} - -// PacketAcknowledgementData returns the SignBytes data for acknowledgement -// verification. -message PacketAcknowledgementData { - bytes path = 1; - bytes acknowledgement = 2; -} - -// PacketReceiptAbsenceData returns the SignBytes data for -// packet receipt absence verification. -message PacketReceiptAbsenceData { - bytes path = 1; -} - -// NextSequenceRecvData returns the SignBytes data for verification of the next -// sequence to be received. -message NextSequenceRecvData { - bytes path = 1; - uint64 next_seq_recv = 2 [(gogoproto.moretags) = "yaml:\"next_seq_recv\""]; -} diff --git a/third_party/proto/ibc/lightclients/solomachine/v2/solomachine.proto b/third_party/proto/ibc/lightclients/solomachine/v2/solomachine.proto deleted file mode 100644 index c735fddddf..0000000000 --- a/third_party/proto/ibc/lightclients/solomachine/v2/solomachine.proto +++ /dev/null @@ -1,189 +0,0 @@ -syntax = "proto3"; - -package ibc.lightclients.solomachine.v2; - -option go_package = "github.com/cosmos/ibc-go/v4/modules/light-clients/06-solomachine/types"; - -import "ibc/core/connection/v1/connection.proto"; -import "ibc/core/channel/v1/channel.proto"; -import "gogoproto/gogo.proto"; -import "google/protobuf/any.proto"; - -// ClientState defines a solo machine client that tracks the current consensus -// state and if the client is frozen. -message ClientState { - option (gogoproto.goproto_getters) = false; - // latest sequence of the client state - uint64 sequence = 1; - // frozen sequence of the solo machine - bool is_frozen = 2 [(gogoproto.moretags) = "yaml:\"is_frozen\""]; - ConsensusState consensus_state = 3 [(gogoproto.moretags) = "yaml:\"consensus_state\""]; - // when set to true, will allow governance to update a solo machine client. - // The client will be unfrozen if it is frozen. - bool allow_update_after_proposal = 4 [(gogoproto.moretags) = "yaml:\"allow_update_after_proposal\""]; -} - -// ConsensusState defines a solo machine consensus state. The sequence of a -// consensus state is contained in the "height" key used in storing the -// consensus state. -message ConsensusState { - option (gogoproto.goproto_getters) = false; - // public key of the solo machine - google.protobuf.Any public_key = 1 [(gogoproto.moretags) = "yaml:\"public_key\""]; - // diversifier allows the same public key to be re-used across different solo - // machine clients (potentially on different chains) without being considered - // misbehaviour. - string diversifier = 2; - uint64 timestamp = 3; -} - -// Header defines a solo machine consensus header -message Header { - option (gogoproto.goproto_getters) = false; - // sequence to update solo machine public key at - uint64 sequence = 1; - uint64 timestamp = 2; - bytes signature = 3; - google.protobuf.Any new_public_key = 4 [(gogoproto.moretags) = "yaml:\"new_public_key\""]; - string new_diversifier = 5 [(gogoproto.moretags) = "yaml:\"new_diversifier\""]; -} - -// Misbehaviour defines misbehaviour for a solo machine which consists -// of a sequence and two signatures over different messages at that sequence. -message Misbehaviour { - option (gogoproto.goproto_getters) = false; - string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; - uint64 sequence = 2; - SignatureAndData signature_one = 3 [(gogoproto.moretags) = "yaml:\"signature_one\""]; - SignatureAndData signature_two = 4 [(gogoproto.moretags) = "yaml:\"signature_two\""]; -} - -// SignatureAndData contains a signature and the data signed over to create that -// signature. -message SignatureAndData { - option (gogoproto.goproto_getters) = false; - bytes signature = 1; - DataType data_type = 2 [(gogoproto.moretags) = "yaml:\"data_type\""]; - bytes data = 3; - uint64 timestamp = 4; -} - -// TimestampedSignatureData contains the signature data and the timestamp of the -// signature. -message TimestampedSignatureData { - option (gogoproto.goproto_getters) = false; - bytes signature_data = 1 [(gogoproto.moretags) = "yaml:\"signature_data\""]; - uint64 timestamp = 2; -} - -// SignBytes defines the signed bytes used for signature verification. -message SignBytes { - option (gogoproto.goproto_getters) = false; - - uint64 sequence = 1; - uint64 timestamp = 2; - string diversifier = 3; - // type of the data used - DataType data_type = 4 [(gogoproto.moretags) = "yaml:\"data_type\""]; - // marshaled data - bytes data = 5; -} - -// DataType defines the type of solo machine proof being created. This is done -// to preserve uniqueness of different data sign byte encodings. -enum DataType { - option (gogoproto.goproto_enum_prefix) = false; - - // Default State - DATA_TYPE_UNINITIALIZED_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "UNSPECIFIED"]; - // Data type for client state verification - DATA_TYPE_CLIENT_STATE = 1 [(gogoproto.enumvalue_customname) = "CLIENT"]; - // Data type for consensus state verification - DATA_TYPE_CONSENSUS_STATE = 2 [(gogoproto.enumvalue_customname) = "CONSENSUS"]; - // Data type for connection state verification - DATA_TYPE_CONNECTION_STATE = 3 [(gogoproto.enumvalue_customname) = "CONNECTION"]; - // Data type for channel state verification - DATA_TYPE_CHANNEL_STATE = 4 [(gogoproto.enumvalue_customname) = "CHANNEL"]; - // Data type for packet commitment verification - DATA_TYPE_PACKET_COMMITMENT = 5 [(gogoproto.enumvalue_customname) = "PACKETCOMMITMENT"]; - // Data type for packet acknowledgement verification - DATA_TYPE_PACKET_ACKNOWLEDGEMENT = 6 [(gogoproto.enumvalue_customname) = "PACKETACKNOWLEDGEMENT"]; - // Data type for packet receipt absence verification - DATA_TYPE_PACKET_RECEIPT_ABSENCE = 7 [(gogoproto.enumvalue_customname) = "PACKETRECEIPTABSENCE"]; - // Data type for next sequence recv verification - DATA_TYPE_NEXT_SEQUENCE_RECV = 8 [(gogoproto.enumvalue_customname) = "NEXTSEQUENCERECV"]; - // Data type for header verification - DATA_TYPE_HEADER = 9 [(gogoproto.enumvalue_customname) = "HEADER"]; -} - -// HeaderData returns the SignBytes data for update verification. -message HeaderData { - option (gogoproto.goproto_getters) = false; - - // header public key - google.protobuf.Any new_pub_key = 1 [(gogoproto.moretags) = "yaml:\"new_pub_key\""]; - // header diversifier - string new_diversifier = 2 [(gogoproto.moretags) = "yaml:\"new_diversifier\""]; -} - -// ClientStateData returns the SignBytes data for client state verification. -message ClientStateData { - option (gogoproto.goproto_getters) = false; - - bytes path = 1; - google.protobuf.Any client_state = 2 [(gogoproto.moretags) = "yaml:\"client_state\""]; -} - -// ConsensusStateData returns the SignBytes data for consensus state -// verification. -message ConsensusStateData { - option (gogoproto.goproto_getters) = false; - - bytes path = 1; - google.protobuf.Any consensus_state = 2 [(gogoproto.moretags) = "yaml:\"consensus_state\""]; -} - -// ConnectionStateData returns the SignBytes data for connection state -// verification. -message ConnectionStateData { - option (gogoproto.goproto_getters) = false; - - bytes path = 1; - ibc.core.connection.v1.ConnectionEnd connection = 2; -} - -// ChannelStateData returns the SignBytes data for channel state -// verification. -message ChannelStateData { - option (gogoproto.goproto_getters) = false; - - bytes path = 1; - ibc.core.channel.v1.Channel channel = 2; -} - -// PacketCommitmentData returns the SignBytes data for packet commitment -// verification. -message PacketCommitmentData { - bytes path = 1; - bytes commitment = 2; -} - -// PacketAcknowledgementData returns the SignBytes data for acknowledgement -// verification. -message PacketAcknowledgementData { - bytes path = 1; - bytes acknowledgement = 2; -} - -// PacketReceiptAbsenceData returns the SignBytes data for -// packet receipt absence verification. -message PacketReceiptAbsenceData { - bytes path = 1; -} - -// NextSequenceRecvData returns the SignBytes data for verification of the next -// sequence to be received. -message NextSequenceRecvData { - bytes path = 1; - uint64 next_seq_recv = 2 [(gogoproto.moretags) = "yaml:\"next_seq_recv\""]; -} diff --git a/third_party/proto/ibc/lightclients/tendermint/v1/tendermint.proto b/third_party/proto/ibc/lightclients/tendermint/v1/tendermint.proto deleted file mode 100644 index 7dd925f58d..0000000000 --- a/third_party/proto/ibc/lightclients/tendermint/v1/tendermint.proto +++ /dev/null @@ -1,115 +0,0 @@ -syntax = "proto3"; - -package ibc.lightclients.tendermint.v1; - -option go_package = "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types"; - -import "tendermint/types/validator.proto"; -import "tendermint/types/types.proto"; -import "confio/proofs.proto"; -import "google/protobuf/duration.proto"; -import "google/protobuf/timestamp.proto"; -import "ibc/core/client/v1/client.proto"; -import "ibc/core/commitment/v1/commitment.proto"; -import "gogoproto/gogo.proto"; - -// ClientState from Tendermint tracks the current validator set, latest height, -// and a possible frozen height. -message ClientState { - option (gogoproto.goproto_getters) = false; - - string chain_id = 1; - Fraction trust_level = 2 [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"trust_level\""]; - // duration of the period since the LastestTimestamp during which the - // submitted headers are valid for upgrade - google.protobuf.Duration trusting_period = 3 - [(gogoproto.nullable) = false, (gogoproto.stdduration) = true, (gogoproto.moretags) = "yaml:\"trusting_period\""]; - // duration of the staking unbonding period - google.protobuf.Duration unbonding_period = 4 [ - (gogoproto.nullable) = false, - (gogoproto.stdduration) = true, - (gogoproto.moretags) = "yaml:\"unbonding_period\"" - ]; - // defines how much new (untrusted) header's Time can drift into the future. - google.protobuf.Duration max_clock_drift = 5 - [(gogoproto.nullable) = false, (gogoproto.stdduration) = true, (gogoproto.moretags) = "yaml:\"max_clock_drift\""]; - // Block height when the client was frozen due to a misbehaviour - ibc.core.client.v1.Height frozen_height = 6 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"frozen_height\""]; - // Latest height the client was updated to - ibc.core.client.v1.Height latest_height = 7 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"latest_height\""]; - - // Proof specifications used in verifying counterparty state - repeated ics23.ProofSpec proof_specs = 8 [(gogoproto.moretags) = "yaml:\"proof_specs\""]; - - // Path at which next upgraded client will be committed. - // Each element corresponds to the key for a single CommitmentProof in the - // chained proof. NOTE: ClientState must stored under - // `{upgradePath}/{upgradeHeight}/clientState` ConsensusState must be stored - // under `{upgradepath}/{upgradeHeight}/consensusState` For SDK chains using - // the default upgrade module, upgrade_path should be []string{"upgrade", - // "upgradedIBCState"}` - repeated string upgrade_path = 9 [(gogoproto.moretags) = "yaml:\"upgrade_path\""]; - - // This flag, when set to true, will allow governance to recover a client - // which has expired - bool allow_update_after_expiry = 10 [(gogoproto.moretags) = "yaml:\"allow_update_after_expiry\""]; - // This flag, when set to true, will allow governance to unfreeze a client - // whose chain has experienced a misbehaviour event - bool allow_update_after_misbehaviour = 11 [(gogoproto.moretags) = "yaml:\"allow_update_after_misbehaviour\""]; -} - -// ConsensusState defines the consensus state from Tendermint. -message ConsensusState { - option (gogoproto.goproto_getters) = false; - - // timestamp that corresponds to the block height in which the ConsensusState - // was stored. - google.protobuf.Timestamp timestamp = 1 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; - // commitment root (i.e app hash) - ibc.core.commitment.v1.MerkleRoot root = 2 [(gogoproto.nullable) = false]; - bytes next_validators_hash = 3 [ - (gogoproto.casttype) = "github.com/tendermint/tendermint/libs/bytes.HexBytes", - (gogoproto.moretags) = "yaml:\"next_validators_hash\"" - ]; -} - -// Misbehaviour is a wrapper over two conflicting Headers -// that implements Misbehaviour interface expected by ICS-02 -message Misbehaviour { - option (gogoproto.goproto_getters) = false; - - string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; - Header header_1 = 2 [(gogoproto.customname) = "Header1", (gogoproto.moretags) = "yaml:\"header_1\""]; - Header header_2 = 3 [(gogoproto.customname) = "Header2", (gogoproto.moretags) = "yaml:\"header_2\""]; -} - -// Header defines the Tendermint client consensus Header. -// It encapsulates all the information necessary to update from a trusted -// Tendermint ConsensusState. The inclusion of TrustedHeight and -// TrustedValidators allows this update to process correctly, so long as the -// ConsensusState for the TrustedHeight exists, this removes race conditions -// among relayers The SignedHeader and ValidatorSet are the new untrusted update -// fields for the client. The TrustedHeight is the height of a stored -// ConsensusState on the client that will be used to verify the new untrusted -// header. The Trusted ConsensusState must be within the unbonding period of -// current time in order to correctly verify, and the TrustedValidators must -// hash to TrustedConsensusState.NextValidatorsHash since that is the last -// trusted validator set at the TrustedHeight. -message Header { - .tendermint.types.SignedHeader signed_header = 1 - [(gogoproto.embed) = true, (gogoproto.moretags) = "yaml:\"signed_header\""]; - - .tendermint.types.ValidatorSet validator_set = 2 [(gogoproto.moretags) = "yaml:\"validator_set\""]; - ibc.core.client.v1.Height trusted_height = 3 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"trusted_height\""]; - .tendermint.types.ValidatorSet trusted_validators = 4 [(gogoproto.moretags) = "yaml:\"trusted_validators\""]; -} - -// Fraction defines the protobuf message type for tmmath.Fraction that only -// supports positive values. -message Fraction { - uint64 numerator = 1; - uint64 denominator = 2; -} diff --git a/third_party/proto/tendermint/abci/types.proto b/third_party/proto/tendermint/abci/types.proto deleted file mode 100644 index 2cbcabb29b..0000000000 --- a/third_party/proto/tendermint/abci/types.proto +++ /dev/null @@ -1,407 +0,0 @@ -syntax = "proto3"; -package tendermint.abci; - -option go_package = "github.com/tendermint/tendermint/abci/types"; - -// For more information on gogo.proto, see: -// https://github.com/gogo/protobuf/blob/master/extensions.md -import "tendermint/crypto/proof.proto"; -import "tendermint/types/types.proto"; -import "tendermint/crypto/keys.proto"; -import "tendermint/types/params.proto"; -import "google/protobuf/timestamp.proto"; -import "gogoproto/gogo.proto"; - -// This file is copied from http://github.com/tendermint/abci -// NOTE: When using custom types, mind the warnings. -// https://github.com/gogo/protobuf/blob/master/custom_types.md#warnings-and-issues - -//---------------------------------------- -// Request types - -message Request { - oneof value { - RequestEcho echo = 1; - RequestFlush flush = 2; - RequestInfo info = 3; - RequestSetOption set_option = 4; - RequestInitChain init_chain = 5; - RequestQuery query = 6; - RequestBeginBlock begin_block = 7; - RequestCheckTx check_tx = 8; - RequestDeliverTx deliver_tx = 9; - RequestEndBlock end_block = 10; - RequestCommit commit = 11; - RequestListSnapshots list_snapshots = 12; - RequestOfferSnapshot offer_snapshot = 13; - RequestLoadSnapshotChunk load_snapshot_chunk = 14; - RequestApplySnapshotChunk apply_snapshot_chunk = 15; - } -} - -message RequestEcho { - string message = 1; -} - -message RequestFlush {} - -message RequestInfo { - string version = 1; - uint64 block_version = 2; - uint64 p2p_version = 3; -} - -// nondeterministic -message RequestSetOption { - string key = 1; - string value = 2; -} - -message RequestInitChain { - google.protobuf.Timestamp time = 1 - [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; - string chain_id = 2; - ConsensusParams consensus_params = 3; - repeated ValidatorUpdate validators = 4 [(gogoproto.nullable) = false]; - bytes app_state_bytes = 5; - int64 initial_height = 6; -} - -message RequestQuery { - bytes data = 1; - string path = 2; - int64 height = 3; - bool prove = 4; -} - -message RequestBeginBlock { - bytes hash = 1; - tendermint.types.Header header = 2 [(gogoproto.nullable) = false]; - LastCommitInfo last_commit_info = 3 [(gogoproto.nullable) = false]; - repeated Evidence byzantine_validators = 4 [(gogoproto.nullable) = false]; -} - -enum CheckTxType { - NEW = 0 [(gogoproto.enumvalue_customname) = "New"]; - RECHECK = 1 [(gogoproto.enumvalue_customname) = "Recheck"]; -} - -message RequestCheckTx { - bytes tx = 1; - CheckTxType type = 2; -} - -message RequestDeliverTx { - bytes tx = 1; -} - -message RequestEndBlock { - int64 height = 1; -} - -message RequestCommit {} - -// lists available snapshots -message RequestListSnapshots { -} - -// offers a snapshot to the application -message RequestOfferSnapshot { - Snapshot snapshot = 1; // snapshot offered by peers - bytes app_hash = 2; // light client-verified app hash for snapshot height -} - -// loads a snapshot chunk -message RequestLoadSnapshotChunk { - uint64 height = 1; - uint32 format = 2; - uint32 chunk = 3; -} - -// Applies a snapshot chunk -message RequestApplySnapshotChunk { - uint32 index = 1; - bytes chunk = 2; - string sender = 3; -} - -//---------------------------------------- -// Response types - -message Response { - oneof value { - ResponseException exception = 1; - ResponseEcho echo = 2; - ResponseFlush flush = 3; - ResponseInfo info = 4; - ResponseSetOption set_option = 5; - ResponseInitChain init_chain = 6; - ResponseQuery query = 7; - ResponseBeginBlock begin_block = 8; - ResponseCheckTx check_tx = 9; - ResponseDeliverTx deliver_tx = 10; - ResponseEndBlock end_block = 11; - ResponseCommit commit = 12; - ResponseListSnapshots list_snapshots = 13; - ResponseOfferSnapshot offer_snapshot = 14; - ResponseLoadSnapshotChunk load_snapshot_chunk = 15; - ResponseApplySnapshotChunk apply_snapshot_chunk = 16; - } -} - -// nondeterministic -message ResponseException { - string error = 1; -} - -message ResponseEcho { - string message = 1; -} - -message ResponseFlush {} - -message ResponseInfo { - string data = 1; - - string version = 2; - uint64 app_version = 3; - - int64 last_block_height = 4; - bytes last_block_app_hash = 5; -} - -// nondeterministic -message ResponseSetOption { - uint32 code = 1; - // bytes data = 2; - string log = 3; - string info = 4; -} - -message ResponseInitChain { - ConsensusParams consensus_params = 1; - repeated ValidatorUpdate validators = 2 [(gogoproto.nullable) = false]; - bytes app_hash = 3; -} - -message ResponseQuery { - uint32 code = 1; - // bytes data = 2; // use "value" instead. - string log = 3; // nondeterministic - string info = 4; // nondeterministic - int64 index = 5; - bytes key = 6; - bytes value = 7; - tendermint.crypto.ProofOps proof_ops = 8; - int64 height = 9; - string codespace = 10; -} - -message ResponseBeginBlock { - repeated Event events = 1 - [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"]; -} - -message ResponseCheckTx { - uint32 code = 1; - bytes data = 2; - string log = 3; // nondeterministic - string info = 4; // nondeterministic - int64 gas_wanted = 5 [json_name = "gas_wanted"]; - int64 gas_used = 6 [json_name = "gas_used"]; - repeated Event events = 7 - [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"]; - string codespace = 8; -} - -message ResponseDeliverTx { - uint32 code = 1; - bytes data = 2; - string log = 3; // nondeterministic - string info = 4; // nondeterministic - int64 gas_wanted = 5 [json_name = "gas_wanted"]; - int64 gas_used = 6 [json_name = "gas_used"]; - repeated Event events = 7 - [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"]; - string codespace = 8; -} - -message ResponseEndBlock { - repeated ValidatorUpdate validator_updates = 1 - [(gogoproto.nullable) = false]; - ConsensusParams consensus_param_updates = 2; - repeated Event events = 3 - [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"]; -} - -message ResponseCommit { - // reserve 1 - bytes data = 2; - int64 retain_height = 3; -} - -message ResponseListSnapshots { - repeated Snapshot snapshots = 1; -} - -message ResponseOfferSnapshot { - Result result = 1; - - enum Result { - UNKNOWN = 0; // Unknown result, abort all snapshot restoration - ACCEPT = 1; // Snapshot accepted, apply chunks - ABORT = 2; // Abort all snapshot restoration - REJECT = 3; // Reject this specific snapshot, try others - REJECT_FORMAT = 4; // Reject all snapshots of this format, try others - REJECT_SENDER = 5; // Reject all snapshots from the sender(s), try others - } -} - -message ResponseLoadSnapshotChunk { - bytes chunk = 1; -} - -message ResponseApplySnapshotChunk { - Result result = 1; - repeated uint32 refetch_chunks = 2; // Chunks to refetch and reapply - repeated string reject_senders = 3; // Chunk senders to reject and ban - - enum Result { - UNKNOWN = 0; // Unknown result, abort all snapshot restoration - ACCEPT = 1; // Chunk successfully accepted - ABORT = 2; // Abort all snapshot restoration - RETRY = 3; // Retry chunk (combine with refetch and reject) - RETRY_SNAPSHOT = 4; // Retry snapshot (combine with refetch and reject) - REJECT_SNAPSHOT = 5; // Reject this snapshot, try others - } -} - -//---------------------------------------- -// Misc. - -// ConsensusParams contains all consensus-relevant parameters -// that can be adjusted by the abci app -message ConsensusParams { - BlockParams block = 1; - tendermint.types.EvidenceParams evidence = 2; - tendermint.types.ValidatorParams validator = 3; - tendermint.types.VersionParams version = 4; -} - -// BlockParams contains limits on the block size. -message BlockParams { - // Note: must be greater than 0 - int64 max_bytes = 1; - // Note: must be greater or equal to -1 - int64 max_gas = 2; -} - -message LastCommitInfo { - int32 round = 1; - repeated VoteInfo votes = 2 [(gogoproto.nullable) = false]; -} - -// Event allows application developers to attach additional information to -// ResponseBeginBlock, ResponseEndBlock, ResponseCheckTx and ResponseDeliverTx. -// Later, transactions may be queried using these events. -message Event { - string type = 1; - repeated EventAttribute attributes = 2 [ - (gogoproto.nullable) = false, - (gogoproto.jsontag) = "attributes,omitempty" - ]; -} - -// EventAttribute is a single key-value pair, associated with an event. -message EventAttribute { - bytes key = 1; - bytes value = 2; - bool index = 3; // nondeterministic -} - -// TxResult contains results of executing the transaction. -// -// One usage is indexing transaction results. -message TxResult { - int64 height = 1; - uint32 index = 2; - bytes tx = 3; - ResponseDeliverTx result = 4 [(gogoproto.nullable) = false]; -} - -//---------------------------------------- -// Blockchain Types - -// Validator -message Validator { - bytes address = 1; // The first 20 bytes of SHA256(public key) - // PubKey pub_key = 2 [(gogoproto.nullable)=false]; - int64 power = 3; // The voting power -} - -// ValidatorUpdate -message ValidatorUpdate { - tendermint.crypto.PublicKey pub_key = 1 [(gogoproto.nullable) = false]; - int64 power = 2; -} - -// VoteInfo -message VoteInfo { - Validator validator = 1 [(gogoproto.nullable) = false]; - bool signed_last_block = 2; -} - -enum EvidenceType { - UNKNOWN = 0; - DUPLICATE_VOTE = 1; - LIGHT_CLIENT_ATTACK = 2; -} - -message Evidence { - EvidenceType type = 1; - // The offending validator - Validator validator = 2 [(gogoproto.nullable) = false]; - // The height when the offense occurred - int64 height = 3; - // The corresponding time where the offense occurred - google.protobuf.Timestamp time = 4 [ - (gogoproto.nullable) = false, - (gogoproto.stdtime) = true - ]; - // Total voting power of the validator set in case the ABCI application does - // not store historical validators. - // https://github.com/tendermint/tendermint/issues/4581 - int64 total_voting_power = 5; -} - -//---------------------------------------- -// State Sync Types - -message Snapshot { - uint64 height = 1; // The height at which the snapshot was taken - uint32 format = 2; // The application-specific snapshot format - uint32 chunks = 3; // Number of chunks in the snapshot - bytes hash = 4; // Arbitrary snapshot hash, equal only if identical - bytes metadata = 5; // Arbitrary application metadata -} - -//---------------------------------------- -// Service Definition - -service ABCIApplication { - rpc Echo(RequestEcho) returns (ResponseEcho); - rpc Flush(RequestFlush) returns (ResponseFlush); - rpc Info(RequestInfo) returns (ResponseInfo); - rpc SetOption(RequestSetOption) returns (ResponseSetOption); - rpc DeliverTx(RequestDeliverTx) returns (ResponseDeliverTx); - rpc CheckTx(RequestCheckTx) returns (ResponseCheckTx); - rpc Query(RequestQuery) returns (ResponseQuery); - rpc Commit(RequestCommit) returns (ResponseCommit); - rpc InitChain(RequestInitChain) returns (ResponseInitChain); - rpc BeginBlock(RequestBeginBlock) returns (ResponseBeginBlock); - rpc EndBlock(RequestEndBlock) returns (ResponseEndBlock); - rpc ListSnapshots(RequestListSnapshots) returns (ResponseListSnapshots); - rpc OfferSnapshot(RequestOfferSnapshot) returns (ResponseOfferSnapshot); - rpc LoadSnapshotChunk(RequestLoadSnapshotChunk) returns (ResponseLoadSnapshotChunk); - rpc ApplySnapshotChunk(RequestApplySnapshotChunk) returns (ResponseApplySnapshotChunk); -} diff --git a/third_party/proto/tendermint/crypto/keys.proto b/third_party/proto/tendermint/crypto/keys.proto deleted file mode 100644 index 16fd7adf3e..0000000000 --- a/third_party/proto/tendermint/crypto/keys.proto +++ /dev/null @@ -1,17 +0,0 @@ -syntax = "proto3"; -package tendermint.crypto; - -option go_package = "github.com/tendermint/tendermint/proto/tendermint/crypto"; - -import "gogoproto/gogo.proto"; - -// PublicKey defines the keys available for use with Tendermint Validators -message PublicKey { - option (gogoproto.compare) = true; - option (gogoproto.equal) = true; - - oneof sum { - bytes ed25519 = 1; - bytes secp256k1 = 2; - } -} diff --git a/third_party/proto/tendermint/crypto/proof.proto b/third_party/proto/tendermint/crypto/proof.proto deleted file mode 100644 index 975df76853..0000000000 --- a/third_party/proto/tendermint/crypto/proof.proto +++ /dev/null @@ -1,41 +0,0 @@ -syntax = "proto3"; -package tendermint.crypto; - -option go_package = "github.com/tendermint/tendermint/proto/tendermint/crypto"; - -import "gogoproto/gogo.proto"; - -message Proof { - int64 total = 1; - int64 index = 2; - bytes leaf_hash = 3; - repeated bytes aunts = 4; -} - -message ValueOp { - // Encoded in ProofOp.Key. - bytes key = 1; - - // To encode in ProofOp.Data - Proof proof = 2; -} - -message DominoOp { - string key = 1; - string input = 2; - string output = 3; -} - -// ProofOp defines an operation used for calculating Merkle root -// The data could be arbitrary format, providing nessecary data -// for example neighbouring node hash -message ProofOp { - string type = 1; - bytes key = 2; - bytes data = 3; -} - -// ProofOps is Merkle proof defined by the list of ProofOps -message ProofOps { - repeated ProofOp ops = 1 [(gogoproto.nullable) = false]; -} diff --git a/third_party/proto/tendermint/libs/bits/types.proto b/third_party/proto/tendermint/libs/bits/types.proto deleted file mode 100644 index 3111d113a5..0000000000 --- a/third_party/proto/tendermint/libs/bits/types.proto +++ /dev/null @@ -1,9 +0,0 @@ -syntax = "proto3"; -package tendermint.libs.bits; - -option go_package = "github.com/tendermint/tendermint/proto/tendermint/libs/bits"; - -message BitArray { - int64 bits = 1; - repeated uint64 elems = 2; -} diff --git a/third_party/proto/tendermint/types/params.proto b/third_party/proto/tendermint/types/params.proto deleted file mode 100644 index 0de7d846fb..0000000000 --- a/third_party/proto/tendermint/types/params.proto +++ /dev/null @@ -1,80 +0,0 @@ -syntax = "proto3"; -package tendermint.types; - -option go_package = "github.com/tendermint/tendermint/proto/tendermint/types"; - -import "gogoproto/gogo.proto"; -import "google/protobuf/duration.proto"; - -option (gogoproto.equal_all) = true; - -// ConsensusParams contains consensus critical parameters that determine the -// validity of blocks. -message ConsensusParams { - BlockParams block = 1 [(gogoproto.nullable) = false]; - EvidenceParams evidence = 2 [(gogoproto.nullable) = false]; - ValidatorParams validator = 3 [(gogoproto.nullable) = false]; - VersionParams version = 4 [(gogoproto.nullable) = false]; -} - -// BlockParams contains limits on the block size. -message BlockParams { - // Max block size, in bytes. - // Note: must be greater than 0 - int64 max_bytes = 1; - // Max gas per block. - // Note: must be greater or equal to -1 - int64 max_gas = 2; - // Minimum time increment between consecutive blocks (in milliseconds) If the - // block header timestamp is ahead of the system clock, decrease this value. - // - // Not exposed to the application. - int64 time_iota_ms = 3; -} - -// EvidenceParams determine how we handle evidence of malfeasance. -message EvidenceParams { - // Max age of evidence, in blocks. - // - // The basic formula for calculating this is: MaxAgeDuration / {average block - // time}. - int64 max_age_num_blocks = 1; - - // Max age of evidence, in time. - // - // It should correspond with an app's "unbonding period" or other similar - // mechanism for handling [Nothing-At-Stake - // attacks](https://github.com/ethereum/wiki/wiki/Proof-of-Stake-FAQ#what-is-the-nothing-at-stake-problem-and-how-can-it-be-fixed). - google.protobuf.Duration max_age_duration = 2 - [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; - - // This sets the maximum size of total evidence in bytes that can be committed in a single block. - // and should fall comfortably under the max block bytes. - // Default is 1048576 or 1MB - int64 max_bytes = 3; -} - -// ValidatorParams restrict the public key types validators can use. -// NOTE: uses ABCI pubkey naming, not Amino names. -message ValidatorParams { - option (gogoproto.populate) = true; - option (gogoproto.equal) = true; - - repeated string pub_key_types = 1; -} - -// VersionParams contains the ABCI application version. -message VersionParams { - option (gogoproto.populate) = true; - option (gogoproto.equal) = true; - - uint64 app_version = 1; -} - -// HashedParams is a subset of ConsensusParams. -// -// It is hashed into the Header.ConsensusHash. -message HashedParams { - int64 block_max_bytes = 1; - int64 block_max_gas = 2; -} diff --git a/third_party/proto/tendermint/types/types.proto b/third_party/proto/tendermint/types/types.proto deleted file mode 100644 index 7f7ea74cac..0000000000 --- a/third_party/proto/tendermint/types/types.proto +++ /dev/null @@ -1,157 +0,0 @@ -syntax = "proto3"; -package tendermint.types; - -option go_package = "github.com/tendermint/tendermint/proto/tendermint/types"; - -import "gogoproto/gogo.proto"; -import "google/protobuf/timestamp.proto"; -import "tendermint/crypto/proof.proto"; -import "tendermint/version/types.proto"; -import "tendermint/types/validator.proto"; - -// BlockIdFlag indicates which BlcokID the signature is for -enum BlockIDFlag { - option (gogoproto.goproto_enum_stringer) = true; - option (gogoproto.goproto_enum_prefix) = false; - - BLOCK_ID_FLAG_UNKNOWN = 0 [(gogoproto.enumvalue_customname) = "BlockIDFlagUnknown"]; - BLOCK_ID_FLAG_ABSENT = 1 [(gogoproto.enumvalue_customname) = "BlockIDFlagAbsent"]; - BLOCK_ID_FLAG_COMMIT = 2 [(gogoproto.enumvalue_customname) = "BlockIDFlagCommit"]; - BLOCK_ID_FLAG_NIL = 3 [(gogoproto.enumvalue_customname) = "BlockIDFlagNil"]; -} - -// SignedMsgType is a type of signed message in the consensus. -enum SignedMsgType { - option (gogoproto.goproto_enum_stringer) = true; - option (gogoproto.goproto_enum_prefix) = false; - - SIGNED_MSG_TYPE_UNKNOWN = 0 [(gogoproto.enumvalue_customname) = "UnknownType"]; - // Votes - SIGNED_MSG_TYPE_PREVOTE = 1 [(gogoproto.enumvalue_customname) = "PrevoteType"]; - SIGNED_MSG_TYPE_PRECOMMIT = 2 [(gogoproto.enumvalue_customname) = "PrecommitType"]; - - // Proposals - SIGNED_MSG_TYPE_PROPOSAL = 32 [(gogoproto.enumvalue_customname) = "ProposalType"]; -} - -// PartsetHeader -message PartSetHeader { - uint32 total = 1; - bytes hash = 2; -} - -message Part { - uint32 index = 1; - bytes bytes = 2; - tendermint.crypto.Proof proof = 3 [(gogoproto.nullable) = false]; -} - -// BlockID -message BlockID { - bytes hash = 1; - PartSetHeader part_set_header = 2 [(gogoproto.nullable) = false]; -} - -// -------------------------------- - -// Header defines the structure of a Tendermint block header. -message Header { - // basic block info - tendermint.version.Consensus version = 1 [(gogoproto.nullable) = false]; - string chain_id = 2 [(gogoproto.customname) = "ChainID"]; - int64 height = 3; - google.protobuf.Timestamp time = 4 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; - - // prev block info - BlockID last_block_id = 5 [(gogoproto.nullable) = false]; - - // hashes of block data - bytes last_commit_hash = 6; // commit from validators from the last block - bytes data_hash = 7; // transactions - - // hashes from the app output from the prev block - bytes validators_hash = 8; // validators for the current block - bytes next_validators_hash = 9; // validators for the next block - bytes consensus_hash = 10; // consensus params for current block - bytes app_hash = 11; // state after txs from the previous block - bytes last_results_hash = 12; // root hash of all results from the txs from the previous block - - // consensus info - bytes evidence_hash = 13; // evidence included in the block - bytes proposer_address = 14; // original proposer of the block -} - -// Data contains the set of transactions included in the block -message Data { - // Txs that will be applied by state @ block.Height+1. - // NOTE: not all txs here are valid. We're just agreeing on the order first. - // This means that block.AppHash does not include these txs. - repeated bytes txs = 1; -} - -// Vote represents a prevote, precommit, or commit vote from validators for -// consensus. -message Vote { - SignedMsgType type = 1; - int64 height = 2; - int32 round = 3; - BlockID block_id = 4 - [(gogoproto.nullable) = false, (gogoproto.customname) = "BlockID"]; // zero if vote is nil. - google.protobuf.Timestamp timestamp = 5 - [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; - bytes validator_address = 6; - int32 validator_index = 7; - bytes signature = 8; -} - -// Commit contains the evidence that a block was committed by a set of validators. -message Commit { - int64 height = 1; - int32 round = 2; - BlockID block_id = 3 [(gogoproto.nullable) = false, (gogoproto.customname) = "BlockID"]; - repeated CommitSig signatures = 4 [(gogoproto.nullable) = false]; -} - -// CommitSig is a part of the Vote included in a Commit. -message CommitSig { - BlockIDFlag block_id_flag = 1; - bytes validator_address = 2; - google.protobuf.Timestamp timestamp = 3 - [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; - bytes signature = 4; -} - -message Proposal { - SignedMsgType type = 1; - int64 height = 2; - int32 round = 3; - int32 pol_round = 4; - BlockID block_id = 5 [(gogoproto.customname) = "BlockID", (gogoproto.nullable) = false]; - google.protobuf.Timestamp timestamp = 6 - [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; - bytes signature = 7; -} - -message SignedHeader { - Header header = 1; - Commit commit = 2; -} - -message LightBlock { - SignedHeader signed_header = 1; - tendermint.types.ValidatorSet validator_set = 2; -} - -message BlockMeta { - BlockID block_id = 1 [(gogoproto.customname) = "BlockID", (gogoproto.nullable) = false]; - int64 block_size = 2; - Header header = 3 [(gogoproto.nullable) = false]; - int64 num_txs = 4; -} - -// TxProof represents a Merkle proof of the presence of a transaction in the Merkle tree. -message TxProof { - bytes root_hash = 1; - bytes data = 2; - tendermint.crypto.Proof proof = 3; -} diff --git a/third_party/proto/tendermint/types/validator.proto b/third_party/proto/tendermint/types/validator.proto deleted file mode 100644 index 49860b96d6..0000000000 --- a/third_party/proto/tendermint/types/validator.proto +++ /dev/null @@ -1,25 +0,0 @@ -syntax = "proto3"; -package tendermint.types; - -option go_package = "github.com/tendermint/tendermint/proto/tendermint/types"; - -import "gogoproto/gogo.proto"; -import "tendermint/crypto/keys.proto"; - -message ValidatorSet { - repeated Validator validators = 1; - Validator proposer = 2; - int64 total_voting_power = 3; -} - -message Validator { - bytes address = 1; - tendermint.crypto.PublicKey pub_key = 2 [(gogoproto.nullable) = false]; - int64 voting_power = 3; - int64 proposer_priority = 4; -} - -message SimpleValidator { - tendermint.crypto.PublicKey pub_key = 1; - int64 voting_power = 2; -} diff --git a/third_party/proto/tendermint/version/types.proto b/third_party/proto/tendermint/version/types.proto deleted file mode 100644 index 6061868bd4..0000000000 --- a/third_party/proto/tendermint/version/types.proto +++ /dev/null @@ -1,24 +0,0 @@ -syntax = "proto3"; -package tendermint.version; - -option go_package = "github.com/tendermint/tendermint/proto/tendermint/version"; - -import "gogoproto/gogo.proto"; - -// App includes the protocol and software version for the application. -// This information is included in ResponseInfo. The App.Protocol can be -// updated in ResponseEndBlock. -message App { - uint64 protocol = 1; - string software = 2; -} - -// Consensus captures the consensus rules for processing a block in the blockchain, -// including all blockchain data structures and the rules of the application's -// state transition machine. -message Consensus { - option (gogoproto.equal) = true; - - uint64 block = 1; - uint64 app = 2; -} diff --git a/x/ccv/consumer/ibc_module.go b/x/ccv/consumer/ibc_module.go index b3dde3d48a..410ca0d0fa 100644 --- a/x/ccv/consumer/ibc_module.go +++ b/x/ccv/consumer/ibc_module.go @@ -5,14 +5,17 @@ import ( "strings" errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" - porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" - host "github.com/cosmos/ibc-go/v4/modules/core/24-host" - ibcexported "github.com/cosmos/ibc-go/v4/modules/core/exported" + + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/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" + host "github.com/cosmos/ibc-go/v7/modules/core/24-host" + ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" + "github.com/cosmos/interchain-security/v2/x/ccv/consumer/keeper" consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" diff --git a/x/ccv/consumer/ibc_module_test.go b/x/ccv/consumer/ibc_module_test.go index 4c8377a8c8..18bbba83cf 100644 --- a/x/ccv/consumer/ibc_module_test.go +++ b/x/ccv/consumer/ibc_module_test.go @@ -5,15 +5,16 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" - conntypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/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" + host "github.com/cosmos/ibc-go/v7/modules/core/24-host" testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" "github.com/cosmos/interchain-security/v2/x/ccv/consumer" consumerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/consumer/keeper" providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) diff --git a/x/ccv/consumer/keeper/changeover.go b/x/ccv/consumer/keeper/changeover.go index 57770a077d..1221792d3c 100644 --- a/x/ccv/consumer/keeper/changeover.go +++ b/x/ccv/consumer/keeper/changeover.go @@ -1,8 +1,8 @@ package keeper import ( + abci "github.com/cometbft/cometbft/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" - abci "github.com/tendermint/tendermint/abci/types" ) // ChangeoverIsComplete returns whether the standalone to consumer changeover process is complete. diff --git a/x/ccv/consumer/keeper/changeover_test.go b/x/ccv/consumer/keeper/changeover_test.go index 971811c204..9296dcb951 100644 --- a/x/ccv/consumer/keeper/changeover_test.go +++ b/x/ccv/consumer/keeper/changeover_test.go @@ -3,13 +3,13 @@ package keeper_test import ( "testing" + abci "github.com/cometbft/cometbft/abci/types" sdkcryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/cosmos/interchain-security/v2/testutil/crypto" uthelpers "github.com/cosmos/interchain-security/v2/testutil/keeper" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" ) func TestChangeoverToConsumer(t *testing.T) { diff --git a/x/ccv/consumer/keeper/distribution.go b/x/ccv/consumer/keeper/distribution.go index 6d56f6c901..fac98c3cfc 100644 --- a/x/ccv/consumer/keeper/distribution.go +++ b/x/ccv/consumer/keeper/distribution.go @@ -7,9 +7,9 @@ import ( errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" - transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/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" "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" @@ -78,7 +78,7 @@ func (k Keeper) DistributeRewardsInternally(ctx sdk.Context) { // tokens do not go through the consumer redistribute split twice in the // event that the transfer fails the tokens are returned to the consumer // chain. - remainingTokens := fpTokens.Sub(consRedistrTokens) + remainingTokens := fpTokens.Sub(consRedistrTokens...) err = k.bankKeeper.SendCoinsFromModuleToModule(ctx, k.feeCollectorName, types.ConsumerToSendToProviderName, remainingTokens) if err != nil { @@ -113,7 +113,6 @@ func (k Keeper) SendRewardsToProvider(ctx sdk.Context) error { timeoutTimestamp := uint64(ctx.BlockTime().Add(transferTimeoutPeriod).UnixNano()) sentCoins := sdk.NewCoins() - // iterate over all whitelisted reward denoms for _, denom := range k.AllowedRewardDenoms(ctx) { // get the balance of the denom in the toSendToProviderTokens address @@ -121,16 +120,17 @@ func (k Keeper) SendRewardsToProvider(ctx sdk.Context) error { // if the balance is not zero, if !balance.IsZero() { - // send the balance to the provider - err := k.ibcTransferKeeper.SendTransfer(ctx, - transfertypes.PortID, - ch, - balance, - tstProviderAddr, - providerAddr, - timeoutHeight, - timeoutTimestamp, - ) + packetTransfer := &transfertypes.MsgTransfer{ + SourcePort: transfertypes.PortID, + SourceChannel: ch, + Token: balance, + Sender: tstProviderAddr.String(), // consumer address to send from + Receiver: providerAddr, // provider fee pool address to send to + TimeoutHeight: timeoutHeight, // timeout height disabled + TimeoutTimestamp: timeoutTimestamp, + Memo: "consumer chain rewards distribution", + } + _, err := k.ibcTransferKeeper.Transfer(ctx, packetTransfer) if err != nil { return err } @@ -250,7 +250,7 @@ func (k Keeper) GetEstimatedNextFeeDistribution(ctx sdk.Context) types.NextFeeDi totalTokens := sdk.NewDecCoinsFromCoins(total...) // truncated decimals are implicitly added to provider consumerTokens, _ := totalTokens.MulDec(frac).TruncateDecimal() - providerTokens := total.Sub(consumerTokens) + providerTokens := total.Sub(consumerTokens...) return types.NextFeeDistributionEstimate{ CurrentHeight: ctx.BlockHeight(), diff --git a/x/ccv/consumer/keeper/distribution_test.go b/x/ccv/consumer/keeper/distribution_test.go index 7e17157c3d..bb09c7e26b 100644 --- a/x/ccv/consumer/keeper/distribution_test.go +++ b/x/ccv/consumer/keeper/distribution_test.go @@ -37,7 +37,7 @@ func TestGetEstimatedNextFeeDistribution(t *testing.T) { feeAmountCoins := sdk.Coins([]sdk.Coin{feeAmount}) feeAmountDec := sdk.NewDecCoinsFromCoins(feeAmountCoins...) consumerTokens, _ := feeAmountDec.MulDec(fracDec).TruncateDecimal() - providerTokens := feeAmountCoins.Sub(consumerTokens) + providerTokens := feeAmountCoins.Sub(consumerTokens...) mAcc := authTypes.NewModuleAccount(&authTypes.BaseAccount{}, "", "auth") // Setup mock calls diff --git a/x/ccv/consumer/keeper/genesis.go b/x/ccv/consumer/keeper/genesis.go index 08f6327909..04c97dd4e3 100644 --- a/x/ccv/consumer/keeper/genesis.go +++ b/x/ccv/consumer/keeper/genesis.go @@ -7,7 +7,7 @@ import ( consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" - abci "github.com/tendermint/tendermint/abci/types" + abci "github.com/cometbft/cometbft/abci/types" ) // InitGenesis initializes the CCV consumer state and binds to PortID. @@ -108,13 +108,12 @@ func (k Keeper) InitGenesis(ctx sdk.Context, state *consumertypes.GenesisState) // populate cross chain validators states with initial valset k.ApplyCCValidatorChanges(ctx, state.InitialValSet) - return state.InitialValSet } // ExportGenesis returns the CCV consumer module's exported genesis func (k Keeper) ExportGenesis(ctx sdk.Context) (genesis *consumertypes.GenesisState) { - params := k.GetParams(ctx) + params := k.GetConsumerParams(ctx) if !params.Enabled { return consumertypes.DefaultGenesisState() } diff --git a/x/ccv/consumer/keeper/genesis_test.go b/x/ccv/consumer/keeper/genesis_test.go index 55c5c41b19..f05d8c960f 100644 --- a/x/ccv/consumer/keeper/genesis_test.go +++ b/x/ccv/consumer/keeper/genesis_test.go @@ -4,19 +4,21 @@ import ( "testing" "time" + abci "github.com/cometbft/cometbft/abci/types" + tmtypes "github.com/cometbft/cometbft/types" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" - ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" "github.com/cosmos/interchain-security/v2/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" consumerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/consumer/keeper" ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" - tmtypes "github.com/tendermint/tendermint/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" @@ -57,8 +59,6 @@ func TestInitGenesis(t *testing.T) { clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"upgrade", "upgradedIBCState"}, - true, - true, ) matPackets := []consumertypes.MaturingVSCPacket{ @@ -72,7 +72,7 @@ func TestInitGenesis(t *testing.T) { { Type: ccv.SlashPacket, Data: &ccv.ConsumerPacketData_SlashPacketData{ - SlashPacketData: ccv.NewSlashPacketData(abciValidator, vscID, stakingtypes.Downtime), + SlashPacketData: ccv.NewSlashPacketData(abciValidator, vscID, stakingtypes.Infraction_INFRACTION_DOWNTIME), }, }, { @@ -125,7 +125,7 @@ func TestInitGenesis(t *testing.T) { assertHeightValsetUpdateIDs(t, ctx, &ck, defaultHeightValsetUpdateIDs) require.Equal(t, validator.Address.Bytes(), ck.GetAllCCValidator(ctx)[0].Address) - require.Equal(t, gs.Params, ck.GetParams(ctx)) + require.Equal(t, gs.Params, ck.GetConsumerParams(ctx)) }, }, { "restart a chain without an established CCV channel", @@ -152,7 +152,7 @@ func TestInitGenesis(t *testing.T) { assertHeightValsetUpdateIDs(t, ctx, &ck, defaultHeightValsetUpdateIDs) assertProviderClientID(t, ctx, &ck, provClientID) require.Equal(t, validator.Address.Bytes(), ck.GetAllCCValidator(ctx)[0].Address) - require.Equal(t, gs.Params, ck.GetParams(ctx)) + require.Equal(t, gs.Params, ck.GetConsumerParams(ctx)) }, }, { "restart a chain with an established CCV channel", @@ -196,7 +196,7 @@ func TestInitGenesis(t *testing.T) { assertHeightValsetUpdateIDs(t, ctx, &ck, updatedHeightValsetUpdateIDs) assertProviderClientID(t, ctx, &ck, provClientID) - require.Equal(t, gs.Params, ck.GetParams(ctx)) + require.Equal(t, gs.Params, ck.GetConsumerParams(ctx)) }, }, } @@ -250,7 +250,7 @@ func TestExportGenesis(t *testing.T) { { Type: ccv.SlashPacket, Data: &ccv.ConsumerPacketData_SlashPacketData{ - SlashPacketData: ccv.NewSlashPacketData(abciValidator, vscID, stakingtypes.Downtime), + SlashPacketData: ccv.NewSlashPacketData(abciValidator, vscID, stakingtypes.Infraction_INFRACTION_DOWNTIME), }, }, { diff --git a/x/ccv/consumer/keeper/grpc_query.go b/x/ccv/consumer/keeper/grpc_query.go index 7fc2e0faeb..9658edf64c 100644 --- a/x/ccv/consumer/keeper/grpc_query.go +++ b/x/ccv/consumer/keeper/grpc_query.go @@ -34,7 +34,7 @@ func (k Keeper) QueryParams(c context.Context, return nil, status.Errorf(codes.InvalidArgument, "empty request") } - p := k.GetParams(ctx) + p := k.GetConsumerParams(ctx) return &types.QueryParamsResponse{Params: p}, nil } diff --git a/x/ccv/consumer/keeper/hooks.go b/x/ccv/consumer/keeper/hooks.go index 6067f2adb3..33a756d525 100644 --- a/x/ccv/consumer/keeper/hooks.go +++ b/x/ccv/consumer/keeper/hooks.go @@ -17,8 +17,10 @@ func (k Keeper) Hooks() Hooks { return Hooks{k} } -func (k Keeper) AfterValidatorBonded(ctx sdk.Context, consAddr sdk.ConsAddress, _ sdk.ValAddress) { +func (k Keeper) AfterValidatorBonded(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) error { if k.hooks != nil { - k.hooks.AfterValidatorBonded(ctx, consAddr, nil) + err := k.hooks.AfterValidatorBonded(ctx, consAddr, nil) + return err } + return nil } diff --git a/x/ccv/consumer/keeper/keeper.go b/x/ccv/consumer/keeper/keeper.go index d420bb9bd4..b50b330efa 100644 --- a/x/ccv/consumer/keeper/keeper.go +++ b/x/ccv/consumer/keeper/keeper.go @@ -12,21 +12,23 @@ import ( paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - conntypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v4/modules/core/24-host" - + 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" + host "github.com/cosmos/ibc-go/v7/modules/core/24-host" + + tmtypes "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/libs/log" + storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" - tmtypes "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/libs/log" ) // Keeper defines the Cross-Chain Validation Consumer Keeper type Keeper struct { - storeKey sdk.StoreKey + storeKey storetypes.StoreKey cdc codec.BinaryCodec paramStore paramtypes.Subspace scopedKeeper ccv.ScopedKeeper @@ -51,7 +53,7 @@ type Keeper struct { // NOTE: the feeCollectorName is in reference to the consumer-chain fee // collector (and not the provider chain) func NewKeeper( - cdc codec.BinaryCodec, key sdk.StoreKey, paramSpace paramtypes.Subspace, + cdc codec.BinaryCodec, key storetypes.StoreKey, paramSpace paramtypes.Subspace, scopedKeeper ccv.ScopedKeeper, channelKeeper ccv.ChannelKeeper, portKeeper ccv.PortKeeper, connectionKeeper ccv.ConnectionKeeper, clientKeeper ccv.ClientKeeper, @@ -86,6 +88,16 @@ func NewKeeper( return k } +// Returns a keeper with cdc, key and paramSpace set it does not raise any panics during registration (eg with IBCKeeper). +// Used only in testing. +func NewNonZeroKeeper(cdc codec.BinaryCodec, key storetypes.StoreKey, paramSpace paramtypes.Subspace) Keeper { + return Keeper{ + storeKey: key, + cdc: cdc, + paramStore: paramSpace, + } +} + // SetStandaloneStakingKeeper sets the standalone staking keeper for the consumer chain. // This method should only be called for previously standalone chains that are now consumers. func (k *Keeper) SetStandaloneStakingKeeper(sk ccv.StakingKeeper) { @@ -128,7 +140,7 @@ func (k Keeper) mustValidateFields() { // Logger returns a module-specific logger. func (k Keeper) Logger(ctx sdk.Context) log.Logger { - return ctx.Logger().With("module", "x/"+host.ModuleName+"-"+types.ModuleName) + return ctx.Logger().With("module", "x/"+host.SubModuleName+"-"+types.ModuleName) } func (k *Keeper) SetHooks(sh ccv.ConsumerHooks) *Keeper { @@ -565,6 +577,21 @@ func (k Keeper) GetAllCCValidator(ctx sdk.Context) (validators []types.CrossChai return validators } +// Implement from stakingkeeper interface +func (k Keeper) GetAllValidators(ctx sdk.Context) (validators []stakingtypes.Validator) { + store := ctx.KVStore(k.storeKey) + + iterator := sdk.KVStorePrefixIterator(store, stakingtypes.ValidatorsKey) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + validator := stakingtypes.MustUnmarshalValidator(k.cdc, iterator.Value()) + validators = append(validators, validator) + } + + return validators +} + // SetPendingPackets sets the pending CCV packets func (k Keeper) SetPendingPackets(ctx sdk.Context, packets ccv.ConsumerPacketDataList) { store := ctx.KVStore(k.storeKey) diff --git a/x/ccv/consumer/keeper/keeper_test.go b/x/ccv/consumer/keeper/keeper_test.go index fe523ce7cf..c6443958b6 100644 --- a/x/ccv/consumer/keeper/keeper_test.go +++ b/x/ccv/consumer/keeper/keeper_test.go @@ -6,17 +6,19 @@ import ( "testing" "time" + abci "github.com/cometbft/cometbft/abci/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" - conntypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + + conntypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" "github.com/cosmos/interchain-security/v2/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" ) @@ -336,7 +338,7 @@ func TestSetPendingPackets(t *testing.T) { SlashPacketData: ccv.NewSlashPacketData( abci.Validator{Address: ed25519.GenPrivKey().PubKey().Address(), Power: int64(0)}, 3, - stakingtypes.DoubleSign, + stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN, ), }, }, @@ -359,7 +361,7 @@ func TestSetPendingPackets(t *testing.T) { Power: int64(2), }, uint64(4), - stakingtypes.Downtime, + stakingtypes.Infraction_INFRACTION_DOWNTIME, ) dataPackets = append(dataPackets, ccv.ConsumerPacketData{ Type: ccv.SlashPacket, diff --git a/x/ccv/consumer/keeper/migration.go b/x/ccv/consumer/keeper/migration.go deleted file mode 100644 index a44b89404b..0000000000 --- a/x/ccv/consumer/keeper/migration.go +++ /dev/null @@ -1,79 +0,0 @@ -package keeper - -import ( - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" - ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" -) - -// Migrator is a struct for handling in-place store migrations. -type Migrator struct { - ccvConsumerKeeper Keeper - ccvConsumerParamSpace paramtypes.Subspace -} - -// NewMigrator returns a new Migrator. -func NewMigrator(ccvConsumerKeeper Keeper, ccvConsumerParamSpace paramtypes.Subspace) Migrator { - return Migrator{ccvConsumerKeeper: ccvConsumerKeeper, ccvConsumerParamSpace: ccvConsumerParamSpace} -} - -// Note: If migrating from v1.2.0-multiden to v2.0.0, there are no migrations required. -// This is due to the fact that the former version includes both of: -// - https://github.com/cosmos/interchain-security/commit/54e9852d3c89a2513cd0170a56c6eec894fc878d -// - https://github.com/cosmos/interchain-security/pull/833 -// both of which handle the introduction of new params. - -// Migratev1Tov2 migrates a consumer from v1.0.0 to v2.0.0. -func (m Migrator) Migratev1Tov2(ctx sdk.Context) error { - // Migrate params - MigrateParamsv1Tov2(ctx, m.ccvConsumerParamSpace) - - return nil -} - -// MigrateParamsv1Tov2 migrates the consumer CCV module params from v1.0.0 to v2.0.0, -// setting default values for new params. -func MigrateParamsv1Tov2(ctx sdk.Context, paramsSubspace paramtypes.Subspace) { - // Get old params - var enabled bool - paramsSubspace.Get(ctx, consumertypes.KeyEnabled, &enabled) - var blocksPerDistributionTransmission int64 - paramsSubspace.Get(ctx, consumertypes.KeyBlocksPerDistributionTransmission, &blocksPerDistributionTransmission) - var distributionTransmissionChannel string - paramsSubspace.Get(ctx, consumertypes.KeyDistributionTransmissionChannel, &distributionTransmissionChannel) - var providerFeePoolAddrStr string - paramsSubspace.Get(ctx, consumertypes.KeyProviderFeePoolAddrStr, &providerFeePoolAddrStr) - var ccvTimeoutPeriod time.Duration - paramsSubspace.Get(ctx, ccvtypes.KeyCCVTimeoutPeriod, &ccvTimeoutPeriod) - var transferTimeoutPeriod time.Duration - paramsSubspace.Get(ctx, consumertypes.KeyTransferTimeoutPeriod, &transferTimeoutPeriod) - var consumerRedistributionFrac string - paramsSubspace.Get(ctx, consumertypes.KeyConsumerRedistributionFrac, &consumerRedistributionFrac) - var historicalEntries int64 - paramsSubspace.Get(ctx, consumertypes.KeyHistoricalEntries, &historicalEntries) - var unbondingPeriod time.Duration - paramsSubspace.Get(ctx, consumertypes.KeyConsumerUnbondingPeriod, &unbondingPeriod) - - // Recycle old params, set new params to default values - defaultParams := consumertypes.DefaultParams() - newParams := consumertypes.NewParams( - enabled, - blocksPerDistributionTransmission, - distributionTransmissionChannel, - providerFeePoolAddrStr, - ccvTimeoutPeriod, - transferTimeoutPeriod, - consumerRedistributionFrac, - historicalEntries, - unbondingPeriod, - defaultParams.SoftOptOutThreshold, - defaultParams.RewardDenoms, - defaultParams.ProviderRewardDenoms, - ) - - // Persist new params - paramsSubspace.SetParamSet(ctx, &newParams) -} diff --git a/x/ccv/consumer/keeper/migration_test.go b/x/ccv/consumer/keeper/migration_test.go deleted file mode 100644 index 29574a4808..0000000000 --- a/x/ccv/consumer/keeper/migration_test.go +++ /dev/null @@ -1,146 +0,0 @@ -package keeper_test - -import ( - "testing" - "time" - - "github.com/cosmos/cosmos-sdk/codec" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/store" - storetypes "github.com/cosmos/cosmos-sdk/store/types" - sdk "github.com/cosmos/cosmos-sdk/types" - paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - consumerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/consumer/keeper" - consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" - ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" - "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/libs/log" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - tmdb "github.com/tendermint/tm-db" -) - -func TestMigrateParamsv1Tov2(t *testing.T) { - // Setup raw store - db := tmdb.NewMemDB() - stateStore := store.NewCommitMultiStore(db) - storeKey := sdk.NewKVStoreKey(paramtypes.StoreKey) - memStoreKey := storetypes.NewMemoryStoreKey("mem_key") - stateStore.MountStoreWithDB(storeKey, sdk.StoreTypeIAVL, db) - stateStore.MountStoreWithDB(memStoreKey, sdk.StoreTypeMemory, nil) - require.NoError(t, stateStore.LoadLatestVersion()) - registry := codectypes.NewInterfaceRegistry() - cdc := codec.NewProtoCodec(registry) - ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger()) - require.NoError(t, stateStore.LoadLatestVersion()) - - // Create new empty subspace - subspace := paramtypes.NewSubspace(cdc, - codec.NewLegacyAmino(), - storeKey, - memStoreKey, - paramtypes.ModuleName, - ).WithKeyTable(v1KeyTable()) // Note that new param key table is set in keeper constructor - - // Set 9 params from v1.0.0 - subspace.Set(ctx, consumertypes.KeyEnabled, true) - subspace.Set(ctx, consumertypes.KeyBlocksPerDistributionTransmission, int64(10)) - subspace.Set(ctx, consumertypes.KeyDistributionTransmissionChannel, "channel-0") - subspace.Set(ctx, consumertypes.KeyProviderFeePoolAddrStr, "cosmos17p3erf5gv2436fd4vyjwmudakts563a497syuz") - subspace.Set(ctx, ccvtypes.KeyCCVTimeoutPeriod, time.Hour) - subspace.Set(ctx, consumertypes.KeyTransferTimeoutPeriod, time.Hour) - subspace.Set(ctx, consumertypes.KeyConsumerRedistributionFrac, "0.5") - subspace.Set(ctx, consumertypes.KeyHistoricalEntries, int64(10)) - subspace.Set(ctx, consumertypes.KeyConsumerUnbondingPeriod, time.Hour) - - // Confirm 3 new params cannot be set with old key table - require.Panics(t, func() { - subspace.Set(ctx, consumertypes.KeySoftOptOutThreshold, "0.05") - }) - require.Panics(t, func() { - subspace.Set(ctx, consumertypes.KeyRewardDenoms, []string{"untrn"}) - }) - require.Panics(t, func() { - subspace.Set(ctx, consumertypes.KeyProviderRewardDenoms, []string{"uatom"}) - }) - - // Now create new subspace, mocking an upgrade where app initialization happens again - subspace = paramtypes.NewSubspace(cdc, - codec.NewLegacyAmino(), - storeKey, - memStoreKey, - paramtypes.ModuleName, - ).WithKeyTable(consumertypes.ParamKeyTable()) // Use v2 key table, this would be set in keeper constructor upon app init - - // Run migration - consumerkeeper.MigrateParamsv1Tov2(ctx, subspace) - - // Use keeper to confirm params are set correctly - keeper := consumerkeeper.Keeper{} - keeper.SetParamSpace(ctx, subspace) - - params := keeper.GetParams(ctx) - require.Equal(t, true, params.Enabled) - require.Equal(t, int64(10), params.BlocksPerDistributionTransmission) - require.Equal(t, "channel-0", params.DistributionTransmissionChannel) - require.Equal(t, "cosmos17p3erf5gv2436fd4vyjwmudakts563a497syuz", params.ProviderFeePoolAddrStr) - require.Equal(t, time.Hour, params.CcvTimeoutPeriod) - require.Equal(t, time.Hour, params.TransferTimeoutPeriod) - require.Equal(t, "0.5", params.ConsumerRedistributionFraction) - require.Equal(t, int64(10), params.HistoricalEntries) - require.Equal(t, time.Hour, params.UnbondingPeriod) - // 3 new params are set to default values - require.Equal(t, "0.05", params.SoftOptOutThreshold) - require.Equal(t, []string(nil), params.RewardDenoms) - require.Equal(t, []string(nil), params.ProviderRewardDenoms) - - // Set new params to other values - params.SoftOptOutThreshold = "0.1" - params.RewardDenoms = []string{"untrn"} - params.ProviderRewardDenoms = []string{"uatom"} - keeper.SetParams(ctx, params) - - require.Equal(t, "0.1", keeper.GetSoftOptOutThreshold(ctx)) - require.Equal(t, []string{"untrn"}, keeper.GetRewardDenoms(ctx)) - require.Equal(t, []string{"uatom"}, keeper.GetProviderRewardDenoms(ctx)) -} - -// v1KeyTable is a copy of the ParamKeyTable method from v1.0.0 -func v1KeyTable() paramtypes.KeyTable { - return paramtypes.NewKeyTable().RegisterParamSet(&v1Params{}) -} - -// ParamSetPairs implements params.ParamSet for v1Params -func (p *v1Params) ParamSetPairs() paramtypes.ParamSetPairs { - return paramtypes.ParamSetPairs{ - paramtypes.NewParamSetPair(consumertypes.KeyEnabled, p.Enabled, ccvtypes.ValidateBool), - paramtypes.NewParamSetPair(consumertypes.KeyBlocksPerDistributionTransmission, - p.BlocksPerDistributionTransmission, ccvtypes.ValidatePositiveInt64), - paramtypes.NewParamSetPair(consumertypes.KeyDistributionTransmissionChannel, - p.DistributionTransmissionChannel, ccvtypes.ValidateDistributionTransmissionChannel), - paramtypes.NewParamSetPair(consumertypes.KeyProviderFeePoolAddrStr, - p.ProviderFeePoolAddrStr, consumertypes.ValidateProviderFeePoolAddrStr), - paramtypes.NewParamSetPair(ccvtypes.KeyCCVTimeoutPeriod, - p.CcvTimeoutPeriod, ccvtypes.ValidateDuration), - paramtypes.NewParamSetPair(consumertypes.KeyTransferTimeoutPeriod, - p.TransferTimeoutPeriod, ccvtypes.ValidateDuration), - paramtypes.NewParamSetPair(consumertypes.KeyConsumerRedistributionFrac, - p.ConsumerRedistributionFraction, ccvtypes.ValidateStringFraction), - paramtypes.NewParamSetPair(consumertypes.KeyHistoricalEntries, - p.HistoricalEntries, ccvtypes.ValidatePositiveInt64), - paramtypes.NewParamSetPair(consumertypes.KeyConsumerUnbondingPeriod, - p.UnbondingPeriod, ccvtypes.ValidateDuration), - } -} - -// v1Params is a copy of the pb generated Params struct from v1.0.0 -type v1Params struct { - Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` - BlocksPerDistributionTransmission int64 `protobuf:"varint,2,opt,name=blocks_per_distribution_transmission,json=blocksPerDistributionTransmission,proto3" json:"blocks_per_distribution_transmission,omitempty"` - DistributionTransmissionChannel string `protobuf:"bytes,3,opt,name=distribution_transmission_channel,json=distributionTransmissionChannel,proto3" json:"distribution_transmission_channel,omitempty"` - ProviderFeePoolAddrStr string `protobuf:"bytes,4,opt,name=provider_fee_pool_addr_str,json=providerFeePoolAddrStr,proto3" json:"provider_fee_pool_addr_str,omitempty"` - CcvTimeoutPeriod time.Duration `protobuf:"bytes,5,opt,name=ccv_timeout_period,json=ccvTimeoutPeriod,proto3,stdduration" json:"ccv_timeout_period"` - TransferTimeoutPeriod time.Duration `protobuf:"bytes,6,opt,name=transfer_timeout_period,json=transferTimeoutPeriod,proto3,stdduration" json:"transfer_timeout_period"` - ConsumerRedistributionFraction string `protobuf:"bytes,7,opt,name=consumer_redistribution_fraction,json=consumerRedistributionFraction,proto3" json:"consumer_redistribution_fraction,omitempty"` - HistoricalEntries int64 `protobuf:"varint,8,opt,name=historical_entries,json=historicalEntries,proto3" json:"historical_entries,omitempty"` - UnbondingPeriod time.Duration `protobuf:"bytes,9,opt,name=unbonding_period,json=unbondingPeriod,proto3,stdduration" json:"unbonding_period"` -} diff --git a/x/ccv/consumer/keeper/params.go b/x/ccv/consumer/keeper/params.go index 9f9d37e025..ad1a0f2cb5 100644 --- a/x/ccv/consumer/keeper/params.go +++ b/x/ccv/consumer/keeper/params.go @@ -4,13 +4,15 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" ) // GetParams returns the params for the consumer ccv module -func (k Keeper) GetParams(ctx sdk.Context) types.Params { +// NOTE: it is different from the GetParams method which is required to implement StakingKeeper interface +func (k Keeper) GetConsumerParams(ctx sdk.Context) types.Params { return types.NewParams( k.GetEnabled(ctx), k.GetBlocksPerDistributionTransmission(ctx), @@ -32,6 +34,14 @@ func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { k.paramStore.SetParamSet(ctx, ¶ms) } +// GetParams implements StakingKeeper GetParams interface method +// it returns an a empty stakingtypes.Params struct +// NOTE: this method must be implemented on the consumer keeper because the evidence module keeper +// in cosmos-sdk v0.47 requires this exact method with this exact signature to be available on the StakingKeepr +func (k Keeper) GetParams(ctx sdk.Context) stakingtypes.Params { + return stakingtypes.Params{} +} + // GetEnabled returns the enabled flag for the consumer module func (k Keeper) GetEnabled(ctx sdk.Context) bool { var enabled bool diff --git a/x/ccv/consumer/keeper/params_test.go b/x/ccv/consumer/keeper/params_test.go index d28c964e56..d8dd63a1cb 100644 --- a/x/ccv/consumer/keeper/params_test.go +++ b/x/ccv/consumer/keeper/params_test.go @@ -33,14 +33,14 @@ func TestParams(t *testing.T) { provideRewardDenoms, ) // these are the default params, IBC suite independently sets enabled=true - params := consumerKeeper.GetParams(ctx) + params := consumerKeeper.GetConsumerParams(ctx) require.Equal(t, expParams, params) newParams := types.NewParams(false, 1000, "channel-2", "cosmos19pe9pg5dv9k5fzgzmsrgnw9rl9asf7ddwhu7lm", 7*24*time.Hour, 25*time.Hour, "0.5", 500, 24*21*time.Hour, "0.05", []string{"untrn"}, []string{"uatom"}) consumerKeeper.SetParams(ctx, newParams) - params = consumerKeeper.GetParams(ctx) + params = consumerKeeper.GetConsumerParams(ctx) require.Equal(t, newParams, params) consumerKeeper.SetBlocksPerDistributionTransmission(ctx, 10) diff --git a/x/ccv/consumer/keeper/relay.go b/x/ccv/consumer/keeper/relay.go index 2bf1580830..f57891bf98 100644 --- a/x/ccv/consumer/keeper/relay.go +++ b/x/ccv/consumer/keeper/relay.go @@ -5,14 +5,15 @@ import ( "strconv" errorsmod "cosmossdk.io/errors" + abci "github.com/cometbft/cometbft/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" - "github.com/cosmos/ibc-go/v4/modules/core/exported" + 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/ibc-go/v7/modules/core/exported" + "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" - abci "github.com/tendermint/tendermint/abci/types" ) // OnRecvVSCPacket sets the pending validator set changes that will be flushed to ABCI on Endblock @@ -123,9 +124,9 @@ func (k Keeper) QueueVSCMaturedPackets(ctx sdk.Context) { } // QueueSlashPacket appends a slash packet containing the given validator data and slashing info to queue. -func (k Keeper) QueueSlashPacket(ctx sdk.Context, validator abci.Validator, valsetUpdateID uint64, infraction stakingtypes.InfractionType) { +func (k Keeper) QueueSlashPacket(ctx sdk.Context, validator abci.Validator, valsetUpdateID uint64, infraction stakingtypes.Infraction) { consAddr := sdk.ConsAddress(validator.Address) - downtime := infraction == stakingtypes.Downtime + downtime := infraction == stakingtypes.Infraction_INFRACTION_DOWNTIME // return if an outstanding downtime request is set for the validator if downtime && k.OutstandingDowntime(ctx, consAddr) { @@ -183,7 +184,6 @@ func (k Keeper) SendPackets(ctx sdk.Context) { pending := k.GetPendingPackets(ctx) for _, p := range pending.GetList() { - // send packet over IBC err := ccv.SendIBCPacket( ctx, diff --git a/x/ccv/consumer/keeper/relay_test.go b/x/ccv/consumer/keeper/relay_test.go index 60fbbfe719..23b3d99339 100644 --- a/x/ccv/consumer/keeper/relay_test.go +++ b/x/ccv/consumer/keeper/relay_test.go @@ -6,21 +6,24 @@ import ( "testing" "time" + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/libs/bytes" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v7/modules/core/24-host" + "github.com/cosmos/interchain-security/v2/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" "github.com/cosmos/interchain-security/v2/x/ccv/types" + "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/libs/bytes" ) // TestOnRecvVSCPacket tests the behavior of OnRecvVSCPacket over various packet scenarios @@ -232,7 +235,7 @@ func TestOnAcknowledgementPacket(t *testing.T) { consumerKeeper.SetProviderChannel(ctx, channelIDToProvider) packetData := types.NewSlashPacketData( - abci.Validator{Address: bytes.HexBytes{}, Power: int64(1)}, uint64(1), stakingtypes.Downtime, + abci.Validator{Address: bytes.HexBytes{}, Power: int64(1)}, uint64(1), stakingtypes.Infraction_INFRACTION_DOWNTIME, ) // AcknowledgePacket is in reference to a packet originally sent from this (consumer) module. diff --git a/x/ccv/consumer/keeper/soft_opt_out_test.go b/x/ccv/consumer/keeper/soft_opt_out_test.go index d1c9a813de..f243b917d7 100644 --- a/x/ccv/consumer/keeper/soft_opt_out_test.go +++ b/x/ccv/consumer/keeper/soft_opt_out_test.go @@ -3,11 +3,13 @@ package keeper_test import ( "testing" + tmtypes "github.com/cometbft/cometbft/types" + "github.com/cosmos/interchain-security/v2/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" + "github.com/stretchr/testify/require" - tmtypes "github.com/tendermint/tendermint/types" ) // Tests that UpdateSmallestNonOptOutPower updates the smallest validator power that cannot soft opt out. diff --git a/x/ccv/consumer/keeper/validators.go b/x/ccv/consumer/keeper/validators.go index 0c7880602e..0f0f246833 100644 --- a/x/ccv/consumer/keeper/validators.go +++ b/x/ccv/consumer/keeper/validators.go @@ -3,12 +3,13 @@ package keeper import ( "time" + "cosmossdk.io/math" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + abci "github.com/cometbft/cometbft/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" - abci "github.com/tendermint/tendermint/abci/types" ) // @@ -51,8 +52,11 @@ func (k Keeper) ApplyCCValidatorChanges(ctx sdk.Context, changes []abci.Validato } k.SetCCValidator(ctx, ccVal) - k.AfterValidatorBonded(ctx, consAddr, nil) - + err = k.AfterValidatorBonded(ctx, consAddr, nil) + if err != nil { + // AfterValidatorBonded is called by the Slashing module and should not return an error. + panic(err) + } } else { // edge case: we received an update for 0 power // but the validator is already deleted. Do not forward @@ -102,32 +106,40 @@ func (k Keeper) ValidatorByConsAddr(sdk.Context, sdk.ConsAddress) stakingtypes.V return stakingtypes.Validator{} } +// Calls SlashWithInfractionReason with Infraction_INFRACTION_UNSPECIFIED. +// ConsumerKeeper must implement StakingKeeper interface. +// This function should not be called anywhere +func (k Keeper) Slash(ctx sdk.Context, addr sdk.ConsAddress, infractionHeight, power int64, slashFactor sdk.Dec) math.Int { + return k.SlashWithInfractionReason(ctx, addr, infractionHeight, power, slashFactor, stakingtypes.Infraction_INFRACTION_UNSPECIFIED) +} + // Slash queues a slashing request for the the provider chain // All queued slashing requests will be cleared in EndBlock -func (k Keeper) Slash(ctx sdk.Context, addr sdk.ConsAddress, infractionHeight, power int64, slashFactor sdk.Dec, infraction stakingtypes.InfractionType) { - if infraction == stakingtypes.InfractionEmpty { - return +// Called by Slashing keeper in SlashWithInfractionReason +func (k Keeper) SlashWithInfractionReason(ctx sdk.Context, addr sdk.ConsAddress, infractionHeight, power int64, slashFactor sdk.Dec, infraction stakingtypes.Infraction) math.Int { + if infraction == stakingtypes.Infraction_INFRACTION_UNSPECIFIED { + return math.NewInt(0) } // If this is a previously standalone chain and infraction happened before the changeover was completed, // slash only on the standalone staking keeper. if k.IsPrevStandaloneChain(ctx) && infractionHeight < k.FirstConsumerHeight(ctx) { - k.standaloneStakingKeeper.Slash(ctx, addr, infractionHeight, power, slashFactor, stakingtypes.InfractionEmpty) - return + // Slash for a standalone chain does not require an infraction reason so we pass in Infraction_INFRACTION_UNSPECIFIED + return k.standaloneStakingKeeper.SlashWithInfractionReason(ctx, addr, infractionHeight, power, slashFactor, stakingtypes.Infraction_INFRACTION_UNSPECIFIED) } // Otherwise infraction happened after the changeover was completed. // if this is a downtime infraction and the validator is allowed to // soft opt out, do not queue a slash packet - if infraction == stakingtypes.Downtime { + if infraction == stakingtypes.Infraction_INFRACTION_DOWNTIME { if power < k.GetSmallestNonOptOutPower(ctx) { // soft opt out k.Logger(ctx).Debug("soft opt out", "validator", addr, "power", power, ) - return + return math.NewInt(0) } } // get VSC ID for infraction height @@ -138,6 +150,9 @@ func (k Keeper) Slash(ctx sdk.Context, addr sdk.ConsAddress, infractionHeight, p "vscID", vscID, ) + // this is the most important step in the function + // everything else is just here to implement StakingKeeper interface + // IBC packets are created from slash data and sent to the provider during EndBlock k.QueueSlashPacket( ctx, abci.Validator{ @@ -147,6 +162,9 @@ func (k Keeper) Slash(ctx sdk.Context, addr sdk.ConsAddress, infractionHeight, p vscID, infraction, ) + + // Only return to comply with the interface restriction + return math.ZeroInt() } // Jail - unimplemented on CCV keeper @@ -286,3 +304,9 @@ func (k Keeper) MustGetCurrentValidatorsAsABCIUpdates(ctx sdk.Context) []abci.Va } return valUpdates } + +// implement interface method needed for x/genutil in sdk v47 +// returns empty updates and err +func (k Keeper) ApplyAndReturnValidatorSetUpdates(sdk.Context) (updates []abci.ValidatorUpdate, err error) { + return +} diff --git a/x/ccv/consumer/keeper/validators_test.go b/x/ccv/consumer/keeper/validators_test.go index a5ad0898e2..c9ce541794 100644 --- a/x/ccv/consumer/keeper/validators_test.go +++ b/x/ccv/consumer/keeper/validators_test.go @@ -3,6 +3,10 @@ package keeper_test import ( "testing" + "cosmossdk.io/math" + abci "github.com/cometbft/cometbft/abci/types" + tmrand "github.com/cometbft/cometbft/libs/rand" + 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" @@ -11,9 +15,6 @@ import ( "github.com/cosmos/interchain-security/v2/x/ccv/consumer/keeper" "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" - tmrand "github.com/tendermint/tendermint/libs/rand" - tmtypes "github.com/tendermint/tendermint/types" ) // TestApplyCCValidatorChanges tests the ApplyCCValidatorChanges method for a consumer keeper @@ -147,7 +148,7 @@ func TestSlash(t *testing.T) { defer ctrl.Finish() // If we call slash with infraction type empty, no slash packet will be queued - consumerKeeper.Slash(ctx, []byte{0x01, 0x02, 0x03}, 5, 6, sdk.NewDec(9.0), stakingtypes.InfractionEmpty) + consumerKeeper.SlashWithInfractionReason(ctx, []byte{0x01, 0x02, 0x03}, 5, 6, sdk.NewDec(9.0), stakingtypes.Infraction_INFRACTION_UNSPECIFIED) pendingPackets := consumerKeeper.GetPendingPackets(ctx) require.Len(t, pendingPackets.List, 0) @@ -158,7 +159,7 @@ func TestSlash(t *testing.T) { consumerKeeper.SetHeightValsetUpdateID(ctx, 5, 6) // Call slash with valid infraction type and confirm 1 slash packet is queued - consumerKeeper.Slash(ctx, []byte{0x01, 0x02, 0x03}, 5, 6, sdk.NewDec(9.0), stakingtypes.Downtime) + consumerKeeper.SlashWithInfractionReason(ctx, []byte{0x01, 0x02, 0x03}, 5, 6, sdk.NewDec(9.0), stakingtypes.Infraction_INFRACTION_DOWNTIME) pendingPackets = consumerKeeper.GetPendingPackets(ctx) require.Len(t, pendingPackets.List, 1) @@ -173,21 +174,21 @@ func TestSlash(t *testing.T) { // If we call slash with infraction type empty, standalone staking keeper's slash will not be called // (if it was called, test would panic without mocking the call) - consumerKeeper.Slash(ctx, []byte{0x01, 0x02, 0x03}, 5, 6, sdk.NewDec(9.0), stakingtypes.InfractionEmpty) + consumerKeeper.SlashWithInfractionReason(ctx, []byte{0x01, 0x02, 0x03}, 5, 6, sdk.NewDec(9.0), stakingtypes.Infraction_INFRACTION_UNSPECIFIED) // Now setup a mock for Slash, and confirm that it is called against // standalone staking keeper with valid infraction type infractionHeight := int64(5) - mocks.MockStakingKeeper.EXPECT().Slash( + mocks.MockStakingKeeper.EXPECT().SlashWithInfractionReason( ctx, []byte{0x01, 0x02, 0x03}, infractionHeight, int64(6), - sdk.MustNewDecFromStr("0.05"), stakingtypes.InfractionEmpty).Times(1) // We pass empty infraction to standalone staking keeper since it's not used + sdk.MustNewDecFromStr("0.05"), stakingtypes.Infraction_INFRACTION_UNSPECIFIED).Times(1) // We pass empty infraction to standalone staking keeper since it's not used // Also setup init genesis height s.t. infraction height is before first consumer height consumerKeeper.SetInitGenesisHeight(ctx, 4) require.Equal(t, consumerKeeper.FirstConsumerHeight(ctx), int64(6)) - consumerKeeper.Slash(ctx, []byte{0x01, 0x02, 0x03}, infractionHeight, 6, - sdk.MustNewDecFromStr("0.05"), stakingtypes.Downtime) + consumerKeeper.SlashWithInfractionReason(ctx, []byte{0x01, 0x02, 0x03}, infractionHeight, 6, + sdk.MustNewDecFromStr("0.05"), stakingtypes.Infraction_INFRACTION_DOWNTIME) } // Tests the getter and setter behavior for historical info @@ -233,7 +234,7 @@ func TestHistoricalInfo(t *testing.T) { } // IsValSetSorted reports whether valset is sorted. -func IsValSetSorted(data []stakingtypes.Validator, powerReduction sdk.Int) bool { +func IsValSetSorted(data []stakingtypes.Validator, powerReduction math.Int) bool { n := len(data) for i := n - 1; i > 0; i-- { if stakingtypes.ValidatorsByVotingPower(data).Less(i, i-1, powerReduction) { diff --git a/x/ccv/consumer/module.go b/x/ccv/consumer/module.go index 61d62293f2..0e87463884 100644 --- a/x/ccv/consumer/module.go +++ b/x/ccv/consumer/module.go @@ -4,13 +4,12 @@ import ( "context" "encoding/json" "fmt" - "math/rand" + abci "github.com/cometbft/cometbft/abci/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - "github.com/gorilla/mux" + "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/spf13/cobra" - abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" @@ -18,7 +17,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" + porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" "github.com/cosmos/interchain-security/v2/x/ccv/consumer/client/cli" "github.com/cosmos/interchain-security/v2/x/ccv/consumer/keeper" @@ -66,10 +65,6 @@ func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncod return data.Validate() } -// RegisterRESTRoutes implements AppModuleBasic interface -func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Router) { -} - // RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the ibc-consumer module. func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { err := consumertypes.RegisterQueryHandlerClient(context.Background(), mux, consumertypes.NewQueryClient(clientCtx)) @@ -109,29 +104,9 @@ func (AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { // TODO } -// Route implements the AppModule interface -func (am AppModule) Route() sdk.Route { - return sdk.Route{} -} - -// QuerierRoute implements the AppModule interface -func (AppModule) QuerierRoute() string { - return consumertypes.QuerierRoute -} - -// LegacyQuerierHandler implements the AppModule interface -func (am AppModule) LegacyQuerierHandler(*codec.LegacyAmino) sdk.Querier { - return nil -} - // RegisterServices registers module services. func (am AppModule) RegisterServices(cfg module.Configurator) { consumertypes.RegisterQueryServer(cfg.QueryServer(), am.keeper) - - m := keeper.NewMigrator(am.keeper, am.paramSpace) - if err := cfg.RegisterMigration(consumertypes.ModuleName, 1, m.Migratev1Tov2); err != nil { - panic(fmt.Sprintf("failed to register migrator: %s", err)) - } } // InitGenesis performs genesis initialization for the consumer module. It returns @@ -228,17 +203,6 @@ func (am AppModule) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.V func (AppModule) GenerateGenesisState(simState *module.SimulationState) { } -// ProposalContents doesn't return any content functions for governance proposals. -func (AppModule) ProposalContents(_ module.SimulationState) []simtypes.WeightedProposalContent { - return nil -} - -// RandomizedParams creates randomized consumer param changes for the simulator. -// TODO -func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange { - return nil -} - // RegisterStoreDecoder registers a decoder for consumer module's types // TODO func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { diff --git a/x/ccv/consumer/types/consumer.pb.go b/x/ccv/consumer/types/consumer.pb.go index 1c457d2277..dd5d991666 100644 --- a/x/ccv/consumer/types/consumer.pb.go +++ b/x/ccv/consumer/types/consumer.pb.go @@ -5,12 +5,12 @@ package types import ( fmt "fmt" + _ "github.com/cosmos/cosmos-proto" types "github.com/cosmos/cosmos-sdk/codec/types" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + github_com_cosmos_gogoproto_types "github.com/cosmos/gogoproto/types" _ "github.com/cosmos/interchain-security/v2/x/ccv/types" - _ "github.com/gogo/protobuf/gogoproto" - proto "github.com/gogo/protobuf/proto" - github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" - _ "github.com/regen-network/cosmos-proto" _ "google.golang.org/protobuf/types/known/durationpb" _ "google.golang.org/protobuf/types/known/timestamppb" io "io" @@ -64,13 +64,15 @@ type Params struct { // which should be smaller than that of the provider in general. UnbondingPeriod time.Duration `protobuf:"bytes,9,opt,name=unbonding_period,json=unbondingPeriod,proto3,stdduration" json:"unbonding_period"` // The threshold for the percentage of validators at the bottom of the set who - // can opt out of running the consumer chain without being punished. For example, a - // value of 0.05 means that the validators in the bottom 5% of the set can opt out + // can opt out of running the consumer chain without being punished. For + // example, a value of 0.05 means that the validators in the bottom 5% of the + // set can opt out SoftOptOutThreshold string `protobuf:"bytes,10,opt,name=soft_opt_out_threshold,json=softOptOutThreshold,proto3" json:"soft_opt_out_threshold,omitempty"` - // Reward denoms. These are the denominations which are allowed to be sent to the provider as rewards. + // Reward denoms. These are the denominations which are allowed to be sent to + // the provider as rewards. RewardDenoms []string `protobuf:"bytes,11,rep,name=reward_denoms,json=rewardDenoms,proto3" json:"reward_denoms,omitempty"` - // Provider-originated reward denoms. These are denoms coming from the provider - // which are allowed to be used as rewards. e.g. "uatom" + // Provider-originated reward denoms. These are denoms coming from the + // provider which are allowed to be used as rewards. e.g. "uatom" ProviderRewardDenoms []string `protobuf:"bytes,12,rep,name=provider_reward_denoms,json=providerRewardDenoms,proto3" json:"provider_reward_denoms,omitempty"` } @@ -462,7 +464,7 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x52 } - n1, err1 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.UnbondingPeriod, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.UnbondingPeriod):]) + n1, err1 := github_com_cosmos_gogoproto_types.StdDurationMarshalTo(m.UnbondingPeriod, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.UnbondingPeriod):]) if err1 != nil { return 0, err1 } @@ -482,7 +484,7 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x3a } - n2, err2 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.TransferTimeoutPeriod, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.TransferTimeoutPeriod):]) + n2, err2 := github_com_cosmos_gogoproto_types.StdDurationMarshalTo(m.TransferTimeoutPeriod, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.TransferTimeoutPeriod):]) if err2 != nil { return 0, err2 } @@ -490,7 +492,7 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintConsumer(dAtA, i, uint64(n2)) i-- dAtA[i] = 0x32 - n3, err3 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.CcvTimeoutPeriod, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.CcvTimeoutPeriod):]) + n3, err3 := github_com_cosmos_gogoproto_types.StdDurationMarshalTo(m.CcvTimeoutPeriod, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.CcvTimeoutPeriod):]) if err3 != nil { return 0, err3 } @@ -625,7 +627,7 @@ func (m *MaturingVSCPacket) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - n5, err5 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.MaturityTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.MaturityTime):]) + n5, err5 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.MaturityTime, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.MaturityTime):]) if err5 != nil { return 0, err5 } @@ -672,9 +674,9 @@ func (m *Params) Size() (n int) { if l > 0 { n += 1 + l + sovConsumer(uint64(l)) } - l = github_com_gogo_protobuf_types.SizeOfStdDuration(m.CcvTimeoutPeriod) + l = github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.CcvTimeoutPeriod) n += 1 + l + sovConsumer(uint64(l)) - l = github_com_gogo_protobuf_types.SizeOfStdDuration(m.TransferTimeoutPeriod) + l = github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.TransferTimeoutPeriod) n += 1 + l + sovConsumer(uint64(l)) l = len(m.ConsumerRedistributionFraction) if l > 0 { @@ -683,7 +685,7 @@ func (m *Params) Size() (n int) { if m.HistoricalEntries != 0 { n += 1 + sovConsumer(uint64(m.HistoricalEntries)) } - l = github_com_gogo_protobuf_types.SizeOfStdDuration(m.UnbondingPeriod) + l = github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.UnbondingPeriod) n += 1 + l + sovConsumer(uint64(l)) l = len(m.SoftOptOutThreshold) if l > 0 { @@ -745,7 +747,7 @@ func (m *MaturingVSCPacket) Size() (n int) { if m.VscId != 0 { n += 1 + sovConsumer(uint64(m.VscId)) } - l = github_com_gogo_protobuf_types.SizeOfStdTime(m.MaturityTime) + l = github_com_cosmos_gogoproto_types.SizeOfStdTime(m.MaturityTime) n += 1 + l + sovConsumer(uint64(l)) return n } @@ -917,7 +919,7 @@ func (m *Params) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := github_com_gogo_protobuf_types.StdDurationUnmarshal(&m.CcvTimeoutPeriod, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_cosmos_gogoproto_types.StdDurationUnmarshal(&m.CcvTimeoutPeriod, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -950,7 +952,7 @@ func (m *Params) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := github_com_gogo_protobuf_types.StdDurationUnmarshal(&m.TransferTimeoutPeriod, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_cosmos_gogoproto_types.StdDurationUnmarshal(&m.TransferTimeoutPeriod, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -1034,7 +1036,7 @@ func (m *Params) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := github_com_gogo_protobuf_types.StdDurationUnmarshal(&m.UnbondingPeriod, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_cosmos_gogoproto_types.StdDurationUnmarshal(&m.UnbondingPeriod, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -1440,7 +1442,7 @@ func (m *MaturingVSCPacket) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.MaturityTime, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(&m.MaturityTime, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/x/ccv/consumer/types/genesis.go b/x/ccv/consumer/types/genesis.go index a21e434de3..54f6fe9651 100644 --- a/x/ccv/consumer/types/genesis.go +++ b/x/ccv/consumer/types/genesis.go @@ -2,10 +2,10 @@ package types import ( errorsmod "cosmossdk.io/errors" - ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + abci "github.com/cometbft/cometbft/abci/types" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - abci "github.com/tendermint/tendermint/abci/types" + ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" ) // NewInitialGenesisState returns a consumer GenesisState for a completely new consumer chain. diff --git a/x/ccv/consumer/types/genesis.pb.go b/x/ccv/consumer/types/genesis.pb.go index 7e5da62359..cbf6675902 100644 --- a/x/ccv/consumer/types/genesis.pb.go +++ b/x/ccv/consumer/types/genesis.pb.go @@ -5,12 +5,12 @@ package types import ( fmt "fmt" - _ "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" - types "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" - types2 "github.com/cosmos/interchain-security/v2/x/ccv/types" - _ "github.com/gogo/protobuf/gogoproto" - proto "github.com/gogo/protobuf/proto" - types1 "github.com/tendermint/tendermint/abci/types" + types "github.com/cometbft/cometbft/abci/types" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + _ "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + _07_tendermint "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + types1 "github.com/cosmos/interchain-security/v2/x/ccv/types" _ "google.golang.org/protobuf/types/known/durationpb" io "io" math "math" @@ -35,19 +35,19 @@ type GenesisState struct { ProviderChannelId string `protobuf:"bytes,3,opt,name=provider_channel_id,json=providerChannelId,proto3" json:"provider_channel_id,omitempty"` NewChain bool `protobuf:"varint,4,opt,name=new_chain,json=newChain,proto3" json:"new_chain,omitempty"` // ProviderClientState filled in on new chain, nil on restart. - ProviderClientState *types.ClientState `protobuf:"bytes,5,opt,name=provider_client_state,json=providerClientState,proto3" json:"provider_client_state,omitempty"` + ProviderClientState *_07_tendermint.ClientState `protobuf:"bytes,5,opt,name=provider_client_state,json=providerClientState,proto3" json:"provider_client_state,omitempty"` // ProviderConsensusState filled in on new chain, nil on restart. - ProviderConsensusState *types.ConsensusState `protobuf:"bytes,6,opt,name=provider_consensus_state,json=providerConsensusState,proto3" json:"provider_consensus_state,omitempty"` + ProviderConsensusState *_07_tendermint.ConsensusState `protobuf:"bytes,6,opt,name=provider_consensus_state,json=providerConsensusState,proto3" json:"provider_consensus_state,omitempty"` // MaturingPackets nil on new chain, filled in on restart. MaturingPackets []MaturingVSCPacket `protobuf:"bytes,7,rep,name=maturing_packets,json=maturingPackets,proto3" json:"maturing_packets"` // InitialValset filled in on new chain and on restart. - InitialValSet []types1.ValidatorUpdate `protobuf:"bytes,8,rep,name=initial_val_set,json=initialValSet,proto3" json:"initial_val_set"` + InitialValSet []types.ValidatorUpdate `protobuf:"bytes,8,rep,name=initial_val_set,json=initialValSet,proto3" json:"initial_val_set"` // HeightToValsetUpdateId nil on new chain, filled in on restart. HeightToValsetUpdateId []HeightToValsetUpdateID `protobuf:"bytes,9,rep,name=height_to_valset_update_id,json=heightToValsetUpdateId,proto3" json:"height_to_valset_update_id"` // OutstandingDowntimes nil on new chain, filled in on restart. OutstandingDowntimeSlashing []OutstandingDowntime `protobuf:"bytes,10,rep,name=outstanding_downtime_slashing,json=outstandingDowntimeSlashing,proto3" json:"outstanding_downtime_slashing"` // PendingConsumerPackets nil on new chain, filled in on restart. - PendingConsumerPackets types2.ConsumerPacketDataList `protobuf:"bytes,11,opt,name=pending_consumer_packets,json=pendingConsumerPackets,proto3" json:"pending_consumer_packets"` + PendingConsumerPackets types1.ConsumerPacketDataList `protobuf:"bytes,11,opt,name=pending_consumer_packets,json=pendingConsumerPackets,proto3" json:"pending_consumer_packets"` // LastTransmissionBlockHeight nil on new chain, filled in on restart. LastTransmissionBlockHeight LastTransmissionBlockHeight `protobuf:"bytes,12,opt,name=last_transmission_block_height,json=lastTransmissionBlockHeight,proto3" json:"last_transmission_block_height"` PreCCV bool `protobuf:"varint,13,opt,name=preCCV,proto3" json:"preCCV,omitempty"` @@ -114,14 +114,14 @@ func (m *GenesisState) GetNewChain() bool { return false } -func (m *GenesisState) GetProviderClientState() *types.ClientState { +func (m *GenesisState) GetProviderClientState() *_07_tendermint.ClientState { if m != nil { return m.ProviderClientState } return nil } -func (m *GenesisState) GetProviderConsensusState() *types.ConsensusState { +func (m *GenesisState) GetProviderConsensusState() *_07_tendermint.ConsensusState { if m != nil { return m.ProviderConsensusState } @@ -135,7 +135,7 @@ func (m *GenesisState) GetMaturingPackets() []MaturingVSCPacket { return nil } -func (m *GenesisState) GetInitialValSet() []types1.ValidatorUpdate { +func (m *GenesisState) GetInitialValSet() []types.ValidatorUpdate { if m != nil { return m.InitialValSet } @@ -156,11 +156,11 @@ func (m *GenesisState) GetOutstandingDowntimeSlashing() []OutstandingDowntime { return nil } -func (m *GenesisState) GetPendingConsumerPackets() types2.ConsumerPacketDataList { +func (m *GenesisState) GetPendingConsumerPackets() types1.ConsumerPacketDataList { if m != nil { return m.PendingConsumerPackets } - return types2.ConsumerPacketDataList{} + return types1.ConsumerPacketDataList{} } func (m *GenesisState) GetLastTransmissionBlockHeight() LastTransmissionBlockHeight { @@ -853,7 +853,7 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { return io.ErrUnexpectedEOF } if m.ProviderClientState == nil { - m.ProviderClientState = &types.ClientState{} + m.ProviderClientState = &_07_tendermint.ClientState{} } if err := m.ProviderClientState.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -889,7 +889,7 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { return io.ErrUnexpectedEOF } if m.ProviderConsensusState == nil { - m.ProviderConsensusState = &types.ConsensusState{} + m.ProviderConsensusState = &_07_tendermint.ConsensusState{} } if err := m.ProviderConsensusState.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -958,7 +958,7 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.InitialValSet = append(m.InitialValSet, types1.ValidatorUpdate{}) + m.InitialValSet = append(m.InitialValSet, types.ValidatorUpdate{}) if err := m.InitialValSet[len(m.InitialValSet)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } diff --git a/x/ccv/consumer/types/genesis_test.go b/x/ccv/consumer/types/genesis_test.go index 0398b39f54..af1badb73b 100644 --- a/x/ccv/consumer/types/genesis_test.go +++ b/x/ccv/consumer/types/genesis_test.go @@ -7,14 +7,14 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" - ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" - abci "github.com/tendermint/tendermint/abci/types" + abci "github.com/cometbft/cometbft/abci/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" - tmtypes "github.com/tendermint/tendermint/types" + tmtypes "github.com/cometbft/cometbft/types" "github.com/cosmos/interchain-security/v2/testutil/crypto" @@ -47,7 +47,7 @@ func TestValidateInitialGenesisState(t *testing.T) { valHash := valSet.Hash() valUpdates := tmtypes.TM2PB.ValidatorUpdates(valSet) - cs := ibctmtypes.NewClientState(chainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) + cs := ibctmtypes.NewClientState(chainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath) consensusState := ibctmtypes.NewConsensusState(time.Now(), commitmenttypes.NewMerkleRoot([]byte("apphash")), valHash) params := types.DefaultParams() @@ -285,7 +285,7 @@ func TestValidateRestartGenesisState(t *testing.T) { SlashPacketData: ccv.NewSlashPacketData( abci.Validator{Address: pubKey.Address(), Power: int64(1)}, 1, - stakingtypes.Downtime), + stakingtypes.Infraction_INFRACTION_DOWNTIME), }, } @@ -294,7 +294,7 @@ func TestValidateRestartGenesisState(t *testing.T) { {Height: 0, ValsetUpdateId: 0}, } - cs := ibctmtypes.NewClientState(chainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) + cs := ibctmtypes.NewClientState(chainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath) consensusState := ibctmtypes.NewConsensusState(time.Now(), commitmenttypes.NewMerkleRoot([]byte("apphash")), valHash) params := types.DefaultParams() diff --git a/x/ccv/consumer/types/query.pb.go b/x/ccv/consumer/types/query.pb.go index 53c84a1f47..a89562d8e1 100644 --- a/x/ccv/consumer/types/query.pb.go +++ b/x/ccv/consumer/types/query.pb.go @@ -6,9 +6,9 @@ package types import ( context "context" fmt "fmt" - _ "github.com/gogo/protobuf/gogoproto" - grpc1 "github.com/gogo/protobuf/grpc" - proto "github.com/gogo/protobuf/proto" + _ "github.com/cosmos/gogoproto/gogoproto" + grpc1 "github.com/cosmos/gogoproto/grpc" + proto "github.com/cosmos/gogoproto/proto" _ "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 b0008e7082..3d5ca0ed74 100644 --- a/x/ccv/democracy/distribution/module.go +++ b/x/ccv/democracy/distribution/module.go @@ -9,13 +9,14 @@ import ( "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" distr "github.com/cosmos/cosmos-sdk/x/distribution" + "github.com/cosmos/cosmos-sdk/x/distribution/exported" "github.com/cosmos/cosmos-sdk/x/distribution/keeper" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" + abci "github.com/cometbft/cometbft/abci/types" distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" - abci "github.com/tendermint/tendermint/abci/types" ) var ( @@ -46,9 +47,9 @@ type AppModule struct { // AppModule constructor. func NewAppModule( cdc codec.Codec, keeper keeper.Keeper, ak distrtypes.AccountKeeper, - bk distrtypes.BankKeeper, sk stakingkeeper.Keeper, feeCollectorName string, + bk distrtypes.BankKeeper, sk stakingkeeper.Keeper, feeCollectorName string, subspace exported.Subspace, ) AppModule { - distrAppMod := distr.NewAppModule(cdc, keeper, ak, bk, sk) + distrAppMod := distr.NewAppModule(cdc, keeper, ak, bk, sk, subspace) return AppModule{ AppModule: distrAppMod, keeper: keeper, diff --git a/x/ccv/democracy/governance/module.go b/x/ccv/democracy/governance/module.go index f90e93d7a9..c293a9e3e3 100644 --- a/x/ccv/democracy/governance/module.go +++ b/x/ccv/democracy/governance/module.go @@ -7,10 +7,12 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" + abci "github.com/cometbft/cometbft/abci/types" gov "github.com/cosmos/cosmos-sdk/x/gov" - "github.com/cosmos/cosmos-sdk/x/gov/keeper" + govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - abci "github.com/tendermint/tendermint/abci/types" + govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" ) const ( @@ -27,22 +29,35 @@ type AppModule struct { // embed the Cosmos SDK's x/governance AppModule gov.AppModule - keeper keeper.Keeper - isProposalWhitelisted func(govtypes.Content) bool + keeper govkeeper.Keeper + isLegacyProposalWhitelisted func(govv1beta1.Content) bool + isModuleWhiteList func(string) bool +} + +type ParamChangeKey struct { + MsgType, Key string } // NewAppModule creates a new AppModule object using the native x/governance module AppModule constructor. -func NewAppModule(cdc codec.Codec, keeper keeper.Keeper, ak govtypes.AccountKeeper, bk govtypes.BankKeeper, isProposalWhitelisted func(govtypes.Content) bool) AppModule { - govAppModule := gov.NewAppModule(cdc, keeper, ak, bk) +func NewAppModule(cdc codec.Codec, + keeper govkeeper.Keeper, + ak govtypes.AccountKeeper, + bk govtypes.BankKeeper, + isProposalWhitelisted func(govv1beta1.Content) bool, + ss govtypes.ParamSubspace, + isModuleWhiteList func(string) bool, +) AppModule { + govAppModule := gov.NewAppModule(cdc, &keeper, ak, bk, ss) return AppModule{ - AppModule: govAppModule, - keeper: keeper, - isProposalWhitelisted: isProposalWhitelisted, + AppModule: govAppModule, + keeper: keeper, + isLegacyProposalWhitelisted: isProposalWhitelisted, + isModuleWhiteList: isModuleWhiteList, } } func (am AppModule) EndBlock(ctx sdk.Context, request abci.RequestEndBlock) []abci.ValidatorUpdate { - am.keeper.IterateActiveProposalsQueue(ctx, ctx.BlockHeader().Time, func(proposal govtypes.Proposal) bool { + am.keeper.IterateActiveProposalsQueue(ctx, ctx.BlockHeader().Time, func(proposal govv1.Proposal) bool { // if there are forbidden proposals in active proposals queue, refund deposit, delete votes for that proposal // and delete proposal from all storages deleteForbiddenProposal(ctx, am, proposal) @@ -52,8 +67,35 @@ func (am AppModule) EndBlock(ctx sdk.Context, request abci.RequestEndBlock) []ab return am.AppModule.EndBlock(ctx, request) } -func deleteForbiddenProposal(ctx sdk.Context, am AppModule, proposal govtypes.Proposal) { - if am.isProposalWhitelisted(proposal.GetContent()) { +// isProposalWhitelisted checks whether a proposal is whitelisted +func isProposalWhitelisted(ctx sdk.Context, am AppModule, proposal govv1.Proposal) bool { + messages := proposal.GetMessages() + + // iterate over all the proposal messages + for _, message := range messages { + sdkMsg, isLegacyProposal := message.GetCachedValue().(*govv1.MsgExecLegacyContent) + if isLegacyProposal { + // legacy gov proposal content + content, err := govv1.LegacyContentFromMessage(sdkMsg) + if err != nil { + continue + } + if !am.isLegacyProposalWhitelisted(content) { + // not whitelisted + return false + } + // not legacy gov proposal content + } else if !am.isModuleWhiteList(message.TypeUrl) { + // not whitelisted + return false + } + } + return true +} + +// deleteForbiddenProposal removes proposals that are not whitelisted +func deleteForbiddenProposal(ctx sdk.Context, am AppModule, proposal govv1.Proposal) { + if isProposalWhitelisted(ctx, am, proposal) { return } @@ -63,13 +105,13 @@ func deleteForbiddenProposal(ctx sdk.Context, am AppModule, proposal govtypes.Pr // private and cannot be called directly from the overridden app module am.keeper.Tally(ctx, proposal) - am.keeper.DeleteProposal(ctx, proposal.ProposalId) - am.keeper.RefundDeposits(ctx, proposal.ProposalId) + am.keeper.DeleteProposal(ctx, proposal.Id) + am.keeper.RefundAndDeleteDeposits(ctx, proposal.Id) ctx.EventManager().EmitEvent( sdk.NewEvent( govtypes.EventTypeActiveProposal, - sdk.NewAttribute(govtypes.AttributeKeyProposalID, fmt.Sprintf("%d", proposal.ProposalId)), + sdk.NewAttribute(govtypes.AttributeKeyProposalID, fmt.Sprintf("%d", proposal.Id)), sdk.NewAttribute(govtypes.AttributeKeyProposalResult, AttributeValueProposalForbidden), ), ) @@ -77,7 +119,7 @@ func deleteForbiddenProposal(ctx sdk.Context, am AppModule, proposal govtypes.Pr logger := am.keeper.Logger(ctx) logger.Info( "proposal is not whitelisted; deleted", - "proposal", proposal.ProposalId, + "proposal", proposal.Id, "title", proposal.GetTitle(), - "total_deposit", proposal.TotalDeposit.String()) + "total_deposit", proposal.TotalDeposit) } diff --git a/x/ccv/democracy/staking/module.go b/x/ccv/democracy/staking/module.go index d2eaf26adb..78489a0166 100644 --- a/x/ccv/democracy/staking/module.go +++ b/x/ccv/democracy/staking/module.go @@ -3,13 +3,14 @@ package staking import ( "encoding/json" + abci "github.com/cometbft/cometbft/abci/types" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/staking" + "github.com/cosmos/cosmos-sdk/x/staking/exported" "github.com/cosmos/cosmos-sdk/x/staking/keeper" "github.com/cosmos/cosmos-sdk/x/staking/types" - abci "github.com/tendermint/tendermint/abci/types" ) // Note: for a democracy consumer, this "democracy staking" keeper is only for governance capabilities, @@ -39,8 +40,8 @@ type AppModule struct { // NewAppModule creates a new AppModule object using the native x/staking module // AppModule constructor. -func NewAppModule(cdc codec.Codec, keeper keeper.Keeper, ak types.AccountKeeper, bk types.BankKeeper) AppModule { - stakingAppMod := staking.NewAppModule(cdc, keeper, ak, bk) +func NewAppModule(cdc codec.Codec, keeper keeper.Keeper, ak types.AccountKeeper, bk types.BankKeeper, subspace exported.Subspace) AppModule { + stakingAppMod := staking.NewAppModule(cdc, &keeper, ak, bk, subspace) return AppModule{ AppModule: stakingAppMod, keeper: keeper, @@ -61,7 +62,7 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json. var genesisState types.GenesisState cdc.MustUnmarshalJSON(data, &genesisState) - _ = staking.InitGenesis(ctx, am.keeper, am.accKeeper, am.bankKeeper, &genesisState) + _ = am.keeper.InitGenesis(ctx, &genesisState) return []abci.ValidatorUpdate{} } diff --git a/x/ccv/provider/client/cli/tx.go b/x/ccv/provider/client/cli/tx.go index 73b1df34c3..a0b9343d8a 100644 --- a/x/ccv/provider/client/cli/tx.go +++ b/x/ccv/provider/client/cli/tx.go @@ -42,8 +42,11 @@ func NewAssignConsumerKeyCmd() *cobra.Command { return err } - txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()). - WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever) + txf, err := tx.NewFactoryCLI(clientCtx, cmd.Flags()) + if err != nil { + return err + } + txf = txf.WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever) providerValAddr := clientCtx.GetFromAddress() diff --git a/x/ccv/provider/client/proposal_handler.go b/x/ccv/provider/client/proposal_handler.go index 76491b86d2..6ccd855ef8 100644 --- a/x/ccv/provider/client/proposal_handler.go +++ b/x/ccv/provider/client/proposal_handler.go @@ -4,7 +4,6 @@ import ( "context" "encoding/json" "fmt" - "net/http" "os" "path/filepath" "time" @@ -12,20 +11,20 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/tx" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/rest" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" govclient "github.com/cosmos/cosmos-sdk/x/gov/client" - govrest "github.com/cosmos/cosmos-sdk/x/gov/client/rest" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" "github.com/spf13/cobra" ) var ( - ConsumerAdditionProposalHandler = govclient.NewProposalHandler(SubmitConsumerAdditionPropTxCmd, ConsumerAdditionProposalRESTHandler) - ConsumerRemovalProposalHandler = govclient.NewProposalHandler(SubmitConsumerRemovalProposalTxCmd, ConsumerRemovalProposalRESTHandler) - EquivocationProposalHandler = govclient.NewProposalHandler(SubmitEquivocationProposalTxCmd, EquivocationProposalRESTHandler) + ConsumerAdditionProposalHandler = govclient.NewProposalHandler(SubmitConsumerAdditionPropTxCmd) + ConsumerRemovalProposalHandler = govclient.NewProposalHandler(SubmitConsumerRemovalProposalTxCmd) + EquivocationProposalHandler = govclient.NewProposalHandler(SubmitEquivocationProposalTxCmd) ) // SubmitConsumerAdditionPropTxCmd returns a CLI command handler for submitting @@ -41,13 +40,13 @@ The proposal details must be supplied via a JSON file. Unbonding period, transfer timeout period and ccv timeout period should be provided as nanosecond time periods. Example: -$ tx gov submit-proposal consumer-addition --from= +$ tx gov submit-legacy-proposal consumer-addition --from= Where proposal.json contains: { "title": "Create the FooChain", - "description": "Gonna be a great chain", + "summary": "Gonna be a great chain", "chain_id": "foochain", "initial_height": { "revision_number": 2, @@ -81,7 +80,7 @@ Where proposal.json contains: CheckPropUnbondingPeriod(clientCtx, proposal.UnbondingPeriod) content := types.NewConsumerAdditionProposal( - proposal.Title, proposal.Description, proposal.ChainId, proposal.InitialHeight, + proposal.Title, proposal.Summary, proposal.ChainId, proposal.InitialHeight, proposal.GenesisHash, proposal.BinaryHash, proposal.SpawnTime, proposal.ConsumerRedistributionFraction, proposal.BlocksPerDistributionTransmission, proposal.DistributionTransmissionChannel, proposal.HistoricalEntries, @@ -94,7 +93,12 @@ Where proposal.json contains: return err } - msg, err := govtypes.NewMsgSubmitProposal(content, deposit, from) + msgContent, err := govv1.NewLegacyContent(content, authtypes.NewModuleAddress(govtypes.ModuleName).String()) + if err != nil { + return err + } + + msg, err := govv1.NewMsgSubmitProposal([]sdk.Msg{msgContent}, deposit, from.String(), "", content.GetTitle(), proposal.Summary) if err != nil { return err } @@ -116,12 +120,12 @@ Submit a consumer chain removal proposal along with an initial deposit. The proposal details must be supplied via a JSON file. Example: -$ tx gov submit-proposal consumer-removal --from= +$ tx gov submit-legacy-proposal consumer-removal --from= Where proposal.json contains: { "title": "Stop the FooChain", - "description": "It was a great chain", + "summary": "It was a great chain", "chain_id": "foochain", "stop_time": "2022-01-27T15:59:50.121607-08:00", "deposit": "10000stake" @@ -137,17 +141,20 @@ Where proposal.json contains: return err } - content := types.NewConsumerRemovalProposal( - proposal.Title, proposal.Description, proposal.ChainId, proposal.StopTime) - + content := types.NewConsumerRemovalProposal(proposal.Title, proposal.Summary, proposal.ChainId, proposal.StopTime) from := clientCtx.GetFromAddress() + msgContent, err := govv1.NewLegacyContent(content, authtypes.NewModuleAddress(govtypes.ModuleName).String()) + if err != nil { + return err + } + deposit, err := sdk.ParseCoinsNormalized(proposal.Deposit) if err != nil { return err } - msg, err := govtypes.NewMsgSubmitProposal(content, deposit, from) + msg, err := govv1.NewMsgSubmitProposal([]sdk.Msg{msgContent}, deposit, from.String(), "", content.GetTitle(), proposal.Summary) if err != nil { return err } @@ -168,12 +175,12 @@ func SubmitEquivocationProposalTxCmd() *cobra.Command { The proposal details must be supplied via a JSON file. Example: -$ tx gov submit-proposal equivocation --from= +$ tx gov submit-legacy-proposal equivocation --from= Where proposal.json contains: { "title": "Equivoque Foo validator", - "description": "He double-signs on the Foobar consumer chain", + "summary": "He double-signs on the Foobar consumer chain", "equivocations": [ { "height": 10420042, @@ -196,16 +203,21 @@ Where proposal.json contains: return err } - content := types.NewEquivocationProposal(proposal.Title, proposal.Description, proposal.Equivocations) + content := types.NewEquivocationProposal(proposal.Title, proposal.Summary, proposal.Equivocations) from := clientCtx.GetFromAddress() + msgContent, err := govv1.NewLegacyContent(content, authtypes.NewModuleAddress(govtypes.ModuleName).String()) + if err != nil { + return err + } + deposit, err := sdk.ParseCoinsNormalized(proposal.Deposit) if err != nil { return err } - msg, err := govtypes.NewMsgSubmitProposal(content, deposit, from) + msg, err := govv1.NewMsgSubmitProposal([]sdk.Msg{msgContent}, deposit, from.String(), "", content.GetTitle(), proposal.Summary) if err != nil { return err } @@ -217,7 +229,7 @@ Where proposal.json contains: type ConsumerAdditionProposalJSON struct { Title string `json:"title"` - Description string `json:"description"` + Summary string `json:"summary"` ChainId string `json:"chain_id"` InitialHeight clienttypes.Height `json:"initial_height"` GenesisHash []byte `json:"genesis_hash"` @@ -236,7 +248,6 @@ type ConsumerAdditionProposalJSON struct { } type ConsumerAdditionProposalReq struct { - BaseReq rest.BaseReq `json:"base_req"` Proposer sdk.AccAddress `json:"proposer"` Title string `json:"title"` @@ -274,15 +285,14 @@ func ParseConsumerAdditionProposalJSON(proposalFile string) (ConsumerAdditionPro } type ConsumerRemovalProposalJSON struct { - Title string `json:"title"` - Description string `json:"description"` - ChainId string `json:"chain_id"` - StopTime time.Time `json:"stop_time"` - Deposit string `json:"deposit"` + Title string `json:"title"` + Summary string `json:"summary"` + ChainId string `json:"chain_id"` + StopTime time.Time `json:"stop_time"` + Deposit string `json:"deposit"` } type ConsumerRemovalProposalReq struct { - BaseReq rest.BaseReq `json:"base_req"` Proposer sdk.AccAddress `json:"proposer"` Title string `json:"title"` @@ -295,13 +305,13 @@ type ConsumerRemovalProposalReq struct { type EquivocationProposalJSON struct { // evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" + Summary string `json:"summary"` types.EquivocationProposal Deposit string `json:"deposit"` } type EquivocationProposalReq struct { - BaseReq rest.BaseReq `json:"base_req"` Proposer sdk.AccAddress `json:"proposer"` // evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" @@ -325,14 +335,6 @@ func ParseEquivocationProposalJSON(proposalFile string) (EquivocationProposalJSO return proposal, nil } -// EquivocationProposalRESTHandler returns a ProposalRESTHandler that exposes the equivocation rest handler. -func EquivocationProposalRESTHandler(clientCtx client.Context) govrest.ProposalRESTHandler { - return govrest.ProposalRESTHandler{ - SubRoute: "equivocation", - Handler: postEquivocationProposalHandlerFn(clientCtx), - } -} - func ParseConsumerRemovalProposalJSON(proposalFile string) (ConsumerRemovalProposalJSON, error) { proposal := ConsumerRemovalProposalJSON{} @@ -348,6 +350,30 @@ func ParseConsumerRemovalProposalJSON(proposalFile string) (ConsumerRemovalPropo return proposal, nil } +func CheckPropUnbondingPeriod(clientCtx client.Context, propUnbondingPeriod time.Duration) { + queryClient := stakingtypes.NewQueryClient(clientCtx) + + res, err := queryClient.Params(context.Background(), &stakingtypes.QueryParamsRequest{}) + if err != nil { + fmt.Println(err.Error()) + return + } + + providerUnbondingTime := res.Params.UnbondingTime + + if providerUnbondingTime < propUnbondingPeriod { + fmt.Printf( + `consumer unbonding period is advised to be smaller than provider unbonding period, but is longer. +This is not a security risk, but will effectively lengthen the unbonding period on the provider. +consumer unbonding: %s +provider unbonding: %s`, + propUnbondingPeriod, + providerUnbondingTime) + } +} + +/* Proposal REST handlers: NOT NEEDED POST 47, BUT PLEASE CHECK THAT ALL FUNCTIONALITY EXISTS IN THE 47 VERSION. + // ConsumerAdditionProposalRESTHandler returns a ProposalRESTHandler that exposes the consumer addition rest handler. func ConsumerAdditionProposalRESTHandler(clientCtx client.Context) govrest.ProposalRESTHandler { return govrest.ProposalRESTHandler{ @@ -452,24 +478,6 @@ func postEquivocationProposalHandlerFn(clientCtx client.Context) http.HandlerFun } } -func CheckPropUnbondingPeriod(clientCtx client.Context, propUnbondingPeriod time.Duration) { - queryClient := stakingtypes.NewQueryClient(clientCtx) - - res, err := queryClient.Params(context.Background(), &stakingtypes.QueryParamsRequest{}) - if err != nil { - fmt.Println(err.Error()) - return - } - providerUnbondingTime := res.Params.UnbondingTime - if providerUnbondingTime < propUnbondingPeriod { - fmt.Printf( - `consumer unbonding period is advised to be smaller than provider unbonding period, but is longer. -This is not a security risk, but will effectively lengthen the unbonding period on the provider. -consumer unbonding: %s -provider unbonding: %s`, - propUnbondingPeriod, - providerUnbondingTime) - } -} +*/ diff --git a/x/ccv/provider/handler_test.go b/x/ccv/provider/handler_test.go index 3b034eab2b..0176e13b71 100644 --- a/x/ccv/provider/handler_test.go +++ b/x/ccv/provider/handler_test.go @@ -5,9 +5,9 @@ import ( "strings" "testing" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" "github.com/cosmos/cosmos-sdk/testutil/testdata" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/x/ccv/provider/ibc_module.go b/x/ccv/provider/ibc_module.go index a37f291340..21eee84f06 100644 --- a/x/ccv/provider/ibc_module.go +++ b/x/ccv/provider/ibc_module.go @@ -7,10 +7,12 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" - porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" - host "github.com/cosmos/ibc-go/v4/modules/core/24-host" - ibcexported "github.com/cosmos/ibc-go/v4/modules/core/exported" + + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" + host "github.com/cosmos/ibc-go/v7/modules/core/24-host" + ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" + "github.com/cosmos/interchain-security/v2/x/ccv/provider/keeper" providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" diff --git a/x/ccv/provider/ibc_module_test.go b/x/ccv/provider/ibc_module_test.go index c7027bf8e1..28a13dfeda 100644 --- a/x/ccv/provider/ibc_module_test.go +++ b/x/ccv/provider/ibc_module_test.go @@ -6,15 +6,18 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - conntypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v4/modules/core/24-host" - ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/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" + host "github.com/cosmos/ibc-go/v7/modules/core/24-host" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" "github.com/cosmos/interchain-security/v2/x/ccv/provider" providerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/provider/keeper" providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) diff --git a/x/ccv/provider/keeper/genesis_test.go b/x/ccv/provider/keeper/genesis_test.go index 40df37e999..5c8ee5838f 100644 --- a/x/ccv/provider/keeper/genesis_test.go +++ b/x/ccv/provider/keeper/genesis_test.go @@ -5,7 +5,7 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" - host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + host "github.com/cosmos/ibc-go/v7/modules/core/24-host" "github.com/cosmos/interchain-security/v2/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" diff --git a/x/ccv/provider/keeper/hooks.go b/x/ccv/provider/keeper/hooks.go index 3cf1e6cc30..a384edfc39 100644 --- a/x/ccv/provider/keeper/hooks.go +++ b/x/ccv/provider/keeper/hooks.go @@ -1,8 +1,6 @@ package keeper import ( - "fmt" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -34,6 +32,20 @@ func (h Hooks) AfterUnbondingInitiated(ctx sdk.Context, id uint64) error { // Do not put the unbonding op on hold if there are no consumer chains return nil } + // Call back into staking to tell it to stop this op from unbonding when the unbonding period is complete + if err := h.k.stakingKeeper.PutUnbondingOnHold(ctx, id); err != nil { + // Note: that in the case of a validator unbonding, AfterUnbondingInitiated is called + // from staking.EndBlock. + + // In this case PutUnbondingOnHold fails if either the unbonding operation was + // not found or the UnbondingOnHoldRefCount is negative. + + // This change should be updated for SDK v0.48 because it will include changes in handling + // check: https://github.com/cosmos/cosmos-sdk/pull/16043 + ctx.Logger().Error("unbonding could not be put on hold: %w", err) + return nil + } + valsetUpdateID := h.k.GetValidatorSetUpdateId(ctx) unbondingOp := providertypes.UnbondingOp{ Id: id, @@ -49,18 +61,22 @@ func (h Hooks) AfterUnbondingInitiated(ctx sdk.Context, id uint64) error { h.k.SetUnbondingOp(ctx, unbondingOp) + // NOTE: This is a temporary fix for v0.47 -> we should not panic in this edge case + // since the AfterUnbondInitiatedHook can be called with a non-existing UnbondingEntry.id + // check: https://github.com/cosmos/cosmos-sdk/pull/16043 + // // Call back into staking to tell it to stop this op from unbonding when the unbonding period is complete - if err := h.k.stakingKeeper.PutUnbondingOnHold(ctx, id); err != nil { - // If there was an error putting the unbonding on hold, panic to end execution for - // the current tx and prevent committal of this invalid state. - // - // Note: that in the case of a validator unbonding, AfterUnbondingInitiated is called - // form staking.EndBlock, thus the following panic would halt the chain. - // In this case PutUnbondingOnHold fails if either the unbonding operation was - // not found or the UnbondingOnHoldRefCount is negative. In either cases, - // the state of the x/staking module of cosmos-sdk is invalid. - panic(fmt.Errorf("unbonding could not be put on hold: %w", err)) - } + // if err := h.k.stakingKeeper.PutUnbondingOnHold(ctx, id); err != nil { + // // If there was an error putting the unbonding on hold, panic to end execution for + // // the current tx and prevent committal of this invalid state. + // // + // // Note: that in the case of a validator unbonding, AfterUnbondingInitiated is called + // // from staking.EndBlock, thus the following panic would halt the chain. + // // In this case PutUnbondingOnHold fails if either the unbonding operation was + // // not found or the UnbondingOnHoldRefCount is negative. In either cases, + // // the state of the x/staking module of cosmos-sdk is invalid. + // panic(fmt.Errorf("unbonding could not be put on hold: %w", err)) + // } return nil } @@ -94,14 +110,15 @@ func ValidatorConsensusKeyInUse(k *Keeper, ctx sdk.Context, valAddr sdk.ValAddre return inUse } -func (h Hooks) AfterValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) { +func (h Hooks) AfterValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) error { if ValidatorConsensusKeyInUse(h.k, ctx, valAddr) { // Abort TX, do NOT allow validator to be created panic("cannot create a validator with a consensus key that is already in use or was recently in use as an assigned consumer chain key") } + return nil } -func (h Hooks) AfterValidatorRemoved(ctx sdk.Context, valConsAddr sdk.ConsAddress, valAddr sdk.ValAddress) { +func (h Hooks) AfterValidatorRemoved(ctx sdk.Context, valConsAddr sdk.ConsAddress, valAddr sdk.ValAddress) error { for _, validatorConsumerPubKey := range h.k.GetAllValidatorConsumerPubKeys(ctx, nil) { if sdk.ConsAddress(validatorConsumerPubKey.ProviderAddr).Equals(valConsAddr) { consumerAddrTmp, err := ccvtypes.TMCryptoPublicKeyToConsAddr(*validatorConsumerPubKey.ConsumerKey) @@ -115,28 +132,38 @@ func (h Hooks) AfterValidatorRemoved(ctx sdk.Context, valConsAddr sdk.ConsAddres h.k.DeleteValidatorConsumerPubKey(ctx, validatorConsumerPubKey.ChainId, providerAddr) } } + + return nil } -func (h Hooks) BeforeDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) { +func (h Hooks) BeforeDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) error { + return nil } -func (h Hooks) BeforeDelegationSharesModified(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) { +func (h Hooks) BeforeDelegationSharesModified(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) error { + return nil } -func (h Hooks) AfterDelegationModified(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) { +func (h Hooks) AfterDelegationModified(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) error { + return nil } -func (h Hooks) BeforeValidatorSlashed(_ sdk.Context, _ sdk.ValAddress, _ sdk.Dec) { +func (h Hooks) BeforeValidatorSlashed(_ sdk.Context, _ sdk.ValAddress, _ sdk.Dec) error { + return nil } -func (h Hooks) BeforeValidatorModified(_ sdk.Context, _ sdk.ValAddress) { +func (h Hooks) BeforeValidatorModified(_ sdk.Context, _ sdk.ValAddress) error { + return nil } -func (h Hooks) AfterValidatorBonded(_ sdk.Context, _ sdk.ConsAddress, _ sdk.ValAddress) { +func (h Hooks) AfterValidatorBonded(_ sdk.Context, _ sdk.ConsAddress, _ sdk.ValAddress) error { + return nil } -func (h Hooks) AfterValidatorBeginUnbonding(_ sdk.Context, _ sdk.ConsAddress, _ sdk.ValAddress) { +func (h Hooks) AfterValidatorBeginUnbonding(_ sdk.Context, _ sdk.ConsAddress, _ sdk.ValAddress) error { + return nil } -func (h Hooks) BeforeDelegationRemoved(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) { +func (h Hooks) BeforeDelegationRemoved(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) error { + return nil } diff --git a/x/ccv/provider/keeper/keeper.go b/x/ccv/provider/keeper/keeper.go index 7494057643..ff14308a22 100644 --- a/x/ccv/provider/keeper/keeper.go +++ b/x/ccv/provider/keeper/keeper.go @@ -8,37 +8,38 @@ import ( errorsmod "cosmossdk.io/errors" "github.com/cosmos/cosmos-sdk/codec" + storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - conntypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v4/modules/core/24-host" - ibcexported "github.com/cosmos/ibc-go/v4/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/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" + host "github.com/cosmos/ibc-go/v7/modules/core/24-host" + ibchost "github.com/cosmos/ibc-go/v7/modules/core/exported" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" - "github.com/tendermint/tendermint/libs/log" + "github.com/cometbft/cometbft/libs/log" ) // Keeper defines the Cross-Chain Validation Provider Keeper type Keeper struct { - storeKey sdk.StoreKey + storeKey storetypes.StoreKey cdc codec.BinaryCodec paramSpace paramtypes.Subspace scopedKeeper ccv.ScopedKeeper channelKeeper ccv.ChannelKeeper portKeeper ccv.PortKeeper connectionKeeper ccv.ConnectionKeeper + accountKeeper ccv.AccountKeeper clientKeeper ccv.ClientKeeper stakingKeeper ccv.StakingKeeper slashingKeeper ccv.SlashingKeeper - accountKeeper ccv.AccountKeeper evidenceKeeper ccv.EvidenceKeeper distributionKeeper ccv.DistributionKeeper bankKeeper ccv.BankKeeper @@ -47,7 +48,7 @@ type Keeper struct { // NewKeeper creates a new provider Keeper instance func NewKeeper( - cdc codec.BinaryCodec, key sdk.StoreKey, paramSpace paramtypes.Subspace, scopedKeeper ccv.ScopedKeeper, + cdc codec.BinaryCodec, key storetypes.StoreKey, paramSpace paramtypes.Subspace, scopedKeeper ccv.ScopedKeeper, channelKeeper ccv.ChannelKeeper, portKeeper ccv.PortKeeper, connectionKeeper ccv.ConnectionKeeper, clientKeeper ccv.ClientKeeper, stakingKeeper ccv.StakingKeeper, slashingKeeper ccv.SlashingKeeper, @@ -115,7 +116,7 @@ func (k Keeper) mustValidateFields() { // Logger returns a module-specific logger. func (k Keeper) Logger(ctx sdk.Context) log.Logger { - return ctx.Logger().With("module", "x/"+host.ModuleName+"-"+types.ModuleName) + return ctx.Logger().With("module", "x/"+ibchost.ModuleName+"-"+types.ModuleName) } // IsBound checks if the CCV module is already bound to the desired port @@ -628,7 +629,7 @@ func (k Keeper) getUnderlyingClient(ctx sdk.Context, connectionID string) ( tmClient, ok = clientState.(*ibctmtypes.ClientState) if !ok { return "", nil, errorsmod.Wrapf(clienttypes.ErrInvalidClientType, - "invalid client type. expected %s, got %s", ibcexported.Tendermint, clientState.ClientType()) + "invalid client type. expected %s, got %s", ibchost.Tendermint, clientState.ClientType()) } return clientID, tmClient, nil } diff --git a/x/ccv/provider/keeper/keeper_test.go b/x/ccv/provider/keeper/keeper_test.go index 64cc268807..db5bf98ea4 100644 --- a/x/ccv/provider/keeper/keeper_test.go +++ b/x/ccv/provider/keeper/keeper_test.go @@ -6,16 +6,15 @@ import ( "testing" "time" + abci "github.com/cometbft/cometbft/abci/types" + tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" ibcsimapp "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/simapp" - cryptotestutil "github.com/cosmos/interchain-security/v2/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" - abci "github.com/tendermint/tendermint/abci/types" - tmprotocrypto "github.com/tendermint/tendermint/proto/tendermint/crypto" "github.com/stretchr/testify/require" ) diff --git a/x/ccv/provider/keeper/key_assignment.go b/x/ccv/provider/keeper/key_assignment.go index 81ded10282..0321e089de 100644 --- a/x/ccv/provider/keeper/key_assignment.go +++ b/x/ccv/provider/keeper/key_assignment.go @@ -10,8 +10,8 @@ import ( "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" - abci "github.com/tendermint/tendermint/abci/types" - tmprotocrypto "github.com/tendermint/tendermint/proto/tendermint/crypto" + abci "github.com/cometbft/cometbft/abci/types" + tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" ) // GetValidatorConsumerPubKey returns a validator's public key assigned for a consumer chain diff --git a/x/ccv/provider/keeper/key_assignment_test.go b/x/ccv/provider/keeper/key_assignment_test.go index da0edb2575..06d2202954 100644 --- a/x/ccv/provider/keeper/key_assignment_test.go +++ b/x/ccv/provider/keeper/key_assignment_test.go @@ -7,13 +7,13 @@ import ( "testing" "time" + abci "github.com/cometbft/cometbft/abci/types" + tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" cryptotestutil "github.com/cosmos/interchain-security/v2/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" - tmprotocrypto "github.com/tendermint/tendermint/proto/tendermint/crypto" providerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/provider/keeper" "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" diff --git a/x/ccv/provider/keeper/migration.go b/x/ccv/provider/keeper/migration.go deleted file mode 100644 index d33fcb7968..0000000000 --- a/x/ccv/provider/keeper/migration.go +++ /dev/null @@ -1,172 +0,0 @@ -package keeper - -import ( - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" - providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" -) - -// Migrator is a struct for handling in-place store migrations. -type Migrator struct { - ccvProviderKeeper Keeper - ccvProviderParamSpace paramtypes.Subspace -} - -// NewMigrator returns a new Migrator. -func NewMigrator(ccvProviderKeeper Keeper, ccvProviderParamSpace paramtypes.Subspace, -) Migrator { - return Migrator{ccvProviderKeeper: ccvProviderKeeper, ccvProviderParamSpace: ccvProviderParamSpace} -} - -// Migratev1Tov2 migrates a provider from v1.0.0 to v2.0.0, and/or consensus version 1 -> 2. -func (m Migrator) Migratev1Tov2(ctx sdk.Context) error { - // Migrate params - MigrateParamsv1Tov2(ctx, - m.ccvProviderParamSpace, - // See https://github.com/cosmos/interchain-security/blob/7861804cb311507ec6aebebbfad60ea42eb8ed4b/x/ccv/provider/keeper/params.go#L84 - // The v1.1.0-multiden version of ICS hardcodes this param as 10 of bond type: k.stakingKeeper.BondDenom(ctx). - // Here we use the same starting value, but the param can now be changed through governance. - sdk.NewCoin(m.ccvProviderKeeper.BondDenom(ctx), sdk.NewInt(10000000)), - ) - - // Consumer genesis states persisted on the provider do not need to be migrated, - // as protobuf serialization is able to gracefully handle unpopulated fields when deserializing. - // See https://github.com/smarshall-spitzbart/ics-migration-tests/commit/b589e3982c26783ed66e954051f7da1ead16de68 - // which passes, proving the addition of preCCV will not break things. - - // Migrate keys to accommodate fix from https://github.com/cosmos/interchain-security/pull/786 - MigrateKeysv1Tov2(ctx, m.ccvProviderKeeper) - - return nil -} - -// MigrateParamsv1Tov2 migrates the provider CCV module params from v1.0.0 to v2.0.0, -// setting default values for new params. -func MigrateParamsv1Tov2(ctx sdk.Context, paramsSubspace paramtypes.Subspace, consumerRewardDenomRegistrationFee sdk.Coin) { - // Get old params - var templateClient ibctmtypes.ClientState - paramsSubspace.Get(ctx, providertypes.KeyTemplateClient, &templateClient) - var trustingPeriodFraction string - paramsSubspace.Get(ctx, providertypes.KeyTrustingPeriodFraction, &trustingPeriodFraction) - var ccvTimeoutPeriod time.Duration - paramsSubspace.Get(ctx, ccvtypes.KeyCCVTimeoutPeriod, &ccvTimeoutPeriod) - var initTimeoutPeriod time.Duration - paramsSubspace.Get(ctx, providertypes.KeyInitTimeoutPeriod, &initTimeoutPeriod) - var vscTimeoutPeriod time.Duration - paramsSubspace.Get(ctx, providertypes.KeyVscTimeoutPeriod, &vscTimeoutPeriod) - var slashMeterReplenishPeriod time.Duration - paramsSubspace.Get(ctx, providertypes.KeySlashMeterReplenishPeriod, &slashMeterReplenishPeriod) - var slashMeterReplenishFraction string - paramsSubspace.Get(ctx, providertypes.KeySlashMeterReplenishFraction, &slashMeterReplenishFraction) - var maxThrottledPackets int64 - paramsSubspace.Get(ctx, providertypes.KeyMaxThrottledPackets, &maxThrottledPackets) - - // Recycle old params, set new param to input value - newParams := providertypes.NewParams( - &templateClient, - trustingPeriodFraction, - ccvTimeoutPeriod, - initTimeoutPeriod, - vscTimeoutPeriod, - slashMeterReplenishPeriod, - slashMeterReplenishFraction, - maxThrottledPackets, - consumerRewardDenomRegistrationFee, - ) - - // Persist new params - paramsSubspace.SetParamSet(ctx, &newParams) -} - -// Due to https://github.com/cosmos/interchain-security/pull/786, -// validators' slash logs are stored under the key prefix for slash acks. -// This method will extract "slash logs" from the slash acks part of the store, and put the slash logs -// in their appropriate store location. -func MigrateKeysv1Tov2(ctx sdk.Context, providerKeeper Keeper) { - keys := providerKeeper.getAllKeysUnderSlashAcksPrefix(ctx) - - // Get valid consumer chainIDs - consumers := providerKeeper.GetAllConsumerChains(ctx) - consumerChainIds := make(map[string]struct{}) - for _, consumer := range consumers { - consumerChainIds[consumer.ChainId] = struct{}{} - } - - keysToMigrate := [][]byte{} - - // iterate through all keys under slash acks prefix - for _, key := range keys { - bzAfterPrefix := key[1:] - // If bz after prefix is in consumerChainIds, - // then this key is a valid slash acks key, no migration needed - if _, ok := consumerChainIds[string(bzAfterPrefix)]; ok { - continue - } - // Otherwise this key is potentially/hopefully a slash log key to migrate - - // Validate that after the prefix, it's just a cons address stored in the key - if err := sdk.VerifyAddressFormat(bzAfterPrefix); err != nil { - // We could panic here, but prob best to log corrupted key and move on. - // This case should not happen! - ctx.Logger().Error("unexpected key under slash acks prefix", "key", key) - continue - } - keysToMigrate = append(keysToMigrate, key) - } - - // Migrate slash logs to their correct store location - store := ctx.KVStore(providerKeeper.storeKey) - for _, key := range keysToMigrate { - keyNoPrefix := key[1:] - keyCorrectPrefix := append([]byte{providertypes.SlashLogBytePrefix}, keyNoPrefix...) - valueBz := store.Get(key) - store.Set(keyCorrectPrefix, valueBz) - store.Delete(key) - } -} - -func (k Keeper) getAllKeysUnderSlashAcksPrefix(ctx sdk.Context) [][]byte { - store := ctx.KVStore(k.storeKey) - prefix := []byte{providertypes.SlashAcksBytePrefix} - iterator := sdk.KVStorePrefixIterator(store, prefix) - defer iterator.Close() - keys := [][]byte{} - for ; iterator.Valid(); iterator.Next() { - keys = append(keys, iterator.Key()) // Values are not used for migration, just keys - } - return keys -} - -// TODO: the following hackyness could be removed if we're able to reference older versions of ICS. -// This would likely require go.mod split, and a testing module that could depend on multiple ICS versions. - -// LEGACY METHOD USED FOR TESTING MIGRATION ONLY. DO NOT USE! -// This method is copy/pasted from ICS v1.0.0. -func SlashLogKeyOnlyForTesting(providerAddr sdk.ConsAddress) []byte { - return append([]byte{providertypes.SlashAcksBytePrefix}, providerAddr.Bytes()...) -} - -// LEGACY METHOD USED FOR TESTING MIGRATION ONLY. DO NOT USE! -// This method mimics SetSlashLog from ICS v1.0.0. -func (k Keeper) SetSlashLogOnlyForTesting( - ctx sdk.Context, - providerAddr sdk.ConsAddress, -) { - store := ctx.KVStore(k.storeKey) - store.Set(SlashLogKeyOnlyForTesting(providerAddr), []byte{}) -} - -// LEGACY METHOD USED FOR TESTING MIGRATION ONLY. DO NOT USE! -// This method mimics GetSlashLog from ICS v1.0.0. -func (k Keeper) GetSlashLogOnlyForTesting( - ctx sdk.Context, - providerAddr sdk.ConsAddress, -) (found bool) { - store := ctx.KVStore(k.storeKey) - bz := store.Get(SlashLogKeyOnlyForTesting(providerAddr)) - return bz != nil -} diff --git a/x/ccv/provider/keeper/migration_test.go b/x/ccv/provider/keeper/migration_test.go deleted file mode 100644 index e488dd2d36..0000000000 --- a/x/ccv/provider/keeper/migration_test.go +++ /dev/null @@ -1,171 +0,0 @@ -package keeper_test - -import ( - "testing" - "time" - - "github.com/cosmos/cosmos-sdk/codec" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/store" - storetypes "github.com/cosmos/cosmos-sdk/store/types" - sdk "github.com/cosmos/cosmos-sdk/types" - paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - types2 "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" - "github.com/cosmos/interchain-security/v2/testutil/crypto" - testutil "github.com/cosmos/interchain-security/v2/testutil/keeper" - providerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/provider/keeper" - providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" - "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/libs/log" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - tmdb "github.com/tendermint/tm-db" -) - -func TestMigrateParamsv1Tov2(t *testing.T) { - // Setup raw store - db := tmdb.NewMemDB() - stateStore := store.NewCommitMultiStore(db) - storeKey := sdk.NewKVStoreKey(paramtypes.StoreKey) - memStoreKey := storetypes.NewMemoryStoreKey("mem_key") - stateStore.MountStoreWithDB(storeKey, sdk.StoreTypeIAVL, db) - stateStore.MountStoreWithDB(memStoreKey, sdk.StoreTypeMemory, nil) - require.NoError(t, stateStore.LoadLatestVersion()) - registry := codectypes.NewInterfaceRegistry() - cdc := codec.NewProtoCodec(registry) - ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger()) - require.NoError(t, stateStore.LoadLatestVersion()) - - // Create new empty subspace - subspace := paramtypes.NewSubspace(cdc, - codec.NewLegacyAmino(), - storeKey, - memStoreKey, - paramtypes.ModuleName, - ).WithKeyTable(v1KeyTable()) // Note that new param key table is set in keeper constructor - - // Set 8 params from v1.0.0 - subspace.Set(ctx, providertypes.KeyTemplateClient, providertypes.DefaultParams().TemplateClient) - subspace.Set(ctx, providertypes.KeyTrustingPeriodFraction, "0.75") - subspace.Set(ctx, ccvtypes.KeyCCVTimeoutPeriod, time.Hour) - subspace.Set(ctx, providertypes.KeyInitTimeoutPeriod, time.Hour) - subspace.Set(ctx, providertypes.KeyVscTimeoutPeriod, time.Hour) - subspace.Set(ctx, providertypes.KeySlashMeterReplenishPeriod, time.Hour) - subspace.Set(ctx, providertypes.KeySlashMeterReplenishFraction, "0.5") - subspace.Set(ctx, providertypes.KeyMaxThrottledPackets, int64(10)) - - // Confirm new param cannot be set with old key table - require.Panics(t, func() { - subspace.Set(ctx, providertypes.KeyConsumerRewardDenomRegistrationFee, sdk.NewInt64Coin("uatom", 100)) - }) - - // Now create new subspace, mocking an upgrade where app initialization happens again - subspace = paramtypes.NewSubspace(cdc, - codec.NewLegacyAmino(), - storeKey, - memStoreKey, - paramtypes.ModuleName, - ).WithKeyTable(providertypes.ParamKeyTable()) // Use v2 key table, this would be set in keeper constructor upon app init - - // Run migration - providerkeeper.MigrateParamsv1Tov2(ctx, subspace, sdk.NewCoin("uatom", sdk.NewInt(100000))) - - // Use keeper to confirm params are set correctly - keeper := providerkeeper.Keeper{} - keeper.SetParamSpace(ctx, subspace) - - params := keeper.GetParams(ctx) - require.Equal(t, providertypes.DefaultParams().TemplateClient, params.TemplateClient) - require.Equal(t, "0.75", params.TrustingPeriodFraction) - require.Equal(t, time.Hour, params.CcvTimeoutPeriod) - require.Equal(t, time.Hour, params.InitTimeoutPeriod) - require.Equal(t, time.Hour, params.VscTimeoutPeriod) - require.Equal(t, time.Hour, params.SlashMeterReplenishPeriod) - require.Equal(t, "0.5", params.SlashMeterReplenishFraction) - require.Equal(t, int64(10), params.MaxThrottledPackets) - // New param should be set - require.Equal(t, sdk.NewCoin("uatom", sdk.NewInt(100000)), params.ConsumerRewardDenomRegistrationFee) - - // Set new param to other values - params.ConsumerRewardDenomRegistrationFee = sdk.NewCoin("uatom", sdk.NewInt(1000000000)) - keeper.SetParams(ctx, params) - require.Equal(t, sdk.NewCoin("uatom", sdk.NewInt(1000000000)), keeper.GetParams(ctx).ConsumerRewardDenomRegistrationFee) -} - -// v1KeyTable is a copy of the ParamKeyTable method from v1.0.0 -func v1KeyTable() paramtypes.KeyTable { - return paramtypes.NewKeyTable().RegisterParamSet(&v1Params{}) -} - -// ParamSetPairs implements params.ParamSet for v1Params -func (p *v1Params) ParamSetPairs() paramtypes.ParamSetPairs { - return paramtypes.ParamSetPairs{ - paramtypes.NewParamSetPair(providertypes.KeyTemplateClient, p.TemplateClient, providertypes.ValidateTemplateClient), - paramtypes.NewParamSetPair(providertypes.KeyTrustingPeriodFraction, p.TrustingPeriodFraction, ccvtypes.ValidateStringFraction), - paramtypes.NewParamSetPair(ccvtypes.KeyCCVTimeoutPeriod, p.CcvTimeoutPeriod, ccvtypes.ValidateDuration), - paramtypes.NewParamSetPair(providertypes.KeyInitTimeoutPeriod, p.InitTimeoutPeriod, ccvtypes.ValidateDuration), - paramtypes.NewParamSetPair(providertypes.KeyVscTimeoutPeriod, p.VscTimeoutPeriod, ccvtypes.ValidateDuration), - paramtypes.NewParamSetPair(providertypes.KeySlashMeterReplenishPeriod, p.SlashMeterReplenishPeriod, ccvtypes.ValidateDuration), - paramtypes.NewParamSetPair(providertypes.KeySlashMeterReplenishFraction, p.SlashMeterReplenishFraction, ccvtypes.ValidateStringFraction), - paramtypes.NewParamSetPair(providertypes.KeyMaxThrottledPackets, p.MaxThrottledPackets, ccvtypes.ValidatePositiveInt64), - } -} - -// v1Params is a copy of the Params struct from v1.0.0 -type v1Params struct { - TemplateClient *types2.ClientState `protobuf:"bytes,1,opt,name=template_client,json=templateClient,proto3" json:"template_client,omitempty"` - TrustingPeriodFraction string `protobuf:"bytes,2,opt,name=trusting_period_fraction,json=trustingPeriodFraction,proto3" json:"trusting_period_fraction,omitempty"` - CcvTimeoutPeriod time.Duration `protobuf:"bytes,3,opt,name=ccv_timeout_period,json=ccvTimeoutPeriod,proto3,stdduration" json:"ccv_timeout_period"` - InitTimeoutPeriod time.Duration `protobuf:"bytes,4,opt,name=init_timeout_period,json=initTimeoutPeriod,proto3,stdduration" json:"init_timeout_period"` - VscTimeoutPeriod time.Duration `protobuf:"bytes,5,opt,name=vsc_timeout_period,json=vscTimeoutPeriod,proto3,stdduration" json:"vsc_timeout_period"` - SlashMeterReplenishPeriod time.Duration `protobuf:"bytes,6,opt,name=slash_meter_replenish_period,json=slashMeterReplenishPeriod,proto3,stdduration" json:"slash_meter_replenish_period"` - SlashMeterReplenishFraction string `protobuf:"bytes,7,opt,name=slash_meter_replenish_fraction,json=slashMeterReplenishFraction,proto3" json:"slash_meter_replenish_fraction,omitempty"` - MaxThrottledPackets int64 `protobuf:"varint,8,opt,name=max_throttled_packets,json=maxThrottledPackets,proto3" json:"max_throttled_packets,omitempty"` -} - -func TestMigrateKeysv1Tov2(t *testing.T) { - providerKeeper, ctx, ctrl, _ := testutil.GetProviderKeeperAndCtx(t, testutil.NewInMemKeeperParams(t)) - defer ctrl.Finish() - - // First we setup a scenario that may show up in prod for v1, - // where both slash logs and slash acks are persisted under the same key prefix - cIds := crypto.GenMultipleCryptoIds(3, 349823489230) - providerKeeper.SetSlashLogOnlyForTesting(ctx, cIds[0].SDKValConsAddress()) // This is the old (incorrect) method of storing slash logs - providerKeeper.SetSlashLogOnlyForTesting(ctx, cIds[1].SDKValConsAddress()) - providerKeeper.SetSlashLogOnlyForTesting(ctx, cIds[2].SDKValConsAddress()) - - // Setup slash acks - p := []string{"alice", "bob", "frank"} - providerKeeper.SetSlashAcks(ctx, "chain-1", p) - p = []string{"charlie", "mac", "dennis"} - providerKeeper.SetSlashAcks(ctx, "chain-2", p) - - // Mock two clients being established with chain-1 and chain-2, - // This is needed for migration logic. - providerKeeper.SetConsumerClientId(ctx, "chain-1", "client-1") - providerKeeper.SetConsumerClientId(ctx, "chain-2", "client-2") - - // Confirm slash logs and slash acks exist together - require.True(t, providerKeeper.GetSlashLogOnlyForTesting(ctx, cIds[0].SDKValConsAddress())) - require.True(t, providerKeeper.GetSlashLogOnlyForTesting(ctx, cIds[1].SDKValConsAddress())) - require.True(t, providerKeeper.GetSlashLogOnlyForTesting(ctx, cIds[2].SDKValConsAddress())) - require.Len(t, providerKeeper.GetSlashAcks(ctx, "chain-1"), 3) - require.Len(t, providerKeeper.GetSlashAcks(ctx, "chain-2"), 3) - - // Run migration - providerkeeper.MigrateKeysv1Tov2(ctx, providerKeeper) - - // Confirm slash logs cannot be found from legacy methods - require.False(t, providerKeeper.GetSlashLogOnlyForTesting(ctx, cIds[0].SDKValConsAddress())) - require.False(t, providerKeeper.GetSlashLogOnlyForTesting(ctx, cIds[1].SDKValConsAddress())) - require.False(t, providerKeeper.GetSlashLogOnlyForTesting(ctx, cIds[2].SDKValConsAddress())) - - // Slash acks remain unchanged - require.Len(t, providerKeeper.GetSlashAcks(ctx, "chain-1"), 3) - require.Len(t, providerKeeper.GetSlashAcks(ctx, "chain-2"), 3) - - // Confirm slash logs can be found from new/correct methods - require.True(t, providerKeeper.GetSlashLog(ctx, cIds[0].ProviderConsAddress())) - require.True(t, providerKeeper.GetSlashLog(ctx, cIds[1].ProviderConsAddress())) - require.True(t, providerKeeper.GetSlashLog(ctx, cIds[2].ProviderConsAddress())) -} diff --git a/x/ccv/provider/keeper/msg_server.go b/x/ccv/provider/keeper/msg_server.go index ea5ff66220..dcef272356 100644 --- a/x/ccv/provider/keeper/msg_server.go +++ b/x/ccv/provider/keeper/msg_server.go @@ -4,12 +4,13 @@ import ( "context" "encoding/base64" - errorsmod "cosmossdk.io/errors" + tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + errorsmod "cosmossdk.io/errors" "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" - tmprotocrypto "github.com/tendermint/tendermint/proto/tendermint/crypto" ) type msgServer struct { diff --git a/x/ccv/provider/keeper/params.go b/x/ccv/provider/keeper/params.go index 98408bcede..56ed85fdd4 100644 --- a/x/ccv/provider/keeper/params.go +++ b/x/ccv/provider/keeper/params.go @@ -5,7 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" diff --git a/x/ccv/provider/keeper/params_test.go b/x/ccv/provider/keeper/params_test.go index eeafe2696c..25c368ca82 100644 --- a/x/ccv/provider/keeper/params_test.go +++ b/x/ccv/provider/keeper/params_test.go @@ -5,9 +5,10 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" - ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" "github.com/stretchr/testify/require" @@ -35,8 +36,6 @@ func TestParams(t *testing.T) { clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, - true, - false, ), "0.25", 7*24*time.Hour, diff --git a/x/ccv/provider/keeper/proposal.go b/x/ccv/provider/keeper/proposal.go index e50619c066..7c4a141ad8 100644 --- a/x/ccv/provider/keeper/proposal.go +++ b/x/ccv/provider/keeper/proposal.go @@ -5,21 +5,21 @@ import ( "strconv" "time" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" errorsmod "cosmossdk.io/errors" + abci "github.com/cometbft/cometbft/abci/types" + tmtypes "github.com/cometbft/cometbft/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" - ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" - "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" - abci "github.com/tendermint/tendermint/abci/types" - tmtypes "github.com/tendermint/tendermint/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" + "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v2/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 68ee7e9663..922573b17c 100644 --- a/x/ccv/provider/keeper/proposal_test.go +++ b/x/ccv/provider/keeper/proposal_test.go @@ -7,13 +7,13 @@ import ( "testing" "time" - _go "github.com/confio/ics23/go" + abci "github.com/cometbft/cometbft/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + _go "github.com/cosmos/ics23/go" "github.com/golang/mock/gomock" - abci "github.com/tendermint/tendermint/abci/types" "github.com/stretchr/testify/require" diff --git a/x/ccv/provider/keeper/relay.go b/x/ccv/provider/keeper/relay.go index ea07e0e9af..fed6f1f8ce 100644 --- a/x/ccv/provider/keeper/relay.go +++ b/x/ccv/provider/keeper/relay.go @@ -7,9 +7,10 @@ import ( errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" - "github.com/cosmos/ibc-go/v4/modules/core/exported" + 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/ibc-go/v7/modules/core/exported" + providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" ) @@ -114,8 +115,18 @@ func (k Keeper) completeMaturedUnbondingOps(ctx sdk.Context) { // Attempt to complete unbonding in staking module err := k.stakingKeeper.UnbondingCanComplete(ctx, id) if err != nil { - // UnbondingCanComplete fails if the unbonding operation was not found, - // which means that the state of the x/staking module of cosmos-sdk is invalid. + if stakingtypes.ErrUnbondingNotFound.Is(err) { + // The unbonding was not found. + unbondingType, found := k.stakingKeeper.GetUnbondingType(ctx, id) + if found && unbondingType == stakingtypes.UnbondingType_UnbondingDelegation { + // If this is an unbonding delegation, it may have been removed + // after through a CancelUnbondingDelegation message + k.Logger(ctx).Debug("unbonding delegation was already removed:", "unbondingID", id) + continue + } + } + // UnbondingCanComplete failing means that the state of the x/staking module + // of cosmos-sdk is invalid. An exception is the case handled above panic(fmt.Sprintf("could not complete unbonding op: %s", err.Error())) } k.Logger(ctx).Debug("unbonding operation matured on all consumers", "opID", id) @@ -327,7 +338,7 @@ func (k Keeper) OnRecvSlashPacket(ctx sdk.Context, packet channeltypes.Packet, d consumerConsAddr := providertypes.NewConsumerConsAddress(data.Validator.Address) providerConsAddr := k.GetProviderAddrFromConsumerAddr(ctx, chainID, consumerConsAddr) - if data.Infraction == stakingtypes.DoubleSign { + if data.Infraction == stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN { // getMappedInfractionHeight is already checked in ValidateSlashPacket infractionHeight, _ := k.getMappedInfractionHeight(ctx, chainID, data.ValsetUpdateId) @@ -382,7 +393,7 @@ func (k Keeper) ValidateSlashPacket(ctx sdk.Context, chainID string, "the validator update id %d for chain %s", data.ValsetUpdateId, chainID) } - if data.Infraction != stakingtypes.DoubleSign && data.Infraction != stakingtypes.Downtime { + if data.Infraction != stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN && data.Infraction != stakingtypes.Infraction_INFRACTION_DOWNTIME { return fmt.Errorf("invalid infraction type: %s", data.Infraction) } diff --git a/x/ccv/provider/keeper/relay_test.go b/x/ccv/provider/keeper/relay_test.go index 7e377db1b1..07e967ae41 100644 --- a/x/ccv/provider/keeper/relay_test.go +++ b/x/ccv/provider/keeper/relay_test.go @@ -4,12 +4,14 @@ import ( "testing" "time" + abci "github.com/cometbft/cometbft/abci/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" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" - exported "github.com/cosmos/ibc-go/v4/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + exported "github.com/cosmos/ibc-go/v7/modules/core/exported" + ibcsimapp "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/simapp" cryptotestutil "github.com/cosmos/interchain-security/v2/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" @@ -17,7 +19,6 @@ import ( providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" "github.com/golang/mock/gomock" - abci "github.com/tendermint/tendermint/abci/types" "github.com/stretchr/testify/require" ) @@ -239,7 +240,7 @@ func TestOnRecvDoubleSignSlashPacket(t *testing.T) { // Generate a new slash packet data instance with double sign infraction type packetData := testkeeper.GetNewSlashPacketData() - packetData.Infraction = stakingtypes.DoubleSign + packetData.Infraction = stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN // Set a block height for the valset update id in the generated packet data providerKeeper.SetValsetUpdateBlockHeight(ctx, packetData.ValsetUpdateId, uint64(15)) @@ -273,7 +274,7 @@ func TestOnRecvDowntimeSlashPacket(t *testing.T) { // Generate a new slash packet data instance with downtime infraction type packetData := testkeeper.GetNewSlashPacketData() - packetData.Infraction = stakingtypes.Downtime + packetData.Infraction = stakingtypes.Infraction_INFRACTION_DOWNTIME // Set a block height for the valset update id in the generated packet data providerKeeper.SetValsetUpdateBlockHeight(ctx, packetData.ValsetUpdateId, uint64(15)) @@ -291,7 +292,7 @@ func TestOnRecvDowntimeSlashPacket(t *testing.T) { // Generate a new downtime packet data instance with downtime infraction type packetData = testkeeper.GetNewSlashPacketData() - packetData.Infraction = stakingtypes.Downtime + packetData.Infraction = stakingtypes.Infraction_INFRACTION_DOWNTIME // Set a block height for the valset update id in the generated packet data providerKeeper.SetValsetUpdateBlockHeight(ctx, packetData.ValsetUpdateId, uint64(15)) @@ -367,22 +368,22 @@ func TestValidateSlashPacket(t *testing.T) { }, { "valid double sign packet with non-zero vscID", - ccv.SlashPacketData{ValsetUpdateId: validVscID, Infraction: stakingtypes.DoubleSign}, + ccv.SlashPacketData{ValsetUpdateId: validVscID, Infraction: stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN}, false, }, { "valid downtime packet with non-zero vscID", - ccv.SlashPacketData{ValsetUpdateId: validVscID, Infraction: stakingtypes.Downtime}, + ccv.SlashPacketData{ValsetUpdateId: validVscID, Infraction: stakingtypes.Infraction_INFRACTION_DOWNTIME}, false, }, { "valid double sign packet with zero vscID", - ccv.SlashPacketData{ValsetUpdateId: 0, Infraction: stakingtypes.DoubleSign}, + ccv.SlashPacketData{ValsetUpdateId: 0, Infraction: stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN}, false, }, { "valid downtime packet with zero vscID", - ccv.SlashPacketData{ValsetUpdateId: 0, Infraction: stakingtypes.Downtime}, + ccv.SlashPacketData{ValsetUpdateId: 0, Infraction: stakingtypes.Infraction_INFRACTION_DOWNTIME}, false, }, } @@ -433,7 +434,7 @@ func TestHandleSlashPacket(t *testing.T) { ccv.SlashPacketData{ Validator: abci.Validator{Address: consumerConsAddr.ToSdkConsAddr()}, ValsetUpdateId: validVscID, - Infraction: stakingtypes.Downtime, + Infraction: stakingtypes.Infraction_INFRACTION_DOWNTIME, }, func(ctx sdk.Context, mocks testkeeper.MockedKeepers, expectedPacketData ccv.SlashPacketData, @@ -454,7 +455,7 @@ func TestHandleSlashPacket(t *testing.T) { ccv.SlashPacketData{ Validator: abci.Validator{Address: consumerConsAddr.ToSdkConsAddr()}, ValsetUpdateId: validVscID, - Infraction: stakingtypes.Downtime, + Infraction: stakingtypes.Infraction_INFRACTION_DOWNTIME, }, func(ctx sdk.Context, mocks testkeeper.MockedKeepers, expectedPacketData ccv.SlashPacketData, @@ -476,7 +477,7 @@ func TestHandleSlashPacket(t *testing.T) { ccv.SlashPacketData{ Validator: abci.Validator{Address: consumerConsAddr.ToSdkConsAddr()}, ValsetUpdateId: 78, // Keeper doesn't have a height mapped to this vscID. - Infraction: stakingtypes.Downtime, + Infraction: stakingtypes.Infraction_INFRACTION_DOWNTIME, }, func(ctx sdk.Context, mocks testkeeper.MockedKeepers, @@ -499,7 +500,7 @@ func TestHandleSlashPacket(t *testing.T) { *ccv.NewSlashPacketData( abci.Validator{Address: consumerConsAddr.ToSdkConsAddr()}, 0, // ValsetUpdateId = 0 uses init chain height. - stakingtypes.Downtime), + stakingtypes.Infraction_INFRACTION_DOWNTIME), func(ctx sdk.Context, mocks testkeeper.MockedKeepers, expectedPacketData ccv.SlashPacketData, ) []*gomock.Call { @@ -516,7 +517,7 @@ func TestHandleSlashPacket(t *testing.T) { *ccv.NewSlashPacketData( abci.Validator{Address: consumerConsAddr.ToSdkConsAddr()}, validVscID, - stakingtypes.Downtime), + stakingtypes.Infraction_INFRACTION_DOWNTIME), func(ctx sdk.Context, mocks testkeeper.MockedKeepers, expectedPacketData ccv.SlashPacketData, ) []*gomock.Call { diff --git a/x/ccv/provider/keeper/throttle.go b/x/ccv/provider/keeper/throttle.go index d832125bfb..d08f7bf5e0 100644 --- a/x/ccv/provider/keeper/throttle.go +++ b/x/ccv/provider/keeper/throttle.go @@ -4,10 +4,12 @@ import ( "fmt" "time" + "cosmossdk.io/math" + tmtypes "github.com/cometbft/cometbft/types" sdktypes "github.com/cosmos/cosmos-sdk/types" + providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" - tmtypes "github.com/tendermint/tendermint/types" ) // This file contains functionality relevant to the throttling of slash and vsc matured packets, aka circuit breaker logic. @@ -68,7 +70,7 @@ func (k Keeper) HandleThrottleQueues(ctx sdktypes.Context, vscMaturedHandledThis // Obtains the effective validator power relevant to a validator consensus address. func (k Keeper) GetEffectiveValPower(ctx sdktypes.Context, valConsAddr providertypes.ProviderConsAddress, -) sdktypes.Int { +) math.Int { // Obtain staking module val object from the provider's consensus address. // Note: if validator is not found or unbonded, this will be handled appropriately in HandleSlashPacket val, found := k.stakingKeeper.GetValidatorByConsAddr(ctx, valConsAddr.ToSdkConsAddr()) @@ -181,7 +183,7 @@ func (k Keeper) ReplenishSlashMeter(ctx sdktypes.Context) { // Note: allowance can change between blocks, since it is directly correlated to total voting power. // The slash meter must be less than or equal to the allowance for this block, before any slash // packet handling logic can be executed. -func (k Keeper) GetSlashMeterAllowance(ctx sdktypes.Context) sdktypes.Int { +func (k Keeper) GetSlashMeterAllowance(ctx sdktypes.Context) math.Int { strFrac := k.GetSlashMeterReplenishFraction(ctx) // MustNewDecFromStr should not panic, since the (string representation) of the slash meter replenish fraction // is validated in ValidateGenesis and anytime the param is mutated. @@ -553,7 +555,7 @@ func (k Keeper) DeleteThrottledPacketData(ctx sdktypes.Context, consumerChainID // to an allowance of validators that can be jailed/tombstoned over time. // // Note: the value of this int should always be in the range of tendermint's [-MaxVotingPower, MaxVotingPower] -func (k Keeper) GetSlashMeter(ctx sdktypes.Context) sdktypes.Int { +func (k Keeper) GetSlashMeter(ctx sdktypes.Context) math.Int { store := ctx.KVStore(k.storeKey) bz := store.Get(providertypes.SlashMeterKey()) if bz == nil { @@ -574,7 +576,7 @@ func (k Keeper) GetSlashMeter(ctx sdktypes.Context) sdktypes.Int { // SetSlashMeter sets the slash meter to the given signed int value // // Note: the value of this int should always be in the range of tendermint's [-MaxTotalVotingPower, MaxTotalVotingPower] -func (k Keeper) SetSlashMeter(ctx sdktypes.Context, value sdktypes.Int) { +func (k Keeper) SetSlashMeter(ctx sdktypes.Context, value math.Int) { // TODO: remove these invariant panics once https://github.com/cosmos/interchain-security/issues/534 is solved. // The following panics are included since they are invariants for slash meter value. diff --git a/x/ccv/provider/keeper/throttle_test.go b/x/ccv/provider/keeper/throttle_test.go index 3b93523d4b..86a0ee1415 100644 --- a/x/ccv/provider/keeper/throttle_test.go +++ b/x/ccv/provider/keeper/throttle_test.go @@ -5,17 +5,20 @@ import ( "testing" "time" - "github.com/cosmos/interchain-security/v2/x/ccv/provider/keeper" - providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" - "github.com/golang/mock/gomock" + "cosmossdk.io/math" + tmtypes "github.com/cometbft/cometbft/types" sdktypes "github.com/cosmos/cosmos-sdk/types" - cryptoutil "github.com/cosmos/interchain-security/v2/testutil/crypto" - testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" + + "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" - tmtypes "github.com/tendermint/tendermint/types" "golang.org/x/exp/slices" + + cryptoutil "github.com/cosmos/interchain-security/v2/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" + "github.com/cosmos/interchain-security/v2/x/ccv/provider/keeper" + providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" + ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" ) // TestHandlePacketDataForChain tests the HandlePacketDataForChain function. Note: Only one consumer is tested here, @@ -179,9 +182,9 @@ func TestSlashMeterReplenishment(t *testing.T) { testCases := []struct { replenishPeriod time.Duration replenishFraction string - totalPower sdktypes.Int + totalPower math.Int // Replenish fraction * total power, also serves as max slash meter value - expectedAllowance sdktypes.Int + expectedAllowance math.Int }{ { replenishPeriod: time.Minute, @@ -451,11 +454,11 @@ func TestTotalVotingPowerChanges(t *testing.T) { // voting power becomes lower from slashing. func TestNegativeSlashMeter(t *testing.T) { testCases := []struct { - slashedPower sdktypes.Int - totalPower sdktypes.Int + slashedPower math.Int + totalPower math.Int replenishFraction string numReplenishesTillFull int - finalMeterValue sdktypes.Int + finalMeterValue math.Int }{ { // Meter is initialized to a value of: 0.01*1000 = 10. @@ -566,9 +569,9 @@ func TestNegativeSlashMeter(t *testing.T) { func TestGetSlashMeterAllowance(t *testing.T) { testCases := []struct { replenishFraction string - totalPower sdktypes.Int + totalPower math.Int // Replenish fraction * total power - expectedAllowance sdktypes.Int + expectedAllowance math.Int }{ { replenishFraction: "0.00", @@ -1246,7 +1249,7 @@ func TestThrottledPacketDataSize(t *testing.T) { // TestSlashMeter tests the getter and setter for the slash gas meter func TestSlashMeter(t *testing.T) { testCases := []struct { - meterValue sdktypes.Int + meterValue math.Int shouldPanic bool }{ {meterValue: sdktypes.NewInt(-7999999999999999999), shouldPanic: true}, diff --git a/x/ccv/provider/module.go b/x/ccv/provider/module.go index bb15b75ab1..ca83c9011b 100644 --- a/x/ccv/provider/module.go +++ b/x/ccv/provider/module.go @@ -4,23 +4,24 @@ import ( "context" "encoding/json" "fmt" - "math/rand" + abci "github.com/cometbft/cometbft/abci/types" "github.com/cosmos/cosmos-sdk/client" "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/module" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + + porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" "github.com/cosmos/interchain-security/v2/x/ccv/provider/client/cli" "github.com/cosmos/interchain-security/v2/x/ccv/provider/keeper" providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - "github.com/gorilla/mux" + "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/spf13/cobra" - abci "github.com/tendermint/tendermint/abci/types" ) var ( @@ -63,10 +64,6 @@ func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncod return data.Validate() } -// RegisterRESTRoutes implements AppModuleBasic interface -func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Router) { -} - // RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the ibc-provider module. func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { err := providertypes.RegisterQueryHandlerClient(context.Background(), mux, providertypes.NewQueryClient(clientCtx)) @@ -106,30 +103,10 @@ func (AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { // TODO } -// Route implements the AppModule interface -func (am AppModule) Route() sdk.Route { - return sdk.Route{} -} - -// QuerierRoute implements the AppModule interface -func (AppModule) QuerierRoute() string { - return providertypes.QuerierRoute -} - -// LegacyQuerierHandler implements the AppModule interface -func (am AppModule) LegacyQuerierHandler(*codec.LegacyAmino) sdk.Querier { - return nil -} - // RegisterServices registers module services. func (am AppModule) RegisterServices(cfg module.Configurator) { providertypes.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) providertypes.RegisterQueryServer(cfg.QueryServer(), am.keeper) - - m := keeper.NewMigrator(*am.keeper, am.paramSpace) - if err := cfg.RegisterMigration(providertypes.ModuleName, 1, m.Migratev1Tov2); err != nil { - panic(fmt.Sprintf("failed to register migrator: %s", err)) - } } // InitGenesis performs genesis initialization for the provider module. It returns no validator updates. @@ -183,16 +160,6 @@ func (am AppModule) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.V func (AppModule) GenerateGenesisState(simState *module.SimulationState) { } -// ProposalContents doesn't return any content functions for governance proposals. -func (AppModule) ProposalContents(_ module.SimulationState) []simtypes.WeightedProposalContent { - return nil -} - -// RandomizedParams creates randomized provider param changes for the simulator. -func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange { - return nil -} - // RegisterStoreDecoder registers a decoder for provider module's types func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { } diff --git a/x/ccv/provider/module_test.go b/x/ccv/provider/module_test.go index 3e2776c4e7..2cb08d0daf 100644 --- a/x/ccv/provider/module_test.go +++ b/x/ccv/provider/module_test.go @@ -5,7 +5,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + + host "github.com/cosmos/ibc-go/v7/modules/core/24-host" + testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" "github.com/cosmos/interchain-security/v2/x/ccv/provider" "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" diff --git a/x/ccv/provider/proposal_handler.go b/x/ccv/provider/proposal_handler.go index 8854b8e57c..2bfb71c73b 100644 --- a/x/ccv/provider/proposal_handler.go +++ b/x/ccv/provider/proposal_handler.go @@ -1,10 +1,11 @@ package provider import ( + govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/cosmos/interchain-security/v2/x/ccv/provider/keeper" "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" ) @@ -12,8 +13,8 @@ import ( // NewProviderProposalHandler defines the handler for consumer addition, // consumer removal and equivocation proposals. // Passed proposals are executed during EndBlock. -func NewProviderProposalHandler(k keeper.Keeper) govtypes.Handler { - return func(ctx sdk.Context, content govtypes.Content) error { +func NewProviderProposalHandler(k keeper.Keeper) govv1beta1.Handler { + return func(ctx sdk.Context, content govv1beta1.Content) error { switch c := content.(type) { case *types.ConsumerAdditionProposal: return k.HandleConsumerAdditionProposal(ctx, c) diff --git a/x/ccv/provider/proposal_handler_test.go b/x/ccv/provider/proposal_handler_test.go index 1e8e9b34b5..35b7821dd7 100644 --- a/x/ccv/provider/proposal_handler_test.go +++ b/x/ccv/provider/proposal_handler_test.go @@ -10,9 +10,10 @@ import ( "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + + govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" "github.com/cosmos/interchain-security/v2/x/ccv/provider" providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" @@ -28,7 +29,7 @@ func TestProviderProposalHandler(t *testing.T) { testCases := []struct { name string - content govtypes.Content + content govv1beta1.Content blockTime time.Time expValidConsumerAddition bool expValidConsumerRemoval bool @@ -79,9 +80,13 @@ func TestProviderProposalHandler(t *testing.T) { }, { name: "unsupported proposal type", - content: distributiontypes.NewCommunityPoolSpendProposal( - "title", "desc", []byte{}, - sdk.NewCoins(sdk.NewCoin("communityfunds", sdk.NewInt(10)))), + // lint rule disabled because this is a test case for an unsupported proposal type + content: &distributiontypes.CommunityPoolSpendProposal{ // nolint:staticcheck + Title: "title", + Description: "desc", + Recipient: "", + Amount: sdk.NewCoins(sdk.NewCoin("communityfunds", sdk.NewInt(10))), + }, }, } diff --git a/x/ccv/provider/types/codec.go b/x/ccv/provider/types/codec.go index 3e4b34dd42..54c29442ae 100644 --- a/x/ccv/provider/types/codec.go +++ b/x/ccv/provider/types/codec.go @@ -5,7 +5,7 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/msgservice" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" ) // RegisterLegacyAminoCodec registers the necessary x/ibc transfer interfaces and concrete types @@ -16,11 +16,11 @@ func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { // RegisterInterfaces registers the provider proposal structs to the interface registry func RegisterInterfaces(registry codectypes.InterfaceRegistry) { registry.RegisterImplementations( - (*govtypes.Content)(nil), + (*govv1beta1.Content)(nil), &ConsumerAdditionProposal{}, ) registry.RegisterImplementations( - (*govtypes.Content)(nil), + (*govv1beta1.Content)(nil), &ConsumerRemovalProposal{}, ) registry.RegisterImplementations( @@ -32,7 +32,7 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { &MsgRegisterConsumerRewardDenom{}, ) registry.RegisterImplementations( - (*govtypes.Content)(nil), + (*govv1beta1.Content)(nil), &EquivocationProposal{}, ) diff --git a/x/ccv/provider/types/genesis.go b/x/ccv/provider/types/genesis.go index 9f7fdc3b11..4508fd6eb6 100644 --- a/x/ccv/provider/types/genesis.go +++ b/x/ccv/provider/types/genesis.go @@ -5,7 +5,8 @@ import ( errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" - host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + host "github.com/cosmos/ibc-go/v7/modules/core/24-host" + ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" ) diff --git a/x/ccv/provider/types/genesis.pb.go b/x/ccv/provider/types/genesis.pb.go index 6d4da633fd..84110c9b96 100644 --- a/x/ccv/provider/types/genesis.pb.go +++ b/x/ccv/provider/types/genesis.pb.go @@ -5,11 +5,11 @@ package types import ( fmt "fmt" + _ "github.com/cometbft/cometbft/proto/tendermint/crypto" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" types1 "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" types "github.com/cosmos/interchain-security/v2/x/ccv/types" - _ "github.com/gogo/protobuf/gogoproto" - proto "github.com/gogo/protobuf/proto" - _ "github.com/tendermint/tendermint/proto/tendermint/crypto" io "io" math "math" math_bits "math/bits" @@ -173,10 +173,12 @@ type ConsumerState struct { InitialHeight uint64 `protobuf:"varint,4,opt,name=initial_height,json=initialHeight,proto3" json:"initial_height,omitempty"` // ConsumerGenesis defines the initial consumer chain genesis states ConsumerGenesis types1.GenesisState `protobuf:"bytes,5,opt,name=consumer_genesis,json=consumerGenesis,proto3" json:"consumer_genesis"` - // PendingValsetChanges defines the pending validator set changes for the consumer chain + // PendingValsetChanges defines the pending validator set changes for the + // consumer chain PendingValsetChanges []types.ValidatorSetChangePacketData `protobuf:"bytes,6,rep,name=pending_valset_changes,json=pendingValsetChanges,proto3" json:"pending_valset_changes"` SlashDowntimeAck []string `protobuf:"bytes,7,rep,name=slash_downtime_ack,json=slashDowntimeAck,proto3" json:"slash_downtime_ack,omitempty"` - // UnbondingOpsIndex defines the unbonding operations waiting on this consumer chain + // UnbondingOpsIndex defines the unbonding operations waiting on this consumer + // chain UnbondingOpsIndex []VscUnbondingOps `protobuf:"bytes,8,rep,name=unbonding_ops_index,json=unbondingOpsIndex,proto3" json:"unbonding_ops_index"` } diff --git a/x/ccv/provider/types/genesis_test.go b/x/ccv/provider/types/genesis_test.go index 0b85d9f6b3..0bf3b98a55 100644 --- a/x/ccv/provider/types/genesis_test.go +++ b/x/ccv/provider/types/genesis_test.go @@ -4,17 +4,19 @@ import ( "testing" "time" + 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/v4/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" - ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + "github.com/cosmos/interchain-security/v2/testutil/crypto" consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" - tmtypes "github.com/tendermint/tendermint/types" ) // Tests validation of consumer states and params within a provider genesis state @@ -74,7 +76,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, - time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), types.DefaultTrustingPeriodFraction, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", 400, sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}), nil, nil, @@ -93,7 +95,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, - time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), types.DefaultTrustingPeriodFraction, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", 400, sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}), nil, nil, @@ -112,7 +114,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, - time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), types.DefaultTrustingPeriodFraction, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", 400, sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}), nil, nil, @@ -131,7 +133,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, - time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), types.DefaultTrustingPeriodFraction, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", 400, sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}), nil, nil, @@ -150,7 +152,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, - 0, clienttypes.Height{}, nil, []string{"ibc", "upgradedIBCState"}, true, false), + 0, clienttypes.Height{}, nil, []string{"ibc", "upgradedIBCState"}), types.DefaultTrustingPeriodFraction, ccv.DefaultCCVTimeoutPeriod, types.DefaultInitTimeoutPeriod, @@ -175,7 +177,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, - time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), "0.0", // 0 trusting period fraction here ccv.DefaultCCVTimeoutPeriod, types.DefaultInitTimeoutPeriod, @@ -200,7 +202,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, - time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), types.DefaultTrustingPeriodFraction, 0, // 0 ccv timeout here types.DefaultInitTimeoutPeriod, @@ -225,7 +227,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, - time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), types.DefaultTrustingPeriodFraction, ccv.DefaultCCVTimeoutPeriod, 0, // 0 init timeout here @@ -250,7 +252,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, - time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), types.DefaultTrustingPeriodFraction, ccv.DefaultCCVTimeoutPeriod, types.DefaultInitTimeoutPeriod, @@ -275,7 +277,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, - time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), types.DefaultTrustingPeriodFraction, ccv.DefaultCCVTimeoutPeriod, types.DefaultInitTimeoutPeriod, @@ -300,7 +302,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, - time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), types.DefaultTrustingPeriodFraction, ccv.DefaultCCVTimeoutPeriod, types.DefaultInitTimeoutPeriod, @@ -325,7 +327,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, - time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), types.DefaultTrustingPeriodFraction, ccv.DefaultCCVTimeoutPeriod, types.DefaultInitTimeoutPeriod, @@ -655,7 +657,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, - time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), types.DefaultTrustingPeriodFraction, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", 400, sdk.Coin{Denom: "st", Amount: sdk.NewInt(10000000)}), nil, nil, @@ -674,7 +676,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, - time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), types.DefaultTrustingPeriodFraction, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", 400, sdk.Coin{Denom: "stake", Amount: sdk.NewInt(-1000000)}), nil, nil, @@ -717,10 +719,7 @@ func getInitialConsumerGenesis(t *testing.T, chainID string) consumertypes.Genes time.Duration(1), clienttypes.Height{RevisionNumber: clienttypes.ParseChainID(chainID), RevisionHeight: 1}, commitmenttypes.GetSDKSpecs(), - []string{"upgrade", "upgradedIBCState"}, - true, - true, - ) + []string{"upgrade", "upgradedIBCState"}) consensusState := ibctmtypes.NewConsensusState(time.Now(), commitmenttypes.NewMerkleRoot([]byte("apphash")), valHash) params := consumertypes.DefaultParams() diff --git a/x/ccv/provider/types/params.go b/x/ccv/provider/types/params.go index 3966232501..487fdda366 100644 --- a/x/ccv/provider/types/params.go +++ b/x/ccv/provider/types/params.go @@ -6,9 +6,11 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" - ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" ) @@ -97,8 +99,6 @@ func DefaultParams() Params { clienttypes.Height{}, // latest(initial) height commitmenttypes.GetSDKSpecs(), []string{"upgrade", "upgradedIBCState"}, - true, - true, ), DefaultTrustingPeriodFraction, ccvtypes.DefaultCCVTimeoutPeriod, diff --git a/x/ccv/provider/types/params_test.go b/x/ccv/provider/types/params_test.go index 42e61f5ebd..bca99670a9 100644 --- a/x/ccv/provider/types/params_test.go +++ b/x/ccv/provider/types/params_test.go @@ -4,12 +4,12 @@ import ( "testing" "time" - sdk "github.com/cosmos/cosmos-sdk/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" - ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" "github.com/stretchr/testify/require" + sdk "github.com/cosmos/cosmos-sdk/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" ) @@ -20,42 +20,44 @@ func TestValidateParams(t *testing.T) { expPass bool }{ {"default params", types.DefaultParams(), true}, - {"custom valid params", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, - time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), + {"custom valid params", types.NewParams( + ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), "0.33", time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", 100, sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}), true}, - {"custom invalid params", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, - 0, clienttypes.Height{}, nil, []string{"ibc", "upgradedIBCState"}, true, false), + {"custom invalid params", types.NewParams( + ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, + 0, clienttypes.Height{}, nil, []string{"ibc", "upgradedIBCState"}), "0.33", time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", 100, sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}), false}, {"blank client", types.NewParams(&ibctmtypes.ClientState{}, "0.33", time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", 100, sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}), false}, {"nil client", types.NewParams(nil, "0.33", time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", 100, sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}), false}, // Check if "0.00" is valid or if a zero dec TrustFraction needs to return an error {"0 trusting period fraction", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, - time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), "0.00", time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", 100, sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}), true}, {"0 ccv timeout period", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, - time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), "0.33", 0, time.Hour, time.Hour, 30*time.Minute, "0.1", 100, sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}), false}, {"0 init timeout period", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, - time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), "0.33", time.Hour, 0, time.Hour, 30*time.Minute, "0.1", 100, sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}), false}, {"0 vsc timeout period", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, - time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), "0.33", time.Hour, time.Hour, 0, 30*time.Minute, "0.1", 100, sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}), false}, {"0 slash meter replenish period", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, - time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), "0.33", time.Hour, time.Hour, 24*time.Hour, 0, "0.1", 100, sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}), false}, {"slash meter replenish fraction over 1", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, - time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), "0.33", time.Hour, time.Hour, 24*time.Hour, time.Hour, "1.5", 100, sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}), false}, {"negative max pending slash packets", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, - time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), "0.33", time.Hour, time.Hour, 24*time.Hour, time.Hour, "0.1", -100, sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}), false}, {"invalid consumer reward denom registration fee denom", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, - time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), "0.33", time.Hour, time.Hour, 24*time.Hour, time.Hour, "0.1", -100, sdk.Coin{Denom: "st", Amount: sdk.NewInt(10000000)}), false}, {"invalid consumer reward denom registration fee amount", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, - time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), "0.33", time.Hour, time.Hour, 24*time.Hour, time.Hour, "0.1", -100, sdk.Coin{Denom: "stake", Amount: sdk.NewInt(-10000000)}), false}, } diff --git a/x/ccv/provider/types/proposal.go b/x/ccv/provider/types/proposal.go index 913152e68c..43f5d027eb 100644 --- a/x/ccv/provider/types/proposal.go +++ b/x/ccv/provider/types/proposal.go @@ -8,8 +8,9 @@ import ( errorsmod "cosmossdk.io/errors" evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" ) @@ -20,15 +21,15 @@ const ( ) var ( - _ govtypes.Content = &ConsumerAdditionProposal{} - _ govtypes.Content = &ConsumerRemovalProposal{} - _ govtypes.Content = &EquivocationProposal{} + _ govv1beta1.Content = &ConsumerAdditionProposal{} + _ govv1beta1.Content = &ConsumerRemovalProposal{} + _ govv1beta1.Content = &EquivocationProposal{} ) func init() { - govtypes.RegisterProposalType(ProposalTypeConsumerAddition) - govtypes.RegisterProposalType(ProposalTypeConsumerRemoval) - govtypes.RegisterProposalType(ProposalTypeEquivocation) + govv1beta1.RegisterProposalType(ProposalTypeConsumerAddition) + govv1beta1.RegisterProposalType(ProposalTypeConsumerRemoval) + govv1beta1.RegisterProposalType(ProposalTypeEquivocation) } // NewConsumerAdditionProposal creates a new consumer addition proposal. @@ -42,7 +43,7 @@ func NewConsumerAdditionProposal(title, description, chainID string, ccvTimeoutPeriod time.Duration, transferTimeoutPeriod time.Duration, unbondingPeriod time.Duration, -) govtypes.Content { +) govv1beta1.Content { return &ConsumerAdditionProposal{ Title: title, Description: description, @@ -77,7 +78,7 @@ func (cccp *ConsumerAdditionProposal) ProposalType() string { // ValidateBasic runs basic stateless validity checks func (cccp *ConsumerAdditionProposal) ValidateBasic() error { - if err := govtypes.ValidateAbstract(cccp); err != nil { + if err := govv1beta1.ValidateAbstract(cccp); err != nil { return err } @@ -165,7 +166,7 @@ func (cccp *ConsumerAdditionProposal) String() string { } // NewConsumerRemovalProposal creates a new consumer removal proposal. -func NewConsumerRemovalProposal(title, description, chainID string, stopTime time.Time) govtypes.Content { +func NewConsumerRemovalProposal(title, description, chainID string, stopTime time.Time) govv1beta1.Content { return &ConsumerRemovalProposal{ Title: title, Description: description, @@ -182,7 +183,7 @@ func (sccp *ConsumerRemovalProposal) ProposalType() string { return ProposalType // ValidateBasic runs basic stateless validity checks func (sccp *ConsumerRemovalProposal) ValidateBasic() error { - if err := govtypes.ValidateAbstract(sccp); err != nil { + if err := govv1beta1.ValidateAbstract(sccp); err != nil { return err } @@ -197,7 +198,7 @@ func (sccp *ConsumerRemovalProposal) ValidateBasic() error { } // NewEquivocationProposal creates a new equivocation proposal. -func NewEquivocationProposal(title, description string, equivocations []*evidencetypes.Equivocation) govtypes.Content { +func NewEquivocationProposal(title, description string, equivocations []*evidencetypes.Equivocation) govv1beta1.Content { return &EquivocationProposal{ Title: title, Description: description, @@ -215,7 +216,7 @@ func (sp *EquivocationProposal) ProposalType() string { // ValidateBasic runs basic stateless validity checks func (sp *EquivocationProposal) ValidateBasic() error { - if err := govtypes.ValidateAbstract(sp); err != nil { + if err := govv1beta1.ValidateAbstract(sp); err != nil { return err } if len(sp.Equivocations) == 0 { diff --git a/x/ccv/provider/types/proposal_test.go b/x/ccv/provider/types/proposal_test.go index d1440eb9a0..4227654bd9 100644 --- a/x/ccv/provider/types/proposal_test.go +++ b/x/ccv/provider/types/proposal_test.go @@ -12,10 +12,12 @@ import ( "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" ) @@ -24,7 +26,7 @@ func TestConsumerAdditionProposalValidateBasic(t *testing.T) { testCases := []struct { name string - proposal govtypes.Content + proposal govv1beta1.Content expPass bool }{ { @@ -245,7 +247,7 @@ func TestMarshalConsumerAdditionProposal(t *testing.T) { // create codec ir := codectypes.NewInterfaceRegistry() types.RegisterInterfaces(ir) - govtypes.RegisterInterfaces(ir) + govv1.RegisterInterfaces(ir) clienttypes.RegisterInterfaces(ir) ibctmtypes.RegisterInterfaces(ir) cdc := codec.NewProtoCodec(ir) @@ -310,7 +312,7 @@ func TestConsumerAdditionProposalString(t *testing.T) { func TestEquivocationProposalValidateBasic(t *testing.T) { tests := []struct { name string - proposal govtypes.Content + proposal govv1beta1.Content expectedError string }{ { diff --git a/x/ccv/provider/types/provider.pb.go b/x/ccv/provider/types/provider.pb.go index acc95ca9af..49c2bb7cda 100644 --- a/x/ccv/provider/types/provider.pb.go +++ b/x/ccv/provider/types/provider.pb.go @@ -5,14 +5,14 @@ package types import ( fmt "fmt" - types3 "github.com/cosmos/cosmos-sdk/types" + crypto "github.com/cometbft/cometbft/proto/tendermint/crypto" + types2 "github.com/cosmos/cosmos-sdk/types" types1 "github.com/cosmos/cosmos-sdk/x/evidence/types" - types "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - types2 "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" - _ "github.com/gogo/protobuf/gogoproto" - proto "github.com/gogo/protobuf/proto" - github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" - crypto "github.com/tendermint/tendermint/proto/tendermint/crypto" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + 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" _ "google.golang.org/protobuf/types/known/durationpb" _ "google.golang.org/protobuf/types/known/timestamppb" io "io" @@ -33,28 +33,34 @@ var _ = time.Kitchen // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain. -// If it passes, then all validators on the provider chain are expected to validate the consumer chain at spawn time -// or get slashed. It is recommended that spawn time occurs after the proposal end time. +// ConsumerAdditionProposal is a governance proposal on the provider chain to +// spawn a new consumer chain. If it passes, then all validators on the provider +// chain are expected to validate the consumer chain at spawn time or get +// slashed. It is recommended that spawn time occurs after the proposal end +// time. type ConsumerAdditionProposal struct { // the title of the proposal Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` // the description of the proposal Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` - // the proposed chain-id of the new consumer chain, must be different from all other consumer chain ids of the executing - // provider chain. + // the proposed chain-id of the new consumer chain, must be different from all + // other consumer chain ids of the executing provider chain. ChainId string `protobuf:"bytes,3,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` // the proposed initial height of new consumer chain. - // For a completely new chain, this will be {0,1}. However, it may be different if this is a chain that is converting to a consumer chain. + // For a completely new chain, this will be {0,1}. However, it may be + // different if this is a chain that is converting to a consumer chain. InitialHeight types.Height `protobuf:"bytes,4,opt,name=initial_height,json=initialHeight,proto3" json:"initial_height"` - // The hash of the consumer chain genesis state without the consumer CCV module genesis params. - // It is used for off-chain confirmation of genesis.json validity by validators and other parties. + // The hash of the consumer chain genesis state without the consumer CCV + // module genesis params. It is used for off-chain confirmation of + // genesis.json validity by validators and other parties. GenesisHash []byte `protobuf:"bytes,5,opt,name=genesis_hash,json=genesisHash,proto3" json:"genesis_hash,omitempty"` - // The hash of the consumer chain binary that should be run by validators on chain initialization. - // It is used for off-chain confirmation of binary validity by validators and other parties. + // The hash of the consumer chain binary that should be run by validators on + // chain initialization. It is used for off-chain confirmation of binary + // validity by validators and other parties. BinaryHash []byte `protobuf:"bytes,6,opt,name=binary_hash,json=binaryHash,proto3" json:"binary_hash,omitempty"` - // spawn time is the time on the provider chain at which the consumer chain genesis is finalized and all validators - // will be responsible for starting their consumer chain validator node. + // spawn time is the time on the provider chain at which the consumer chain + // genesis is finalized and all validators will be responsible for starting + // their consumer chain validator node. SpawnTime time.Time `protobuf:"bytes,7,opt,name=spawn_time,json=spawnTime,proto3,stdtime" json:"spawn_time"` // Unbonding period for the consumer, // which should be smaller than that of the provider in general. @@ -67,8 +73,10 @@ type ConsumerAdditionProposal struct { // during distribution events. The fraction is a string representing a // decimal number. For example "0.75" would represent 75%. ConsumerRedistributionFraction string `protobuf:"bytes,11,opt,name=consumer_redistribution_fraction,json=consumerRedistributionFraction,proto3" json:"consumer_redistribution_fraction,omitempty"` - // BlocksPerDistributionTransmission is the number of blocks between ibc-token-transfers from the consumer chain to the provider chain. - // On sending transmission event, `consumer_redistribution_fraction` of the accumulated tokens are sent to the consumer redistribution address. + // BlocksPerDistributionTransmission is the number of blocks between + // ibc-token-transfers from the consumer chain to the provider chain. On + // sending transmission event, `consumer_redistribution_fraction` of the + // accumulated tokens are sent to the consumer redistribution address. BlocksPerDistributionTransmission int64 `protobuf:"varint,12,opt,name=blocks_per_distribution_transmission,json=blocksPerDistributionTransmission,proto3" json:"blocks_per_distribution_transmission,omitempty"` // The number of historical info entries to persist in store. // This param is a part of the cosmos sdk staking module. In the case of @@ -77,9 +85,9 @@ type ConsumerAdditionProposal struct { // The ID of a token transfer channel used for the Reward Distribution // sub-protocol. If DistributionTransmissionChannel == "", a new transfer // channel is created on top of the same connection as the CCV channel. - // Note that transfer_channel_id is the ID of the channel end on the consumer chain. - // it is most relevant for chains performing a sovereign to consumer changeover - // in order to maintan the existing ibc transfer channel + // Note that transfer_channel_id is the ID of the channel end on the consumer + // chain. it is most relevant for chains performing a sovereign to consumer + // changeover in order to maintan the existing ibc transfer channel DistributionTransmissionChannel string `protobuf:"bytes,14,opt,name=distribution_transmission_channel,json=distributionTransmissionChannel,proto3" json:"distribution_transmission_channel,omitempty"` } @@ -115,9 +123,10 @@ func (m *ConsumerAdditionProposal) XXX_DiscardUnknown() { var xxx_messageInfo_ConsumerAdditionProposal proto.InternalMessageInfo -// ConsumerRemovalProposal is a governance proposal on the provider chain to remove (and stop) a consumer chain. -// If it passes, all the consumer chain's state is removed from the provider chain. The outstanding unbonding -// operation funds are released. +// ConsumerRemovalProposal is a governance proposal on the provider chain to +// remove (and stop) a consumer chain. If it passes, all the consumer chain's +// state is removed from the provider chain. The outstanding unbonding operation +// funds are released. type ConsumerRemovalProposal struct { // the title of the proposal Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` @@ -125,7 +134,8 @@ type ConsumerRemovalProposal struct { Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` // the chain-id of the consumer chain to be stopped ChainId string `protobuf:"bytes,3,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` - // the time on the provider chain at which all validators are responsible to stop their consumer chain validator node + // the time on the provider chain at which all validators are responsible to + // stop their consumer chain validator node StopTime time.Time `protobuf:"bytes,4,opt,name=stop_time,json=stopTime,proto3,stdtime" json:"stop_time"` } @@ -253,8 +263,9 @@ func (m *EquivocationProposal) GetEquivocations() []*types1.Equivocation { return nil } -// A persisted queue entry indicating that a slash packet data instance needs to be handled. -// This type belongs in the "global" queue, to coordinate slash packet handling times between consumers. +// A persisted queue entry indicating that a slash packet data instance needs to +// be handled. This type belongs in the "global" queue, to coordinate slash +// packet handling times between consumers. type GlobalSlashEntry struct { // Block time that slash packet was received by provider chain. // This field is used for store key iteration ordering. @@ -267,7 +278,8 @@ type GlobalSlashEntry struct { // The provider's consensus address of the validator being slashed. // This field is used to obtain validator power in HandleThrottleQueues. // - // This field is not used in the store key, but is persisted in value bytes, see QueueGlobalSlashEntry. + // This field is not used in the store key, but is persisted in value bytes, + // see QueueGlobalSlashEntry. ProviderValConsAddr []byte `protobuf:"bytes,4,opt,name=provider_val_cons_addr,json=providerValConsAddr,proto3" json:"provider_val_cons_addr,omitempty"` } @@ -334,12 +346,14 @@ func (m *GlobalSlashEntry) GetProviderValConsAddr() []byte { // Params defines the parameters for CCV Provider module type Params struct { - TemplateClient *types2.ClientState `protobuf:"bytes,1,opt,name=template_client,json=templateClient,proto3" json:"template_client,omitempty"` - // TrustingPeriodFraction is used to compute the consumer and provider IBC client's TrustingPeriod from the chain defined UnbondingPeriod + TemplateClient *_07_tendermint.ClientState `protobuf:"bytes,1,opt,name=template_client,json=templateClient,proto3" json:"template_client,omitempty"` + // TrustingPeriodFraction is used to compute the consumer and provider IBC + // client's TrustingPeriod from the chain defined UnbondingPeriod TrustingPeriodFraction string `protobuf:"bytes,2,opt,name=trusting_period_fraction,json=trustingPeriodFraction,proto3" json:"trusting_period_fraction,omitempty"` // Sent IBC packets will timeout after this duration CcvTimeoutPeriod time.Duration `protobuf:"bytes,3,opt,name=ccv_timeout_period,json=ccvTimeoutPeriod,proto3,stdduration" json:"ccv_timeout_period"` - // The channel initialization (IBC channel opening handshake) will timeout after this duration + // The channel initialization (IBC channel opening handshake) will timeout + // after this duration InitTimeoutPeriod time.Duration `protobuf:"bytes,4,opt,name=init_timeout_period,json=initTimeoutPeriod,proto3,stdduration" json:"init_timeout_period"` // The VSC packets sent by the provider will timeout after this duration. // Note that unlike ccv_timeout_period which is an IBC param, @@ -348,14 +362,15 @@ type Params struct { VscTimeoutPeriod time.Duration `protobuf:"bytes,5,opt,name=vsc_timeout_period,json=vscTimeoutPeriod,proto3,stdduration" json:"vsc_timeout_period"` // The period for which the slash meter is replenished SlashMeterReplenishPeriod time.Duration `protobuf:"bytes,6,opt,name=slash_meter_replenish_period,json=slashMeterReplenishPeriod,proto3,stdduration" json:"slash_meter_replenish_period"` - // The fraction of total voting power that is replenished to the slash meter every replenish period. - // This param also serves as a maximum fraction of total voting power that the slash meter can hold. + // The fraction of total voting power that is replenished to the slash meter + // every replenish period. This param also serves as a maximum fraction of + // total voting power that the slash meter can hold. SlashMeterReplenishFraction string `protobuf:"bytes,7,opt,name=slash_meter_replenish_fraction,json=slashMeterReplenishFraction,proto3" json:"slash_meter_replenish_fraction,omitempty"` // The maximum amount of throttled slash or vsc matured packets // that can be queued for a single consumer before the provider chain halts. MaxThrottledPackets int64 `protobuf:"varint,8,opt,name=max_throttled_packets,json=maxThrottledPackets,proto3" json:"max_throttled_packets,omitempty"` // The fee required to be paid to add a reward denom - ConsumerRewardDenomRegistrationFee types3.Coin `protobuf:"bytes,9,opt,name=consumer_reward_denom_registration_fee,json=consumerRewardDenomRegistrationFee,proto3" json:"consumer_reward_denom_registration_fee"` + ConsumerRewardDenomRegistrationFee types2.Coin `protobuf:"bytes,9,opt,name=consumer_reward_denom_registration_fee,json=consumerRewardDenomRegistrationFee,proto3" json:"consumer_reward_denom_registration_fee"` } func (m *Params) Reset() { *m = Params{} } @@ -391,7 +406,7 @@ func (m *Params) XXX_DiscardUnknown() { var xxx_messageInfo_Params proto.InternalMessageInfo -func (m *Params) GetTemplateClient() *types2.ClientState { +func (m *Params) GetTemplateClient() *_07_tendermint.ClientState { if m != nil { return m.TemplateClient } @@ -447,11 +462,11 @@ func (m *Params) GetMaxThrottledPackets() int64 { return 0 } -func (m *Params) GetConsumerRewardDenomRegistrationFee() types3.Coin { +func (m *Params) GetConsumerRewardDenomRegistrationFee() types2.Coin { if m != nil { return m.ConsumerRewardDenomRegistrationFee } - return types3.Coin{} + return types2.Coin{} } type HandshakeMetadata struct { @@ -552,7 +567,8 @@ func (m *SlashAcks) GetAddresses() []string { return nil } -// ConsumerAdditionProposals holds pending governance proposals on the provider chain to spawn a new chain. +// ConsumerAdditionProposals holds pending governance proposals on the provider +// chain to spawn a new chain. type ConsumerAdditionProposals struct { // proposals waiting for spawn_time to pass Pending []*ConsumerAdditionProposal `protobuf:"bytes,1,rep,name=pending,proto3" json:"pending,omitempty"` @@ -598,7 +614,8 @@ func (m *ConsumerAdditionProposals) GetPending() []*ConsumerAdditionProposal { return nil } -// ConsumerRemovalProposals holds pending governance proposals on the provider chain to remove (and stop) a consumer chain. +// ConsumerRemovalProposals holds pending governance proposals on the provider +// chain to remove (and stop) a consumer chain. type ConsumerRemovalProposals struct { // proposals waiting for stop_time to pass Pending []*ConsumerRemovalProposal `protobuf:"bytes,1,rep,name=pending,proto3" json:"pending,omitempty"` @@ -1015,7 +1032,8 @@ func (m *KeyAssignmentReplacement) GetPower() int64 { } // Used to serialize the ValidatorConsumerPubKey index from key assignment -// ValidatorConsumerPubKey: (chainID, providerAddr consAddr) -> consumerKey tmprotocrypto.PublicKey +// ValidatorConsumerPubKey: (chainID, providerAddr consAddr) -> consumerKey +// tmprotocrypto.PublicKey type ValidatorConsumerPubKey struct { ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` ProviderAddr []byte `protobuf:"bytes,2,opt,name=provider_addr,json=providerAddr,proto3" json:"provider_addr,omitempty"` @@ -1077,7 +1095,8 @@ func (m *ValidatorConsumerPubKey) GetConsumerKey() *crypto.PublicKey { } // Used to serialize the ValidatorConsumerAddr index from key assignment -// ValidatorByConsumerAddr: (chainID, consumerAddr consAddr) -> providerAddr consAddr +// ValidatorByConsumerAddr: (chainID, consumerAddr consAddr) -> providerAddr +// consAddr type ValidatorByConsumerAddr struct { ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` ConsumerAddr []byte `protobuf:"bytes,2,opt,name=consumer_addr,json=consumerAddr,proto3" json:"consumer_addr,omitempty"` @@ -1374,7 +1393,7 @@ func (m *ConsumerAdditionProposal) MarshalToSizedBuffer(dAtA []byte) (int, error i-- dAtA[i] = 0x5a } - n1, err1 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.TransferTimeoutPeriod, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.TransferTimeoutPeriod):]) + n1, err1 := github_com_cosmos_gogoproto_types.StdDurationMarshalTo(m.TransferTimeoutPeriod, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.TransferTimeoutPeriod):]) if err1 != nil { return 0, err1 } @@ -1382,7 +1401,7 @@ func (m *ConsumerAdditionProposal) MarshalToSizedBuffer(dAtA []byte) (int, error i = encodeVarintProvider(dAtA, i, uint64(n1)) i-- dAtA[i] = 0x52 - n2, err2 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.CcvTimeoutPeriod, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.CcvTimeoutPeriod):]) + n2, err2 := github_com_cosmos_gogoproto_types.StdDurationMarshalTo(m.CcvTimeoutPeriod, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.CcvTimeoutPeriod):]) if err2 != nil { return 0, err2 } @@ -1390,7 +1409,7 @@ func (m *ConsumerAdditionProposal) MarshalToSizedBuffer(dAtA []byte) (int, error i = encodeVarintProvider(dAtA, i, uint64(n2)) i-- dAtA[i] = 0x4a - n3, err3 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.UnbondingPeriod, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.UnbondingPeriod):]) + n3, err3 := github_com_cosmos_gogoproto_types.StdDurationMarshalTo(m.UnbondingPeriod, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.UnbondingPeriod):]) if err3 != nil { return 0, err3 } @@ -1398,7 +1417,7 @@ func (m *ConsumerAdditionProposal) MarshalToSizedBuffer(dAtA []byte) (int, error i = encodeVarintProvider(dAtA, i, uint64(n3)) i-- dAtA[i] = 0x42 - n4, err4 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.SpawnTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.SpawnTime):]) + n4, err4 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.SpawnTime, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.SpawnTime):]) if err4 != nil { return 0, err4 } @@ -1474,7 +1493,7 @@ func (m *ConsumerRemovalProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) _ = i var l int _ = l - n6, err6 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.StopTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.StopTime):]) + n6, err6 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.StopTime, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.StopTime):]) if err6 != nil { return 0, err6 } @@ -1596,7 +1615,7 @@ func (m *GlobalSlashEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x12 } - n7, err7 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.RecvTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.RecvTime):]) + n7, err7 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.RecvTime, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.RecvTime):]) if err7 != nil { return 0, err7 } @@ -1649,7 +1668,7 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x3a } - n9, err9 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.SlashMeterReplenishPeriod, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.SlashMeterReplenishPeriod):]) + n9, err9 := github_com_cosmos_gogoproto_types.StdDurationMarshalTo(m.SlashMeterReplenishPeriod, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.SlashMeterReplenishPeriod):]) if err9 != nil { return 0, err9 } @@ -1657,7 +1676,7 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintProvider(dAtA, i, uint64(n9)) i-- dAtA[i] = 0x32 - n10, err10 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.VscTimeoutPeriod, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.VscTimeoutPeriod):]) + n10, err10 := github_com_cosmos_gogoproto_types.StdDurationMarshalTo(m.VscTimeoutPeriod, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.VscTimeoutPeriod):]) if err10 != nil { return 0, err10 } @@ -1665,7 +1684,7 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintProvider(dAtA, i, uint64(n10)) i-- dAtA[i] = 0x2a - n11, err11 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.InitTimeoutPeriod, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.InitTimeoutPeriod):]) + n11, err11 := github_com_cosmos_gogoproto_types.StdDurationMarshalTo(m.InitTimeoutPeriod, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.InitTimeoutPeriod):]) if err11 != nil { return 0, err11 } @@ -1673,7 +1692,7 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintProvider(dAtA, i, uint64(n11)) i-- dAtA[i] = 0x22 - n12, err12 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.CcvTimeoutPeriod, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.CcvTimeoutPeriod):]) + n12, err12 := github_com_cosmos_gogoproto_types.StdDurationMarshalTo(m.CcvTimeoutPeriod, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.CcvTimeoutPeriod):]) if err12 != nil { return 0, err12 } @@ -2053,7 +2072,7 @@ func (m *VscSendTimestamp) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - n16, err16 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp):]) + n16, err16 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.Timestamp):]) if err16 != nil { return 0, err16 } @@ -2295,13 +2314,13 @@ func (m *ConsumerAdditionProposal) Size() (n int) { if l > 0 { n += 1 + l + sovProvider(uint64(l)) } - l = github_com_gogo_protobuf_types.SizeOfStdTime(m.SpawnTime) + l = github_com_cosmos_gogoproto_types.SizeOfStdTime(m.SpawnTime) n += 1 + l + sovProvider(uint64(l)) - l = github_com_gogo_protobuf_types.SizeOfStdDuration(m.UnbondingPeriod) + l = github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.UnbondingPeriod) n += 1 + l + sovProvider(uint64(l)) - l = github_com_gogo_protobuf_types.SizeOfStdDuration(m.CcvTimeoutPeriod) + l = github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.CcvTimeoutPeriod) n += 1 + l + sovProvider(uint64(l)) - l = github_com_gogo_protobuf_types.SizeOfStdDuration(m.TransferTimeoutPeriod) + l = github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.TransferTimeoutPeriod) n += 1 + l + sovProvider(uint64(l)) l = len(m.ConsumerRedistributionFraction) if l > 0 { @@ -2338,7 +2357,7 @@ func (m *ConsumerRemovalProposal) Size() (n int) { if l > 0 { n += 1 + l + sovProvider(uint64(l)) } - l = github_com_gogo_protobuf_types.SizeOfStdTime(m.StopTime) + l = github_com_cosmos_gogoproto_types.SizeOfStdTime(m.StopTime) n += 1 + l + sovProvider(uint64(l)) return n } @@ -2372,7 +2391,7 @@ func (m *GlobalSlashEntry) Size() (n int) { } var l int _ = l - l = github_com_gogo_protobuf_types.SizeOfStdTime(m.RecvTime) + l = github_com_cosmos_gogoproto_types.SizeOfStdTime(m.RecvTime) n += 1 + l + sovProvider(uint64(l)) l = len(m.ConsumerChainID) if l > 0 { @@ -2402,13 +2421,13 @@ func (m *Params) Size() (n int) { if l > 0 { n += 1 + l + sovProvider(uint64(l)) } - l = github_com_gogo_protobuf_types.SizeOfStdDuration(m.CcvTimeoutPeriod) + l = github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.CcvTimeoutPeriod) n += 1 + l + sovProvider(uint64(l)) - l = github_com_gogo_protobuf_types.SizeOfStdDuration(m.InitTimeoutPeriod) + l = github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.InitTimeoutPeriod) n += 1 + l + sovProvider(uint64(l)) - l = github_com_gogo_protobuf_types.SizeOfStdDuration(m.VscTimeoutPeriod) + l = github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.VscTimeoutPeriod) n += 1 + l + sovProvider(uint64(l)) - l = github_com_gogo_protobuf_types.SizeOfStdDuration(m.SlashMeterReplenishPeriod) + l = github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.SlashMeterReplenishPeriod) n += 1 + l + sovProvider(uint64(l)) l = len(m.SlashMeterReplenishFraction) if l > 0 { @@ -2578,7 +2597,7 @@ func (m *VscSendTimestamp) Size() (n int) { if m.VscId != 0 { n += 1 + sovProvider(uint64(m.VscId)) } - l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp) + l = github_com_cosmos_gogoproto_types.SizeOfStdTime(m.Timestamp) n += 1 + l + sovProvider(uint64(l)) return n } @@ -2926,7 +2945,7 @@ func (m *ConsumerAdditionProposal) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.SpawnTime, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(&m.SpawnTime, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -2959,7 +2978,7 @@ func (m *ConsumerAdditionProposal) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := github_com_gogo_protobuf_types.StdDurationUnmarshal(&m.UnbondingPeriod, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_cosmos_gogoproto_types.StdDurationUnmarshal(&m.UnbondingPeriod, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -2992,7 +3011,7 @@ func (m *ConsumerAdditionProposal) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := github_com_gogo_protobuf_types.StdDurationUnmarshal(&m.CcvTimeoutPeriod, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_cosmos_gogoproto_types.StdDurationUnmarshal(&m.CcvTimeoutPeriod, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -3025,7 +3044,7 @@ func (m *ConsumerAdditionProposal) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := github_com_gogo_protobuf_types.StdDurationUnmarshal(&m.TransferTimeoutPeriod, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_cosmos_gogoproto_types.StdDurationUnmarshal(&m.TransferTimeoutPeriod, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -3306,7 +3325,7 @@ func (m *ConsumerRemovalProposal) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.StopTime, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(&m.StopTime, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -3537,7 +3556,7 @@ func (m *GlobalSlashEntry) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.RecvTime, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(&m.RecvTime, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -3706,7 +3725,7 @@ func (m *Params) Unmarshal(dAtA []byte) error { return io.ErrUnexpectedEOF } if m.TemplateClient == nil { - m.TemplateClient = &types2.ClientState{} + m.TemplateClient = &_07_tendermint.ClientState{} } if err := m.TemplateClient.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -3773,7 +3792,7 @@ func (m *Params) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := github_com_gogo_protobuf_types.StdDurationUnmarshal(&m.CcvTimeoutPeriod, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_cosmos_gogoproto_types.StdDurationUnmarshal(&m.CcvTimeoutPeriod, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -3806,7 +3825,7 @@ func (m *Params) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := github_com_gogo_protobuf_types.StdDurationUnmarshal(&m.InitTimeoutPeriod, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_cosmos_gogoproto_types.StdDurationUnmarshal(&m.InitTimeoutPeriod, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -3839,7 +3858,7 @@ func (m *Params) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := github_com_gogo_protobuf_types.StdDurationUnmarshal(&m.VscTimeoutPeriod, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_cosmos_gogoproto_types.StdDurationUnmarshal(&m.VscTimeoutPeriod, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -3872,7 +3891,7 @@ func (m *Params) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := github_com_gogo_protobuf_types.StdDurationUnmarshal(&m.SlashMeterReplenishPeriod, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_cosmos_gogoproto_types.StdDurationUnmarshal(&m.SlashMeterReplenishPeriod, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -4965,7 +4984,7 @@ func (m *VscSendTimestamp) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Timestamp, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(&m.Timestamp, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/x/ccv/provider/types/query.pb.go b/x/ccv/provider/types/query.pb.go index b205b0a7ea..5d4fc19077 100644 --- a/x/ccv/provider/types/query.pb.go +++ b/x/ccv/provider/types/query.pb.go @@ -6,12 +6,12 @@ package types import ( context "context" fmt "fmt" + _ "github.com/cosmos/gogoproto/gogoproto" + 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/v2/x/ccv/consumer/types" types1 "github.com/cosmos/interchain-security/v2/x/ccv/types" - _ "github.com/gogo/protobuf/gogoproto" - grpc1 "github.com/gogo/protobuf/grpc" - proto "github.com/gogo/protobuf/proto" - github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" _ "google.golang.org/genproto/googleapis/api/annotations" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" @@ -632,10 +632,11 @@ var xxx_messageInfo_QueryThrottleStateRequest proto.InternalMessageInfo type QueryThrottleStateResponse struct { // current slash_meter state SlashMeter int64 `protobuf:"varint,1,opt,name=slash_meter,json=slashMeter,proto3" json:"slash_meter,omitempty"` - // allowance of voting power units (int) that the slash meter is given per replenish period - // this also serves as the max value for the meter. + // allowance of voting power units (int) that the slash meter is given per + // replenish period this also serves as the max value for the meter. SlashMeterAllowance int64 `protobuf:"varint,2,opt,name=slash_meter_allowance,json=slashMeterAllowance,proto3" json:"slash_meter_allowance,omitempty"` - // next time the slash meter could potentially be replenished, iff it's not full + // next time the slash meter could potentially be replenished, iff it's not + // full NextReplenishCandidate time.Time `protobuf:"bytes,3,opt,name=next_replenish_candidate,json=nextReplenishCandidate,proto3,stdtime" json:"next_replenish_candidate"` // data relevant to currently throttled slash packets Packets []*ThrottledSlashPacket `protobuf:"bytes,4,rep,name=packets,proto3" json:"packets,omitempty"` @@ -810,7 +811,8 @@ func (m *QueryThrottledConsumerPacketDataResponse) GetPacketDataInstances() []Th return nil } -// A query wrapper type for the global entry and data relevant to a throttled slash packet. +// A query wrapper type for the global entry and data relevant to a throttled +// slash packet. type ThrottledSlashPacket struct { GlobalEntry GlobalSlashEntry `protobuf:"bytes,1,opt,name=global_entry,json=globalEntry,proto3" json:"global_entry"` Data types1.SlashPacketData `protobuf:"bytes,2,opt,name=data,proto3" json:"data"` @@ -863,7 +865,8 @@ func (m *ThrottledSlashPacket) GetData() types1.SlashPacketData { return types1.SlashPacketData{} } -// ThrottledPacketDataWrapper contains either SlashPacketData or VSCMaturedPacketData +// ThrottledPacketDataWrapper contains either SlashPacketData or +// VSCMaturedPacketData type ThrottledPacketDataWrapper struct { // Types that are valid to be assigned to Data: // *ThrottledPacketDataWrapper_SlashPacket @@ -1180,12 +1183,14 @@ type QueryClient interface { // QueryProviderAddr returns the provider chain validator // given a consumer chain validator address QueryValidatorProviderAddr(ctx context.Context, in *QueryValidatorProviderAddrRequest, opts ...grpc.CallOption) (*QueryValidatorProviderAddrResponse, error) - // QueryThrottleState returns the main on-chain state relevant to currently throttled slash packets + // QueryThrottleState returns the main on-chain state relevant to currently + // throttled slash packets QueryThrottleState(ctx context.Context, in *QueryThrottleStateRequest, opts ...grpc.CallOption) (*QueryThrottleStateResponse, error) - // QueryThrottledConsumerPacketData returns a list of pending packet data instances - // (slash packet and vsc matured) for a single consumer chain + // QueryThrottledConsumerPacketData returns a list of pending packet data + // instances (slash packet and vsc matured) for a single consumer chain QueryThrottledConsumerPacketData(ctx context.Context, in *QueryThrottledConsumerPacketDataRequest, opts ...grpc.CallOption) (*QueryThrottledConsumerPacketDataResponse, error) - // QueryRegisteredConsumerRewardDenoms returns a list of consumer reward denoms that are registered + // QueryRegisteredConsumerRewardDenoms returns a list of consumer reward + // denoms that are registered QueryRegisteredConsumerRewardDenoms(ctx context.Context, in *QueryRegisteredConsumerRewardDenomsRequest, opts ...grpc.CallOption) (*QueryRegisteredConsumerRewardDenomsResponse, error) } @@ -1296,12 +1301,14 @@ type QueryServer interface { // QueryProviderAddr returns the provider chain validator // given a consumer chain validator address QueryValidatorProviderAddr(context.Context, *QueryValidatorProviderAddrRequest) (*QueryValidatorProviderAddrResponse, error) - // QueryThrottleState returns the main on-chain state relevant to currently throttled slash packets + // QueryThrottleState returns the main on-chain state relevant to currently + // throttled slash packets QueryThrottleState(context.Context, *QueryThrottleStateRequest) (*QueryThrottleStateResponse, error) - // QueryThrottledConsumerPacketData returns a list of pending packet data instances - // (slash packet and vsc matured) for a single consumer chain + // QueryThrottledConsumerPacketData returns a list of pending packet data + // instances (slash packet and vsc matured) for a single consumer chain QueryThrottledConsumerPacketData(context.Context, *QueryThrottledConsumerPacketDataRequest) (*QueryThrottledConsumerPacketDataResponse, error) - // QueryRegisteredConsumerRewardDenoms returns a list of consumer reward denoms that are registered + // QueryRegisteredConsumerRewardDenoms returns a list of consumer reward + // denoms that are registered QueryRegisteredConsumerRewardDenoms(context.Context, *QueryRegisteredConsumerRewardDenomsRequest) (*QueryRegisteredConsumerRewardDenomsResponse, error) } @@ -2015,7 +2022,7 @@ func (m *QueryThrottleStateResponse) MarshalToSizedBuffer(dAtA []byte) (int, err dAtA[i] = 0x22 } } - n4, err4 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.NextReplenishCandidate, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.NextReplenishCandidate):]) + n4, err4 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.NextReplenishCandidate, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.NextReplenishCandidate):]) if err4 != nil { return 0, err4 } @@ -2488,7 +2495,7 @@ func (m *QueryThrottleStateResponse) Size() (n int) { if m.SlashMeterAllowance != 0 { n += 1 + sovQuery(uint64(m.SlashMeterAllowance)) } - l = github_com_gogo_protobuf_types.SizeOfStdTime(m.NextReplenishCandidate) + l = github_com_cosmos_gogoproto_types.SizeOfStdTime(m.NextReplenishCandidate) n += 1 + l + sovQuery(uint64(l)) if len(m.Packets) > 0 { for _, e := range m.Packets { @@ -3836,7 +3843,7 @@ func (m *QueryThrottleStateResponse) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.NextReplenishCandidate, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(&m.NextReplenishCandidate, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/x/ccv/provider/types/tx.pb.go b/x/ccv/provider/types/tx.pb.go index 3603695359..746f92b417 100644 --- a/x/ccv/provider/types/tx.pb.go +++ b/x/ccv/provider/types/tx.pb.go @@ -6,11 +6,11 @@ package types import ( context "context" fmt "fmt" + _ "github.com/cosmos/cosmos-proto" _ "github.com/cosmos/cosmos-sdk/codec/types" - _ "github.com/gogo/protobuf/gogoproto" - grpc1 "github.com/gogo/protobuf/grpc" - proto "github.com/gogo/protobuf/proto" - _ "github.com/regen-network/cosmos-proto" + _ "github.com/cosmos/gogoproto/gogoproto" + grpc1 "github.com/cosmos/gogoproto/grpc" + proto "github.com/cosmos/gogoproto/proto" _ "google.golang.org/genproto/googleapis/api/annotations" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" @@ -152,7 +152,8 @@ func (m *MsgRegisterConsumerRewardDenom) XXX_DiscardUnknown() { var xxx_messageInfo_MsgRegisterConsumerRewardDenom proto.InternalMessageInfo -// MsgRegisterConsumerRewardDenomResponse defines the Msg/RegisterConsumerRewardDenom response type. +// MsgRegisterConsumerRewardDenomResponse defines the +// Msg/RegisterConsumerRewardDenom response type. type MsgRegisterConsumerRewardDenomResponse struct { } diff --git a/x/ccv/types/ccv.go b/x/ccv/types/ccv.go index 6ec3a6c7c3..62111a7b65 100644 --- a/x/ccv/types/ccv.go +++ b/x/ccv/types/ccv.go @@ -4,8 +4,8 @@ import ( "fmt" errorsmod "cosmossdk.io/errors" + abci "github.com/cometbft/cometbft/abci/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - abci "github.com/tendermint/tendermint/abci/types" ) func NewValidatorSetChangePacketData(valUpdates []abci.ValidatorUpdate, valUpdateID uint64, slashAcks []string) ValidatorSetChangePacketData { @@ -51,7 +51,7 @@ func (mat VSCMaturedPacketData) GetBytes() []byte { return bytes } -func NewSlashPacketData(validator abci.Validator, valUpdateId uint64, infractionType stakingtypes.InfractionType) *SlashPacketData { +func NewSlashPacketData(validator abci.Validator, valUpdateId uint64, infractionType stakingtypes.Infraction) *SlashPacketData { return &SlashPacketData{ Validator: validator, ValsetUpdateId: valUpdateId, @@ -64,7 +64,7 @@ func (vdt SlashPacketData) ValidateBasic() error { return errorsmod.Wrap(ErrInvalidPacketData, "validator fields cannot be empty") } - if vdt.Infraction == stakingtypes.InfractionEmpty { + if vdt.Infraction == stakingtypes.Infraction_INFRACTION_UNSPECIFIED { return errorsmod.Wrap(ErrInvalidPacketData, "invalid infraction type") } diff --git a/x/ccv/types/ccv.pb.go b/x/ccv/types/ccv.pb.go index 510ee2022c..ea2d38dc84 100644 --- a/x/ccv/types/ccv.pb.go +++ b/x/ccv/types/ccv.pb.go @@ -5,10 +5,10 @@ package types import ( fmt "fmt" + types "github.com/cometbft/cometbft/abci/types" types1 "github.com/cosmos/cosmos-sdk/x/staking/types" - _ "github.com/gogo/protobuf/gogoproto" - proto "github.com/gogo/protobuf/proto" - types "github.com/tendermint/tendermint/abci/types" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" io "io" math "math" math_bits "math/bits" @@ -224,7 +224,7 @@ type SlashPacketData struct { // map to the infraction block height on the provider ValsetUpdateId uint64 `protobuf:"varint,2,opt,name=valset_update_id,json=valsetUpdateId,proto3" json:"valset_update_id,omitempty"` // tell if the slashing is for a downtime or a double-signing infraction - Infraction types1.InfractionType `protobuf:"varint,3,opt,name=infraction,proto3,enum=cosmos.staking.v1beta1.InfractionType" json:"infraction,omitempty"` + Infraction types1.Infraction `protobuf:"varint,3,opt,name=infraction,proto3,enum=cosmos.staking.v1beta1.Infraction" json:"infraction,omitempty"` } func (m *SlashPacketData) Reset() { *m = SlashPacketData{} } @@ -274,14 +274,15 @@ func (m *SlashPacketData) GetValsetUpdateId() uint64 { return 0 } -func (m *SlashPacketData) GetInfraction() types1.InfractionType { +func (m *SlashPacketData) GetInfraction() types1.Infraction { if m != nil { return m.Infraction } - return types1.InfractionEmpty + return types1.Infraction_INFRACTION_UNSPECIFIED } -// MaturedUnbondingOps defines a list of ids corresponding to ids of matured unbonding operations. +// MaturedUnbondingOps defines a list of ids corresponding to ids of matured +// unbonding operations. type MaturedUnbondingOps struct { Ids []uint64 `protobuf:"varint,1,rep,packed,name=ids,proto3" json:"ids,omitempty"` } @@ -481,51 +482,51 @@ func init() { } var fileDescriptor_68bd5f3242e6f29c = []byte{ - // 699 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x94, 0xcf, 0x6e, 0xda, 0x4a, - 0x14, 0xc6, 0xed, 0x60, 0x45, 0xca, 0x20, 0x25, 0x8e, 0x2f, 0xf7, 0x8a, 0xf8, 0xde, 0xeb, 0x58, - 0x56, 0xd4, 0xa2, 0x56, 0xb5, 0x8b, 0xd3, 0x45, 0xd5, 0x6e, 0x1a, 0x08, 0x11, 0xa8, 0xf9, 0x83, - 0xec, 0x90, 0xaa, 0xdd, 0x58, 0x83, 0x3d, 0x81, 0x11, 0x60, 0x23, 0xcf, 0x60, 0x95, 0x37, 0xa8, - 0xb2, 0xea, 0x0b, 0x64, 0x55, 0xf5, 0x41, 0xba, 0xcb, 0x32, 0xbb, 0x66, 0x15, 0x55, 0xc9, 0x1b, - 0xf4, 0x09, 0x2a, 0x0f, 0x86, 0x10, 0x70, 0x90, 0xb2, 0x62, 0x38, 0x73, 0xce, 0x07, 0xdf, 0x6f, - 0x3e, 0x1d, 0xb0, 0x85, 0x7d, 0x8a, 0x42, 0xb7, 0x0d, 0xb1, 0xef, 0x10, 0xe4, 0x0e, 0x42, 0x4c, - 0x87, 0x86, 0xeb, 0x46, 0x46, 0x54, 0x8c, 0x3f, 0xf4, 0x7e, 0x18, 0xd0, 0x40, 0x92, 0x53, 0xba, - 0xf4, 0xf8, 0x3a, 0x2a, 0xca, 0x5b, 0x6e, 0x40, 0x7a, 0x01, 0x31, 0x08, 0x85, 0x1d, 0xec, 0xb7, - 0x8c, 0xa8, 0xd8, 0x44, 0x14, 0x16, 0xc7, 0xdf, 0x47, 0x0a, 0x72, 0xae, 0x15, 0xb4, 0x02, 0x76, - 0x34, 0xe2, 0x53, 0x52, 0xfd, 0x97, 0x22, 0xdf, 0x43, 0x61, 0x0f, 0xfb, 0xd4, 0x80, 0x4d, 0x17, - 0x1b, 0x74, 0xd8, 0x47, 0x64, 0x74, 0xa9, 0x5d, 0xf1, 0xe0, 0xbf, 0x13, 0xd8, 0xc5, 0x1e, 0xa4, - 0x41, 0x68, 0x23, 0x5a, 0x6e, 0x43, 0xbf, 0x85, 0xea, 0xd0, 0xed, 0x20, 0xba, 0x0b, 0x29, 0x94, - 0x02, 0xb0, 0x1e, 0x8d, 0xef, 0x9d, 0x41, 0xdf, 0x83, 0x14, 0x91, 0x3c, 0xaf, 0x66, 0x0a, 0x59, - 0x53, 0xd5, 0xef, 0x94, 0xf5, 0x58, 0x59, 0x9f, 0x28, 0x35, 0x58, 0x63, 0x49, 0xbd, 0xb8, 0xde, - 0xe4, 0x7e, 0x5f, 0x6f, 0xe6, 0x87, 0xb0, 0xd7, 0x7d, 0xa3, 0xcd, 0x09, 0x69, 0x96, 0x18, 0xdd, - 0x1f, 0x21, 0x52, 0x01, 0xc4, 0x35, 0x82, 0x68, 0xd2, 0xe4, 0x60, 0x2f, 0xbf, 0xa4, 0xf2, 0x05, - 0xc1, 0x5a, 0x1d, 0xd5, 0x47, 0x8d, 0x35, 0x4f, 0xfa, 0x1f, 0x00, 0xd2, 0x85, 0xa4, 0xed, 0x40, - 0xb7, 0x43, 0xf2, 0x19, 0x35, 0x53, 0x58, 0xb1, 0x56, 0x58, 0x65, 0xc7, 0xed, 0x10, 0x2d, 0x00, - 0x1b, 0x0f, 0x39, 0x23, 0x92, 0x05, 0x84, 0x2e, 0x26, 0x34, 0x71, 0xf2, 0x5a, 0x7f, 0x98, 0xbd, - 0xbe, 0x08, 0x4f, 0x49, 0x88, 0x1d, 0x5a, 0x4c, 0x4b, 0x7b, 0x07, 0x72, 0x27, 0x76, 0xf9, 0x00, - 0xd2, 0x41, 0x88, 0xbc, 0x29, 0x84, 0x69, 0x8e, 0xf8, 0x34, 0x47, 0xda, 0x4f, 0x1e, 0xac, 0xd9, - 0xb1, 0x81, 0xa9, 0x69, 0x0b, 0xac, 0x4c, 0x18, 0xb1, 0xb1, 0xac, 0x29, 0x3f, 0x0c, 0xbe, 0x94, - 0x4f, 0x90, 0x8b, 0x33, 0xc8, 0x35, 0xeb, 0x4e, 0xe6, 0x11, 0x8c, 0xf7, 0x00, 0xc0, 0xfe, 0x69, - 0x08, 0x5d, 0x8a, 0x03, 0x3f, 0x9f, 0x51, 0xf9, 0xc2, 0xaa, 0xf9, 0x44, 0x1f, 0xa5, 0x51, 0x1f, - 0xa7, 0x2f, 0x49, 0xa3, 0x5e, 0x9b, 0x74, 0x1e, 0x0f, 0xfb, 0xc8, 0x9a, 0x9a, 0xd4, 0x9e, 0x82, - 0xbf, 0x12, 0x30, 0x0d, 0xbf, 0x19, 0xf8, 0x1e, 0xf6, 0x5b, 0x47, 0x7d, 0x22, 0x89, 0x20, 0x83, - 0xbd, 0x51, 0x9e, 0x04, 0x2b, 0x3e, 0x6a, 0xdf, 0x97, 0x80, 0x54, 0x0e, 0x7c, 0x32, 0xe8, 0xa1, - 0x70, 0x8a, 0xc2, 0x1e, 0x10, 0xe2, 0xd8, 0x32, 0x00, 0xab, 0xa6, 0xb9, 0xe8, 0xbd, 0xe6, 0xa7, - 0xd9, 0xbf, 0x61, 0xf3, 0xd2, 0x07, 0xb0, 0x46, 0xee, 0x03, 0x66, 0xc6, 0xb3, 0xe6, 0xf3, 0x45, - 0x92, 0x33, 0x6f, 0x52, 0xe5, 0xac, 0x59, 0x15, 0xe9, 0x14, 0xe4, 0x22, 0xe2, 0xce, 0x3d, 0x3e, - 0x43, 0x96, 0x35, 0x5f, 0x2e, 0x0c, 0x58, 0x4a, 0x68, 0xaa, 0x9c, 0x95, 0xaa, 0x57, 0x5a, 0x06, - 0x82, 0x07, 0x29, 0xd4, 0x9a, 0xe0, 0x9f, 0x79, 0xa3, 0xfb, 0x98, 0x50, 0xa9, 0x7a, 0x2f, 0xda, - 0xfa, 0xe3, 0x50, 0x4d, 0x07, 0xfa, 0xd9, 0x0f, 0x3e, 0xed, 0x47, 0x62, 0x9a, 0xd2, 0x5b, 0xa0, - 0x96, 0x8f, 0x0e, 0xed, 0xc6, 0x41, 0xc5, 0x72, 0xea, 0x3b, 0xe5, 0xf7, 0x95, 0x63, 0xe7, 0xf8, - 0x63, 0xbd, 0xe2, 0x34, 0x0e, 0xed, 0x7a, 0xa5, 0x5c, 0xdb, 0xab, 0x55, 0x76, 0x45, 0x4e, 0xfe, - 0xfb, 0xec, 0x5c, 0x5d, 0x6f, 0xf8, 0xa4, 0x8f, 0x5c, 0x7c, 0x8a, 0xc7, 0x3e, 0x24, 0x03, 0xc8, - 0xa9, 0xc3, 0xf6, 0xfe, 0x8e, 0x5d, 0x15, 0x79, 0x79, 0xed, 0xec, 0x5c, 0xcd, 0x4e, 0x31, 0x97, - 0xb6, 0xc1, 0x46, 0xea, 0x40, 0x4c, 0x4e, 0x5c, 0x92, 0x73, 0x67, 0xe7, 0xaa, 0x78, 0x32, 0x43, - 0x4b, 0x16, 0xbe, 0x7c, 0x53, 0xb8, 0xd2, 0xe1, 0xc5, 0x8d, 0xc2, 0x5f, 0xde, 0x28, 0xfc, 0xaf, - 0x1b, 0x85, 0xff, 0x7a, 0xab, 0x70, 0x97, 0xb7, 0x0a, 0x77, 0x75, 0xab, 0x70, 0x9f, 0x5e, 0xb5, - 0x30, 0x6d, 0x0f, 0x9a, 0xba, 0x1b, 0xf4, 0x8c, 0x64, 0xbd, 0xde, 0xa1, 0x7a, 0x31, 0xd9, 0xd3, - 0x91, 0x69, 0x7c, 0x66, 0xcb, 0x9a, 0xad, 0xcd, 0xe6, 0x32, 0xdb, 0x9b, 0xdb, 0x7f, 0x02, 0x00, - 0x00, 0xff, 0xff, 0xb7, 0xf6, 0x8f, 0xaa, 0xd4, 0x05, 0x00, 0x00, + // 697 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x94, 0xcf, 0x6a, 0xdb, 0x4a, + 0x14, 0xc6, 0xa5, 0x58, 0x04, 0x32, 0x86, 0x44, 0xd1, 0xf5, 0xbd, 0x38, 0xba, 0xad, 0x22, 0x44, + 0xa0, 0xa6, 0xa5, 0x52, 0xad, 0x74, 0x51, 0xda, 0x4d, 0x63, 0xc7, 0xc1, 0xa6, 0xf9, 0x63, 0xa4, + 0x38, 0xa5, 0xdd, 0x88, 0xb1, 0x34, 0xb1, 0x07, 0xdb, 0x1a, 0xa3, 0x19, 0x8b, 0xfa, 0x0d, 0x4a, + 0x56, 0x7d, 0x81, 0xac, 0x4a, 0x1f, 0xa4, 0xbb, 0x2c, 0x03, 0xdd, 0x64, 0x15, 0x4a, 0xf2, 0x06, + 0x7d, 0x82, 0x22, 0x59, 0x76, 0x1c, 0x5b, 0x31, 0x64, 0xe5, 0xf1, 0x99, 0x73, 0x3e, 0xf1, 0xfd, + 0xe6, 0xe3, 0x80, 0x2d, 0xec, 0x33, 0x14, 0xb8, 0x6d, 0x88, 0x7d, 0x87, 0x22, 0x77, 0x10, 0x60, + 0x36, 0x34, 0x5c, 0x37, 0x34, 0xc2, 0x62, 0xf4, 0xa3, 0xf7, 0x03, 0xc2, 0x88, 0x24, 0xa7, 0x74, + 0xe9, 0xd1, 0x75, 0x58, 0x94, 0xb7, 0x5c, 0x42, 0x7b, 0x84, 0x1a, 0x94, 0xc1, 0x0e, 0xf6, 0x5b, + 0x46, 0x58, 0x6c, 0x22, 0x06, 0x8b, 0xe3, 0xff, 0x23, 0x05, 0x39, 0xd7, 0x22, 0x2d, 0x12, 0x1f, + 0x8d, 0xe8, 0x94, 0x54, 0xff, 0x67, 0xc8, 0xf7, 0x50, 0xd0, 0xc3, 0x3e, 0x33, 0x60, 0xd3, 0xc5, + 0x06, 0x1b, 0xf6, 0x11, 0x1d, 0x5d, 0x6a, 0x57, 0x3c, 0x78, 0x72, 0x02, 0xbb, 0xd8, 0x83, 0x8c, + 0x04, 0x36, 0x62, 0xe5, 0x36, 0xf4, 0x5b, 0xa8, 0x0e, 0xdd, 0x0e, 0x62, 0xbb, 0x90, 0x41, 0x89, + 0x80, 0xf5, 0x70, 0x7c, 0xef, 0x0c, 0xfa, 0x1e, 0x64, 0x88, 0xe6, 0x79, 0x35, 0x53, 0xc8, 0x9a, + 0xaa, 0x7e, 0xa7, 0xac, 0x47, 0xca, 0xfa, 0x44, 0xa9, 0x11, 0x37, 0x96, 0xd4, 0x8b, 0xeb, 0x4d, + 0xee, 0xcf, 0xf5, 0x66, 0x7e, 0x08, 0x7b, 0xdd, 0xb7, 0xda, 0x9c, 0x90, 0x66, 0x89, 0xe1, 0xfd, + 0x11, 0x2a, 0x15, 0x40, 0x54, 0xa3, 0x88, 0x25, 0x4d, 0x0e, 0xf6, 0xf2, 0x4b, 0x2a, 0x5f, 0x10, + 0xac, 0xd5, 0x51, 0x7d, 0xd4, 0x58, 0xf3, 0xa4, 0xa7, 0x00, 0xd0, 0x2e, 0xa4, 0x6d, 0x07, 0xba, + 0x1d, 0x9a, 0xcf, 0xa8, 0x99, 0xc2, 0x8a, 0xb5, 0x12, 0x57, 0x76, 0xdc, 0x0e, 0xd5, 0x08, 0xd8, + 0x78, 0xc8, 0x19, 0x95, 0x2c, 0x20, 0x74, 0x31, 0x65, 0x89, 0x93, 0x37, 0xfa, 0xc3, 0xec, 0xf5, + 0x45, 0x78, 0x4a, 0x42, 0xe4, 0xd0, 0x8a, 0xb5, 0xb4, 0xf7, 0x20, 0x77, 0x62, 0x97, 0x0f, 0x20, + 0x1b, 0x04, 0xc8, 0x9b, 0x42, 0x98, 0xe6, 0x88, 0x4f, 0x73, 0xa4, 0xfd, 0xe2, 0xc1, 0x9a, 0x1d, + 0x19, 0x98, 0x9a, 0xb6, 0xc0, 0xca, 0x84, 0x51, 0x3c, 0x96, 0x35, 0xe5, 0x87, 0xc1, 0x97, 0xf2, + 0x09, 0x72, 0x71, 0x06, 0xb9, 0x66, 0xdd, 0xc9, 0x3c, 0x82, 0x71, 0x09, 0x00, 0xec, 0x9f, 0x06, + 0xd0, 0x65, 0x98, 0xf8, 0xf9, 0x8c, 0xca, 0x17, 0x56, 0x4d, 0x4d, 0x1f, 0xa5, 0x51, 0x1f, 0xa7, + 0x2f, 0x49, 0xa3, 0x5e, 0x9b, 0x74, 0x5a, 0x53, 0x53, 0xda, 0x33, 0xf0, 0x4f, 0x02, 0xa5, 0xe1, + 0x37, 0x89, 0xef, 0x61, 0xbf, 0x75, 0xd4, 0xa7, 0x92, 0x08, 0x32, 0xd8, 0x1b, 0x65, 0x49, 0xb0, + 0xa2, 0xa3, 0xf6, 0x63, 0x09, 0x48, 0x65, 0xe2, 0xd3, 0x41, 0x0f, 0x05, 0x53, 0x04, 0xf6, 0x80, + 0x10, 0x45, 0x36, 0x36, 0xbf, 0x6a, 0x9a, 0x8b, 0xde, 0x6a, 0x7e, 0xfa, 0x78, 0xd8, 0x47, 0x56, + 0x3c, 0x2f, 0x7d, 0x04, 0x6b, 0xf4, 0x3e, 0xdc, 0xd8, 0x74, 0xd6, 0x7c, 0xb1, 0x48, 0x72, 0xe6, + 0x3d, 0xaa, 0x9c, 0x35, 0xab, 0x22, 0x9d, 0x82, 0x5c, 0x48, 0xdd, 0xb9, 0x87, 0x8f, 0x71, 0x65, + 0xcd, 0x57, 0x0b, 0xc3, 0x95, 0x12, 0x98, 0x2a, 0x67, 0xa5, 0xea, 0x95, 0x96, 0x81, 0xe0, 0x41, + 0x06, 0xb5, 0x26, 0xf8, 0x6f, 0xde, 0xe8, 0x3e, 0xa6, 0x4c, 0xaa, 0xde, 0x8b, 0xb5, 0xfe, 0x38, + 0x54, 0xd3, 0x61, 0x7e, 0xfe, 0x93, 0x4f, 0xfb, 0x48, 0x44, 0x53, 0x7a, 0x07, 0xd4, 0xf2, 0xd1, + 0xa1, 0xdd, 0x38, 0xa8, 0x58, 0x4e, 0x7d, 0xa7, 0xfc, 0xa1, 0x72, 0xec, 0x1c, 0x7f, 0xaa, 0x57, + 0x9c, 0xc6, 0xa1, 0x5d, 0xaf, 0x94, 0x6b, 0x7b, 0xb5, 0xca, 0xae, 0xc8, 0xc9, 0xff, 0x9e, 0x9d, + 0xab, 0xeb, 0x0d, 0x9f, 0xf6, 0x91, 0x8b, 0x4f, 0xf1, 0xd8, 0x87, 0x64, 0x00, 0x39, 0x75, 0xd8, + 0xde, 0xdf, 0xb1, 0xab, 0x22, 0x2f, 0xaf, 0x9d, 0x9d, 0xab, 0xd9, 0x29, 0xe6, 0xd2, 0x36, 0xd8, + 0x48, 0x1d, 0x88, 0xc8, 0x89, 0x4b, 0x72, 0xee, 0xec, 0x5c, 0x15, 0x4f, 0x66, 0x68, 0xc9, 0xc2, + 0xd7, 0xef, 0x0a, 0x57, 0x3a, 0xbc, 0xb8, 0x51, 0xf8, 0xcb, 0x1b, 0x85, 0xff, 0x7d, 0xa3, 0xf0, + 0xdf, 0x6e, 0x15, 0xee, 0xf2, 0x56, 0xe1, 0xae, 0x6e, 0x15, 0xee, 0xf3, 0xeb, 0x16, 0x66, 0xed, + 0x41, 0x53, 0x77, 0x49, 0xcf, 0x48, 0x56, 0xeb, 0x1d, 0xaa, 0x97, 0x93, 0x1d, 0x1d, 0x9a, 0xc6, + 0x97, 0x78, 0x51, 0xc7, 0x2b, 0xb3, 0xb9, 0x1c, 0xef, 0xcc, 0xed, 0xbf, 0x01, 0x00, 0x00, 0xff, + 0xff, 0x5e, 0x61, 0xe5, 0xc6, 0xd0, 0x05, 0x00, 0x00, } func (m *ValidatorSetChangePacketData) Marshal() (dAtA []byte, err error) { @@ -1382,7 +1383,7 @@ func (m *SlashPacketData) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Infraction |= types1.InfractionType(b&0x7F) << shift + m.Infraction |= types1.Infraction(b&0x7F) << shift if b < 0x80 { break } diff --git a/x/ccv/types/ccv_test.go b/x/ccv/types/ccv_test.go index 5f8b6add34..51979fb4da 100644 --- a/x/ccv/types/ccv_test.go +++ b/x/ccv/types/ccv_test.go @@ -3,11 +3,11 @@ package types_test import ( "testing" + abci "github.com/cometbft/cometbft/abci/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" "github.com/cosmos/interchain-security/v2/x/ccv/types" "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" ) func TestPacketDataValidateBasic(t *testing.T) { diff --git a/x/ccv/types/expected_keepers.go b/x/ccv/types/expected_keepers.go index 7f18324c8d..8176d193b2 100644 --- a/x/ccv/types/expected_keepers.go +++ b/x/ccv/types/expected_keepers.go @@ -4,18 +4,20 @@ import ( context "context" "time" + "cosmossdk.io/math" 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" evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - conntypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" - ibcexported "github.com/cosmos/ibc-go/v4/modules/core/exported" + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/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" + ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" - abci "github.com/tendermint/tendermint/abci/types" + abci "github.com/cometbft/cometbft/abci/types" ) // StakingKeeper defines the contract expected by provider-chain ccv module from a Staking Module that will keep track @@ -29,11 +31,12 @@ type StakingKeeper interface { GetLastValidatorPower(ctx sdk.Context, operator sdk.ValAddress) (power int64) // slash the validator and delegators of the validator, specifying offence height, offence power, and slash fraction Jail(sdk.Context, sdk.ConsAddress) // jail a validator - Slash(sdk.Context, sdk.ConsAddress, int64, int64, sdk.Dec, stakingtypes.InfractionType) + Slash(sdk.Context, sdk.ConsAddress, int64, int64, sdk.Dec) math.Int + SlashWithInfractionReason(sdk.Context, sdk.ConsAddress, int64, int64, sdk.Dec, stakingtypes.Infraction) math.Int Unjail(ctx sdk.Context, addr sdk.ConsAddress) GetValidator(ctx sdk.Context, addr sdk.ValAddress) (validator stakingtypes.Validator, found bool) IterateLastValidatorPowers(ctx sdk.Context, cb func(addr sdk.ValAddress, power int64) (stop bool)) - PowerReduction(ctx sdk.Context) sdk.Int + PowerReduction(ctx sdk.Context) math.Int PutUnbondingOnHold(ctx sdk.Context, id uint64) error IterateValidators(ctx sdk.Context, f func(index int64, validator stakingtypes.ValidatorI) (stop bool)) Validator(ctx sdk.Context, addr sdk.ValAddress) stakingtypes.ValidatorI @@ -41,8 +44,9 @@ type StakingKeeper interface { ValidatorByConsAddr(ctx sdk.Context, consAddr sdk.ConsAddress) stakingtypes.ValidatorI Delegation(ctx sdk.Context, addr sdk.AccAddress, valAddr sdk.ValAddress) stakingtypes.DelegationI MaxValidators(ctx sdk.Context) uint32 - GetLastTotalPower(ctx sdk.Context) sdk.Int + GetLastTotalPower(ctx sdk.Context) math.Int GetLastValidators(ctx sdk.Context) (validators []stakingtypes.Validator) + GetUnbondingType(ctx sdk.Context, id uint64) (unbondingType stakingtypes.UnbondingType, found bool) BondDenom(ctx sdk.Context) (res string) } @@ -65,7 +69,15 @@ type SlashingKeeper interface { type ChannelKeeper interface { GetChannel(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) GetNextSequenceSend(ctx sdk.Context, portID, channelID string) (uint64, bool) - SendPacket(ctx sdk.Context, channelCap *capabilitytypes.Capability, packet ibcexported.PacketI) error + SendPacket( + ctx sdk.Context, + chanCap *capabilitytypes.Capability, + sourcePort string, + sourceChannel string, + timeoutHeight clienttypes.Height, + timeoutTimestamp uint64, + data []byte, + ) (sequence uint64, err error) WriteAcknowledgement(ctx sdk.Context, chanCap *capabilitytypes.Capability, packet ibcexported.PacketI, acknowledgement ibcexported.Acknowledgement) error ChanCloseInit(ctx sdk.Context, portID, channelID string, chanCap *capabilitytypes.Capability) error } @@ -95,7 +107,7 @@ type DistributionKeeper interface { // ConsumerHooks event hooks for newly bonded cross-chain validators type ConsumerHooks interface { - AfterValidatorBonded(ctx sdk.Context, consAddr sdk.ConsAddress, _ sdk.ValAddress) + AfterValidatorBonded(ctx sdk.Context, consAddr sdk.ConsAddress, valAddresses sdk.ValAddress) error } // BankKeeper defines the expected interface needed to retrieve account balances. @@ -113,16 +125,7 @@ type AccountKeeper interface { // IBCTransferKeeper defines the expected interface needed for distribution transfer // of tokens from the consumer to the provider chain type IBCTransferKeeper interface { - SendTransfer( - ctx sdk.Context, - sourcePort, - sourceChannel string, - token sdk.Coin, - sender sdk.AccAddress, - receiver string, - timeoutHeight clienttypes.Height, - timeoutTimestamp uint64, - ) error + Transfer(context.Context, *transfertypes.MsgTransfer) (*transfertypes.MsgTransferResponse, error) } // IBCKeeper defines the expected interface needed for openning a diff --git a/x/ccv/types/shared_params.go b/x/ccv/types/shared_params.go index 04f1cf54e1..8ff676bded 100644 --- a/x/ccv/types/shared_params.go +++ b/x/ccv/types/shared_params.go @@ -5,7 +5,7 @@ import ( "time" sdktypes "github.com/cosmos/cosmos-sdk/types" - ibchost "github.com/cosmos/ibc-go/v4/modules/core/24-host" + ibchost "github.com/cosmos/ibc-go/v7/modules/core/24-host" ) const ( diff --git a/x/ccv/types/utils.go b/x/ccv/types/utils.go index 1d75152186..f27dab2b04 100644 --- a/x/ccv/types/utils.go +++ b/x/ccv/types/utils.go @@ -6,13 +6,13 @@ import ( "time" errorsmod "cosmossdk.io/errors" + abci "github.com/cometbft/cometbft/abci/types" + tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" sdk "github.com/cosmos/cosmos-sdk/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v4/modules/core/24-host" - abci "github.com/tendermint/tendermint/abci/types" - tmprotocrypto "github.com/tendermint/tendermint/proto/tendermint/crypto" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v7/modules/core/24-host" ) func AccumulateChanges(currentChanges, newChanges []abci.ValidatorUpdate) []abci.ValidatorUpdate { @@ -60,36 +60,29 @@ func SendIBCPacket( ctx sdk.Context, scopedKeeper ScopedKeeper, channelKeeper ChannelKeeper, - channelID string, - portID string, + sourceChannelID string, + sourcePortID string, packetData []byte, timeoutPeriod time.Duration, ) error { - channel, ok := channelKeeper.GetChannel(ctx, portID, channelID) + _, ok := channelKeeper.GetChannel(ctx, sourcePortID, sourceChannelID) if !ok { - return errorsmod.Wrapf(channeltypes.ErrChannelNotFound, "channel not found for channel ID: %s", channelID) + return errorsmod.Wrapf(channeltypes.ErrChannelNotFound, "channel not found for channel ID: %s", sourceChannelID) } - channelCap, ok := scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(portID, channelID)) + channelCap, ok := scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(sourcePortID, sourceChannelID)) if !ok { return errorsmod.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") } - // get the next sequence - sequence, found := channelKeeper.GetNextSequenceSend(ctx, portID, channelID) - if !found { - return errorsmod.Wrapf( - channeltypes.ErrSequenceSendNotFound, - "source port: %s, source channel: %s", portID, channelID, - ) - } - packet := channeltypes.NewPacket( - packetData, sequence, - portID, channelID, - channel.Counterparty.PortId, channel.Counterparty.ChannelId, - clienttypes.Height{}, uint64(ctx.BlockTime().Add(timeoutPeriod).UnixNano()), + _, err := channelKeeper.SendPacket(ctx, + channelCap, + sourcePortID, + sourceChannelID, + clienttypes.Height{}, // timeout height disabled + uint64(ctx.BlockTime().Add(timeoutPeriod).UnixNano()), // timeout timestamp + packetData, ) - - return channelKeeper.SendPacket(ctx, channelCap, packet) + return err } // AppendMany appends a variable number of byte slices together diff --git a/x/ccv/types/utils_test.go b/x/ccv/types/utils_test.go index 7faad14757..1267daf119 100644 --- a/x/ccv/types/utils_test.go +++ b/x/ccv/types/utils_test.go @@ -3,11 +3,11 @@ package types_test import ( "testing" + abci "github.com/cometbft/cometbft/abci/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" ibcsimapp "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/simapp" "github.com/cosmos/interchain-security/v2/x/ccv/types" "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" ) func TestAccumulateChanges(t *testing.T) { From df67cc2a2326c35b3b6fa32a08d4494763646eac Mon Sep 17 00:00:00 2001 From: MSalopek Date: Wed, 21 Jun 2023 11:32:35 +0200 Subject: [PATCH 023/134] chore: bump v2 to v3 (#1043) --- .../ante/forbidden_proposals_ante_test.go | 4 ++-- app/consumer-democracy/ante_handler.go | 6 +++--- app/consumer-democracy/app.go | 20 +++++++++---------- .../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 | 14 ++++++------- app/provider/app.go | 16 +++++++-------- app/sovereign/app.go | 8 ++++---- cmd/interchain-security-cd/cmd/root.go | 4 ++-- cmd/interchain-security-cd/main.go | 4 ++-- cmd/interchain-security-cdd/cmd/root.go | 4 ++-- cmd/interchain-security-cdd/main.go | 4 ++-- cmd/interchain-security-pd/cmd/root.go | 4 ++-- cmd/interchain-security-pd/main.go | 4 ++-- cmd/interchain-security-sd/cmd/root.go | 4 ++-- cmd/interchain-security-sd/main.go | 4 ++-- go.mod | 4 ++-- legacy_ibc_testing/simapp/test_helpers.go | 2 +- legacy_ibc_testing/testing/app.go | 6 +++--- legacy_ibc_testing/testing/chain.go | 4 ++-- tests/difference/core/driver/core_test.go | 12 +++++------ tests/difference/core/driver/setup.go | 20 +++++++++---------- tests/e2e/actions.go | 6 +++--- tests/integration/common.go | 10 +++++----- tests/integration/democracy.go | 8 ++++---- tests/integration/distribution.go | 6 +++--- tests/integration/expired_client.go | 4 ++-- tests/integration/instance_test.go | 10 +++++----- tests/integration/key_assignment.go | 4 ++-- tests/integration/normal_operations.go | 2 +- tests/integration/setup.go | 10 +++++----- tests/integration/slashing.go | 6 +++--- tests/integration/stop_consumer.go | 4 ++-- tests/integration/throttle.go | 6 +++--- tests/integration/unbonding.go | 4 ++-- tests/integration/valset_update.go | 2 +- testutil/crypto/crypto.go | 2 +- testutil/ibc_testing/generic_setup.go | 8 ++++---- testutil/ibc_testing/specific_setup.go | 8 ++++---- testutil/integration/debug_test.go | 10 +++++----- testutil/integration/interfaces.go | 8 ++++---- testutil/keeper/expectations.go | 4 ++-- testutil/keeper/unit_test_helpers.go | 10 +++++----- testutil/simibc/chain_util.go | 4 ++-- testutil/simibc/relay_util.go | 4 ++-- testutil/simibc/relayed_path.go | 2 +- x/ccv/consumer/client/cli/query.go | 2 +- x/ccv/consumer/ibc_module.go | 8 ++++---- x/ccv/consumer/ibc_module_test.go | 10 +++++----- x/ccv/consumer/keeper/changeover_test.go | 4 ++-- x/ccv/consumer/keeper/distribution.go | 4 ++-- x/ccv/consumer/keeper/distribution_test.go | 4 ++-- x/ccv/consumer/keeper/genesis.go | 4 ++-- x/ccv/consumer/keeper/genesis_test.go | 10 +++++----- x/ccv/consumer/keeper/grpc_query.go | 2 +- 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/params.go | 4 ++-- x/ccv/consumer/keeper/params_test.go | 6 +++--- x/ccv/consumer/keeper/relay.go | 4 ++-- x/ccv/consumer/keeper/relay_test.go | 8 ++++---- x/ccv/consumer/keeper/soft_opt_out.go | 2 +- x/ccv/consumer/keeper/soft_opt_out_test.go | 6 +++--- x/ccv/consumer/keeper/validators.go | 2 +- x/ccv/consumer/keeper/validators_test.go | 8 ++++---- x/ccv/consumer/module.go | 6 +++--- x/ccv/consumer/types/consumer.pb.go | 2 +- 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.go | 2 +- x/ccv/consumer/types/params_test.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_module.go | 6 +++--- x/ccv/provider/ibc_module_test.go | 10 +++++----- x/ccv/provider/keeper/distribution.go | 4 ++-- x/ccv/provider/keeper/distribution_test.go | 6 +++--- x/ccv/provider/keeper/genesis.go | 4 ++-- x/ccv/provider/keeper/genesis_test.go | 12 +++++------ x/ccv/provider/keeper/grpc_query.go | 4 ++-- x/ccv/provider/keeper/hooks.go | 4 ++-- x/ccv/provider/keeper/hooks_test.go | 6 +++--- x/ccv/provider/keeper/keeper.go | 6 +++--- x/ccv/provider/keeper/keeper_test.go | 10 +++++----- 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/proposal.go | 6 +++--- x/ccv/provider/keeper/proposal_test.go | 12 +++++------ x/ccv/provider/keeper/relay.go | 4 ++-- x/ccv/provider/keeper/relay_test.go | 12 +++++------ x/ccv/provider/keeper/throttle.go | 4 ++-- x/ccv/provider/keeper/throttle_test.go | 10 +++++----- x/ccv/provider/module.go | 6 +++--- 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 | 4 ++-- x/ccv/provider/types/genesis.go | 2 +- x/ccv/provider/types/genesis.pb.go | 4 ++-- x/ccv/provider/types/genesis_test.go | 8 ++++---- 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/params.go | 4 ++-- 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/query.pb.go | 4 ++-- x/ccv/types/ccv_test.go | 2 +- x/ccv/types/utils_test.go | 4 ++-- 122 files changed, 336 insertions(+), 336 deletions(-) diff --git a/app/consumer-democracy/ante/forbidden_proposals_ante_test.go b/app/consumer-democracy/ante/forbidden_proposals_ante_test.go index 5c67506e7c..bbe9f6a5dd 100644 --- a/app/consumer-democracy/ante/forbidden_proposals_ante_test.go +++ b/app/consumer-democracy/ante/forbidden_proposals_ante_test.go @@ -10,8 +10,8 @@ import ( govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" "github.com/cosmos/cosmos-sdk/x/params/types/proposal" - app "github.com/cosmos/interchain-security/v2/app/consumer-democracy" - "github.com/cosmos/interchain-security/v2/app/consumer-democracy/ante" + app "github.com/cosmos/interchain-security/v3/app/consumer-democracy" + "github.com/cosmos/interchain-security/v3/app/consumer-democracy/ante" "github.com/stretchr/testify/require" ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" diff --git a/app/consumer-democracy/ante_handler.go b/app/consumer-democracy/ante_handler.go index b031c9fadc..e27986a482 100644 --- a/app/consumer-democracy/ante_handler.go +++ b/app/consumer-democracy/ante_handler.go @@ -7,9 +7,9 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/ante" ibcante "github.com/cosmos/ibc-go/v7/modules/core/ante" ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" - democracyante "github.com/cosmos/interchain-security/v2/app/consumer-democracy/ante" - consumerante "github.com/cosmos/interchain-security/v2/app/consumer/ante" - ibcconsumerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/consumer/keeper" + democracyante "github.com/cosmos/interchain-security/v3/app/consumer-democracy/ante" + consumerante "github.com/cosmos/interchain-security/v3/app/consumer/ante" + ibcconsumerkeeper "github.com/cosmos/interchain-security/v3/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 e72b62c9e5..298087262d 100644 --- a/app/consumer-democracy/app.go +++ b/app/consumer-democracy/app.go @@ -15,7 +15,7 @@ import ( consensusparamtypes "github.com/cosmos/cosmos-sdk/x/consensus/types" "github.com/cosmos/cosmos-sdk/x/genutil" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" - appparams "github.com/cosmos/interchain-security/v2/app/params" + appparams "github.com/cosmos/interchain-security/v3/app/params" autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" @@ -86,25 +86,25 @@ import ( porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" ibchost "github.com/cosmos/ibc-go/v7/modules/core/exported" ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" - ibctestingcore "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/core" - ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" + ibctestingcore "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/core" + ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" "github.com/spf13/cast" distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" - testutil "github.com/cosmos/interchain-security/v2/testutil/integration" - ccvdistr "github.com/cosmos/interchain-security/v2/x/ccv/democracy/distribution" + testutil "github.com/cosmos/interchain-security/v3/testutil/integration" + ccvdistr "github.com/cosmos/interchain-security/v3/x/ccv/democracy/distribution" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - ccvstaking "github.com/cosmos/interchain-security/v2/x/ccv/democracy/staking" + ccvstaking "github.com/cosmos/interchain-security/v3/x/ccv/democracy/staking" gov "github.com/cosmos/cosmos-sdk/x/gov" govclient "github.com/cosmos/cosmos-sdk/x/gov/client" 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" - ccvgov "github.com/cosmos/interchain-security/v2/x/ccv/democracy/governance" + ccvgov "github.com/cosmos/interchain-security/v3/x/ccv/democracy/governance" // add mint mint "github.com/cosmos/cosmos-sdk/x/mint" @@ -113,9 +113,9 @@ import ( paramproposal "github.com/cosmos/cosmos-sdk/x/params/types/proposal" tendermint "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - consumer "github.com/cosmos/interchain-security/v2/x/ccv/consumer" - consumerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/consumer/keeper" - consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" + consumer "github.com/cosmos/interchain-security/v3/x/ccv/consumer" + consumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" // unnamed import of statik for swagger UI support _ "github.com/cosmos/cosmos-sdk/client/docs/statik" diff --git a/app/consumer-democracy/proposals_whitelisting_test.go b/app/consumer-democracy/proposals_whitelisting_test.go index 3b8bbdb855..a51709ae4a 100644 --- a/app/consumer-democracy/proposals_whitelisting_test.go +++ b/app/consumer-democracy/proposals_whitelisting_test.go @@ -3,9 +3,9 @@ package app_test import ( "testing" - appConsumer "github.com/cosmos/interchain-security/v2/app/consumer-democracy" - ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" - icstestingutils "github.com/cosmos/interchain-security/v2/testutil/ibc_testing" + appConsumer "github.com/cosmos/interchain-security/v3/app/consumer-democracy" + ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" + icstestingutils "github.com/cosmos/interchain-security/v3/testutil/ibc_testing" "github.com/stretchr/testify/require" ) diff --git a/app/consumer/ante/disabled_modules_ante_test.go b/app/consumer/ante/disabled_modules_ante_test.go index 2eb95e1ddb..dd58e8b79e 100644 --- a/app/consumer/ante/disabled_modules_ante_test.go +++ b/app/consumer/ante/disabled_modules_ante_test.go @@ -8,8 +8,8 @@ import ( evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" ibcclienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" - "github.com/cosmos/interchain-security/v2/app/consumer/ante" - "github.com/cosmos/interchain-security/v2/app/params" + "github.com/cosmos/interchain-security/v3/app/consumer/ante" + "github.com/cosmos/interchain-security/v3/app/params" "github.com/stretchr/testify/require" ) diff --git a/app/consumer/ante/msg_filter_ante_test.go b/app/consumer/ante/msg_filter_ante_test.go index 7ff11dc10f..76b3dec604 100644 --- a/app/consumer/ante/msg_filter_ante_test.go +++ b/app/consumer/ante/msg_filter_ante_test.go @@ -6,8 +6,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" ibcclienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" - "github.com/cosmos/interchain-security/v2/app/consumer/ante" - "github.com/cosmos/interchain-security/v2/app/params" + "github.com/cosmos/interchain-security/v3/app/consumer/ante" + "github.com/cosmos/interchain-security/v3/app/params" "github.com/stretchr/testify/require" ) diff --git a/app/consumer/ante_handler.go b/app/consumer/ante_handler.go index be33266f8d..f963150626 100644 --- a/app/consumer/ante_handler.go +++ b/app/consumer/ante_handler.go @@ -8,8 +8,8 @@ import ( ibcante "github.com/cosmos/ibc-go/v7/modules/core/ante" ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" - consumerante "github.com/cosmos/interchain-security/v2/app/consumer/ante" - ibcconsumerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/consumer/keeper" + consumerante "github.com/cosmos/interchain-security/v3/app/consumer/ante" + ibcconsumerkeeper "github.com/cosmos/interchain-security/v3/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 34c18bb249..20b6695dfa 100644 --- a/app/consumer/app.go +++ b/app/consumer/app.go @@ -81,19 +81,19 @@ import ( porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" ibchost "github.com/cosmos/ibc-go/v7/modules/core/exported" ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" - appparams "github.com/cosmos/interchain-security/v2/app/params" - ibctestingcore "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/core" - ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" + appparams "github.com/cosmos/interchain-security/v3/app/params" + ibctestingcore "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/core" + ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" "github.com/spf13/cast" tendermint "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - ibcconsumer "github.com/cosmos/interchain-security/v2/x/ccv/consumer" - ibcconsumerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/consumer/keeper" - ibcconsumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" + ibcconsumer "github.com/cosmos/interchain-security/v3/x/ccv/consumer" + ibcconsumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" + ibcconsumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" // unnamed import of statik for swagger UI support _ "github.com/cosmos/cosmos-sdk/client/docs/statik" - testutil "github.com/cosmos/interchain-security/v2/testutil/integration" + testutil "github.com/cosmos/interchain-security/v3/testutil/integration" ) const ( diff --git a/app/provider/app.go b/app/provider/app.go index 1c73131b63..3fefd34daa 100644 --- a/app/provider/app.go +++ b/app/provider/app.go @@ -14,7 +14,7 @@ import ( autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" - appparams "github.com/cosmos/interchain-security/v2/app/params" + appparams "github.com/cosmos/interchain-security/v3/app/params" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" @@ -93,8 +93,8 @@ import ( ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" tendermint "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - ibctestingcore "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/core" - ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" + ibctestingcore "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/core" + ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" dbm "github.com/cometbft/cometbft-db" abci "github.com/cometbft/cometbft/abci/types" @@ -103,12 +103,12 @@ import ( tmos "github.com/cometbft/cometbft/libs/os" "github.com/spf13/cast" - ibcprovider "github.com/cosmos/interchain-security/v2/x/ccv/provider" - ibcproviderclient "github.com/cosmos/interchain-security/v2/x/ccv/provider/client" - ibcproviderkeeper "github.com/cosmos/interchain-security/v2/x/ccv/provider/keeper" - providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" + ibcprovider "github.com/cosmos/interchain-security/v3/x/ccv/provider" + ibcproviderclient "github.com/cosmos/interchain-security/v3/x/ccv/provider/client" + ibcproviderkeeper "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" + providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" - testutil "github.com/cosmos/interchain-security/v2/testutil/integration" + testutil "github.com/cosmos/interchain-security/v3/testutil/integration" // unnamed import of statik for swagger UI support _ "github.com/cosmos/cosmos-sdk/client/docs/statik" diff --git a/app/sovereign/app.go b/app/sovereign/app.go index 9c729885f4..e616b92514 100644 --- a/app/sovereign/app.go +++ b/app/sovereign/app.go @@ -7,7 +7,7 @@ import ( "os" "path/filepath" - appparams "github.com/cosmos/interchain-security/v2/app/params" + appparams "github.com/cosmos/interchain-security/v3/app/params" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" @@ -82,14 +82,14 @@ import ( porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" ibchost "github.com/cosmos/ibc-go/v7/modules/core/exported" ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" - ibctestingcore "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/core" - ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" + ibctestingcore "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/core" + ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" "github.com/spf13/cast" sdkdistr "github.com/cosmos/cosmos-sdk/x/distribution" distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" - testutil "github.com/cosmos/interchain-security/v2/testutil/integration" + testutil "github.com/cosmos/interchain-security/v3/testutil/integration" sdkstaking "github.com/cosmos/cosmos-sdk/x/staking" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" diff --git a/cmd/interchain-security-cd/cmd/root.go b/cmd/interchain-security-cd/cmd/root.go index 10af60f25f..5fac172a96 100644 --- a/cmd/interchain-security-cd/cmd/root.go +++ b/cmd/interchain-security-cd/cmd/root.go @@ -28,8 +28,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/crisis" genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" - consumer "github.com/cosmos/interchain-security/v2/app/consumer" - "github.com/cosmos/interchain-security/v2/app/params" + consumer "github.com/cosmos/interchain-security/v3/app/consumer" + "github.com/cosmos/interchain-security/v3/app/params" ) // 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 589869cd43..012e5c6d44 100644 --- a/cmd/interchain-security-cd/main.go +++ b/cmd/interchain-security-cd/main.go @@ -5,8 +5,8 @@ import ( "github.com/cosmos/cosmos-sdk/server" svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" - app "github.com/cosmos/interchain-security/v2/app/consumer" - "github.com/cosmos/interchain-security/v2/cmd/interchain-security-cd/cmd" + app "github.com/cosmos/interchain-security/v3/app/consumer" + "github.com/cosmos/interchain-security/v3/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 615bdf499c..1e3f038717 100644 --- a/cmd/interchain-security-cdd/cmd/root.go +++ b/cmd/interchain-security-cdd/cmd/root.go @@ -29,8 +29,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/crisis" genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" - cdd "github.com/cosmos/interchain-security/v2/app/consumer-democracy" - "github.com/cosmos/interchain-security/v2/app/params" + cdd "github.com/cosmos/interchain-security/v3/app/consumer-democracy" + "github.com/cosmos/interchain-security/v3/app/params" ) // 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 f209f0046a..5d04ea379b 100644 --- a/cmd/interchain-security-cdd/main.go +++ b/cmd/interchain-security-cdd/main.go @@ -5,8 +5,8 @@ import ( "github.com/cosmos/cosmos-sdk/server" svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" - app "github.com/cosmos/interchain-security/v2/app/consumer-democracy" - "github.com/cosmos/interchain-security/v2/cmd/interchain-security-cdd/cmd" + app "github.com/cosmos/interchain-security/v3/app/consumer-democracy" + "github.com/cosmos/interchain-security/v3/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 e480acfc34..246e1c182b 100644 --- a/cmd/interchain-security-pd/cmd/root.go +++ b/cmd/interchain-security-pd/cmd/root.go @@ -28,8 +28,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/crisis" genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" - "github.com/cosmos/interchain-security/v2/app/params" - providerApp "github.com/cosmos/interchain-security/v2/app/provider" + "github.com/cosmos/interchain-security/v3/app/params" + providerApp "github.com/cosmos/interchain-security/v3/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 d39371adc1..9ad1cd67cc 100644 --- a/cmd/interchain-security-pd/main.go +++ b/cmd/interchain-security-pd/main.go @@ -5,8 +5,8 @@ import ( "github.com/cosmos/cosmos-sdk/server" svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" - app "github.com/cosmos/interchain-security/v2/app/provider" - "github.com/cosmos/interchain-security/v2/cmd/interchain-security-pd/cmd" + app "github.com/cosmos/interchain-security/v3/app/provider" + "github.com/cosmos/interchain-security/v3/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 955da62464..a93c841474 100644 --- a/cmd/interchain-security-sd/cmd/root.go +++ b/cmd/interchain-security-sd/cmd/root.go @@ -28,8 +28,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/crisis" genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" - "github.com/cosmos/interchain-security/v2/app/params" - sovereignApp "github.com/cosmos/interchain-security/v2/app/sovereign" + "github.com/cosmos/interchain-security/v3/app/params" + sovereignApp "github.com/cosmos/interchain-security/v3/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 42675b10d2..7c4dc35493 100644 --- a/cmd/interchain-security-sd/main.go +++ b/cmd/interchain-security-sd/main.go @@ -5,8 +5,8 @@ import ( "github.com/cosmos/cosmos-sdk/server" svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" - app "github.com/cosmos/interchain-security/v2/app/sovereign" - "github.com/cosmos/interchain-security/v2/cmd/interchain-security-sd/cmd" + app "github.com/cosmos/interchain-security/v3/app/sovereign" + "github.com/cosmos/interchain-security/v3/cmd/interchain-security-sd/cmd" ) func main() { diff --git a/go.mod b/go.mod index b199160aa2..dd821f8c98 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ -module github.com/cosmos/interchain-security/v2 +module github.com/cosmos/interchain-security/v3 -go 1.19 +go 1.20 require ( cosmossdk.io/errors v1.0.0-beta.7 diff --git a/legacy_ibc_testing/simapp/test_helpers.go b/legacy_ibc_testing/simapp/test_helpers.go index 2d11af5790..249fffb903 100644 --- a/legacy_ibc_testing/simapp/test_helpers.go +++ b/legacy_ibc_testing/simapp/test_helpers.go @@ -18,7 +18,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/errors" "github.com/stretchr/testify/require" - "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/simapp/helpers" + "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/simapp/helpers" ) /* diff --git a/legacy_ibc_testing/testing/app.go b/legacy_ibc_testing/testing/app.go index ce4e32c90f..8a1fef452c 100644 --- a/legacy_ibc_testing/testing/app.go +++ b/legacy_ibc_testing/testing/app.go @@ -6,7 +6,7 @@ import ( "time" "cosmossdk.io/math" - "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/core" + "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/core" abci "github.com/cometbft/cometbft/abci/types" tmproto "github.com/cometbft/cometbft/proto/tendermint/types" @@ -26,8 +26,8 @@ import ( "github.com/cosmos/ibc-go/v7/modules/core/keeper" - "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/simapp" - consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" + "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/simapp" + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" ) /* diff --git a/legacy_ibc_testing/testing/chain.go b/legacy_ibc_testing/testing/chain.go index c037ca43c8..945c5b94d0 100644 --- a/legacy_ibc_testing/testing/chain.go +++ b/legacy_ibc_testing/testing/chain.go @@ -35,8 +35,8 @@ import ( ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" "github.com/cosmos/ibc-go/v7/testing/mock" - ibctestingcore "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/core" - "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/simapp" + ibctestingcore "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/core" + "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/simapp" ) /* diff --git a/tests/difference/core/driver/core_test.go b/tests/difference/core/driver/core_test.go index df20aef074..648955f66d 100644 --- a/tests/difference/core/driver/core_test.go +++ b/tests/difference/core/driver/core_test.go @@ -9,18 +9,18 @@ import ( "github.com/stretchr/testify/suite" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" - ibctestingcore "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/core" - ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" + ibctestingcore "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/core" + ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - appConsumer "github.com/cosmos/interchain-security/v2/app/consumer" - appProvider "github.com/cosmos/interchain-security/v2/app/provider" + appConsumer "github.com/cosmos/interchain-security/v3/app/consumer" + appProvider "github.com/cosmos/interchain-security/v3/app/provider" - simibc "github.com/cosmos/interchain-security/v2/testutil/simibc" + simibc "github.com/cosmos/interchain-security/v3/testutil/simibc" slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" - consumerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/consumer/keeper" + consumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" ) type CoreSuite struct { diff --git a/tests/difference/core/driver/setup.go b/tests/difference/core/driver/setup.go index 1e77588c64..ff42784bc5 100644 --- a/tests/difference/core/driver/setup.go +++ b/tests/difference/core/driver/setup.go @@ -19,7 +19,7 @@ import ( "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" - ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" + ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" @@ -33,15 +33,15 @@ import ( slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" - appConsumer "github.com/cosmos/interchain-security/v2/app/consumer" - appProvider "github.com/cosmos/interchain-security/v2/app/provider" - icstestingutils "github.com/cosmos/interchain-security/v2/testutil/ibc_testing" - simibc "github.com/cosmos/interchain-security/v2/testutil/simibc" - consumerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/consumer/keeper" - consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" - providerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/provider/keeper" - - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + appConsumer "github.com/cosmos/interchain-security/v3/app/consumer" + appProvider "github.com/cosmos/interchain-security/v3/app/provider" + icstestingutils "github.com/cosmos/interchain-security/v3/testutil/ibc_testing" + simibc "github.com/cosmos/interchain-security/v3/testutil/simibc" + consumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + providerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" + + ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) type Builder struct { diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index a16f6b3bd4..2e8cd38a9b 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -15,9 +15,9 @@ import ( evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" - consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" - "github.com/cosmos/interchain-security/v2/x/ccv/provider/client" - "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/client" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" "github.com/tidwall/gjson" ) diff --git a/tests/integration/common.go b/tests/integration/common.go index 8f32193206..d387760724 100644 --- a/tests/integration/common.go +++ b/tests/integration/common.go @@ -16,11 +16,11 @@ import ( commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" "github.com/cosmos/ibc-go/v7/modules/core/exported" ibctm "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" - icstestingutils "github.com/cosmos/interchain-security/v2/testutil/ibc_testing" - testutil "github.com/cosmos/interchain-security/v2/testutil/integration" - providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" + icstestingutils "github.com/cosmos/interchain-security/v3/testutil/ibc_testing" + testutil "github.com/cosmos/interchain-security/v3/testutil/integration" + providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" "github.com/stretchr/testify/require" ) diff --git a/tests/integration/democracy.go b/tests/integration/democracy.go index c1262b31c1..f914d581d7 100644 --- a/tests/integration/democracy.go +++ b/tests/integration/democracy.go @@ -6,15 +6,15 @@ import ( "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" - ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" - icstestingutils "github.com/cosmos/interchain-security/v2/testutil/ibc_testing" + ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" + icstestingutils "github.com/cosmos/interchain-security/v3/testutil/ibc_testing" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" - testutil "github.com/cosmos/interchain-security/v2/testutil/integration" - consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" + testutil "github.com/cosmos/interchain-security/v3/testutil/integration" + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" "github.com/stretchr/testify/suite" ) diff --git a/tests/integration/distribution.go b/tests/integration/distribution.go index 58132fcc62..8ba2a8756b 100644 --- a/tests/integration/distribution.go +++ b/tests/integration/distribution.go @@ -8,9 +8,9 @@ import ( govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" - consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" - providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) // This test is valid for minimal viable consumer chain diff --git a/tests/integration/expired_client.go b/tests/integration/expired_client.go index ae7570a57f..89c8280b33 100644 --- a/tests/integration/expired_client.go +++ b/tests/integration/expired_client.go @@ -11,8 +11,8 @@ import ( ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" ibctm "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" + ccv "github.com/cosmos/interchain-security/v3/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 7e1e8dd608..7602f02c5e 100644 --- a/tests/integration/instance_test.go +++ b/tests/integration/instance_test.go @@ -3,11 +3,11 @@ package integration_test import ( "testing" - appConsumer "github.com/cosmos/interchain-security/v2/app/consumer" - appConsumerDemocracy "github.com/cosmos/interchain-security/v2/app/consumer-democracy" - appProvider "github.com/cosmos/interchain-security/v2/app/provider" - intg "github.com/cosmos/interchain-security/v2/tests/integration" - icstestingutils "github.com/cosmos/interchain-security/v2/testutil/ibc_testing" + appConsumer "github.com/cosmos/interchain-security/v3/app/consumer" + appConsumerDemocracy "github.com/cosmos/interchain-security/v3/app/consumer-democracy" + appProvider "github.com/cosmos/interchain-security/v3/app/provider" + intg "github.com/cosmos/interchain-security/v3/tests/integration" + icstestingutils "github.com/cosmos/interchain-security/v3/testutil/ibc_testing" "github.com/stretchr/testify/suite" ) diff --git a/tests/integration/key_assignment.go b/tests/integration/key_assignment.go index e6a794fedf..5ffabbeab4 100644 --- a/tests/integration/key_assignment.go +++ b/tests/integration/key_assignment.go @@ -7,8 +7,8 @@ import ( stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/cosmos/ibc-go/v7/testing/mock" - providerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/provider/keeper" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + providerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" + ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) func (s *CCVTestSuite) TestKeyAssignment() { diff --git a/tests/integration/normal_operations.go b/tests/integration/normal_operations.go index 3318e29940..af2137e5dc 100644 --- a/tests/integration/normal_operations.go +++ b/tests/integration/normal_operations.go @@ -3,7 +3,7 @@ package integration import ( tmproto "github.com/cometbft/cometbft/proto/tendermint/types" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" - consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/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 86084545c6..07987ce0d7 100644 --- a/tests/integration/setup.go +++ b/tests/integration/setup.go @@ -7,15 +7,15 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" "github.com/cosmos/ibc-go/v7/testing/mock" - testutil "github.com/cosmos/interchain-security/v2/testutil/integration" + testutil "github.com/cosmos/interchain-security/v3/testutil/integration" - icstestingutils "github.com/cosmos/interchain-security/v2/testutil/ibc_testing" - consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + icstestingutils "github.com/cosmos/interchain-security/v3/testutil/ibc_testing" + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" - ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" + ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" "github.com/stretchr/testify/suite" ) diff --git a/tests/integration/slashing.go b/tests/integration/slashing.go index 8b4cb80547..d4e960a9cd 100644 --- a/tests/integration/slashing.go +++ b/tests/integration/slashing.go @@ -11,13 +11,13 @@ import ( evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" tmtypes "github.com/cometbft/cometbft/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" - keepertestutil "github.com/cosmos/interchain-security/v2/testutil/keeper" - providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" + keepertestutil "github.com/cosmos/interchain-security/v3/testutil/keeper" + providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ) // TestRelayAndApplyDowntimePacket tests that downtime slash packets can be properly relayed diff --git a/tests/integration/stop_consumer.go b/tests/integration/stop_consumer.go index fda0aeb441..f6e0d77d59 100644 --- a/tests/integration/stop_consumer.go +++ b/tests/integration/stop_consumer.go @@ -6,8 +6,8 @@ import ( 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/v2/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v3/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 289c57e9d0..92800cd1bb 100644 --- a/tests/integration/throttle.go +++ b/tests/integration/throttle.go @@ -8,9 +8,9 @@ import ( stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" - icstestingutils "github.com/cosmos/interchain-security/v2/testutil/ibc_testing" - providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" + icstestingutils "github.com/cosmos/interchain-security/v3/testutil/ibc_testing" + providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) const fullSlashMeterString = "1.0" diff --git a/tests/integration/unbonding.go b/tests/integration/unbonding.go index 6b14099d45..87454be324 100644 --- a/tests/integration/unbonding.go +++ b/tests/integration/unbonding.go @@ -6,8 +6,8 @@ import ( "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" - providerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/provider/keeper" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + providerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" + ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) // TestUndelegationNormalOperation tests that undelegations complete after diff --git a/tests/integration/valset_update.go b/tests/integration/valset_update.go index 6e231976c4..e1c0d920ea 100644 --- a/tests/integration/valset_update.go +++ b/tests/integration/valset_update.go @@ -8,7 +8,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/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" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) // TestPacketRoundtrip tests a CCV packet roundtrip when tokens are bonded on provider diff --git a/testutil/crypto/crypto.go b/testutil/crypto/crypto.go index 1becc4248e..dd733f0ab3 100644 --- a/testutil/crypto/crypto.go +++ b/testutil/crypto/crypto.go @@ -11,7 +11,7 @@ import ( sdkcryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdktypes "github.com/cosmos/cosmos-sdk/types" sdkstakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" + providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" tmcrypto "github.com/cometbft/cometbft/crypto" tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" diff --git a/testutil/ibc_testing/generic_setup.go b/testutil/ibc_testing/generic_setup.go index 67e169af98..e784ee23b7 100644 --- a/testutil/ibc_testing/generic_setup.go +++ b/testutil/ibc_testing/generic_setup.go @@ -6,10 +6,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" - ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" - testutil "github.com/cosmos/interchain-security/v2/testutil/integration" - testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" - consumerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/consumer/keeper" + ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" + testutil "github.com/cosmos/interchain-security/v3/testutil/integration" + testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" + consumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" "github.com/stretchr/testify/suite" diff --git a/testutil/ibc_testing/specific_setup.go b/testutil/ibc_testing/specific_setup.go index ab9715ebd9..01c8315de8 100644 --- a/testutil/ibc_testing/specific_setup.go +++ b/testutil/ibc_testing/specific_setup.go @@ -8,14 +8,14 @@ import ( "encoding/json" simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" - ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" + ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" tmdb "github.com/cometbft/cometbft-db" "github.com/cometbft/cometbft/libs/log" - appConsumer "github.com/cosmos/interchain-security/v2/app/consumer" - appConsumerDemocracy "github.com/cosmos/interchain-security/v2/app/consumer-democracy" - appProvider "github.com/cosmos/interchain-security/v2/app/provider" + appConsumer "github.com/cosmos/interchain-security/v3/app/consumer" + appConsumerDemocracy "github.com/cosmos/interchain-security/v3/app/consumer-democracy" + appProvider "github.com/cosmos/interchain-security/v3/app/provider" ) // ProviderAppIniter implements ibctesting.AppIniter for a provider app diff --git a/testutil/integration/debug_test.go b/testutil/integration/debug_test.go index b6456663a9..3d04c540ee 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/v2/app/consumer" - appConsumerDemocracy "github.com/cosmos/interchain-security/v2/app/consumer-democracy" - appProvider "github.com/cosmos/interchain-security/v2/app/provider" - integr "github.com/cosmos/interchain-security/v2/tests/integration" - icstestingutils "github.com/cosmos/interchain-security/v2/testutil/ibc_testing" + appConsumer "github.com/cosmos/interchain-security/v3/app/consumer" + appConsumerDemocracy "github.com/cosmos/interchain-security/v3/app/consumer-democracy" + appProvider "github.com/cosmos/interchain-security/v3/app/provider" + integr "github.com/cosmos/interchain-security/v3/tests/integration" + icstestingutils "github.com/cosmos/interchain-security/v3/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 6fe667c2fa..41e6fd70c3 100644 --- a/testutil/integration/interfaces.go +++ b/testutil/integration/interfaces.go @@ -16,10 +16,10 @@ import ( slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" "github.com/cosmos/cosmos-sdk/x/staking/types" - ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" - consumerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/consumer/keeper" - providerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/provider/keeper" - ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" + ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" + consumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" + providerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" + ccvtypes "github.com/cosmos/interchain-security/v3/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 06b5008750..1e59085d23 100644 --- a/testutil/keeper/expectations.go +++ b/testutil/keeper/expectations.go @@ -13,10 +13,10 @@ import ( 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" - providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" + providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" host "github.com/cosmos/ibc-go/v7/modules/core/24-host" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" extra "github.com/oxyno-zeta/gomock-extra-matcher" ) diff --git a/testutil/keeper/unit_test_helpers.go b/testutil/keeper/unit_test_helpers.go index d13ab17a63..b8e69a4045 100644 --- a/testutil/keeper/unit_test_helpers.go +++ b/testutil/keeper/unit_test_helpers.go @@ -19,11 +19,11 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - consumerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/consumer/keeper" - consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" - providerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/provider/keeper" - providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - "github.com/cosmos/interchain-security/v2/x/ccv/types" + consumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + providerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" + providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + "github.com/cosmos/interchain-security/v3/x/ccv/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" diff --git a/testutil/simibc/chain_util.go b/testutil/simibc/chain_util.go index 50015834e3..0e6d14cd38 100644 --- a/testutil/simibc/chain_util.go +++ b/testutil/simibc/chain_util.go @@ -7,8 +7,8 @@ import ( tmproto "github.com/cometbft/cometbft/proto/tendermint/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" - ibctestingcore "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/core" - ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" + ibctestingcore "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/core" + ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" ) // BeginBlock updates the current header and calls the app.BeginBlock method. diff --git a/testutil/simibc/relay_util.go b/testutil/simibc/relay_util.go index 48e127aa60..7015dc72c1 100644 --- a/testutil/simibc/relay_util.go +++ b/testutil/simibc/relay_util.go @@ -8,8 +8,8 @@ import ( channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v7/modules/core/24-host" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - simapp "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/simapp" - ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" + simapp "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/simapp" + ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" "github.com/stretchr/testify/require" ) diff --git a/testutil/simibc/relayed_path.go b/testutil/simibc/relayed_path.go index b5339b2923..dfc5febe9c 100644 --- a/testutil/simibc/relayed_path.go +++ b/testutil/simibc/relayed_path.go @@ -5,7 +5,7 @@ import ( "time" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - ibctesting "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/testing" + ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" ) // RelayedPath is a wrapper around ibctesting.Path gives fine-grained diff --git a/x/ccv/consumer/client/cli/query.go b/x/ccv/consumer/client/cli/query.go index 3c42a8a33c..dc88aaf9d9 100644 --- a/x/ccv/consumer/client/cli/query.go +++ b/x/ccv/consumer/client/cli/query.go @@ -5,7 +5,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" + "github.com/cosmos/interchain-security/v3/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 410ca0d0fa..d55a1998af 100644 --- a/x/ccv/consumer/ibc_module.go +++ b/x/ccv/consumer/ibc_module.go @@ -16,10 +16,10 @@ import ( host "github.com/cosmos/ibc-go/v7/modules/core/24-host" ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" - "github.com/cosmos/interchain-security/v2/x/ccv/consumer/keeper" - consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" - providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - "github.com/cosmos/interchain-security/v2/x/ccv/types" + "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + "github.com/cosmos/interchain-security/v3/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 18bbba83cf..9e326bcbe6 100644 --- a/x/ccv/consumer/ibc_module_test.go +++ b/x/ccv/consumer/ibc_module_test.go @@ -9,11 +9,11 @@ import ( conntypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v7/modules/core/24-host" - testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" - "github.com/cosmos/interchain-security/v2/x/ccv/consumer" - consumerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/consumer/keeper" - providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" + "github.com/cosmos/interchain-security/v3/x/ccv/consumer" + consumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" + providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" diff --git a/x/ccv/consumer/keeper/changeover_test.go b/x/ccv/consumer/keeper/changeover_test.go index 9296dcb951..4009890b52 100644 --- a/x/ccv/consumer/keeper/changeover_test.go +++ b/x/ccv/consumer/keeper/changeover_test.go @@ -6,8 +6,8 @@ import ( abci "github.com/cometbft/cometbft/abci/types" sdkcryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/cosmos/interchain-security/v2/testutil/crypto" - uthelpers "github.com/cosmos/interchain-security/v2/testutil/keeper" + "github.com/cosmos/interchain-security/v3/testutil/crypto" + uthelpers "github.com/cosmos/interchain-security/v3/testutil/keeper" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) diff --git a/x/ccv/consumer/keeper/distribution.go b/x/ccv/consumer/keeper/distribution.go index fac98c3cfc..e2c8d2a403 100644 --- a/x/ccv/consumer/keeper/distribution.go +++ b/x/ccv/consumer/keeper/distribution.go @@ -11,8 +11,8 @@ 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/v2/x/ccv/consumer/types" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + ccv "github.com/cosmos/interchain-security/v3/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 bb09c7e26b..07f49b5b8c 100644 --- a/x/ccv/consumer/keeper/distribution_test.go +++ b/x/ccv/consumer/keeper/distribution_test.go @@ -8,8 +8,8 @@ import ( "github.com/stretchr/testify/require" authTypes "github.com/cosmos/cosmos-sdk/x/auth/types" - testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" - "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" + testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" + "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" "github.com/golang/mock/gomock" ) diff --git a/x/ccv/consumer/keeper/genesis.go b/x/ccv/consumer/keeper/genesis.go index 04c97dd4e3..d9e905bbd8 100644 --- a/x/ccv/consumer/keeper/genesis.go +++ b/x/ccv/consumer/keeper/genesis.go @@ -4,8 +4,8 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" abci "github.com/cometbft/cometbft/abci/types" ) diff --git a/x/ccv/consumer/keeper/genesis_test.go b/x/ccv/consumer/keeper/genesis_test.go index f05d8c960f..a2c0f6a88b 100644 --- a/x/ccv/consumer/keeper/genesis_test.go +++ b/x/ccv/consumer/keeper/genesis_test.go @@ -12,17 +12,17 @@ import ( clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - "github.com/cosmos/interchain-security/v2/testutil/crypto" - testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" - consumerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/consumer/keeper" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + "github.com/cosmos/interchain-security/v3/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" + consumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" + ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" - consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/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 9658edf64c..299e485faf 100644 --- a/x/ccv/consumer/keeper/grpc_query.go +++ b/x/ccv/consumer/keeper/grpc_query.go @@ -4,7 +4,7 @@ import ( "context" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" + "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) diff --git a/x/ccv/consumer/keeper/hooks.go b/x/ccv/consumer/keeper/hooks.go index 33a756d525..da3058555b 100644 --- a/x/ccv/consumer/keeper/hooks.go +++ b/x/ccv/consumer/keeper/hooks.go @@ -2,7 +2,7 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) var _ ccv.ConsumerHooks = Keeper{} diff --git a/x/ccv/consumer/keeper/keeper.go b/x/ccv/consumer/keeper/keeper.go index b50b330efa..24a1234065 100644 --- a/x/ccv/consumer/keeper/keeper.go +++ b/x/ccv/consumer/keeper/keeper.go @@ -22,8 +22,8 @@ import ( storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + ccv "github.com/cosmos/interchain-security/v3/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 c6443958b6..7b23c777c5 100644 --- a/x/ccv/consumer/keeper/keeper_test.go +++ b/x/ccv/consumer/keeper/keeper_test.go @@ -12,10 +12,10 @@ import ( stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" conntypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" - "github.com/cosmos/interchain-security/v2/testutil/crypto" - testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" - "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + "github.com/cosmos/interchain-security/v3/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" + "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" diff --git a/x/ccv/consumer/keeper/params.go b/x/ccv/consumer/keeper/params.go index ad1a0f2cb5..ccffd96ee5 100644 --- a/x/ccv/consumer/keeper/params.go +++ b/x/ccv/consumer/keeper/params.go @@ -6,8 +6,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" - ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" + "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + ccvtypes "github.com/cosmos/interchain-security/v3/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 d8dd63a1cb..7573613199 100644 --- a/x/ccv/consumer/keeper/params_test.go +++ b/x/ccv/consumer/keeper/params_test.go @@ -4,9 +4,9 @@ import ( "testing" "time" - testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" - "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" + "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" "github.com/stretchr/testify/require" ) diff --git a/x/ccv/consumer/keeper/relay.go b/x/ccv/consumer/keeper/relay.go index f57891bf98..d9e922ed3d 100644 --- a/x/ccv/consumer/keeper/relay.go +++ b/x/ccv/consumer/keeper/relay.go @@ -12,8 +12,8 @@ import ( channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" "github.com/cosmos/ibc-go/v7/modules/core/exported" - "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + ccv "github.com/cosmos/interchain-security/v3/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 23b3d99339..299d316d21 100644 --- a/x/ccv/consumer/keeper/relay_test.go +++ b/x/ccv/consumer/keeper/relay_test.go @@ -17,10 +17,10 @@ import ( channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v7/modules/core/24-host" - "github.com/cosmos/interchain-security/v2/testutil/crypto" - testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" - consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" - "github.com/cosmos/interchain-security/v2/x/ccv/types" + "github.com/cosmos/interchain-security/v3/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + "github.com/cosmos/interchain-security/v3/x/ccv/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" diff --git a/x/ccv/consumer/keeper/soft_opt_out.go b/x/ccv/consumer/keeper/soft_opt_out.go index 26b490633d..23a27d4b96 100644 --- a/x/ccv/consumer/keeper/soft_opt_out.go +++ b/x/ccv/consumer/keeper/soft_opt_out.go @@ -5,7 +5,7 @@ import ( "sort" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" + "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" ) // SetSmallestNonOptOutPower sets the smallest validator power that cannot soft opt out. diff --git a/x/ccv/consumer/keeper/soft_opt_out_test.go b/x/ccv/consumer/keeper/soft_opt_out_test.go index f243b917d7..34e5570674 100644 --- a/x/ccv/consumer/keeper/soft_opt_out_test.go +++ b/x/ccv/consumer/keeper/soft_opt_out_test.go @@ -5,9 +5,9 @@ import ( tmtypes "github.com/cometbft/cometbft/types" - "github.com/cosmos/interchain-security/v2/testutil/crypto" - testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" - "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" + "github.com/cosmos/interchain-security/v3/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" + "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" "github.com/stretchr/testify/require" ) diff --git a/x/ccv/consumer/keeper/validators.go b/x/ccv/consumer/keeper/validators.go index 0f0f246833..068767546b 100644 --- a/x/ccv/consumer/keeper/validators.go +++ b/x/ccv/consumer/keeper/validators.go @@ -9,7 +9,7 @@ import ( abci "github.com/cometbft/cometbft/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" + "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" ) // diff --git a/x/ccv/consumer/keeper/validators_test.go b/x/ccv/consumer/keeper/validators_test.go index c9ce541794..724ce787d0 100644 --- a/x/ccv/consumer/keeper/validators_test.go +++ b/x/ccv/consumer/keeper/validators_test.go @@ -10,10 +10,10 @@ import ( cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/cosmos/interchain-security/v2/testutil/crypto" - testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" - "github.com/cosmos/interchain-security/v2/x/ccv/consumer/keeper" - "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" + "github.com/cosmos/interchain-security/v3/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" + "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" + "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" "github.com/stretchr/testify/require" ) diff --git a/x/ccv/consumer/module.go b/x/ccv/consumer/module.go index 0e87463884..3d80fb1df1 100644 --- a/x/ccv/consumer/module.go +++ b/x/ccv/consumer/module.go @@ -19,10 +19,10 @@ import ( simtypes "github.com/cosmos/cosmos-sdk/types/simulation" porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" - "github.com/cosmos/interchain-security/v2/x/ccv/consumer/client/cli" - "github.com/cosmos/interchain-security/v2/x/ccv/consumer/keeper" + "github.com/cosmos/interchain-security/v3/x/ccv/consumer/client/cli" + "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" - consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" ) var ( diff --git a/x/ccv/consumer/types/consumer.pb.go b/x/ccv/consumer/types/consumer.pb.go index dd5d991666..6ab018cf26 100644 --- a/x/ccv/consumer/types/consumer.pb.go +++ b/x/ccv/consumer/types/consumer.pb.go @@ -10,7 +10,7 @@ import ( _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/cosmos/gogoproto/proto" github_com_cosmos_gogoproto_types "github.com/cosmos/gogoproto/types" - _ "github.com/cosmos/interchain-security/v2/x/ccv/types" + _ "github.com/cosmos/interchain-security/v3/x/ccv/types" _ "google.golang.org/protobuf/types/known/durationpb" _ "google.golang.org/protobuf/types/known/timestamppb" io "io" diff --git a/x/ccv/consumer/types/genesis.go b/x/ccv/consumer/types/genesis.go index 54f6fe9651..82b6e2c1fa 100644 --- a/x/ccv/consumer/types/genesis.go +++ b/x/ccv/consumer/types/genesis.go @@ -5,7 +5,7 @@ import ( abci "github.com/cometbft/cometbft/abci/types" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) // NewInitialGenesisState returns a consumer GenesisState for a completely new consumer chain. diff --git a/x/ccv/consumer/types/genesis.pb.go b/x/ccv/consumer/types/genesis.pb.go index cbf6675902..1511df9ccd 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/ibc-go/v7/modules/core/04-channel/types" _07_tendermint "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - types1 "github.com/cosmos/interchain-security/v2/x/ccv/types" + types1 "github.com/cosmos/interchain-security/v3/x/ccv/types" _ "google.golang.org/protobuf/types/known/durationpb" io "io" math "math" diff --git a/x/ccv/consumer/types/genesis_test.go b/x/ccv/consumer/types/genesis_test.go index af1badb73b..9ce1c4927a 100644 --- a/x/ccv/consumer/types/genesis_test.go +++ b/x/ccv/consumer/types/genesis_test.go @@ -12,13 +12,13 @@ import ( commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" + "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" tmtypes "github.com/cometbft/cometbft/types" - "github.com/cosmos/interchain-security/v2/testutil/crypto" + "github.com/cosmos/interchain-security/v3/testutil/crypto" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" "github.com/stretchr/testify/require" ) diff --git a/x/ccv/consumer/types/keys.go b/x/ccv/consumer/types/keys.go index 093f78b450..24be1819c6 100644 --- a/x/ccv/consumer/types/keys.go +++ b/x/ccv/consumer/types/keys.go @@ -5,7 +5,7 @@ import ( time "time" sdk "github.com/cosmos/cosmos-sdk/types" - ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) const ( diff --git a/x/ccv/consumer/types/params.go b/x/ccv/consumer/types/params.go index 7ab51fbad8..485bb8fda5 100644 --- a/x/ccv/consumer/types/params.go +++ b/x/ccv/consumer/types/params.go @@ -7,7 +7,7 @@ import ( sdktypes "github.com/cosmos/cosmos-sdk/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) const ( diff --git a/x/ccv/consumer/types/params_test.go b/x/ccv/consumer/types/params_test.go index 98233505d7..531f7e39f2 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" - consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" ) // Tests the validation of consumer params that happens at genesis diff --git a/x/ccv/democracy/distribution/module.go b/x/ccv/democracy/distribution/module.go index 3d5ca0ed74..7f4842314e 100644 --- a/x/ccv/democracy/distribution/module.go +++ b/x/ccv/democracy/distribution/module.go @@ -13,7 +13,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/distribution/keeper" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" abci "github.com/cometbft/cometbft/abci/types" distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" diff --git a/x/ccv/provider/client/cli/query.go b/x/ccv/provider/client/cli/query.go index aa1a996f12..1240e242f0 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/v2/x/ccv/provider/types" + "github.com/cosmos/interchain-security/v3/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 a0b9343d8a..ca167dbb60 100644 --- a/x/ccv/provider/client/cli/tx.go +++ b/x/ccv/provider/client/cli/tx.go @@ -12,7 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/version" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" + "github.com/cosmos/interchain-security/v3/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 6ccd855ef8..9c02dd3c23 100644 --- a/x/ccv/provider/client/proposal_handler.go +++ b/x/ccv/provider/client/proposal_handler.go @@ -17,7 +17,7 @@ import ( govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" - "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" "github.com/spf13/cobra" ) diff --git a/x/ccv/provider/handler.go b/x/ccv/provider/handler.go index dc0c8cbc4f..6f3bb29092 100644 --- a/x/ccv/provider/handler.go +++ b/x/ccv/provider/handler.go @@ -4,8 +4,8 @@ import ( errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/interchain-security/v2/x/ccv/provider/keeper" - "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" + "github.com/cosmos/interchain-security/v3/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 0176e13b71..8871d15669 100644 --- a/x/ccv/provider/handler_test.go +++ b/x/ccv/provider/handler_test.go @@ -12,11 +12,11 @@ import ( "github.com/cosmos/cosmos-sdk/testutil/testdata" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - testcrypto "github.com/cosmos/interchain-security/v2/testutil/crypto" - testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" - "github.com/cosmos/interchain-security/v2/x/ccv/provider" - keeper "github.com/cosmos/interchain-security/v2/x/ccv/provider/keeper" - providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" + testcrypto "github.com/cosmos/interchain-security/v3/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" + "github.com/cosmos/interchain-security/v3/x/ccv/provider" + keeper "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" + providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ) func TestInvalidMsg(t *testing.T) { diff --git a/x/ccv/provider/ibc_module.go b/x/ccv/provider/ibc_module.go index 21eee84f06..b543c8927e 100644 --- a/x/ccv/provider/ibc_module.go +++ b/x/ccv/provider/ibc_module.go @@ -13,9 +13,9 @@ import ( host "github.com/cosmos/ibc-go/v7/modules/core/24-host" ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" - "github.com/cosmos/interchain-security/v2/x/ccv/provider/keeper" - providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" + providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v3/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 28a13dfeda..42279fbb73 100644 --- a/x/ccv/provider/ibc_module_test.go +++ b/x/ccv/provider/ibc_module_test.go @@ -12,11 +12,11 @@ import ( host "github.com/cosmos/ibc-go/v7/modules/core/24-host" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" - "github.com/cosmos/interchain-security/v2/x/ccv/provider" - providerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/provider/keeper" - providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" + "github.com/cosmos/interchain-security/v3/x/ccv/provider" + providerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" + providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" diff --git a/x/ccv/provider/keeper/distribution.go b/x/ccv/provider/keeper/distribution.go index 759de65147..ee6070e27b 100644 --- a/x/ccv/provider/keeper/distribution.go +++ b/x/ccv/provider/keeper/distribution.go @@ -2,8 +2,8 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" - consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" - "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ) // EndBlockRD executes EndBlock 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 a9aa6d88fb..4188eedaef 100644 --- a/x/ccv/provider/keeper/distribution_test.go +++ b/x/ccv/provider/keeper/distribution_test.go @@ -4,9 +4,9 @@ import ( "testing" sdk "github.com/cosmos/cosmos-sdk/types" - testutil "github.com/cosmos/interchain-security/v2/testutil/keeper" - consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" - "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" + testutil "github.com/cosmos/interchain-security/v3/testutil/keeper" + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) diff --git a/x/ccv/provider/keeper/genesis.go b/x/ccv/provider/keeper/genesis.go index 89845304d8..996b73d4a5 100644 --- a/x/ccv/provider/keeper/genesis.go +++ b/x/ccv/provider/keeper/genesis.go @@ -4,8 +4,8 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v3/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 5c8ee5838f..fe666dcc2c 100644 --- a/x/ccv/provider/keeper/genesis_test.go +++ b/x/ccv/provider/keeper/genesis_test.go @@ -6,13 +6,13 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" host "github.com/cosmos/ibc-go/v7/modules/core/24-host" - "github.com/cosmos/interchain-security/v2/testutil/crypto" - testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" + "github.com/cosmos/interchain-security/v3/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" - consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" - "github.com/cosmos/interchain-security/v2/x/ccv/provider/keeper" - providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" + providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) diff --git a/x/ccv/provider/keeper/grpc_query.go b/x/ccv/provider/keeper/grpc_query.go index df7c28f758..f43761fd0e 100644 --- a/x/ccv/provider/keeper/grpc_query.go +++ b/x/ccv/provider/keeper/grpc_query.go @@ -6,8 +6,8 @@ import ( errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) diff --git a/x/ccv/provider/keeper/hooks.go b/x/ccv/provider/keeper/hooks.go index a384edfc39..2f2cb8ee0b 100644 --- a/x/ccv/provider/keeper/hooks.go +++ b/x/ccv/provider/keeper/hooks.go @@ -4,8 +4,8 @@ import ( stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" sdk "github.com/cosmos/cosmos-sdk/types" - providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" + providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) // Wrapper struct diff --git a/x/ccv/provider/keeper/hooks_test.go b/x/ccv/provider/keeper/hooks_test.go index e364f61d13..463ed5fff5 100644 --- a/x/ccv/provider/keeper/hooks_test.go +++ b/x/ccv/provider/keeper/hooks_test.go @@ -4,9 +4,9 @@ import ( "testing" sdk "github.com/cosmos/cosmos-sdk/types" - cryptotestutil "github.com/cosmos/interchain-security/v2/testutil/crypto" - testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" - providerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/provider/keeper" + cryptotestutil "github.com/cosmos/interchain-security/v3/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" + providerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" "github.com/golang/mock/gomock" ) diff --git a/x/ccv/provider/keeper/keeper.go b/x/ccv/provider/keeper/keeper.go index ff14308a22..03caf0aba5 100644 --- a/x/ccv/provider/keeper/keeper.go +++ b/x/ccv/provider/keeper/keeper.go @@ -20,9 +20,9 @@ import ( ibchost "github.com/cosmos/ibc-go/v7/modules/core/exported" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" - "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" "github.com/cometbft/cometbft/libs/log" ) diff --git a/x/ccv/provider/keeper/keeper_test.go b/x/ccv/provider/keeper/keeper_test.go index db5bf98ea4..f34bf262a5 100644 --- a/x/ccv/provider/keeper/keeper_test.go +++ b/x/ccv/provider/keeper/keeper_test.go @@ -10,11 +10,11 @@ import ( tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" - ibcsimapp "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/simapp" - cryptotestutil "github.com/cosmos/interchain-security/v2/testutil/crypto" - testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" - "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + ibcsimapp "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/simapp" + cryptotestutil "github.com/cosmos/interchain-security/v3/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" "github.com/stretchr/testify/require" ) diff --git a/x/ccv/provider/keeper/key_assignment.go b/x/ccv/provider/keeper/key_assignment.go index 0321e089de..eb4fecd64f 100644 --- a/x/ccv/provider/keeper/key_assignment.go +++ b/x/ccv/provider/keeper/key_assignment.go @@ -7,8 +7,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" abci "github.com/cometbft/cometbft/abci/types" tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" diff --git a/x/ccv/provider/keeper/key_assignment_test.go b/x/ccv/provider/keeper/key_assignment_test.go index 06d2202954..c06099ca60 100644 --- a/x/ccv/provider/keeper/key_assignment_test.go +++ b/x/ccv/provider/keeper/key_assignment_test.go @@ -11,13 +11,13 @@ import ( tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - cryptotestutil "github.com/cosmos/interchain-security/v2/testutil/crypto" - testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" + cryptotestutil "github.com/cosmos/interchain-security/v3/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" "github.com/stretchr/testify/require" - providerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/provider/keeper" - "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" + providerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" "github.com/golang/mock/gomock" ) diff --git a/x/ccv/provider/keeper/msg_server.go b/x/ccv/provider/keeper/msg_server.go index dcef272356..d7051cc392 100644 --- a/x/ccv/provider/keeper/msg_server.go +++ b/x/ccv/provider/keeper/msg_server.go @@ -9,8 +9,8 @@ import ( stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" errorsmod "cosmossdk.io/errors" - "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) type msgServer struct { diff --git a/x/ccv/provider/keeper/params.go b/x/ccv/provider/keeper/params.go index 56ed85fdd4..adfc574ba9 100644 --- a/x/ccv/provider/keeper/params.go +++ b/x/ccv/provider/keeper/params.go @@ -7,8 +7,8 @@ import ( ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + ccvtypes "github.com/cosmos/interchain-security/v3/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 25c368ca82..cfaec35dc7 100644 --- a/x/ccv/provider/keeper/params_test.go +++ b/x/ccv/provider/keeper/params_test.go @@ -9,8 +9,8 @@ import ( commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" - providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" + testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" + providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" "github.com/stretchr/testify/require" ) diff --git a/x/ccv/provider/keeper/proposal.go b/x/ccv/provider/keeper/proposal.go index 7c4a141ad8..0ce71d6efc 100644 --- a/x/ccv/provider/keeper/proposal.go +++ b/x/ccv/provider/keeper/proposal.go @@ -17,9 +17,9 @@ import ( commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" - "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v3/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 922573b17c..1170a0f368 100644 --- a/x/ccv/provider/keeper/proposal_test.go +++ b/x/ccv/provider/keeper/proposal_test.go @@ -17,12 +17,12 @@ import ( "github.com/stretchr/testify/require" - cryptoutil "github.com/cosmos/interchain-security/v2/testutil/crypto" - testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" - consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" - providerkeeper "github.com/cosmos/interchain-security/v2/x/ccv/provider/keeper" - providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" + cryptoutil "github.com/cosmos/interchain-security/v3/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + providerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" + providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) // diff --git a/x/ccv/provider/keeper/relay.go b/x/ccv/provider/keeper/relay.go index fed6f1f8ce..1aa0858da6 100644 --- a/x/ccv/provider/keeper/relay.go +++ b/x/ccv/provider/keeper/relay.go @@ -11,8 +11,8 @@ import ( channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" "github.com/cosmos/ibc-go/v7/modules/core/exported" - providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) // OnRecvVSCMaturedPacket handles a VSCMatured packet diff --git a/x/ccv/provider/keeper/relay_test.go b/x/ccv/provider/keeper/relay_test.go index 07e967ae41..15305d8eea 100644 --- a/x/ccv/provider/keeper/relay_test.go +++ b/x/ccv/provider/keeper/relay_test.go @@ -12,12 +12,12 @@ import ( channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" exported "github.com/cosmos/ibc-go/v7/modules/core/exported" - ibcsimapp "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/simapp" - cryptotestutil "github.com/cosmos/interchain-security/v2/testutil/crypto" - testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" - "github.com/cosmos/interchain-security/v2/x/ccv/provider/keeper" - providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + ibcsimapp "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/simapp" + cryptotestutil "github.com/cosmos/interchain-security/v3/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" + providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" diff --git a/x/ccv/provider/keeper/throttle.go b/x/ccv/provider/keeper/throttle.go index d08f7bf5e0..ddfe1b1763 100644 --- a/x/ccv/provider/keeper/throttle.go +++ b/x/ccv/provider/keeper/throttle.go @@ -8,8 +8,8 @@ import ( tmtypes "github.com/cometbft/cometbft/types" sdktypes "github.com/cosmos/cosmos-sdk/types" - providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" + providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) // This file contains functionality relevant to the throttling of slash and vsc matured packets, aka circuit breaker logic. diff --git a/x/ccv/provider/keeper/throttle_test.go b/x/ccv/provider/keeper/throttle_test.go index 86a0ee1415..7cd39a8382 100644 --- a/x/ccv/provider/keeper/throttle_test.go +++ b/x/ccv/provider/keeper/throttle_test.go @@ -14,11 +14,11 @@ import ( "github.com/stretchr/testify/require" "golang.org/x/exp/slices" - cryptoutil "github.com/cosmos/interchain-security/v2/testutil/crypto" - testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" - "github.com/cosmos/interchain-security/v2/x/ccv/provider/keeper" - providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" + cryptoutil "github.com/cosmos/interchain-security/v3/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" + providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) // TestHandlePacketDataForChain tests the HandlePacketDataForChain function. Note: Only one consumer is tested here, diff --git a/x/ccv/provider/module.go b/x/ccv/provider/module.go index ca83c9011b..556cbcfefa 100644 --- a/x/ccv/provider/module.go +++ b/x/ccv/provider/module.go @@ -16,9 +16,9 @@ import ( porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - "github.com/cosmos/interchain-security/v2/x/ccv/provider/client/cli" - "github.com/cosmos/interchain-security/v2/x/ccv/provider/keeper" - providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/client/cli" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" + providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/spf13/cobra" diff --git a/x/ccv/provider/module_test.go b/x/ccv/provider/module_test.go index 2cb08d0daf..0eee81cc1f 100644 --- a/x/ccv/provider/module_test.go +++ b/x/ccv/provider/module_test.go @@ -8,10 +8,10 @@ import ( host "github.com/cosmos/ibc-go/v7/modules/core/24-host" - testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" - "github.com/cosmos/interchain-security/v2/x/ccv/provider" - "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" + "github.com/cosmos/interchain-security/v3/x/ccv/provider" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/x/ccv/provider/proposal_handler.go b/x/ccv/provider/proposal_handler.go index 2bfb71c73b..ebebb9c967 100644 --- a/x/ccv/provider/proposal_handler.go +++ b/x/ccv/provider/proposal_handler.go @@ -6,8 +6,8 @@ import ( errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/interchain-security/v2/x/ccv/provider/keeper" - "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" + "github.com/cosmos/interchain-security/v3/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 35b7821dd7..4f78695935 100644 --- a/x/ccv/provider/proposal_handler_test.go +++ b/x/ccv/provider/proposal_handler_test.go @@ -14,9 +14,9 @@ import ( govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" - testkeeper "github.com/cosmos/interchain-security/v2/testutil/keeper" - "github.com/cosmos/interchain-security/v2/x/ccv/provider" - providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" + testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" + "github.com/cosmos/interchain-security/v3/x/ccv/provider" + providertypes "github.com/cosmos/interchain-security/v3/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 29098b4521..1a13123e88 100644 --- a/x/ccv/provider/types/consumer.go +++ b/x/ccv/provider/types/consumer.go @@ -1,8 +1,8 @@ package types import ( - consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) func NewConsumerStates( diff --git a/x/ccv/provider/types/genesis.go b/x/ccv/provider/types/genesis.go index 4508fd6eb6..5a9358e736 100644 --- a/x/ccv/provider/types/genesis.go +++ b/x/ccv/provider/types/genesis.go @@ -7,7 +7,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" host "github.com/cosmos/ibc-go/v7/modules/core/24-host" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) func NewGenesisState( diff --git a/x/ccv/provider/types/genesis.pb.go b/x/ccv/provider/types/genesis.pb.go index 84110c9b96..4737530390 100644 --- a/x/ccv/provider/types/genesis.pb.go +++ b/x/ccv/provider/types/genesis.pb.go @@ -8,8 +8,8 @@ import ( _ "github.com/cometbft/cometbft/proto/tendermint/crypto" _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/cosmos/gogoproto/proto" - types1 "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" - types "github.com/cosmos/interchain-security/v2/x/ccv/types" + types1 "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + types "github.com/cosmos/interchain-security/v3/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 0bf3b98a55..de5c77a803 100644 --- a/x/ccv/provider/types/genesis_test.go +++ b/x/ccv/provider/types/genesis_test.go @@ -11,10 +11,10 @@ import ( commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - "github.com/cosmos/interchain-security/v2/testutil/crypto" - consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" - "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v2/x/ccv/types" + "github.com/cosmos/interchain-security/v3/testutil/crypto" + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" "github.com/stretchr/testify/require" ) diff --git a/x/ccv/provider/types/key_assignment.go b/x/ccv/provider/types/key_assignment.go index 3ecee9379a..659ca91e83 100644 --- a/x/ccv/provider/types/key_assignment.go +++ b/x/ccv/provider/types/key_assignment.go @@ -6,7 +6,7 @@ import ( errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" - ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" + ccvtypes "github.com/cosmos/interchain-security/v3/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 4e15f566ef..ee4c11015b 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/v2/x/ccv/types" + ccvtypes "github.com/cosmos/interchain-security/v3/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 03493c1138..3bb891ddce 100644 --- a/x/ccv/provider/types/keys_test.go +++ b/x/ccv/provider/types/keys_test.go @@ -5,8 +5,8 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" - cryptoutil "github.com/cosmos/interchain-security/v2/testutil/crypto" - providertypes "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" + cryptoutil "github.com/cosmos/interchain-security/v3/testutil/crypto" + providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" "github.com/stretchr/testify/require" ) diff --git a/x/ccv/provider/types/params.go b/x/ccv/provider/types/params.go index 487fdda366..0495d1a89e 100644 --- a/x/ccv/provider/types/params.go +++ b/x/ccv/provider/types/params.go @@ -11,8 +11,8 @@ import ( commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - consumertypes "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types" - ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) const ( diff --git a/x/ccv/provider/types/params_test.go b/x/ccv/provider/types/params_test.go index bca99670a9..7a4b9aabf2 100644 --- a/x/ccv/provider/types/params_test.go +++ b/x/ccv/provider/types/params_test.go @@ -10,7 +10,7 @@ import ( clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" + "github.com/cosmos/interchain-security/v3/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 43f5d027eb..89e8cb9822 100644 --- a/x/ccv/provider/types/proposal.go +++ b/x/ccv/provider/types/proposal.go @@ -11,7 +11,7 @@ import ( govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" - ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) const ( diff --git a/x/ccv/provider/types/proposal_test.go b/x/ccv/provider/types/proposal_test.go index 4227654bd9..b3f27e1415 100644 --- a/x/ccv/provider/types/proposal_test.go +++ b/x/ccv/provider/types/proposal_test.go @@ -18,7 +18,7 @@ import ( clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ) func TestConsumerAdditionProposalValidateBasic(t *testing.T) { diff --git a/x/ccv/provider/types/query.pb.go b/x/ccv/provider/types/query.pb.go index 5d4fc19077..f8a4f04d23 100644 --- a/x/ccv/provider/types/query.pb.go +++ b/x/ccv/provider/types/query.pb.go @@ -10,8 +10,8 @@ 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/v2/x/ccv/consumer/types" - types1 "github.com/cosmos/interchain-security/v2/x/ccv/types" + types "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + types1 "github.com/cosmos/interchain-security/v3/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/ccv_test.go b/x/ccv/types/ccv_test.go index 51979fb4da..5aadafe6ec 100644 --- a/x/ccv/types/ccv_test.go +++ b/x/ccv/types/ccv_test.go @@ -6,7 +6,7 @@ import ( abci "github.com/cometbft/cometbft/abci/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" - "github.com/cosmos/interchain-security/v2/x/ccv/types" + "github.com/cosmos/interchain-security/v3/x/ccv/types" "github.com/stretchr/testify/require" ) diff --git a/x/ccv/types/utils_test.go b/x/ccv/types/utils_test.go index 1267daf119..0182b68306 100644 --- a/x/ccv/types/utils_test.go +++ b/x/ccv/types/utils_test.go @@ -5,8 +5,8 @@ import ( abci "github.com/cometbft/cometbft/abci/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" - ibcsimapp "github.com/cosmos/interchain-security/v2/legacy_ibc_testing/simapp" - "github.com/cosmos/interchain-security/v2/x/ccv/types" + ibcsimapp "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/simapp" + "github.com/cosmos/interchain-security/v3/x/ccv/types" "github.com/stretchr/testify/require" ) From 3d15f77e19e9aa70527af85b3d89b04c033190fa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Jun 2023 11:42:11 +0200 Subject: [PATCH 024/134] build(deps): bump github.com/spf13/cast from 1.5.0 to 1.5.1 (#1053) Bumps [github.com/spf13/cast](https://github.com/spf13/cast) from 1.5.0 to 1.5.1. - [Release notes](https://github.com/spf13/cast/releases) - [Commits](https://github.com/spf13/cast/compare/v1.5.0...v1.5.1) --- updated-dependencies: - dependency-name: github.com/spf13/cast dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index dd821f8c98..49e0fd4dee 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/kylelemons/godebug v1.1.0 github.com/oxyno-zeta/gomock-extra-matcher v1.1.0 github.com/rakyll/statik v0.1.7 // indirect - github.com/spf13/cast v1.5.0 + github.com/spf13/cast v1.5.1 github.com/spf13/cobra v1.6.1 github.com/stretchr/testify v1.8.2 github.com/tidwall/gjson v1.14.4 diff --git a/go.sum b/go.sum index d175ed9849..f6403f86a5 100644 --- a/go.sum +++ b/go.sum @@ -482,7 +482,7 @@ github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/ github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= -github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= @@ -1071,8 +1071,8 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= -github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= +github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= From 223e83cba320a82b7a17fc949169a84311a7d756 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Jun 2023 11:43:38 +0200 Subject: [PATCH 025/134] build(deps): bump github.com/stretchr/testify from 1.8.2 to 1.8.4 (#1051) Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.8.2 to 1.8.4. - [Release notes](https://github.com/stretchr/testify/releases) - [Commits](https://github.com/stretchr/testify/compare/v1.8.2...v1.8.4) --- updated-dependencies: - dependency-name: github.com/stretchr/testify dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Marius Poke --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 49e0fd4dee..e9c505b920 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/rakyll/statik v0.1.7 // indirect github.com/spf13/cast v1.5.1 github.com/spf13/cobra v1.6.1 - github.com/stretchr/testify v1.8.2 + github.com/stretchr/testify v1.8.4 github.com/tidwall/gjson v1.14.4 golang.org/x/crypto v0.7.0 // indirect golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc diff --git a/go.sum b/go.sum index f6403f86a5..281a319404 100644 --- a/go.sum +++ b/go.sum @@ -1106,8 +1106,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= From 7c306e2cf2ca91259099aa733c1b56cf3a8a96b9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Jun 2023 11:45:32 +0200 Subject: [PATCH 026/134] build(deps): bump github.com/cosmos/ibc-go/v7 from 7.0.0 to 7.1.0 (#1050) Bumps [github.com/cosmos/ibc-go/v7](https://github.com/cosmos/ibc-go) from 7.0.0 to 7.1.0. - [Release notes](https://github.com/cosmos/ibc-go/releases) - [Changelog](https://github.com/cosmos/ibc-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/cosmos/ibc-go/compare/v7.0.0...v7.1.0) --- updated-dependencies: - dependency-name: github.com/cosmos/ibc-go/v7 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 8 +++----- go.sum | 17 ++++++----------- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/go.mod b/go.mod index e9c505b920..ee1c62d762 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/cometbft/cometbft-db v0.8.0 github.com/cosmos/cosmos-sdk v0.47.3 github.com/cosmos/gogoproto v1.4.10 - github.com/cosmos/ibc-go/v7 v7.0.0 + github.com/cosmos/ibc-go/v7 v7.1.0 github.com/cosmos/ics23/go v0.10.0 github.com/golang/mock v1.6.0 github.com/golang/protobuf v1.5.3 @@ -22,7 +22,7 @@ require ( github.com/spf13/cobra v1.6.1 github.com/stretchr/testify v1.8.4 github.com/tidwall/gjson v1.14.4 - golang.org/x/crypto v0.7.0 // indirect + golang.org/x/crypto v0.8.0 // indirect golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc golang.org/x/net v0.9.0 // indirect golang.org/x/sys v0.7.0 // indirect @@ -81,7 +81,6 @@ require ( github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect - github.com/go-playground/universal-translator v0.18.0 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect @@ -115,7 +114,6 @@ require ( github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect github.com/klauspost/compress v1.16.3 // indirect - github.com/leodido/go-urn v1.2.1 // indirect github.com/lib/pq v1.10.7 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/linxGnu/grocksdb v1.7.16 // indirect @@ -149,7 +147,6 @@ require ( github.com/tidwall/btree v1.6.0 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect - github.com/ugorji/go/codec v1.2.7 // indirect github.com/ulikunitz/xz v0.5.11 // indirect github.com/zondax/hid v0.9.1 // indirect github.com/zondax/ledger-go v0.14.1 // indirect @@ -172,6 +169,7 @@ require github.com/spf13/viper v1.15.0 require ( cosmossdk.io/log v1.1.0 // indirect + github.com/go-playground/locales v0.14.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/rs/zerolog v1.29.1 // indirect ) diff --git a/go.sum b/go.sum index 281a319404..b79f6784cb 100644 --- a/go.sum +++ b/go.sum @@ -393,8 +393,8 @@ github.com/cosmos/gogoproto v1.4.10 h1:QH/yT8X+c0F4ZDacDv3z+xE3WU1P1Z3wQoLMBRJoK github.com/cosmos/gogoproto v1.4.10/go.mod h1:3aAZzeRWpAwr+SS/LLkICX2/kDFyaYVzckBDzygIxek= github.com/cosmos/iavl v0.20.0 h1:fTVznVlepH0KK8NyKq8w+U7c2L6jofa27aFX6YGlm38= github.com/cosmos/iavl v0.20.0/go.mod h1:WO7FyvaZJoH65+HFOsDir7xU9FWk2w9cHXNW1XHcl7A= -github.com/cosmos/ibc-go/v7 v7.0.0 h1:j4kyywlG0hhDmT9FmSaR5iCIka7Pz7kJTxGWY1nlV9Q= -github.com/cosmos/ibc-go/v7 v7.0.0/go.mod h1:BFh8nKWjr5zeR2OZfhkzdgDzj1+KjRn3aJLpwapStj8= +github.com/cosmos/ibc-go/v7 v7.1.0 h1:SCLgs7tqVnzdIDO5MRLgovAnc696vTTKl+8qsTu8IMM= +github.com/cosmos/ibc-go/v7 v7.1.0/go.mod h1:7MptlWeIyqmDiuJeRAFqBvXKY8Hybd+rF8vMSmGd2zg= github.com/cosmos/ics23/go v0.10.0 h1:iXqLLgp2Lp+EdpIuwXTYIQU+AiHj9mOC2X9ab++bZDM= github.com/cosmos/ics23/go v0.10.0/go.mod h1:ZfJSmng/TBNTBkFemHHHj5YY7VAU/MBU980F4VU1NG0= github.com/cosmos/ledger-cosmos-go v0.12.2 h1:/XYaBlE2BJxtvpkHiBm97gFGSGmYGKunKyF3nNqAXZA= @@ -493,8 +493,8 @@ github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= -github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8= github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= @@ -522,9 +522,8 @@ github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= -github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= -github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= @@ -535,7 +534,6 @@ github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= -github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -834,7 +832,6 @@ github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= -github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= @@ -1133,11 +1130,9 @@ github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqri github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/tyler-smith/go-bip39 v1.0.2/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= -github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= @@ -1212,8 +1207,8 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= +golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= From e910efeef30b941b853121e30a2d222af9721fd4 Mon Sep 17 00:00:00 2001 From: MSalopek Date: Wed, 21 Jun 2023 12:45:28 +0200 Subject: [PATCH 027/134] chore: add release/v3.0.x targets for bots (#1046) Co-authored-by: Marius Poke --- .github/dependabot.yml | 12 +++++++++++- .mergify.yml | 8 ++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 42241f2b1d..ec9119084e 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -26,4 +26,14 @@ updates: # Only allow automated security-related dependency updates on release branches. open-pull-requests-limit: 0 labels: - - dependencies \ No newline at end of file + - dependencies + + - package-ecosystem: gomod + directory: "/" + schedule: + interval: daily + target-branch: "release/v3.0.x" + # Only allow automated security-related dependency updates on release branches. + open-pull-requests-limit: 0 + labels: + - dependencies diff --git a/.mergify.yml b/.mergify.yml index 7eae0395e1..63b8b61550 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -18,3 +18,11 @@ pull_request_rules: backport: branches: - release/v2.0.x + - name: Backport patches to the release/v3.0.x branch + conditions: + - base=main + - label=A:backport/v3.0.x + actions: + backport: + branches: + - release/v3.0.x From 44ec75f9d1a71508bb6a15edc9b85af3f837b396 Mon Sep 17 00:00:00 2001 From: Marius Poke Date: Wed, 21 Jun 2023 12:46:41 +0200 Subject: [PATCH 028/134] docs: add v3.0.0 changelog (#1056) add v3 changelog --- CHANGELOG.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5960c76238..c7cb03404c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,21 @@ Add an entry to the unreleased section whenever merging a PR to main that is not targeted at a specific release. These entries will eventually be included in a release. -## v.2.0.0 +## v3.0.0 + +Date: June 21st, 2023 + +Interchain Security v3 uses SDK 0.47 and IBC 7. + +* (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.0.0 Date: June 1st, 2023 From ed04399147a0c3847645f3e68f41ea16db4c0f48 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Thu, 22 Jun 2023 00:41:30 -0700 Subject: [PATCH 029/134] chore: finish go1.20 bump (#1058) * more * fix rands --- .github/workflows/automated-tests.yml | 2 +- .github/workflows/build.yml | 2 +- .github/workflows/golangci-lint.yml | 2 +- .github/workflows/manual-e2e.yml | 4 +- .github/workflows/nightly-e2e.yml | 2 +- README.md | 4 +- x/ccv/provider/keeper/key_assignment_test.go | 41 +++++++++++++------- x/ccv/provider/keeper/throttle_test.go | 10 +++-- 8 files changed, 40 insertions(+), 27 deletions(-) diff --git a/.github/workflows/automated-tests.yml b/.github/workflows/automated-tests.yml index 175bec9545..13b4d5cbc4 100644 --- a/.github/workflows/automated-tests.yml +++ b/.github/workflows/automated-tests.yml @@ -23,7 +23,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v4 with: - go-version: "1.19" # The Go version to download (if necessary) and use. + go-version: "1.20" # The Go version to download (if necessary) and use. # - name: Proto Check # run: make proto-check - name: Unit, integration and difference tests diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ab15d52ae0..ec188dd429 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,7 +21,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v4 with: - go-version: "1.19" # The Go version to download (if necessary) and use. + go-version: "1.20" # The Go version to download (if necessary) and use. - name: Test with coverage run: go test -coverpkg=./x/... -coverprofile=coverage.out ./... - name: SonarCloud Scan diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 28eba10b41..11e422b923 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -19,7 +19,7 @@ jobs: steps: - uses: actions/setup-go@v4 with: - go-version: "1.19" + go-version: "1.20" - uses: actions/checkout@v3 - name: golangci-lint uses: golangci/golangci-lint-action@v3 diff --git a/.github/workflows/manual-e2e.yml b/.github/workflows/manual-e2e.yml index 400e2a81ab..899e4ba230 100644 --- a/.github/workflows/manual-e2e.yml +++ b/.github/workflows/manual-e2e.yml @@ -11,7 +11,7 @@ jobs: steps: - uses: actions/setup-go@v4 with: - go-version: "1.19" + go-version: "1.20" - uses: actions/checkout@v3 - name: Checkout LFS objects @@ -20,7 +20,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v4 with: - go-version: "1.19" # The Go version to download (if necessary) and use. + go-version: "1.20" # The Go version to download (if necessary) and use. - name: E2E tests run: make test-e2e diff --git a/.github/workflows/nightly-e2e.yml b/.github/workflows/nightly-e2e.yml index 0fe0e48d81..f69125e6b8 100644 --- a/.github/workflows/nightly-e2e.yml +++ b/.github/workflows/nightly-e2e.yml @@ -24,7 +24,7 @@ jobs: steps: - uses: actions/setup-go@v4 with: - go-version: "1.19" + go-version: "1.20" - uses: actions/checkout@v3 diff --git a/README.md b/README.md index df86648ea4..bb6da8be76 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,8 @@ For more details on the Replicated Security protocol, take a look at the [docs]( ```bash ## For OSX or Linux -# go 1.18 (https://formulae.brew.sh/formula/go) -brew install go@1.19 +# go 1.20 (https://formulae.brew.sh/formula/go) +brew install go@1.20 # jq (optional, for testnet) (https://formulae.brew.sh/formula/jq) brew install jq # docker (optional, for integration tests, testnet) (https://docs.docker.com/get-docker/) diff --git a/x/ccv/provider/keeper/key_assignment_test.go b/x/ccv/provider/keeper/key_assignment_test.go index c06099ca60..49ef8698cb 100644 --- a/x/ccv/provider/keeper/key_assignment_test.go +++ b/x/ccv/provider/keeper/key_assignment_test.go @@ -47,7 +47,9 @@ func TestGetAllValidatorConsumerPubKey(t *testing.T) { pk, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - rand.Seed(time.Now().Unix()) + seed := time.Now().UnixNano() + rng := rand.New(rand.NewSource(seed)) + chainIDs := []string{"consumer-1", "consumer-2", "consumer-3"} numAssignments := 10 testAssignments := []types.ValidatorConsumerPubKey{} @@ -56,7 +58,7 @@ func TestGetAllValidatorConsumerPubKey(t *testing.T) { providerAddr := cryptotestutil.NewCryptoIdentityFromIntSeed(numAssignments + i).ProviderConsAddress() testAssignments = append(testAssignments, types.ValidatorConsumerPubKey{ - ChainId: chainIDs[rand.Intn(len(chainIDs))], + ChainId: chainIDs[rng.Intn(len(chainIDs))], ProviderAddr: providerAddr.ToSdkConsAddr(), ConsumerKey: &consumerKey, }, @@ -125,7 +127,9 @@ func TestGetAllValidatorsByConsumerAddr(t *testing.T) { pk, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - rand.Seed(time.Now().Unix()) + seed := time.Now().UnixNano() + rng := rand.New(rand.NewSource(seed)) + chainIDs := []string{"consumer-1", "consumer-2", "consumer-3"} numAssignments := 10 testAssignments := []types.ValidatorByConsumerAddr{} @@ -134,7 +138,7 @@ func TestGetAllValidatorsByConsumerAddr(t *testing.T) { providerAddr := cryptotestutil.NewCryptoIdentityFromIntSeed(numAssignments + i).ProviderConsAddress() testAssignments = append(testAssignments, types.ValidatorByConsumerAddr{ - ChainId: chainIDs[rand.Intn(len(chainIDs))], + ChainId: chainIDs[rng.Intn(len(chainIDs))], ConsumerAddr: consumerAddr.ToSdkConsAddr(), ProviderAddr: providerAddr.ToSdkConsAddr(), }, @@ -205,7 +209,9 @@ func TestGetAllKeyAssignmentReplacements(t *testing.T) { chainID := "consumer-1" - rand.Seed(time.Now().Unix()) + seed := time.Now().UnixNano() + rng := rand.New(rand.NewSource(seed)) + numAssignments := 10 testAssignments := []types.KeyAssignmentReplacement{} for i := 0; i < numAssignments; i++ { @@ -215,7 +221,7 @@ func TestGetAllKeyAssignmentReplacements(t *testing.T) { types.KeyAssignmentReplacement{ ProviderAddr: providerAddr.ToSdkConsAddr(), PrevCKey: &consumerKey, - Power: rand.Int63(), + Power: rng.Int63(), }, ) } @@ -264,7 +270,9 @@ func TestGetAllConsumerAddrsToPrune(t *testing.T) { pk, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - rand.Seed(time.Now().Unix()) + seed := time.Now().UnixNano() + rng := rand.New(rand.NewSource(seed)) + chainIDs := []string{"consumer-1", "consumer-2", "consumer-3"} numAssignments := 10 testAssignments := []types.ConsumerAddrsToPrune{} @@ -276,8 +284,8 @@ func TestGetAllConsumerAddrsToPrune(t *testing.T) { } testAssignments = append(testAssignments, types.ConsumerAddrsToPrune{ - ChainId: chainIDs[rand.Intn(len(chainIDs))], - VscId: rand.Uint64(), + ChainId: chainIDs[rng.Intn(len(chainIDs))], + VscId: rng.Uint64(), ConsumerAddrs: &consumerAddresses, }, ) @@ -705,14 +713,17 @@ func TestSimulatedAssignmentsAndUpdateApplication(t *testing.T) { assignableIDS = append(assignableIDS, cryptotestutil.NewCryptoIdentityFromIntSeed(i)) } + seed := time.Now().UnixNano() + rng := rand.New(rand.NewSource(seed)) + // Helper: simulates creation of staking module EndBlock updates. getStakingUpdates := func() (ret []abci.ValidatorUpdate) { // Get a random set of validators to update. It is important to test subsets of all validators. - validators := rand.Perm(len(providerIDS))[0:rand.Intn(len(providerIDS)+1)] + validators := rng.Perm(len(providerIDS))[0:rng.Intn(len(providerIDS)+1)] for _, i := range validators { // Power 0, 1, or 2 represents // deletion, update (from 0 or 2), update (from 0 or 1) - power := rand.Intn(3) + power := rng.Intn(3) ret = append(ret, abci.ValidatorUpdate{ PubKey: providerIDS[i].TMProtoCryptoPublicKey(), Power: int64(power), @@ -723,9 +734,9 @@ func TestSimulatedAssignmentsAndUpdateApplication(t *testing.T) { // Helper: simulates creation of assignment tx's to be done. getAssignments := func() (ret []Assignment) { - for i, numAssignments := 0, rand.Intn(NUM_ASSIGNMENTS_PER_BLOCK_MAX); i < numAssignments; i++ { - randomIxP := rand.Intn(len(providerIDS)) - randomIxC := rand.Intn(len(assignableIDS)) + for i, numAssignments := 0, rng.Intn(NUM_ASSIGNMENTS_PER_BLOCK_MAX); i < numAssignments; i++ { + randomIxP := rng.Intn(len(providerIDS)) + randomIxC := rng.Intn(len(assignableIDS)) ret = append(ret, Assignment{ val: providerIDS[randomIxP].SDKStakingValidator(), ck: assignableIDS[randomIxC].TMProtoCryptoPublicKey(), @@ -832,7 +843,7 @@ func TestSimulatedAssignmentsAndUpdateApplication(t *testing.T) { // delivery of maturity packets from the consumer chain. prunedVscid := greatestPrunedVSCID + // +1 and -1 because id was incremented (-1), (+1) to make upper bound inclusive - rand.Intn(int(k.GetValidatorSetUpdateId(ctx))+1-1-greatestPrunedVSCID) + rng.Intn(int(k.GetValidatorSetUpdateId(ctx))+1-1-greatestPrunedVSCID) k.PruneKeyAssignments(ctx, CHAINID, uint64(prunedVscid)) greatestPrunedVSCID = prunedVscid diff --git a/x/ccv/provider/keeper/throttle_test.go b/x/ccv/provider/keeper/throttle_test.go index 7cd39a8382..f923c53e98 100644 --- a/x/ccv/provider/keeper/throttle_test.go +++ b/x/ccv/provider/keeper/throttle_test.go @@ -784,8 +784,9 @@ func TestGlobalSlashEntryDeletion(t *testing.T) { // Instantiate shuffled copy of above slice shuffledEntries := append([]providertypes.GlobalSlashEntry{}, entries...) - rand.Seed(now.UnixNano()) - rand.Shuffle(len(shuffledEntries), func(i, j int) { + seed := time.Now().UnixNano() + rng := rand.New(rand.NewSource(seed)) + rng.Shuffle(len(shuffledEntries), func(i, j int) { shuffledEntries[i], shuffledEntries[j] = shuffledEntries[j], shuffledEntries[i] }) @@ -1192,7 +1193,8 @@ func TestPanicIfTooMuchThrottledPacketData(t *testing.T) { defaultParams.MaxThrottledPackets = tc.max providerKeeper.SetParams(ctx, defaultParams) - rand.Seed(time.Now().UnixNano()) + seed := time.Now().UnixNano() + rng := rand.New(rand.NewSource(seed)) // Queuing up a couple data instances for another chain shouldn't matter err := providerKeeper.QueueThrottledPacketData(ctx, "chain-17", 0, testkeeper.GetNewSlashPacketData()) @@ -1203,7 +1205,7 @@ func TestPanicIfTooMuchThrottledPacketData(t *testing.T) { // Queue packet data instances until we reach the max (some slash packets, some VSC matured packets) reachedMax := false for i := 0; i < int(tc.max); i++ { - randBool := rand.Intn(2) == 0 + randBool := rng.Intn(2) == 0 var data interface{} if randBool { data = testkeeper.GetNewSlashPacketData() From acc494ffea097bfcd31900f7a37044da46700636 Mon Sep 17 00:00:00 2001 From: MSalopek Date: Thu, 22 Jun 2023 13:23:17 +0200 Subject: [PATCH 030/134] fix: re-enable make proto-check and update proto options (#1060) * fix: update proto build tooling * fix: re-enable make proto-check in CI * chore: proto check that works (#1063) * wip * works * comments --------- Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> --- .github/workflows/automated-tests.yml | 4 +- Makefile | 32 ++-- .../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 +- proto/interchain_security/ccv/v1/ccv.proto | 2 +- scripts/protocgen.sh | 2 +- x/ccv/consumer/types/consumer.pb.go | 70 ++++----- x/ccv/consumer/types/genesis.pb.go | 94 +++++------ x/ccv/consumer/types/query.pb.go | 66 ++++---- x/ccv/provider/types/genesis.pb.go | 90 +++++------ x/ccv/provider/types/provider.pb.go | 148 +++++++++--------- x/ccv/provider/types/query.pb.go | 6 +- x/ccv/provider/types/tx.pb.go | 18 +-- x/ccv/types/ccv.pb.go | 6 +- 19 files changed, 280 insertions(+), 272 deletions(-) diff --git a/.github/workflows/automated-tests.yml b/.github/workflows/automated-tests.yml index 13b4d5cbc4..d48b8ef817 100644 --- a/.github/workflows/automated-tests.yml +++ b/.github/workflows/automated-tests.yml @@ -24,8 +24,8 @@ jobs: uses: actions/setup-go@v4 with: go-version: "1.20" # The Go version to download (if necessary) and use. - # - name: Proto Check - # run: make proto-check + - name: Proto Check + run: make proto-check - name: Unit, integration and difference tests run: go test ./... - name: E2E tests diff --git a/Makefile b/Makefile index 69cdfa74be..28c02f7c85 100644 --- a/Makefile +++ b/Makefile @@ -122,19 +122,27 @@ proto-gen: @$(protoImage) sh ./scripts/protocgen.sh; proto-check: - @if git diff --quiet; then \ - echo "No files were modified before running 'make proto-gen'."; \ + @if git diff --quiet --exit-code main...HEAD -- proto; then \ + echo "Pass! No committed changes found in /proto directory between the currently checked out branch and main."; \ else \ - echo "Error: Uncommitted changes exist before running 'make proto-gen'. Please commit or stash your changes."; \ - exit 1; \ - fi - @$(MAKE) proto-gen - @if git diff --quiet; then \ - echo "No files were modified after running 'make proto-gen'. Pass!"; \ - else \ - echo "Error: Files were modified after running 'make proto-gen'. Please commit changes to .pb files"; \ - exit 1; \ - fi + echo "Committed changes found in /proto directory between the currently checked out branch and main."; \ + modified_protos=$$(git diff --name-only main...HEAD proto); \ + modified_pb_files= ; \ + for proto_file in $${modified_protos}; do \ + proto_name=$$(basename "$${proto_file}" .proto); \ + pb_files=$$(find x/ccv -name "$${proto_name}.pb.go"); \ + for pb_file in $${pb_files}; do \ + if git diff --quiet --exit-code main...HEAD -- "$${pb_file}"; then \ + echo "Missing committed changes in $${pb_file}"; \ + exit 1; \ + else \ + modified_pb_files+="$${pb_file} "; \ + fi \ + done \ + done; \ + echo "Pass! Correctly modified pb files: "; \ + echo $${modified_pb_files}; \ + fi proto-format: @echo "Formatting Protobuf files" diff --git a/proto/interchain_security/ccv/consumer/v1/consumer.proto b/proto/interchain_security/ccv/consumer/v1/consumer.proto index 1487e579a8..97ba14f6da 100644 --- a/proto/interchain_security/ccv/consumer/v1/consumer.proto +++ b/proto/interchain_security/ccv/consumer/v1/consumer.proto @@ -3,7 +3,7 @@ package interchain_security.ccv.consumer.v1; import "interchain_security/ccv/v1/ccv.proto"; -option go_package = "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types"; +option go_package = "github.com/cosmos/interchain-security/v3/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 739ac2798e..9c9418ef3c 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/v2/x/ccv/consumer/types"; +option go_package = "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types"; import "interchain_security/ccv/v1/ccv.proto"; import "interchain_security/ccv/consumer/v1/consumer.proto"; diff --git a/proto/interchain_security/ccv/consumer/v1/query.proto b/proto/interchain_security/ccv/consumer/v1/query.proto index b5576b57fe..df90b1d0aa 100644 --- a/proto/interchain_security/ccv/consumer/v1/query.proto +++ b/proto/interchain_security/ccv/consumer/v1/query.proto @@ -1,7 +1,7 @@ syntax = "proto3"; package interchain_security.ccv.consumer.v1; -option go_package = "github.com/cosmos/interchain-security/v2/x/ccv/consumer/types"; +option go_package = "github.com/cosmos/interchain-security/v3/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 e1c241413b..e1f6ab2e1a 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/v2/x/ccv/provider/types"; +option go_package = "github.com/cosmos/interchain-security/v3/x/ccv/provider/types"; import "gogoproto/gogo.proto"; import "interchain_security/ccv/v1/ccv.proto"; diff --git a/proto/interchain_security/ccv/provider/v1/provider.proto b/proto/interchain_security/ccv/provider/v1/provider.proto index f235f0831a..b986255ce5 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/v2/x/ccv/provider/types"; +option go_package = "github.com/cosmos/interchain-security/v3/x/ccv/provider/types"; import "gogoproto/gogo.proto"; import "google/protobuf/timestamp.proto"; diff --git a/proto/interchain_security/ccv/provider/v1/query.proto b/proto/interchain_security/ccv/provider/v1/query.proto index 4709b287dd..431099be79 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/v2/x/ccv/provider/types"; +option go_package = "github.com/cosmos/interchain-security/v3/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 3093132727..257ab6e4e4 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/v2/x/ccv/provider/types"; +option go_package = "github.com/cosmos/interchain-security/v3/x/ccv/provider/types"; import "google/api/annotations.proto"; import "gogoproto/gogo.proto"; diff --git a/proto/interchain_security/ccv/v1/ccv.proto b/proto/interchain_security/ccv/v1/ccv.proto index 730366ea7f..ffae373aa6 100644 --- a/proto/interchain_security/ccv/v1/ccv.proto +++ b/proto/interchain_security/ccv/v1/ccv.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package interchain_security.ccv.v1; -option go_package = "github.com/cosmos/interchain-security/v2/x/ccv/types"; +option go_package = "github.com/cosmos/interchain-security/v3/x/ccv/types"; import "cosmos/staking/v1beta1/staking.proto"; diff --git a/scripts/protocgen.sh b/scripts/protocgen.sh index a6ca6098e4..7332a554f2 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/v2/* ./ +cp -r github.com/cosmos/interchain-security/v3/* ./ rm -rf github.com diff --git a/x/ccv/consumer/types/consumer.pb.go b/x/ccv/consumer/types/consumer.pb.go index 6ab018cf26..90d5d6e12b 100644 --- a/x/ccv/consumer/types/consumer.pb.go +++ b/x/ccv/consumer/types/consumer.pb.go @@ -369,53 +369,53 @@ var fileDescriptor_5b27a82b276e7f93 = []byte{ // 786 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0xcf, 0x6e, 0xdb, 0x36, 0x18, 0x8f, 0x96, 0xd6, 0x4d, 0x98, 0x14, 0x6b, 0x59, 0x2f, 0x55, 0x33, 0x40, 0x76, 0xdd, 0x1e, - 0x7c, 0x89, 0x84, 0x3a, 0xdb, 0xa5, 0xc0, 0x0e, 0x8d, 0xb3, 0xa2, 0xdd, 0xbf, 0x78, 0xaa, 0xd1, + 0x7c, 0x89, 0x84, 0x26, 0xdb, 0xa5, 0xc0, 0x0e, 0xb5, 0xb3, 0xa2, 0xdd, 0xbf, 0x78, 0xaa, 0xd1, 0x01, 0xdb, 0x81, 0xa0, 0x28, 0x5a, 0x22, 0x22, 0x91, 0x02, 0x49, 0xa9, 0xd3, 0x7d, 0x0f, 0xd0, 0xe3, 0x1e, 0x61, 0x0f, 0xb0, 0x87, 0x28, 0x76, 0xea, 0x71, 0xa7, 0x6e, 0x48, 0xde, 0x60, 0x4f, 0x30, 0x90, 0x92, 0x5c, 0x3b, 0x6d, 0x80, 0xdc, 0xf8, 0xe9, 0xf7, 0xfb, 0x7e, 0xfa, 0xfe, 0x83, - 0x09, 0xe3, 0x9a, 0x4a, 0x92, 0x62, 0xc6, 0x91, 0xa2, 0xa4, 0x94, 0x4c, 0xd7, 0x01, 0x21, 0x55, - 0x40, 0x04, 0x57, 0x65, 0x4e, 0x65, 0x50, 0x3d, 0x5a, 0xbe, 0xfd, 0x42, 0x0a, 0x2d, 0xe0, 0x83, - 0x8f, 0xf8, 0xf8, 0x84, 0x54, 0xfe, 0x92, 0x57, 0x3d, 0xda, 0x7f, 0x78, 0x99, 0xb0, 0xd1, 0x23, - 0x55, 0x23, 0xb5, 0x7f, 0x2f, 0x11, 0x22, 0xc9, 0x68, 0x60, 0xad, 0xa8, 0x5c, 0x04, 0x98, 0xd7, - 0x2d, 0xd4, 0x4f, 0x44, 0x22, 0xec, 0x33, 0x30, 0xaf, 0xce, 0x81, 0x08, 0x95, 0x0b, 0x85, 0x1a, - 0xa0, 0x31, 0x5a, 0xc8, 0xbb, 0xa8, 0x15, 0x97, 0x12, 0x6b, 0x26, 0x78, 0x8b, 0x0f, 0x2e, 0xe2, - 0x9a, 0xe5, 0x54, 0x69, 0x9c, 0x17, 0x0d, 0x61, 0xf4, 0x5b, 0x0f, 0xf4, 0x66, 0x58, 0xe2, 0x5c, - 0x41, 0x17, 0xdc, 0xa0, 0x1c, 0x47, 0x19, 0x8d, 0x5d, 0x67, 0xe8, 0x8c, 0xb7, 0xc2, 0xce, 0x84, - 0x27, 0xe0, 0x61, 0x94, 0x09, 0x72, 0xaa, 0x50, 0x41, 0x25, 0x8a, 0x99, 0xd2, 0x92, 0x45, 0xa5, - 0xf9, 0x0d, 0xd2, 0x12, 0x73, 0x95, 0x33, 0xa5, 0x98, 0xe0, 0xee, 0x27, 0x43, 0x67, 0xbc, 0x19, - 0xde, 0x6f, 0xb8, 0x33, 0x2a, 0x8f, 0x57, 0x98, 0xf3, 0x15, 0x22, 0xfc, 0x06, 0xdc, 0xbf, 0x54, - 0x05, 0x91, 0x14, 0x73, 0x4e, 0x33, 0x77, 0x73, 0xe8, 0x8c, 0xb7, 0xc3, 0x41, 0x7c, 0x89, 0xc8, - 0xb4, 0xa1, 0xc1, 0xc7, 0x60, 0xbf, 0x90, 0xa2, 0x62, 0x31, 0x95, 0x68, 0x41, 0x29, 0x2a, 0x84, - 0xc8, 0x10, 0x8e, 0x63, 0x89, 0x94, 0x96, 0xee, 0x35, 0x2b, 0xb2, 0xd7, 0x31, 0x9e, 0x52, 0x3a, - 0x13, 0x22, 0x7b, 0x12, 0xc7, 0xf2, 0x85, 0x96, 0xf0, 0x47, 0x00, 0x09, 0xa9, 0x90, 0x29, 0x8a, - 0x28, 0xb5, 0xc9, 0x8e, 0x89, 0xd8, 0xbd, 0x3e, 0x74, 0xc6, 0x3b, 0x93, 0x7b, 0x7e, 0x53, 0x3b, - 0xbf, 0xab, 0x9d, 0x7f, 0xdc, 0xd6, 0xf6, 0x68, 0xeb, 0xcd, 0xbb, 0xc1, 0xc6, 0xef, 0xff, 0x0c, - 0x9c, 0xf0, 0x16, 0x21, 0xd5, 0xbc, 0xf1, 0x9e, 0x59, 0x67, 0xf8, 0x0b, 0xb8, 0x6b, 0xb3, 0x59, - 0x50, 0x79, 0x51, 0xb7, 0x77, 0x75, 0xdd, 0xcf, 0x3a, 0x8d, 0x75, 0xf1, 0x67, 0x60, 0xd8, 0xcd, - 0x1b, 0x92, 0x74, 0xad, 0x84, 0x0b, 0x89, 0x89, 0x79, 0xb8, 0x37, 0x6c, 0xc6, 0x5e, 0xc7, 0x0b, - 0xd7, 0x68, 0x4f, 0x5b, 0x16, 0x3c, 0x00, 0x30, 0x65, 0x4a, 0x0b, 0xc9, 0x08, 0xce, 0x10, 0xe5, - 0x5a, 0x32, 0xaa, 0xdc, 0x2d, 0xdb, 0xc0, 0xdb, 0xef, 0x91, 0xaf, 0x1b, 0x00, 0xfe, 0x00, 0x6e, - 0x95, 0x3c, 0x12, 0x3c, 0x66, 0x3c, 0xe9, 0xd2, 0xd9, 0xbe, 0x7a, 0x3a, 0x9f, 0x2e, 0x9d, 0xdb, - 0x44, 0x0e, 0xc1, 0x9e, 0x12, 0x0b, 0x8d, 0x44, 0xa1, 0x91, 0xa9, 0x90, 0x4e, 0x25, 0x55, 0xa9, - 0xc8, 0x62, 0x17, 0xd8, 0xf0, 0xef, 0x18, 0xf4, 0xa4, 0xd0, 0x27, 0xa5, 0x9e, 0x77, 0x10, 0x7c, - 0x00, 0x6e, 0x4a, 0xfa, 0x0a, 0xcb, 0x18, 0xc5, 0x94, 0x8b, 0x5c, 0xb9, 0x3b, 0xc3, 0xcd, 0xf1, - 0x76, 0xb8, 0xdb, 0x7c, 0x3c, 0xb6, 0xdf, 0xe0, 0x17, 0x60, 0xd9, 0x6c, 0xb4, 0xce, 0xde, 0xb5, - 0xec, 0x7e, 0x87, 0x86, 0x2b, 0x5e, 0xa3, 0x2f, 0xc1, 0xe7, 0xdf, 0x61, 0xa5, 0x57, 0xe7, 0xeb, - 0xc8, 0x4c, 0xf1, 0x33, 0xca, 0x92, 0x54, 0xc3, 0x3d, 0xd0, 0x4b, 0xed, 0xcb, 0x6e, 0xc6, 0x66, + 0x43, 0xc6, 0x35, 0x95, 0x24, 0xc5, 0x8c, 0x23, 0x45, 0x49, 0x29, 0x99, 0xae, 0x03, 0x42, 0xaa, + 0x80, 0x08, 0xae, 0xca, 0x9c, 0xca, 0xa0, 0x7a, 0xb4, 0x7c, 0xfb, 0x85, 0x14, 0x5a, 0xc0, 0x07, + 0x1f, 0xf1, 0xf1, 0x09, 0xa9, 0xfc, 0x25, 0xaf, 0x7a, 0xb4, 0xff, 0xf0, 0x32, 0x61, 0xa3, 0x47, + 0xaa, 0x46, 0x6a, 0xff, 0x5e, 0x22, 0x44, 0x92, 0xd1, 0xc0, 0x5a, 0x51, 0xb9, 0x08, 0x30, 0xaf, + 0x5b, 0xa8, 0x9f, 0x88, 0x44, 0xd8, 0x67, 0x60, 0x5e, 0x9d, 0x03, 0x11, 0x2a, 0x17, 0x0a, 0x35, + 0x40, 0x63, 0xb4, 0x90, 0x77, 0x51, 0x2b, 0x2e, 0x25, 0xd6, 0x4c, 0xf0, 0x16, 0x1f, 0x5c, 0xc4, + 0x35, 0xcb, 0xa9, 0xd2, 0x38, 0x2f, 0x1a, 0xc2, 0xe8, 0xb7, 0x1e, 0xe8, 0xcd, 0xb0, 0xc4, 0xb9, + 0x82, 0x2e, 0xb8, 0x41, 0x39, 0x8e, 0x32, 0x1a, 0xbb, 0xce, 0xd0, 0x19, 0x6f, 0x85, 0x9d, 0x09, + 0x4f, 0xc0, 0xc3, 0x28, 0x13, 0xe4, 0x54, 0xa1, 0x82, 0x4a, 0x14, 0x33, 0xa5, 0x25, 0x8b, 0x4a, + 0xf3, 0x1b, 0xa4, 0x25, 0xe6, 0x2a, 0x67, 0x4a, 0x31, 0xc1, 0xdd, 0x4f, 0x86, 0xce, 0x78, 0x33, + 0xbc, 0xdf, 0x70, 0x67, 0x54, 0x1e, 0xaf, 0x30, 0xe7, 0x2b, 0x44, 0xf8, 0x0d, 0xb8, 0x7f, 0xa9, + 0x0a, 0x22, 0x29, 0xe6, 0x9c, 0x66, 0xee, 0xe6, 0xd0, 0x19, 0x6f, 0x87, 0x83, 0xf8, 0x12, 0x91, + 0x69, 0x43, 0x83, 0x8f, 0xc1, 0x7e, 0x21, 0x45, 0xc5, 0x62, 0x2a, 0xd1, 0x82, 0x52, 0x54, 0x08, + 0x91, 0x21, 0x1c, 0xc7, 0x12, 0x29, 0x2d, 0xdd, 0x6b, 0x56, 0x64, 0xaf, 0x63, 0x3c, 0xa5, 0x74, + 0x26, 0x44, 0xf6, 0x24, 0x8e, 0xe5, 0x0b, 0x2d, 0xe1, 0x8f, 0x00, 0x12, 0x52, 0x21, 0x53, 0x14, + 0x51, 0x6a, 0x93, 0x1d, 0x13, 0xb1, 0x7b, 0x7d, 0xe8, 0x8c, 0x77, 0x0e, 0xef, 0xf9, 0x4d, 0xed, + 0xfc, 0xae, 0x76, 0xfe, 0x71, 0x5b, 0xdb, 0xc9, 0xd6, 0x9b, 0x77, 0x83, 0x8d, 0xdf, 0xff, 0x19, + 0x38, 0xe1, 0x2d, 0x42, 0xaa, 0x79, 0xe3, 0x3d, 0xb3, 0xce, 0xf0, 0x17, 0x70, 0xd7, 0x66, 0xb3, + 0xa0, 0xf2, 0xa2, 0x6e, 0xef, 0xea, 0xba, 0x9f, 0x75, 0x1a, 0xeb, 0xe2, 0xcf, 0xc0, 0xb0, 0x9b, + 0x37, 0x24, 0xe9, 0x5a, 0x09, 0x17, 0x12, 0x13, 0xf3, 0x70, 0x6f, 0xd8, 0x8c, 0xbd, 0x8e, 0x17, + 0xae, 0xd1, 0x9e, 0xb6, 0x2c, 0x78, 0x00, 0x60, 0xca, 0x94, 0x16, 0x92, 0x11, 0x9c, 0x21, 0xca, + 0xb5, 0x64, 0x54, 0xb9, 0x5b, 0xb6, 0x81, 0xb7, 0xdf, 0x23, 0x5f, 0x37, 0x00, 0xfc, 0x01, 0xdc, + 0x2a, 0x79, 0x24, 0x78, 0xcc, 0x78, 0xd2, 0xa5, 0xb3, 0x7d, 0xf5, 0x74, 0x3e, 0x5d, 0x3a, 0xb7, + 0x89, 0x1c, 0x81, 0x3d, 0x25, 0x16, 0x1a, 0x89, 0x42, 0x23, 0x53, 0x21, 0x9d, 0x4a, 0xaa, 0x52, + 0x91, 0xc5, 0x2e, 0xb0, 0xe1, 0xdf, 0x31, 0xe8, 0x49, 0xa1, 0x4f, 0x4a, 0x3d, 0xef, 0x20, 0xf8, + 0x00, 0xdc, 0x94, 0xf4, 0x15, 0x96, 0x31, 0x8a, 0x29, 0x17, 0xb9, 0x72, 0x77, 0x86, 0x9b, 0xe3, + 0xed, 0x70, 0xb7, 0xf9, 0x78, 0x6c, 0xbf, 0xc1, 0x2f, 0xc0, 0xb2, 0xd9, 0x68, 0x9d, 0xbd, 0x6b, + 0xd9, 0xfd, 0x0e, 0x0d, 0x57, 0xbc, 0x46, 0x5f, 0x82, 0xcf, 0xbf, 0xc3, 0x4a, 0xaf, 0xce, 0xd7, + 0xc4, 0x4c, 0xf1, 0x33, 0xca, 0x92, 0x54, 0xc3, 0x3d, 0xd0, 0x4b, 0xed, 0xcb, 0x6e, 0xc6, 0x66, 0xd8, 0x5a, 0xa3, 0x3f, 0x1c, 0x70, 0x67, 0x2a, 0x85, 0x52, 0x53, 0xb3, 0xf3, 0x2f, 0x71, 0xc6, 0x62, 0xac, 0x85, 0x34, 0xab, 0x64, 0x26, 0x90, 0x2a, 0x65, 0x1d, 0x76, 0xc3, 0xce, 0x84, 0x7d, 0x70, 0xbd, 0x10, 0xaf, 0xa8, 0x6c, 0x77, 0xa5, 0x31, 0x20, 0x06, 0xbd, 0xa2, 0x8c, 0x4e, 0x69, - 0x6d, 0x87, 0x7e, 0x67, 0xd2, 0xff, 0xa0, 0xa8, 0x4f, 0x78, 0x7d, 0x74, 0xf8, 0xdf, 0xbb, 0xc1, + 0x6d, 0x87, 0x7e, 0xe7, 0xb0, 0xff, 0x41, 0x51, 0x9f, 0xf0, 0x7a, 0x72, 0xf4, 0xdf, 0xbb, 0xc1, 0xdd, 0x1a, 0xe7, 0xd9, 0xe3, 0x91, 0xe9, 0x2e, 0xe5, 0xaa, 0x54, 0xa8, 0xf1, 0x1b, 0xfd, 0xf5, 0xe7, 0x41, 0xbf, 0xbd, 0x0c, 0x44, 0xd6, 0x85, 0x16, 0xfe, 0xac, 0x8c, 0xbe, 0xa5, 0x75, 0xd8, 0x0a, 0x8f, 0x34, 0xb8, 0xfd, 0x3d, 0xd6, 0xa5, 0x64, 0x3c, 0x79, 0xf9, 0x62, 0x3a, 0xc3, 0xe4, 0x94, 0x6a, 0x13, 0x4d, 0xa5, 0xc8, 0xf3, 0x66, 0xe1, 0xaf, 0x85, 0x8d, 0x01, 0x9f, 0x83, 0x9b, - 0xb9, 0xa5, 0xea, 0xda, 0x8e, 0xb0, 0x8d, 0x75, 0x67, 0xb2, 0xff, 0x41, 0x50, 0xf3, 0xee, 0x98, - 0x34, 0xad, 0x7e, 0x6d, 0x5a, 0xbd, 0xdb, 0xb9, 0x1a, 0xf0, 0xe8, 0xa7, 0x37, 0x67, 0x9e, 0xf3, + 0xb9, 0xa5, 0xea, 0xda, 0x8e, 0xb0, 0x8d, 0x75, 0xe7, 0x70, 0xff, 0x83, 0xa0, 0xe6, 0xdd, 0x31, + 0x69, 0x5a, 0xfd, 0xda, 0xb4, 0x7a, 0xb7, 0x73, 0x35, 0xe0, 0xe4, 0xa7, 0x37, 0x67, 0x9e, 0xf3, 0xf6, 0xcc, 0x73, 0xfe, 0x3d, 0xf3, 0x9c, 0xd7, 0xe7, 0xde, 0xc6, 0xdb, 0x73, 0x6f, 0xe3, 0xef, 0x73, 0x6f, 0xe3, 0xe7, 0xaf, 0x12, 0xa6, 0xd3, 0x32, 0xf2, 0x89, 0xc8, 0xdb, 0x93, 0x16, 0xbc, - 0xbf, 0x9e, 0x07, 0xcb, 0xeb, 0x59, 0x4d, 0x82, 0x5f, 0xd7, 0x6f, 0xb3, 0xae, 0x0b, 0xaa, 0xa2, - 0x9e, 0x0d, 0xe2, 0xf0, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x2e, 0x03, 0xd8, 0xe3, 0xcc, 0x05, + 0xbf, 0x9e, 0x07, 0xcb, 0xeb, 0x59, 0x1d, 0x05, 0xbf, 0xae, 0xdf, 0x66, 0x5d, 0x17, 0x54, 0x45, + 0x3d, 0x1b, 0xc4, 0xd1, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0x26, 0xe0, 0xb8, 0xdf, 0xcc, 0x05, 0x00, 0x00, } diff --git a/x/ccv/consumer/types/genesis.pb.go b/x/ccv/consumer/types/genesis.pb.go index 1511df9ccd..7a503f0e77 100644 --- a/x/ccv/consumer/types/genesis.pb.go +++ b/x/ccv/consumer/types/genesis.pb.go @@ -291,53 +291,53 @@ var fileDescriptor_2db73a6057a27482 = []byte{ // 786 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x55, 0x4b, 0x8f, 0xe3, 0x34, 0x1c, 0x6f, 0x76, 0x87, 0xd2, 0x7a, 0x76, 0xd9, 0xc1, 0x03, 0x55, 0x68, 0x45, 0x28, 0x03, 0x87, - 0x4a, 0x40, 0xac, 0x16, 0x09, 0x21, 0x21, 0x10, 0x4c, 0x47, 0x82, 0x4a, 0x0b, 0xac, 0xda, 0xdd, - 0x22, 0xed, 0x25, 0x72, 0x1d, 0x93, 0x58, 0x9b, 0xd8, 0x91, 0xed, 0x64, 0xd8, 0x03, 0x17, 0xae, - 0x5c, 0xf8, 0x58, 0x7b, 0x9c, 0x23, 0x27, 0x84, 0x66, 0xbe, 0x03, 0x67, 0x14, 0xdb, 0xe9, 0x83, - 0xe9, 0x88, 0x9e, 0x12, 0xe7, 0xff, 0x7b, 0xfc, 0x1f, 0x8e, 0x0d, 0xc6, 0x8c, 0x6b, 0x2a, 0x49, - 0x8a, 0x19, 0x8f, 0x14, 0x25, 0xa5, 0x64, 0xfa, 0x25, 0x22, 0xa4, 0x42, 0x44, 0x70, 0x55, 0xe6, - 0x54, 0xa2, 0x6a, 0x8c, 0x12, 0xca, 0xa9, 0x62, 0x2a, 0x2c, 0xa4, 0xd0, 0x02, 0x7e, 0xb0, 0x87, - 0x12, 0x12, 0x52, 0x85, 0x0d, 0x25, 0xac, 0xc6, 0xfd, 0x0f, 0xef, 0xd2, 0xad, 0xc6, 0xf5, 0xc3, - 0x4a, 0xf5, 0x27, 0x87, 0xb8, 0xaf, 0x65, 0x2d, 0x67, 0xa0, 0x29, 0x8f, 0xa9, 0xcc, 0x19, 0xd7, - 0x08, 0xaf, 0x08, 0x43, 0xfa, 0x65, 0x41, 0x5d, 0x6e, 0x7d, 0xc4, 0x56, 0x04, 0x65, 0x2c, 0x49, - 0x35, 0xc9, 0x18, 0xe5, 0x5a, 0xa1, 0x2d, 0x74, 0x35, 0xde, 0x5a, 0x39, 0xc2, 0xfb, 0x35, 0x81, - 0x08, 0x49, 0x11, 0x49, 0x31, 0xe7, 0x34, 0x33, 0x8e, 0xf6, 0xd5, 0x41, 0x82, 0x44, 0x88, 0x24, - 0xa3, 0xc8, 0xac, 0x56, 0xe5, 0xcf, 0x28, 0x2e, 0x25, 0xd6, 0x4c, 0x70, 0x17, 0x7f, 0x2b, 0x11, - 0x89, 0x30, 0xaf, 0xa8, 0x7e, 0xb3, 0x5f, 0xcf, 0xfe, 0xe9, 0x80, 0x07, 0xdf, 0xda, 0xbe, 0x2d, - 0x34, 0xd6, 0x14, 0xce, 0x40, 0xbb, 0xc0, 0x12, 0xe7, 0xca, 0xf7, 0x86, 0xde, 0xe8, 0x78, 0xf2, - 0x51, 0x78, 0x40, 0x1f, 0xc3, 0x27, 0x86, 0x72, 0x7e, 0xf4, 0xea, 0xaf, 0xf7, 0x5a, 0x73, 0x27, - 0x00, 0x3f, 0x06, 0xb0, 0x90, 0xa2, 0x62, 0x31, 0x95, 0x91, 0xad, 0x33, 0x62, 0xb1, 0x7f, 0x6f, - 0xe8, 0x8d, 0xba, 0xf3, 0x93, 0x26, 0x32, 0x35, 0x81, 0x59, 0x0c, 0x43, 0x70, 0xba, 0x41, 0xdb, - 0xca, 0x6a, 0xf8, 0x7d, 0x03, 0x7f, 0x73, 0x0d, 0xb7, 0x91, 0x59, 0x0c, 0x07, 0xa0, 0xcb, 0xe9, - 0x65, 0x64, 0x12, 0xf3, 0x8f, 0x86, 0xde, 0xa8, 0x33, 0xef, 0x70, 0x7a, 0x39, 0xad, 0xd7, 0x30, - 0x02, 0x6f, 0xff, 0xd7, 0x5a, 0xd5, 0xe5, 0xf9, 0xaf, 0x35, 0x45, 0xad, 0x48, 0xb8, 0x3d, 0x80, - 0x70, 0xab, 0xe5, 0xd5, 0x38, 0xb4, 0x59, 0x99, 0x8e, 0xcc, 0x4f, 0x77, 0x53, 0xb5, 0x6d, 0x4a, - 0x81, 0xbf, 0x31, 0x10, 0x5c, 0x51, 0xae, 0x4a, 0xe5, 0x3c, 0xda, 0xc6, 0x23, 0xfc, 0x5f, 0x8f, - 0x86, 0x66, 0x6d, 0x7a, 0x6b, 0x9b, 0x9d, 0xef, 0x30, 0x01, 0x27, 0x39, 0xd6, 0xa5, 0x64, 0x3c, - 0x89, 0x0a, 0x4c, 0x5e, 0x50, 0xad, 0xfc, 0xd7, 0x87, 0xf7, 0x47, 0xc7, 0x93, 0xcf, 0x0e, 0x1a, - 0xcd, 0xf7, 0x8e, 0xbc, 0x5c, 0x4c, 0x9f, 0x18, 0xba, 0x9b, 0xd2, 0xa3, 0x46, 0xd5, 0x7e, 0x55, - 0xf0, 0x07, 0xf0, 0x88, 0x71, 0xa6, 0x19, 0xce, 0xa2, 0x0a, 0x67, 0x91, 0xa2, 0xda, 0xef, 0x18, - 0x9f, 0xe1, 0x76, 0xe2, 0xf5, 0x5e, 0x0e, 0x97, 0x38, 0x63, 0x31, 0xd6, 0x42, 0x3e, 0x2b, 0x62, - 0xac, 0xa9, 0x53, 0x7c, 0xe8, 0xe8, 0x4b, 0x9c, 0x2d, 0xa8, 0x86, 0xbf, 0x82, 0x7e, 0x4a, 0xeb, - 0xf2, 0x23, 0x2d, 0x6a, 0x45, 0x45, 0x75, 0x54, 0x1a, 0x7c, 0x3d, 0xd7, 0xae, 0x91, 0xfe, 0xe2, - 0xa0, 0x12, 0xbe, 0x33, 0x32, 0x4f, 0xc5, 0xd2, 0x88, 0x58, 0xcf, 0xd9, 0x85, 0x73, 0xed, 0xa5, - 0xfb, 0xa2, 0x31, 0xfc, 0xcd, 0x03, 0xef, 0x8a, 0x52, 0x2b, 0x8d, 0x79, 0x5c, 0xf7, 0x2e, 0x16, - 0x97, 0x5c, 0xb3, 0x9c, 0x46, 0x2a, 0xc3, 0x2a, 0x65, 0x3c, 0xf1, 0x81, 0x49, 0xe1, 0xf3, 0x83, - 0x52, 0xf8, 0x71, 0xa3, 0x74, 0xe1, 0x84, 0x9c, 0xff, 0x40, 0xdc, 0x0e, 0x2d, 0x9c, 0x05, 0x94, - 0xc0, 0x2f, 0xa8, 0xf5, 0x6f, 0xd4, 0xd6, 0x43, 0x3c, 0x36, 0xdb, 0x64, 0x72, 0xa7, 0xbd, 0xdb, - 0x22, 0x35, 0xc7, 0x8e, 0xe8, 0x02, 0x6b, 0xfc, 0x98, 0xa9, 0x66, 0x80, 0x3d, 0xa7, 0xbc, 0x0b, - 0x52, 0xf0, 0x77, 0x0f, 0x04, 0x19, 0x56, 0x3a, 0xd2, 0x12, 0x73, 0x95, 0x33, 0xa5, 0x98, 0xe0, - 0xd1, 0x2a, 0x13, 0xe4, 0x45, 0x64, 0x7b, 0xe5, 0x3f, 0x30, 0xd6, 0x5f, 0x1f, 0x54, 0xf9, 0x63, - 0xac, 0xf4, 0xd3, 0x2d, 0xa5, 0xf3, 0x5a, 0xc8, 0x4e, 0xa4, 0xe9, 0x40, 0x76, 0x37, 0x04, 0xf6, - 0x40, 0xbb, 0x90, 0x74, 0x3a, 0x5d, 0xfa, 0x0f, 0xcd, 0x3f, 0xea, 0x56, 0x67, 0xcf, 0x41, 0x6f, - 0xff, 0x58, 0x6b, 0x86, 0x4b, 0xb3, 0x3e, 0x81, 0x8e, 0xe6, 0x6e, 0x05, 0x47, 0xe0, 0xe4, 0xd6, - 0x2e, 0xba, 0x67, 0x10, 0x6f, 0x54, 0x3b, 0xa3, 0x3f, 0x7b, 0x06, 0x4e, 0xf7, 0xcc, 0x0b, 0x7e, - 0x05, 0x06, 0x55, 0xb3, 0x71, 0xb7, 0x7e, 0x5a, 0x1c, 0xc7, 0x92, 0x2a, 0x7b, 0xde, 0x75, 0xe7, - 0xef, 0xac, 0x21, 0xeb, 0xff, 0xf0, 0x1b, 0x0b, 0x38, 0xff, 0xe9, 0xd5, 0x75, 0xe0, 0x5d, 0x5d, - 0x07, 0xde, 0xdf, 0xd7, 0x81, 0xf7, 0xc7, 0x4d, 0xd0, 0xba, 0xba, 0x09, 0x5a, 0x7f, 0xde, 0x04, - 0xad, 0xe7, 0x5f, 0x26, 0x4c, 0xa7, 0xe5, 0x2a, 0x24, 0x22, 0x47, 0x44, 0xa8, 0x5c, 0x28, 0xb4, - 0x69, 0xed, 0x27, 0xeb, 0x2b, 0xa3, 0x9a, 0xa0, 0x5f, 0x76, 0xef, 0x0d, 0x73, 0x29, 0xac, 0xda, - 0xe6, 0x2c, 0xfe, 0xf4, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x86, 0x37, 0xab, 0xfd, 0xe6, 0x06, + 0x4a, 0x40, 0xac, 0x76, 0x25, 0x84, 0x84, 0x40, 0x30, 0x1d, 0x09, 0x2a, 0x2d, 0xb0, 0x6a, 0x77, + 0x8b, 0xb4, 0x97, 0xc8, 0x75, 0x4c, 0x62, 0x6d, 0x62, 0x47, 0xb6, 0x93, 0x61, 0x0f, 0x5c, 0xb8, + 0x72, 0xe1, 0x63, 0xed, 0x71, 0x8f, 0x9c, 0x10, 0x9a, 0xf9, 0x0e, 0x9c, 0x51, 0x6c, 0xa7, 0x0f, + 0xa6, 0xa3, 0xed, 0x29, 0x71, 0xfe, 0xbf, 0xc7, 0xff, 0xe1, 0xd8, 0x60, 0xcc, 0xb8, 0xa6, 0x92, + 0xa4, 0x98, 0xf1, 0x48, 0x51, 0x52, 0x4a, 0xa6, 0x5f, 0x20, 0x42, 0x2a, 0x44, 0x04, 0x57, 0x65, + 0x4e, 0x25, 0xaa, 0xc6, 0x28, 0xa1, 0x9c, 0x2a, 0xa6, 0xc2, 0x42, 0x0a, 0x2d, 0xe0, 0x47, 0x7b, + 0x28, 0x21, 0x21, 0x55, 0xd8, 0x50, 0xc2, 0x6a, 0xdc, 0xff, 0xf8, 0x36, 0xdd, 0x6a, 0x5c, 0x3f, + 0xac, 0x54, 0x7f, 0x72, 0x88, 0xfb, 0x5a, 0xd6, 0x72, 0x06, 0x9a, 0xf2, 0x98, 0xca, 0x9c, 0x71, + 0x8d, 0xf0, 0x8a, 0x30, 0xa4, 0x5f, 0x14, 0xd4, 0xe5, 0xd6, 0x47, 0x6c, 0x45, 0x50, 0xc6, 0x92, + 0x54, 0x93, 0x8c, 0x51, 0xae, 0x15, 0xda, 0x42, 0x57, 0xe3, 0xad, 0x95, 0x23, 0x7c, 0x58, 0x13, + 0x88, 0x90, 0x14, 0x91, 0x14, 0x73, 0x4e, 0x33, 0xe3, 0x68, 0x5f, 0x1d, 0x24, 0x48, 0x84, 0x48, + 0x32, 0x8a, 0xcc, 0x6a, 0x55, 0xfe, 0x82, 0xe2, 0x52, 0x62, 0xcd, 0x04, 0x77, 0xf1, 0x77, 0x12, + 0x91, 0x08, 0xf3, 0x8a, 0xea, 0x37, 0xfb, 0xf5, 0xec, 0xdf, 0x0e, 0xb8, 0xf7, 0x9d, 0xed, 0xdb, + 0x42, 0x63, 0x4d, 0xe1, 0x0c, 0xb4, 0x0b, 0x2c, 0x71, 0xae, 0x7c, 0x6f, 0xe8, 0x8d, 0x8e, 0x27, + 0x9f, 0x84, 0x07, 0xf4, 0x31, 0x7c, 0x6c, 0x28, 0xe7, 0x47, 0x2f, 0xff, 0xfe, 0xa0, 0x35, 0x77, + 0x02, 0xf0, 0x53, 0x00, 0x0b, 0x29, 0x2a, 0x16, 0x53, 0x19, 0xd9, 0x3a, 0x23, 0x16, 0xfb, 0x77, + 0x86, 0xde, 0xa8, 0x3b, 0x3f, 0x69, 0x22, 0x53, 0x13, 0x98, 0xc5, 0x30, 0x04, 0xa7, 0x1b, 0xb4, + 0xad, 0xac, 0x86, 0xdf, 0x35, 0xf0, 0xb7, 0xd7, 0x70, 0x1b, 0x99, 0xc5, 0x70, 0x00, 0xba, 0x9c, + 0x5e, 0x46, 0x26, 0x31, 0xff, 0x68, 0xe8, 0x8d, 0x3a, 0xf3, 0x0e, 0xa7, 0x97, 0xd3, 0x7a, 0x0d, + 0x23, 0xf0, 0xee, 0xff, 0xad, 0x55, 0x5d, 0x9e, 0xff, 0x46, 0x53, 0xd4, 0x8a, 0x84, 0xdb, 0x03, + 0x08, 0xb7, 0x5a, 0x5e, 0x8d, 0x43, 0x9b, 0x95, 0xe9, 0xc8, 0xfc, 0x74, 0x37, 0x55, 0xdb, 0xa6, + 0x14, 0xf8, 0x1b, 0x03, 0xc1, 0x15, 0xe5, 0xaa, 0x54, 0xce, 0xa3, 0x6d, 0x3c, 0xc2, 0xd7, 0x7a, + 0x34, 0x34, 0x6b, 0xd3, 0x5b, 0xdb, 0xec, 0x7c, 0x87, 0x09, 0x38, 0xc9, 0xb1, 0x2e, 0x25, 0xe3, + 0x49, 0x54, 0x60, 0xf2, 0x9c, 0x6a, 0xe5, 0xbf, 0x39, 0xbc, 0x3b, 0x3a, 0x9e, 0x7c, 0x7e, 0xd0, + 0x68, 0x7e, 0x70, 0xe4, 0xe5, 0x62, 0xfa, 0xd8, 0xd0, 0xdd, 0x94, 0x1e, 0x34, 0xaa, 0xf6, 0xab, + 0x82, 0x3f, 0x82, 0x07, 0x8c, 0x33, 0xcd, 0x70, 0x16, 0x55, 0x38, 0x8b, 0x14, 0xd5, 0x7e, 0xc7, + 0xf8, 0x0c, 0xb7, 0x13, 0xaf, 0xf7, 0x72, 0xb8, 0xc4, 0x19, 0x8b, 0xb1, 0x16, 0xf2, 0x69, 0x11, + 0x63, 0x4d, 0x9d, 0xe2, 0x7d, 0x47, 0x5f, 0xe2, 0x6c, 0x41, 0x35, 0xfc, 0x0d, 0xf4, 0x53, 0x5a, + 0x97, 0x1f, 0x69, 0x51, 0x2b, 0x2a, 0xaa, 0xa3, 0xd2, 0xe0, 0xeb, 0xb9, 0x76, 0x8d, 0xf4, 0x97, + 0x07, 0x95, 0xf0, 0xbd, 0x91, 0x79, 0x22, 0x96, 0x46, 0xc4, 0x7a, 0xce, 0x2e, 0x9c, 0x6b, 0x2f, + 0xdd, 0x17, 0x8d, 0xe1, 0xef, 0x1e, 0x78, 0x5f, 0x94, 0x5a, 0x69, 0xcc, 0xe3, 0xba, 0x77, 0xb1, + 0xb8, 0xe4, 0x9a, 0xe5, 0x34, 0x52, 0x19, 0x56, 0x29, 0xe3, 0x89, 0x0f, 0x4c, 0x0a, 0x5f, 0x1c, + 0x94, 0xc2, 0x4f, 0x1b, 0xa5, 0x0b, 0x27, 0xe4, 0xfc, 0x07, 0xe2, 0x66, 0x68, 0xe1, 0x2c, 0xa0, + 0x04, 0x7e, 0x41, 0xad, 0x7f, 0xa3, 0xb6, 0x1e, 0xe2, 0xb1, 0xd9, 0x26, 0x93, 0x5b, 0xed, 0xdd, + 0x16, 0xa9, 0x39, 0x76, 0x44, 0x17, 0x58, 0xe3, 0x47, 0x4c, 0x35, 0x03, 0xec, 0x39, 0xe5, 0x5d, + 0x90, 0x82, 0x7f, 0x78, 0x20, 0xc8, 0xb0, 0xd2, 0x91, 0x96, 0x98, 0xab, 0x9c, 0x29, 0xc5, 0x04, + 0x8f, 0x56, 0x99, 0x20, 0xcf, 0x23, 0xdb, 0x2b, 0xff, 0x9e, 0xb1, 0xfe, 0xe6, 0xa0, 0xca, 0x1f, + 0x61, 0xa5, 0x9f, 0x6c, 0x29, 0x9d, 0xd7, 0x42, 0x76, 0x22, 0x4d, 0x07, 0xb2, 0xdb, 0x21, 0xb0, + 0x07, 0xda, 0x85, 0xa4, 0xd3, 0xe9, 0xd2, 0xbf, 0x6f, 0xfe, 0x51, 0xb7, 0x3a, 0x7b, 0x06, 0x7a, + 0xfb, 0xc7, 0x5a, 0x33, 0x5c, 0x9a, 0xf5, 0x09, 0x74, 0x34, 0x77, 0x2b, 0x38, 0x02, 0x27, 0x37, + 0x76, 0xd1, 0x1d, 0x83, 0x78, 0xab, 0xda, 0x19, 0xfd, 0xd9, 0x53, 0x70, 0xba, 0x67, 0x5e, 0xf0, + 0x6b, 0x30, 0xa8, 0x9a, 0x8d, 0xbb, 0xf5, 0xd3, 0xe2, 0x38, 0x96, 0x54, 0xd9, 0xf3, 0xae, 0x3b, + 0x7f, 0x6f, 0x0d, 0x59, 0xff, 0x87, 0xdf, 0x5a, 0xc0, 0xf9, 0xcf, 0x2f, 0xaf, 0x02, 0xef, 0xd5, + 0x55, 0xe0, 0xfd, 0x73, 0x15, 0x78, 0x7f, 0x5e, 0x07, 0xad, 0x57, 0xd7, 0x41, 0xeb, 0xaf, 0xeb, + 0xa0, 0xf5, 0xec, 0xab, 0x84, 0xe9, 0xb4, 0x5c, 0x85, 0x44, 0xe4, 0x88, 0x08, 0x95, 0x0b, 0x85, + 0x36, 0xad, 0xfd, 0x6c, 0x7d, 0x65, 0x54, 0x0f, 0xd1, 0xaf, 0xbb, 0xf7, 0x86, 0xb9, 0x14, 0x56, + 0x6d, 0x73, 0x16, 0x3f, 0xfc, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x8e, 0xd4, 0xcb, 0xc1, 0xe6, 0x06, 0x00, 0x00, } diff --git a/x/ccv/consumer/types/query.pb.go b/x/ccv/consumer/types/query.pb.go index a89562d8e1..5b9c52d962 100644 --- a/x/ccv/consumer/types/query.pb.go +++ b/x/ccv/consumer/types/query.pb.go @@ -308,40 +308,40 @@ func init() { } var fileDescriptor_f627751d3cc10225 = []byte{ - // 522 bytes of a gzipped FileDescriptorProto + // 521 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0xcf, 0x8b, 0xd3, 0x40, - 0x14, 0x6e, 0xb6, 0x3f, 0xc4, 0x59, 0xbc, 0x8c, 0x15, 0x42, 0x95, 0xb8, 0x44, 0xc1, 0xaa, 0x34, - 0xe3, 0x76, 0x0f, 0xab, 0x07, 0x51, 0x56, 0x5d, 0x14, 0x54, 0xd6, 0x22, 0x08, 0x5e, 0xd6, 0xe9, - 0xf4, 0x6d, 0x3a, 0xd0, 0x64, 0xb2, 0x33, 0x93, 0xd0, 0xde, 0xc4, 0x3f, 0x40, 0x04, 0xff, 0x13, - 0x2f, 0xfe, 0x0b, 0x7b, 0x5c, 0xf0, 0xe2, 0x49, 0xa4, 0xf5, 0x8f, 0xf0, 0x28, 0x99, 0x24, 0x6b, - 0x0a, 0xba, 0x8d, 0xe0, 0x6d, 0xfa, 0x7d, 0xef, 0x7d, 0xef, 0x9b, 0x6f, 0x5e, 0x83, 0x08, 0x0f, - 0x35, 0x48, 0x36, 0xa6, 0x3c, 0xdc, 0x57, 0xc0, 0x62, 0xc9, 0xf5, 0x8c, 0x30, 0x96, 0x10, 0x26, - 0x42, 0x15, 0x07, 0x20, 0x49, 0xb2, 0x49, 0x0e, 0x63, 0x90, 0x33, 0x2f, 0x92, 0x42, 0x0b, 0x7c, - 0xe5, 0x0f, 0x0d, 0x1e, 0x63, 0x89, 0x57, 0x34, 0x78, 0xc9, 0x66, 0xa7, 0xed, 0x0b, 0x5f, 0x98, - 0x7a, 0x92, 0x9e, 0xb2, 0xd6, 0xce, 0x25, 0x5f, 0x08, 0x7f, 0x02, 0x84, 0x46, 0x9c, 0xd0, 0x30, - 0x14, 0x9a, 0x6a, 0x2e, 0x42, 0x95, 0xb3, 0xfd, 0x2a, 0x4e, 0x4e, 0x86, 0x98, 0x1e, 0xf7, 0xfd, - 0x1a, 0xba, 0xf8, 0x1c, 0xa6, 0x7a, 0x17, 0xe0, 0x21, 0x57, 0x5a, 0xf2, 0x61, 0x9c, 0x4a, 0x3e, - 0x52, 0x9a, 0x07, 0x54, 0x03, 0xbe, 0x8a, 0xce, 0xb1, 0x58, 0x4a, 0x08, 0xf5, 0x63, 0xe0, 0xfe, - 0x58, 0xdb, 0xd6, 0x86, 0xd5, 0xad, 0x0f, 0x96, 0x41, 0xec, 0x20, 0x34, 0xa1, 0xaa, 0x28, 0x59, - 0x33, 0x25, 0x25, 0x24, 0xe5, 0x43, 0x98, 0x16, 0x7c, 0x3d, 0xe3, 0x7f, 0x23, 0x78, 0x0b, 0x5d, - 0x18, 0x95, 0xa6, 0xef, 0x1f, 0x48, 0xca, 0xd2, 0x83, 0xdd, 0xd8, 0xb0, 0xba, 0x67, 0x07, 0xed, - 0x32, 0xb9, 0x9b, 0x73, 0xb8, 0x8d, 0x9a, 0x5a, 0x68, 0x3a, 0xb1, 0x9b, 0xa6, 0x28, 0xfb, 0x91, - 0x8e, 0xd2, 0x62, 0x4f, 0x8a, 0x84, 0x8f, 0x40, 0xda, 0x2d, 0x43, 0x95, 0x90, 0x8c, 0x7f, 0x90, - 0x87, 0x60, 0x9f, 0x29, 0xf8, 0x02, 0x71, 0xaf, 0xa3, 0x6b, 0x2f, 0xd2, 0xc7, 0x3a, 0x25, 0x94, - 0x01, 0x1c, 0xc6, 0xa0, 0xb4, 0xfb, 0xd6, 0x42, 0xdd, 0xd5, 0xb5, 0x2a, 0x12, 0xa1, 0x02, 0xfc, - 0x12, 0x35, 0x46, 0x54, 0x53, 0x93, 0xdf, 0x7a, 0xff, 0xbe, 0x57, 0x61, 0x09, 0xbc, 0xd3, 0x74, - 0x8d, 0x9a, 0xdb, 0x46, 0xd8, 0x38, 0xd8, 0xa3, 0x92, 0x06, 0xaa, 0x30, 0xf6, 0x06, 0x9d, 0x5f, - 0x42, 0x73, 0x0b, 0x4f, 0x50, 0x2b, 0x32, 0x48, 0x6e, 0xe2, 0x66, 0x25, 0x13, 0x99, 0xc8, 0x4e, - 0xe3, 0xe8, 0xdb, 0xe5, 0xda, 0x20, 0x17, 0xe8, 0x7f, 0xae, 0xa3, 0xa6, 0x19, 0x81, 0x7f, 0x5a, - 0xc8, 0xfe, 0x5b, 0x08, 0xf8, 0x69, 0xa5, 0x09, 0x15, 0xf3, 0xee, 0x3c, 0xfb, 0x4f, 0x6a, 0x59, - 0x1c, 0xee, 0xbd, 0x77, 0x5f, 0x7e, 0x7c, 0x5c, 0xbb, 0x83, 0xb7, 0x57, 0xff, 0x83, 0xd3, 0x55, - 0xed, 0x1d, 0x00, 0xf4, 0xca, 0x8b, 0x88, 0x3f, 0x59, 0x68, 0xbd, 0x94, 0x33, 0xde, 0xae, 0xee, - 0x6f, 0xe9, 0xbd, 0x3a, 0xb7, 0xff, 0xbd, 0x31, 0xbf, 0xc3, 0x2d, 0x73, 0x87, 0x1b, 0xb8, 0xbb, - 0xfa, 0x0e, 0xd9, 0xcb, 0xed, 0xbc, 0x3a, 0x9a, 0x3b, 0xd6, 0xf1, 0xdc, 0xb1, 0xbe, 0xcf, 0x1d, - 0xeb, 0xc3, 0xc2, 0xa9, 0x1d, 0x2f, 0x9c, 0xda, 0xd7, 0x85, 0x53, 0x7b, 0x7d, 0xd7, 0xe7, 0x7a, - 0x1c, 0x0f, 0x3d, 0x26, 0x02, 0xc2, 0x84, 0x0a, 0x84, 0x2a, 0x89, 0xf6, 0x4e, 0x44, 0x93, 0x3e, - 0x99, 0x2e, 0x2b, 0xeb, 0x59, 0x04, 0x6a, 0xd8, 0x32, 0x1f, 0x94, 0xad, 0x5f, 0x01, 0x00, 0x00, - 0xff, 0xff, 0xc4, 0xb4, 0x4e, 0xea, 0x10, 0x05, 0x00, 0x00, + 0x14, 0x6e, 0xfa, 0x4b, 0x9c, 0xc5, 0xcb, 0x58, 0x21, 0x54, 0x89, 0x4b, 0x15, 0xac, 0x4a, 0x33, + 0x6e, 0x7b, 0x58, 0x3d, 0x88, 0xb2, 0xea, 0xa2, 0xa0, 0xb2, 0x16, 0x41, 0xf0, 0xb2, 0x4e, 0xa7, + 0x6f, 0xd3, 0x81, 0x26, 0x93, 0x9d, 0x99, 0x84, 0xf6, 0x26, 0xfe, 0x01, 0x22, 0xf8, 0x9f, 0x78, + 0xf1, 0x5f, 0xd8, 0xe3, 0x82, 0x17, 0x4f, 0x22, 0xad, 0x7f, 0x84, 0x47, 0xc9, 0x24, 0x59, 0x53, + 0xd0, 0x6d, 0x04, 0x6f, 0xd3, 0xef, 0x7b, 0xef, 0x7b, 0xdf, 0x7c, 0xf3, 0x1a, 0x44, 0x78, 0xa0, + 0x41, 0xb2, 0x09, 0xe5, 0xc1, 0xbe, 0x02, 0x16, 0x49, 0xae, 0xe7, 0x84, 0xb1, 0x98, 0x30, 0x11, + 0xa8, 0xc8, 0x07, 0x49, 0xe2, 0x2d, 0x72, 0x18, 0x81, 0x9c, 0xbb, 0xa1, 0x14, 0x5a, 0xe0, 0x2b, + 0x7f, 0x68, 0x70, 0x19, 0x8b, 0xdd, 0xbc, 0xc1, 0x8d, 0xb7, 0xda, 0x2d, 0x4f, 0x78, 0xc2, 0xd4, + 0x93, 0xe4, 0x94, 0xb6, 0xb6, 0x2f, 0x79, 0x42, 0x78, 0x53, 0x20, 0x34, 0xe4, 0x84, 0x06, 0x81, + 0xd0, 0x54, 0x73, 0x11, 0xa8, 0x8c, 0xed, 0x97, 0x71, 0x72, 0x32, 0xc4, 0xf4, 0x74, 0xde, 0x57, + 0xd1, 0xc5, 0xe7, 0x30, 0xd3, 0xbb, 0x00, 0x0f, 0xb9, 0xd2, 0x92, 0x8f, 0xa2, 0x44, 0xf2, 0x91, + 0xd2, 0xdc, 0xa7, 0x1a, 0xf0, 0x55, 0x74, 0x8e, 0x45, 0x52, 0x42, 0xa0, 0x1f, 0x03, 0xf7, 0x26, + 0xda, 0xb6, 0x36, 0xad, 0x6e, 0x6d, 0xb8, 0x0a, 0x62, 0x07, 0xa1, 0x29, 0x55, 0x79, 0x49, 0xd5, + 0x94, 0x14, 0x90, 0x84, 0x0f, 0x60, 0x96, 0xf3, 0xb5, 0x94, 0xff, 0x8d, 0xe0, 0x01, 0xba, 0x30, + 0x2e, 0x4c, 0xdf, 0x3f, 0x90, 0x94, 0x25, 0x07, 0xbb, 0xbe, 0x69, 0x75, 0xcf, 0x0e, 0x5b, 0x45, + 0x72, 0x37, 0xe3, 0x70, 0x0b, 0x35, 0xb4, 0xd0, 0x74, 0x6a, 0x37, 0x4c, 0x51, 0xfa, 0x23, 0x19, + 0xa5, 0xc5, 0x9e, 0x14, 0x31, 0x1f, 0x83, 0xb4, 0x9b, 0x86, 0x2a, 0x20, 0x29, 0xff, 0x20, 0x0b, + 0xc1, 0x3e, 0x93, 0xf3, 0x39, 0xd2, 0xb9, 0x8e, 0xae, 0xbd, 0x48, 0x1e, 0xeb, 0x94, 0x50, 0x86, + 0x70, 0x18, 0x81, 0xd2, 0x9d, 0xb7, 0x16, 0xea, 0xae, 0xaf, 0x55, 0xa1, 0x08, 0x14, 0xe0, 0x97, + 0xa8, 0x3e, 0xa6, 0x9a, 0x9a, 0xfc, 0x36, 0xfa, 0xf7, 0xdd, 0x12, 0x4b, 0xe0, 0x9e, 0xa6, 0x6b, + 0xd4, 0x3a, 0x2d, 0x84, 0x8d, 0x83, 0x3d, 0x2a, 0xa9, 0xaf, 0x72, 0x63, 0x6f, 0xd0, 0xf9, 0x15, + 0x34, 0xb3, 0xf0, 0x04, 0x35, 0x43, 0x83, 0x64, 0x26, 0x6e, 0x96, 0x32, 0x91, 0x8a, 0xec, 0xd4, + 0x8f, 0xbe, 0x5d, 0xae, 0x0c, 0x33, 0x81, 0xfe, 0xe7, 0x1a, 0x6a, 0x98, 0x11, 0xf8, 0xa7, 0x85, + 0xec, 0xbf, 0x85, 0x80, 0x9f, 0x96, 0x9a, 0x50, 0x32, 0xef, 0xf6, 0xb3, 0xff, 0xa4, 0x96, 0xc6, + 0xd1, 0xb9, 0xf7, 0xee, 0xcb, 0x8f, 0x8f, 0xd5, 0x3b, 0x78, 0x7b, 0xfd, 0x3f, 0x38, 0x59, 0xd5, + 0xde, 0x01, 0x40, 0xaf, 0xb8, 0x88, 0xf8, 0x93, 0x85, 0x36, 0x0a, 0x39, 0xe3, 0xed, 0xf2, 0xfe, + 0x56, 0xde, 0xab, 0x7d, 0xfb, 0xdf, 0x1b, 0xb3, 0x3b, 0xdc, 0x32, 0x77, 0xb8, 0x81, 0xbb, 0xeb, + 0xef, 0x90, 0xbe, 0xdc, 0xce, 0xab, 0xa3, 0x85, 0x63, 0x1d, 0x2f, 0x1c, 0xeb, 0xfb, 0xc2, 0xb1, + 0x3e, 0x2c, 0x9d, 0xca, 0xf1, 0xd2, 0xa9, 0x7c, 0x5d, 0x3a, 0x95, 0xd7, 0x77, 0x3d, 0xae, 0x27, + 0xd1, 0xc8, 0x65, 0xc2, 0x27, 0x4c, 0x28, 0x5f, 0xa8, 0x82, 0x68, 0xef, 0x44, 0x34, 0x1e, 0x90, + 0xd9, 0xaa, 0xb2, 0x9e, 0x87, 0xa0, 0x46, 0x4d, 0xf3, 0x41, 0x19, 0xfc, 0x0a, 0x00, 0x00, 0xff, + 0xff, 0xcc, 0x57, 0x2e, 0xd6, 0x10, 0x05, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/x/ccv/provider/types/genesis.pb.go b/x/ccv/provider/types/genesis.pb.go index 4737530390..0e4e4f2cf3 100644 --- a/x/ccv/provider/types/genesis.pb.go +++ b/x/ccv/provider/types/genesis.pb.go @@ -339,58 +339,58 @@ var fileDescriptor_48411d9c7900d48e = []byte{ // 856 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xdd, 0x8e, 0xdb, 0x44, 0x14, 0x5e, 0xef, 0xa6, 0xdb, 0xcd, 0x6c, 0x77, 0x59, 0x86, 0x55, 0x70, 0xb3, 0x90, 0xae, 0x02, - 0x48, 0x91, 0x00, 0x1b, 0x07, 0x2e, 0xf8, 0xeb, 0x45, 0xd3, 0x4a, 0x10, 0x21, 0x44, 0x94, 0xfe, - 0x20, 0x95, 0x0b, 0x6b, 0x32, 0x1e, 0x25, 0x43, 0xec, 0x19, 0x6b, 0x66, 0x6c, 0x6a, 0x21, 0x24, - 0x2a, 0x5e, 0x80, 0xb7, 0xa2, 0x97, 0xbd, 0xe4, 0xaa, 0x42, 0xbb, 0x6f, 0xc0, 0x13, 0x20, 0x8f, - 0xc7, 0xae, 0xbd, 0x24, 0x90, 0xf4, 0x2e, 0x3e, 0xdf, 0x9c, 0xef, 0x3b, 0x67, 0xce, 0xcc, 0x37, + 0x48, 0x91, 0x00, 0x1b, 0xa7, 0x5c, 0xf0, 0xd7, 0x8b, 0xa6, 0x95, 0x20, 0x42, 0x88, 0x28, 0xfd, + 0x41, 0x2a, 0x17, 0xd6, 0x64, 0x3c, 0x4a, 0x86, 0xd8, 0x33, 0xd6, 0xcc, 0xd8, 0xd4, 0x42, 0x48, + 0x54, 0xbc, 0x00, 0x6f, 0x45, 0x2f, 0x7b, 0xc9, 0x55, 0x85, 0x76, 0xdf, 0x80, 0x27, 0x40, 0x1e, + 0x8f, 0x5d, 0x7b, 0x49, 0x20, 0xe1, 0x2e, 0x3e, 0xdf, 0x9c, 0xef, 0x3b, 0x67, 0xce, 0xcc, 0x37, 0x01, 0x1e, 0x65, 0x8a, 0x08, 0xbc, 0x40, 0x94, 0xf9, 0x92, 0xe0, 0x44, 0x50, 0x95, 0xb9, 0x18, 0xa7, 0x6e, 0x2c, 0x78, 0x4a, 0x03, 0x22, 0xdc, 0xd4, 0x73, 0xe7, 0x84, 0x11, 0x49, 0xa5, 0x13, 0x0b, 0xae, 0x38, 0x7c, 0x67, 0x45, 0x8a, 0x83, 0x71, 0xea, 0x94, 0x29, 0x4e, 0xea, 0x75, 0x4f, 0xe7, 0x7c, 0xce, 0xf5, 0x7a, 0x37, 0xff, 0x55, 0xa4, 0x76, 0xdf, 0x5d, 0xa7, 0x96, 0x7a, 0xae, - 0x61, 0x50, 0xbc, 0x3b, 0xdc, 0xa4, 0xa6, 0x4a, 0xec, 0x7f, 0x72, 0x30, 0x67, 0x32, 0x89, 0x8a, + 0x61, 0x50, 0xbc, 0x3b, 0xdc, 0xa4, 0xa6, 0x4a, 0xec, 0x3f, 0x72, 0x30, 0x67, 0x32, 0x89, 0x8a, 0x9c, 0xf2, 0xb7, 0xc9, 0xf1, 0x36, 0xc9, 0x69, 0xf4, 0xde, 0x7d, 0x4b, 0x11, 0x16, 0x10, 0x11, - 0x51, 0xa6, 0x5c, 0x2c, 0xb2, 0x58, 0x71, 0x77, 0x49, 0x32, 0x83, 0xf6, 0xff, 0x68, 0x83, 0x1b, - 0x5f, 0x15, 0xeb, 0xef, 0x2b, 0xa4, 0x08, 0x1c, 0x80, 0x93, 0x14, 0x85, 0x92, 0x28, 0x3f, 0x89, - 0x03, 0xa4, 0x88, 0x4f, 0x03, 0xdb, 0x3a, 0xb7, 0x06, 0xad, 0xe9, 0x71, 0x11, 0x7f, 0xa8, 0xc3, - 0xe3, 0x00, 0xfe, 0x0c, 0x5e, 0x2b, 0x55, 0x7d, 0x99, 0xe7, 0x4a, 0x7b, 0xf7, 0x7c, 0x6f, 0x70, - 0x38, 0x1c, 0x3a, 0x1b, 0x6c, 0xb7, 0x73, 0xd7, 0xe4, 0x6a, 0xd9, 0x51, 0xef, 0xd9, 0x8b, 0x5b, - 0x3b, 0x7f, 0xbf, 0xb8, 0xd5, 0xc9, 0x50, 0x14, 0x7e, 0xde, 0xbf, 0x42, 0xdc, 0x9f, 0x1e, 0xe3, - 0xfa, 0x72, 0x09, 0x7f, 0x00, 0x47, 0x09, 0x9b, 0x71, 0x16, 0x50, 0x36, 0xf7, 0x79, 0x2c, 0xed, - 0x3d, 0x2d, 0xfd, 0xd1, 0x46, 0xd2, 0x0f, 0xcb, 0xcc, 0xef, 0xe2, 0x51, 0x2b, 0x17, 0x9e, 0xde, - 0x48, 0x5e, 0x86, 0x24, 0x44, 0xe0, 0x34, 0x42, 0x2a, 0x11, 0xc4, 0x6f, 0x6a, 0xb4, 0xce, 0xad, - 0xc1, 0xe1, 0xd0, 0x5d, 0xab, 0x91, 0x7a, 0xce, 0xb7, 0x3a, 0x2f, 0xa8, 0x29, 0xc8, 0x29, 0x2c, - 0xc8, 0xea, 0x31, 0xf8, 0x0b, 0xe8, 0x5e, 0xdd, 0x66, 0x5f, 0x71, 0x7f, 0x41, 0xe8, 0x7c, 0xa1, - 0xec, 0x6b, 0xba, 0x99, 0x2f, 0x36, 0x6a, 0xe6, 0x51, 0x63, 0x2a, 0x0f, 0xf8, 0xd7, 0x9a, 0xc2, - 0xf4, 0xd5, 0x49, 0x57, 0xa2, 0xf0, 0x37, 0x0b, 0x9c, 0x55, 0x7b, 0x8c, 0x82, 0x80, 0x2a, 0xca, - 0x99, 0x1f, 0x0b, 0x1e, 0x73, 0x89, 0x42, 0x69, 0xef, 0xeb, 0x02, 0x6e, 0x6f, 0x35, 0xc8, 0x3b, - 0x86, 0x66, 0x62, 0x58, 0x4c, 0x09, 0x37, 0xf1, 0x1a, 0x5c, 0xc2, 0x5f, 0x2d, 0xd0, 0xad, 0xaa, - 0x10, 0x24, 0xe2, 0x29, 0x0a, 0x6b, 0x45, 0x5c, 0xd7, 0x45, 0x7c, 0xb9, 0x55, 0x11, 0xd3, 0x82, + 0x51, 0xa6, 0x5c, 0x2c, 0xb2, 0x58, 0x71, 0x77, 0x49, 0x32, 0x83, 0xf6, 0x7f, 0x6f, 0x83, 0x1b, + 0x5f, 0x16, 0xeb, 0x1f, 0x28, 0xa4, 0x08, 0x1c, 0x80, 0x93, 0x14, 0x85, 0x92, 0x28, 0x3f, 0x89, + 0x03, 0xa4, 0x88, 0x4f, 0x03, 0xdb, 0x3a, 0xb7, 0x06, 0xad, 0xe9, 0x71, 0x11, 0x7f, 0xa4, 0xc3, + 0xe3, 0x00, 0xfe, 0x04, 0x5e, 0x2b, 0x55, 0x7d, 0x99, 0xe7, 0x4a, 0x7b, 0xf7, 0x7c, 0x6f, 0x70, + 0x38, 0x1c, 0x3a, 0x1b, 0x6c, 0xb7, 0x73, 0xcf, 0xe4, 0x6a, 0xd9, 0x51, 0xef, 0xf9, 0xcb, 0x5b, + 0x3b, 0x7f, 0xbd, 0xbc, 0xd5, 0xc9, 0x50, 0x14, 0x7e, 0xd6, 0xbf, 0x42, 0xdc, 0x9f, 0x1e, 0xe3, + 0xfa, 0x72, 0x09, 0xbf, 0x07, 0x47, 0x09, 0x9b, 0x71, 0x16, 0x50, 0x36, 0xf7, 0x79, 0x2c, 0xed, + 0x3d, 0x2d, 0xfd, 0xd1, 0x46, 0xd2, 0x8f, 0xca, 0xcc, 0x6f, 0xe3, 0x51, 0x2b, 0x17, 0x9e, 0xde, + 0x48, 0x5e, 0x85, 0x24, 0x44, 0xe0, 0x34, 0x42, 0x2a, 0x11, 0xc4, 0x6f, 0x6a, 0xb4, 0xce, 0xad, + 0xc1, 0xe1, 0xd0, 0x5d, 0xab, 0x91, 0x7a, 0xce, 0x37, 0x3a, 0x2f, 0xa8, 0x29, 0xc8, 0x29, 0x2c, + 0xc8, 0xea, 0x31, 0xf8, 0x33, 0xe8, 0x5e, 0xdd, 0x66, 0x5f, 0x71, 0x7f, 0x41, 0xe8, 0x7c, 0xa1, + 0xec, 0x6b, 0xba, 0x99, 0xcf, 0x37, 0x6a, 0xe6, 0x71, 0x63, 0x2a, 0x0f, 0xf9, 0x57, 0x9a, 0xc2, + 0xf4, 0xd5, 0x49, 0x57, 0xa2, 0xf0, 0x57, 0x0b, 0x9c, 0x55, 0x7b, 0x8c, 0x82, 0x80, 0x2a, 0xca, + 0x99, 0x1f, 0x0b, 0x1e, 0x73, 0x89, 0x42, 0x69, 0xef, 0xeb, 0x02, 0xee, 0x6c, 0x35, 0xc8, 0xbb, + 0x86, 0x66, 0x62, 0x58, 0x4c, 0x09, 0x37, 0xf1, 0x1a, 0x5c, 0xc2, 0x5f, 0x2c, 0xd0, 0xad, 0xaa, + 0x10, 0x24, 0xe2, 0x29, 0x0a, 0x6b, 0x45, 0x5c, 0xd7, 0x45, 0x7c, 0xb1, 0x55, 0x11, 0xd3, 0x82, 0xe5, 0x4a, 0x0d, 0x36, 0x5e, 0x0d, 0x4b, 0x38, 0x06, 0xfb, 0x31, 0x12, 0x28, 0x92, 0xf6, 0x81, 0x1e, 0xee, 0xfb, 0x1b, 0xa9, 0x4d, 0x74, 0x8a, 0x21, 0x37, 0x04, 0xba, 0x9b, 0x14, 0x85, 0x34, - 0x40, 0x8a, 0x0b, 0xbf, 0xea, 0x2b, 0x4e, 0x66, 0xf9, 0x7d, 0xb3, 0xdb, 0x5b, 0x74, 0xf3, 0xa8, - 0xa4, 0x29, 0xdb, 0x9a, 0x24, 0xb3, 0x6f, 0x48, 0x56, 0x76, 0x93, 0xae, 0x80, 0x73, 0x0d, 0xf8, - 0xd4, 0x02, 0x67, 0x15, 0x28, 0xfd, 0x59, 0xe6, 0xd7, 0x87, 0x2c, 0x6c, 0xf0, 0x2a, 0x35, 0x8c, - 0xb2, 0xda, 0x84, 0xc5, 0xbf, 0x6a, 0x90, 0x4d, 0x1c, 0xa6, 0xe0, 0xcd, 0x86, 0xa8, 0xcc, 0xcf, - 0x75, 0x2c, 0x12, 0x46, 0xec, 0x43, 0x2d, 0xff, 0xd9, 0xb6, 0xa7, 0x4a, 0xc8, 0x07, 0x7c, 0x92, - 0x13, 0x18, 0xed, 0x53, 0xbc, 0x02, 0xeb, 0x3f, 0x6d, 0x81, 0xa3, 0x86, 0xa7, 0xc0, 0x9b, 0xe0, - 0xa0, 0x10, 0x31, 0x16, 0xd6, 0x9e, 0x5e, 0xd7, 0xdf, 0xe3, 0x00, 0xbe, 0x0d, 0x00, 0x5e, 0x20, - 0xc6, 0x48, 0x98, 0x83, 0xbb, 0x1a, 0x6c, 0x9b, 0xc8, 0x38, 0x80, 0x67, 0xa0, 0x8d, 0x43, 0x4a, - 0x98, 0xca, 0xd1, 0x3d, 0x8d, 0x1e, 0x14, 0x81, 0x71, 0x00, 0xdf, 0x03, 0xc7, 0x94, 0x51, 0x45, - 0x51, 0x58, 0x5e, 0xd7, 0x96, 0xf6, 0xc7, 0x23, 0x13, 0x35, 0x57, 0x6c, 0x06, 0x4e, 0xaa, 0x7d, - 0x30, 0x8e, 0x6c, 0x5f, 0xd3, 0x67, 0xcc, 0x5b, 0xbb, 0x01, 0x95, 0xdb, 0xa7, 0x9e, 0x53, 0x77, - 0x65, 0xd3, 0x78, 0xe5, 0xb7, 0x06, 0x83, 0x0a, 0x74, 0x62, 0x52, 0xf8, 0x93, 0x71, 0x93, 0xbc, - 0x87, 0x39, 0x29, 0x2f, 0xf0, 0xa7, 0xff, 0x65, 0x55, 0xd5, 0x80, 0xef, 0x13, 0x75, 0x57, 0xa7, - 0x4d, 0x10, 0x5e, 0x12, 0x75, 0x0f, 0x29, 0x54, 0xee, 0xb4, 0x61, 0x2f, 0x3c, 0xa6, 0x58, 0x24, - 0xe1, 0x07, 0x00, 0xca, 0x10, 0xc9, 0x85, 0x1f, 0xf0, 0x9f, 0x98, 0xa2, 0x11, 0xf1, 0x11, 0x5e, - 0xea, 0xdb, 0xda, 0x9e, 0x9e, 0x68, 0xe4, 0x9e, 0x01, 0xee, 0xe0, 0x25, 0xfc, 0x11, 0xbc, 0xd1, - 0x70, 0x51, 0x9f, 0xb2, 0x80, 0x3c, 0xb1, 0x0f, 0x74, 0x81, 0x9f, 0x6c, 0x76, 0x14, 0x25, 0xae, - 0x9b, 0xa7, 0x29, 0xee, 0xf5, 0xba, 0x67, 0x8f, 0x73, 0xd2, 0xfe, 0x63, 0xd0, 0x59, 0x6d, 0x87, - 0x5b, 0x3c, 0x6b, 0x1d, 0xb0, 0x6f, 0xc6, 0xba, 0xab, 0x71, 0xf3, 0x35, 0xfa, 0xfe, 0xd9, 0x45, - 0xcf, 0x7a, 0x7e, 0xd1, 0xb3, 0xfe, 0xba, 0xe8, 0x59, 0xbf, 0x5f, 0xf6, 0x76, 0x9e, 0x5f, 0xf6, - 0x76, 0xfe, 0xbc, 0xec, 0xed, 0x3c, 0xbe, 0x3d, 0xa7, 0x6a, 0x91, 0xcc, 0x1c, 0xcc, 0x23, 0x17, - 0x73, 0x19, 0x71, 0xe9, 0xbe, 0xec, 0xea, 0xc3, 0xea, 0x99, 0x4e, 0x87, 0xee, 0x93, 0xe6, 0x7f, - 0x02, 0x95, 0xc5, 0x44, 0xce, 0xf6, 0xf5, 0x4b, 0xfc, 0xf1, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, - 0xae, 0x7b, 0x97, 0x91, 0xd8, 0x08, 0x00, 0x00, + 0x40, 0x8a, 0x0b, 0xbf, 0xea, 0x2b, 0x4e, 0x66, 0xf9, 0x7d, 0xb3, 0xdb, 0x5b, 0x74, 0xf3, 0xb8, + 0xa4, 0x29, 0xdb, 0x9a, 0x24, 0xb3, 0xaf, 0x49, 0x56, 0x76, 0x93, 0xae, 0x80, 0x73, 0x0d, 0xf8, + 0xcc, 0x02, 0x67, 0x15, 0x28, 0xfd, 0x59, 0xe6, 0xd7, 0x87, 0x2c, 0x6c, 0xf0, 0x7f, 0x6a, 0x18, + 0x65, 0xb5, 0x09, 0x8b, 0x7f, 0xd4, 0x20, 0x9b, 0x38, 0x4c, 0xc1, 0x9b, 0x0d, 0x51, 0x99, 0x9f, + 0xeb, 0x58, 0x24, 0x8c, 0xd8, 0x87, 0x5a, 0xfe, 0xd3, 0x6d, 0x4f, 0x95, 0x90, 0x0f, 0xf9, 0x24, + 0x27, 0x30, 0xda, 0xa7, 0x78, 0x05, 0xd6, 0x7f, 0xd6, 0x02, 0x47, 0x0d, 0x4f, 0x81, 0x37, 0xc1, + 0x41, 0x21, 0x62, 0x2c, 0xac, 0x3d, 0xbd, 0xae, 0xbf, 0xc7, 0x01, 0x7c, 0x1b, 0x00, 0xbc, 0x40, + 0x8c, 0x91, 0x30, 0x07, 0x77, 0x35, 0xd8, 0x36, 0x91, 0x71, 0x00, 0xcf, 0x40, 0x1b, 0x87, 0x94, + 0x30, 0x95, 0xa3, 0x7b, 0x1a, 0x3d, 0x28, 0x02, 0xe3, 0x00, 0xbe, 0x07, 0x8e, 0x29, 0xa3, 0x8a, + 0xa2, 0xb0, 0xbc, 0xae, 0x2d, 0xed, 0x8f, 0x47, 0x26, 0x6a, 0xae, 0xd8, 0x0c, 0x9c, 0x54, 0xfb, + 0x60, 0x1c, 0xd9, 0xbe, 0xa6, 0xcf, 0x98, 0xb7, 0x76, 0x03, 0x2a, 0xb7, 0x4f, 0x3d, 0xa7, 0xee, + 0xca, 0xa6, 0xf1, 0xca, 0x6f, 0x0d, 0x06, 0x15, 0xe8, 0xc4, 0xa4, 0xf0, 0x27, 0xe3, 0x26, 0x79, + 0x0f, 0x73, 0x52, 0x5e, 0xe0, 0x4f, 0xfe, 0xcd, 0xaa, 0xaa, 0x01, 0x3f, 0x20, 0xea, 0x9e, 0x4e, + 0x9b, 0x20, 0xbc, 0x24, 0xea, 0x3e, 0x52, 0xa8, 0xdc, 0x69, 0xc3, 0x5e, 0x78, 0x4c, 0xb1, 0x48, + 0xc2, 0x0f, 0x00, 0x94, 0x21, 0x92, 0x0b, 0x3f, 0xe0, 0x3f, 0x32, 0x45, 0x23, 0xe2, 0x23, 0xbc, + 0xd4, 0xb7, 0xb5, 0x3d, 0x3d, 0xd1, 0xc8, 0x7d, 0x03, 0xdc, 0xc5, 0x4b, 0xf8, 0x03, 0x78, 0xa3, + 0xe1, 0xa2, 0x3e, 0x65, 0x01, 0x79, 0x6a, 0x1f, 0xe8, 0x02, 0x3f, 0xde, 0xec, 0x28, 0x4a, 0x5c, + 0x37, 0x4f, 0x53, 0xdc, 0xeb, 0x75, 0xcf, 0x1e, 0xe7, 0xa4, 0xfd, 0x27, 0xa0, 0xb3, 0xda, 0x0e, + 0xb7, 0x78, 0xd6, 0x3a, 0x60, 0xdf, 0x8c, 0x75, 0x57, 0xe3, 0xe6, 0x6b, 0xf4, 0xdd, 0xf3, 0x8b, + 0x9e, 0xf5, 0xe2, 0xa2, 0x67, 0xfd, 0x79, 0xd1, 0xb3, 0x7e, 0xbb, 0xec, 0xed, 0xbc, 0xb8, 0xec, + 0xed, 0xfc, 0x71, 0xd9, 0xdb, 0x79, 0x72, 0x67, 0x4e, 0xd5, 0x22, 0x99, 0x39, 0x98, 0x47, 0x2e, + 0xe6, 0x32, 0xe2, 0xd2, 0x7d, 0xd5, 0xd5, 0x87, 0xd5, 0x33, 0x9d, 0xde, 0x76, 0x9f, 0x36, 0xff, + 0x13, 0xa8, 0x2c, 0x26, 0x72, 0xb6, 0xaf, 0x5f, 0xe2, 0xdb, 0x7f, 0x07, 0x00, 0x00, 0xff, 0xff, + 0xa6, 0x98, 0xf7, 0xad, 0xd8, 0x08, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { diff --git a/x/ccv/provider/types/provider.pb.go b/x/ccv/provider/types/provider.pb.go index 49c2bb7cda..e651a5415c 100644 --- a/x/ccv/provider/types/provider.pb.go +++ b/x/ccv/provider/types/provider.pb.go @@ -1249,104 +1249,104 @@ var fileDescriptor_f22ec409a72b7b72 = []byte{ // 1598 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0x4b, 0x73, 0xdc, 0xc6, 0x11, 0x26, 0xb8, 0x7c, 0xed, 0x2c, 0x1f, 0x12, 0x44, 0x59, 0x4b, 0x85, 0x59, 0xae, 0xe0, 0xc4, - 0xc5, 0x94, 0xcb, 0xd8, 0x90, 0xbe, 0xa4, 0x54, 0x71, 0xb9, 0xc8, 0x95, 0x65, 0xd1, 0x8c, 0xad, + 0xc5, 0x94, 0xcb, 0xd8, 0x90, 0xba, 0xa4, 0x54, 0x71, 0xb9, 0xc8, 0x95, 0x65, 0xd1, 0x8c, 0xad, 0x35, 0xc8, 0x50, 0x95, 0xe4, 0x80, 0x1a, 0x0c, 0x5a, 0xbb, 0x53, 0x04, 0x30, 0xd0, 0xcc, 0x00, 0xd2, 0x5e, 0x72, 0xce, 0xd1, 0xb9, 0xb9, 0x92, 0x8b, 0xf3, 0x0b, 0xf2, 0x37, 0x7c, 0xf4, 0x31, - 0x27, 0x3b, 0x45, 0x1d, 0x72, 0xc8, 0x9f, 0x48, 0xcd, 0xe0, 0xcd, 0x87, 0xb2, 0xaa, 0xc4, 0x37, + 0x27, 0x3b, 0x45, 0x1d, 0x72, 0xc8, 0x9f, 0x48, 0xcd, 0xe0, 0xcd, 0x87, 0xb3, 0xaa, 0xc4, 0x37, 0xcc, 0x4c, 0xf7, 0xd7, 0xdd, 0xd3, 0xdd, 0x5f, 0x0f, 0xd0, 0x3e, 0x8d, 0x24, 0x70, 0x32, 0xc1, 0x34, 0x72, 0x05, 0x90, 0x84, 0x53, 0x39, 0x1d, 0x10, 0x92, 0x0e, 0x62, 0xce, 0x52, 0xea, 0x03, 0x1f, 0xa4, 0x7b, 0xe5, 0xb7, 0x1d, 0x73, 0x26, 0x99, 0xf9, 0xee, 0x35, 0x3a, 0x36, 0x21, 0xa9, 0x5d, 0xca, 0xa5, 0x7b, 0xf7, 0x37, 0xc7, 0x6c, 0xcc, 0xb4, 0xfc, 0x40, 0x7d, 0x65, 0xaa, 0xf7, - 0x77, 0xc6, 0x8c, 0x8d, 0x03, 0x18, 0xe8, 0x95, 0x97, 0x3c, 0x1f, 0x48, 0x1a, 0x82, 0x90, 0x38, + 0x77, 0xc6, 0x8c, 0x8d, 0x03, 0x18, 0xe8, 0x95, 0x97, 0xbc, 0x18, 0x48, 0x1a, 0x82, 0x90, 0x38, 0x8c, 0x73, 0x81, 0xde, 0x65, 0x01, 0x3f, 0xe1, 0x58, 0x52, 0x16, 0x15, 0x00, 0xd4, 0x23, 0x03, 0xc2, 0x38, 0x0c, 0x48, 0x40, 0x21, 0x92, 0xca, 0xbd, 0xec, 0x2b, 0x17, 0x18, 0x28, 0x81, 0x80, 0x8e, 0x27, 0x32, 0xdb, 0x16, 0x03, 0x09, 0x91, 0x0f, 0x3c, 0xa4, 0x99, 0x70, 0xb5, 0xca, 0x15, 0xb6, 0x6b, 0xe7, 0x84, 0x4f, 0x63, 0xc9, 0x06, 0xe7, 0x30, 0x15, 0xf9, 0xe9, 0x7b, 0x84, 0x89, 0x90, 0x89, 0x01, 0xa8, 0xc0, 0x22, 0x02, 0x83, 0x74, 0xcf, 0x03, 0x89, 0xf7, 0xca, 0x8d, 0xc2, - 0xef, 0x5c, 0xce, 0xc3, 0xa2, 0x92, 0x21, 0x8c, 0xe6, 0x7e, 0x5b, 0x3f, 0x2c, 0xa1, 0xee, 0x90, + 0xef, 0x5c, 0xce, 0xc3, 0xa2, 0x92, 0x21, 0x8c, 0xe6, 0x7e, 0x5b, 0xdf, 0x2f, 0xa1, 0xee, 0x90, 0x45, 0x22, 0x09, 0x81, 0x1f, 0xf8, 0x3e, 0x55, 0x21, 0x8d, 0x38, 0x8b, 0x99, 0xc0, 0x81, 0xb9, 0x89, 0x16, 0x25, 0x95, 0x01, 0x74, 0x8d, 0xbe, 0xb1, 0xdb, 0x76, 0xb2, 0x85, 0xd9, 0x47, 0x1d, 0x1f, 0x04, 0xe1, 0x34, 0x56, 0xc2, 0xdd, 0x79, 0x7d, 0x56, 0xdf, 0x32, 0xb7, 0xd0, 0x4a, 0x96, - 0x05, 0xea, 0x77, 0x5b, 0xfa, 0x78, 0x59, 0xaf, 0x8f, 0x7c, 0xf3, 0x53, 0xb4, 0x4e, 0x23, 0x2a, + 0x05, 0xea, 0x77, 0x5b, 0xfa, 0x78, 0x59, 0xaf, 0x8f, 0x7c, 0xf3, 0x13, 0xb4, 0x4e, 0x23, 0x2a, 0x29, 0x0e, 0xdc, 0x09, 0xa8, 0xdb, 0xe8, 0x2e, 0xf4, 0x8d, 0xdd, 0xce, 0xfe, 0x7d, 0x9b, 0x7a, - 0xc4, 0x56, 0x17, 0x68, 0xe7, 0xd7, 0x96, 0xee, 0xd9, 0x4f, 0xb4, 0xc4, 0xe1, 0xc2, 0xb7, 0xdf, - 0xef, 0xcc, 0x39, 0x6b, 0xb9, 0x5e, 0xb6, 0x69, 0x3e, 0x40, 0xab, 0x63, 0x88, 0x40, 0x50, 0xe1, - 0x4e, 0xb0, 0x98, 0x74, 0x17, 0xfb, 0xc6, 0xee, 0xaa, 0xd3, 0xc9, 0xf7, 0x9e, 0x60, 0x31, 0x31, + 0xc4, 0x56, 0x17, 0x68, 0xe7, 0xd7, 0x96, 0xee, 0xd9, 0x4f, 0xb5, 0xc4, 0xe1, 0xc2, 0x37, 0xdf, + 0xed, 0xcc, 0x39, 0x6b, 0xb9, 0x5e, 0xb6, 0x69, 0x3e, 0x40, 0xab, 0x63, 0x88, 0x40, 0x50, 0xe1, + 0x4e, 0xb0, 0x98, 0x74, 0x17, 0xfb, 0xc6, 0xee, 0xaa, 0xd3, 0xc9, 0xf7, 0x9e, 0x62, 0x31, 0x31, 0x77, 0x50, 0xc7, 0xa3, 0x11, 0xe6, 0xd3, 0x4c, 0x62, 0x49, 0x4b, 0xa0, 0x6c, 0x4b, 0x0b, 0x0c, - 0x11, 0x12, 0x31, 0x7e, 0x19, 0xb9, 0x2a, 0xdb, 0xdd, 0xe5, 0xdc, 0x91, 0x2c, 0xd3, 0x76, 0x91, - 0x69, 0xfb, 0xb4, 0x28, 0x85, 0xc3, 0x15, 0xe5, 0xc8, 0x57, 0x3f, 0xec, 0x18, 0x4e, 0x5b, 0xeb, - 0xa9, 0x13, 0xf3, 0x0b, 0x74, 0x2b, 0x89, 0x3c, 0x16, 0xf9, 0x34, 0x1a, 0xbb, 0x31, 0x70, 0xca, - 0xfc, 0xee, 0x8a, 0x86, 0xda, 0xba, 0x02, 0xf5, 0x28, 0x2f, 0x9a, 0x0c, 0xe9, 0x6b, 0x85, 0xb4, - 0x51, 0x2a, 0x8f, 0xb4, 0xae, 0xf9, 0x25, 0x32, 0x09, 0x49, 0xb5, 0x4b, 0x2c, 0x91, 0x05, 0x62, + 0x11, 0x12, 0x31, 0x7e, 0x15, 0xb9, 0x2a, 0xdb, 0xdd, 0xe5, 0xdc, 0x91, 0x2c, 0xd3, 0x76, 0x91, + 0x69, 0xfb, 0xb4, 0x28, 0x85, 0xc3, 0x15, 0xe5, 0xc8, 0x97, 0xdf, 0xef, 0x18, 0x4e, 0x5b, 0xeb, + 0xa9, 0x13, 0xf3, 0x73, 0x74, 0x2b, 0x89, 0x3c, 0x16, 0xf9, 0x34, 0x1a, 0xbb, 0x31, 0x70, 0xca, + 0xfc, 0xee, 0x8a, 0x86, 0xda, 0xba, 0x02, 0xf5, 0x38, 0x2f, 0x9a, 0x0c, 0xe9, 0x2b, 0x85, 0xb4, + 0x51, 0x2a, 0x8f, 0xb4, 0xae, 0xf9, 0x05, 0x32, 0x09, 0x49, 0xb5, 0x4b, 0x2c, 0x91, 0x05, 0x62, 0x7b, 0x76, 0xc4, 0x5b, 0x84, 0xa4, 0xa7, 0x99, 0x76, 0x0e, 0xf9, 0x07, 0x74, 0x4f, 0x72, 0x1c, - 0x89, 0xe7, 0xc0, 0x2f, 0xe3, 0xa2, 0xd9, 0x71, 0xef, 0x16, 0x18, 0x4d, 0xf0, 0x27, 0xa8, 0x4f, - 0xf2, 0x02, 0x72, 0x39, 0xf8, 0x54, 0x48, 0x4e, 0xbd, 0x44, 0xe9, 0xba, 0xcf, 0x39, 0x26, 0xba, - 0x46, 0x3a, 0xba, 0x08, 0x7a, 0x85, 0x9c, 0xd3, 0x10, 0x7b, 0x9c, 0x4b, 0x99, 0x4f, 0xd1, 0xcf, + 0x89, 0x17, 0xc0, 0x2f, 0xe3, 0xa2, 0xd9, 0x71, 0xef, 0x16, 0x18, 0x4d, 0xf0, 0xa7, 0xa8, 0x4f, + 0xf2, 0x02, 0x72, 0x39, 0xf8, 0x54, 0x48, 0x4e, 0xbd, 0x44, 0xe9, 0xba, 0x2f, 0x38, 0x26, 0xba, + 0x46, 0x3a, 0xba, 0x08, 0x7a, 0x85, 0x9c, 0xd3, 0x10, 0x7b, 0x92, 0x4b, 0x99, 0xcf, 0xd0, 0xcf, 0xbc, 0x80, 0x91, 0x73, 0xa1, 0x9c, 0x73, 0x1b, 0x48, 0xda, 0x74, 0x48, 0x85, 0x50, 0x68, 0xab, - 0x7d, 0x63, 0xb7, 0xe5, 0x3c, 0xc8, 0x64, 0x47, 0xc0, 0x1f, 0xd5, 0x24, 0x4f, 0x6b, 0x82, 0xe6, + 0x7d, 0x63, 0xb7, 0xe5, 0x3c, 0xc8, 0x64, 0x47, 0xc0, 0x1f, 0xd7, 0x24, 0x4f, 0x6b, 0x82, 0xe6, 0x07, 0xc8, 0x9c, 0x50, 0x21, 0x19, 0xa7, 0x04, 0x07, 0x2e, 0x44, 0x92, 0x53, 0x10, 0xdd, 0x35, - 0xad, 0x7e, 0xbb, 0x3a, 0xf9, 0x24, 0x3b, 0x30, 0x3f, 0x43, 0x0f, 0x6e, 0x34, 0xea, 0x92, 0x09, - 0x8e, 0x22, 0x08, 0xba, 0xeb, 0x3a, 0x94, 0x1d, 0xff, 0x06, 0x9b, 0xc3, 0x4c, 0xec, 0xe1, 0xca, - 0x9f, 0xbe, 0xd9, 0x99, 0xfb, 0xfa, 0x9b, 0x9d, 0x39, 0xeb, 0xef, 0x06, 0xba, 0x37, 0x2c, 0x03, + 0xad, 0x7e, 0xbb, 0x3a, 0xf9, 0x38, 0x3b, 0x30, 0x3f, 0x45, 0x0f, 0x6e, 0x34, 0xea, 0x92, 0x09, + 0x8e, 0x22, 0x08, 0xba, 0xeb, 0x3a, 0x94, 0x1d, 0xff, 0x06, 0x9b, 0xc3, 0x4c, 0xec, 0xd1, 0xca, + 0x9f, 0xbe, 0xde, 0x99, 0xfb, 0xea, 0xeb, 0x9d, 0x39, 0xeb, 0xef, 0x06, 0xba, 0x37, 0x2c, 0x03, 0x0f, 0x59, 0x8a, 0x83, 0x1f, 0xb3, 0xc1, 0x0e, 0x50, 0x5b, 0x48, 0x16, 0x67, 0x25, 0xbd, 0xf0, - 0x16, 0x25, 0xbd, 0xa2, 0xd4, 0xd4, 0x81, 0xf5, 0x57, 0x03, 0x6d, 0x7e, 0xf2, 0x22, 0xa1, 0x29, + 0x16, 0x25, 0xbd, 0xa2, 0xd4, 0xd4, 0x81, 0xf5, 0x57, 0x03, 0x6d, 0x7e, 0xfc, 0x32, 0xa1, 0x29, 0x23, 0xf8, 0xff, 0xc2, 0x07, 0xc7, 0x68, 0x0d, 0x6a, 0x78, 0xa2, 0xdb, 0xea, 0xb7, 0x76, 0x3b, 0xfb, 0x3f, 0xb7, 0x33, 0x72, 0xb2, 0x4b, 0xce, 0xca, 0x09, 0xca, 0xae, 0x5b, 0x77, 0x9a, 0xba, - 0xd6, 0xbf, 0x0d, 0x74, 0xeb, 0xd3, 0x80, 0x79, 0x38, 0x38, 0x09, 0xb0, 0x98, 0xa8, 0xe4, 0x4d, - 0x55, 0xd4, 0x1c, 0xf2, 0xae, 0xd1, 0xde, 0xcd, 0x1c, 0xb5, 0x52, 0xd3, 0x7d, 0xfc, 0x31, 0xba, - 0x5d, 0xd6, 0x71, 0x79, 0xb9, 0x3a, 0x98, 0xc3, 0x3b, 0x17, 0xdf, 0xef, 0x6c, 0x14, 0x39, 0x1c, - 0xea, 0x8b, 0x7e, 0xe4, 0x6c, 0x90, 0xc6, 0x86, 0x6f, 0xf6, 0x50, 0x87, 0x7a, 0xc4, 0x15, 0xf0, - 0xc2, 0x8d, 0x92, 0x50, 0xe7, 0x65, 0xc1, 0x69, 0x53, 0x8f, 0x9c, 0xc0, 0x8b, 0x2f, 0x92, 0xd0, - 0xfc, 0x10, 0xbd, 0x53, 0x0c, 0x22, 0x37, 0xc5, 0x81, 0xab, 0xf4, 0x5d, 0xec, 0xfb, 0x5c, 0xa7, - 0x69, 0xd5, 0xb9, 0x53, 0x9c, 0x9e, 0xe1, 0x40, 0x19, 0x3b, 0xf0, 0x7d, 0x6e, 0xfd, 0x6b, 0x11, - 0x2d, 0x8d, 0x30, 0xc7, 0xa1, 0x30, 0x4f, 0xd1, 0x86, 0x84, 0x30, 0x0e, 0xb0, 0x04, 0x37, 0xe3, - 0xc8, 0x3c, 0xd2, 0xf7, 0x35, 0x77, 0xd6, 0x67, 0x8b, 0x5d, 0x9b, 0x26, 0xe9, 0x9e, 0x3d, 0xd4, - 0xbb, 0x27, 0x12, 0x4b, 0x70, 0xd6, 0x0b, 0x8c, 0x6c, 0xd3, 0xfc, 0x15, 0xea, 0x4a, 0x9e, 0x08, - 0x59, 0xb1, 0x57, 0xd5, 0xb6, 0x59, 0x2a, 0xdf, 0x29, 0xce, 0xb3, 0x86, 0x2f, 0xdb, 0xf5, 0x7a, - 0xa2, 0x6a, 0xfd, 0x2f, 0x44, 0x75, 0x82, 0xee, 0x28, 0x96, 0xbf, 0x8c, 0xb9, 0x30, 0x3b, 0xe6, - 0x6d, 0xa5, 0xdf, 0x04, 0xfd, 0x12, 0x99, 0xa9, 0x20, 0x97, 0x31, 0x17, 0xdf, 0xc2, 0xcf, 0x54, - 0x90, 0x26, 0xa4, 0x8f, 0xb6, 0x85, 0x2a, 0x3e, 0x37, 0x04, 0xa9, 0x69, 0x2f, 0x0e, 0x20, 0xa2, - 0x62, 0x52, 0x80, 0x2f, 0xcd, 0x0e, 0xbe, 0xa5, 0x81, 0x3e, 0x57, 0x38, 0x4e, 0x01, 0x93, 0x5b, - 0x19, 0xa2, 0xde, 0xf5, 0x56, 0xca, 0x04, 0x2d, 0xeb, 0x04, 0xfd, 0xe4, 0x1a, 0x88, 0x32, 0x4b, - 0xfb, 0xe8, 0x6e, 0x88, 0x5f, 0xb9, 0x72, 0xc2, 0x99, 0x94, 0x01, 0xf8, 0x6e, 0x8c, 0xc9, 0x39, - 0x48, 0xa1, 0x67, 0x54, 0xcb, 0xb9, 0x13, 0xe2, 0x57, 0xa7, 0xc5, 0xd9, 0x28, 0x3b, 0x32, 0x05, - 0x7a, 0xaf, 0x46, 0xe9, 0x2f, 0x31, 0xf7, 0x5d, 0x1f, 0x22, 0x16, 0xba, 0x1c, 0xc6, 0x8a, 0xf7, - 0x70, 0xc6, 0xee, 0x00, 0xe5, 0x58, 0xca, 0x1b, 0x59, 0xbd, 0x32, 0xca, 0x26, 0x1e, 0x32, 0x1a, - 0xe5, 0xb3, 0xdb, 0xaa, 0x98, 0x5f, 0xa1, 0x3d, 0x52, 0x60, 0x4e, 0x0d, 0xeb, 0x31, 0x80, 0xe5, - 0xa1, 0xdb, 0x4f, 0x70, 0xe4, 0x8b, 0x09, 0x3e, 0x87, 0xcf, 0x41, 0x62, 0x1f, 0x4b, 0xdc, 0xe8, - 0x99, 0xe7, 0x00, 0x6e, 0xcc, 0x58, 0x90, 0xf5, 0x4c, 0x46, 0x41, 0x65, 0xcf, 0x3c, 0x06, 0x18, - 0x31, 0x16, 0xa8, 0x9e, 0x31, 0xbb, 0x68, 0x39, 0x05, 0x2e, 0xaa, 0x0a, 0x2e, 0x96, 0xd6, 0x2f, - 0x50, 0x5b, 0x93, 0xc6, 0x01, 0x39, 0x17, 0xe6, 0x36, 0x6a, 0x2b, 0x24, 0x10, 0x02, 0x44, 0xd7, - 0xe8, 0xb7, 0x76, 0xdb, 0x4e, 0xb5, 0x61, 0x49, 0xb4, 0x75, 0xd3, 0xbb, 0x48, 0x98, 0xcf, 0xd0, - 0x72, 0x0c, 0x7a, 0x68, 0x6b, 0xc5, 0xce, 0xfe, 0x47, 0xf6, 0x0c, 0x6f, 0x4f, 0xfb, 0x26, 0x40, - 0xa7, 0x40, 0xb3, 0x78, 0xf5, 0x1a, 0xbb, 0x34, 0x2b, 0x84, 0x79, 0x76, 0xd9, 0xe8, 0xaf, 0xdf, - 0xca, 0xe8, 0x25, 0xbc, 0xca, 0xe6, 0xfb, 0xa8, 0x73, 0x90, 0x85, 0xfd, 0x1b, 0x2a, 0xe4, 0xd5, - 0x6b, 0x59, 0xad, 0x5f, 0xcb, 0x67, 0x68, 0x3d, 0x1f, 0x71, 0xa7, 0x4c, 0x13, 0x9f, 0xf9, 0x53, - 0x84, 0xf2, 0xd9, 0xa8, 0x08, 0x33, 0x4b, 0x4b, 0x3b, 0xdf, 0x39, 0xf2, 0x1b, 0xa3, 0x6a, 0xbe, - 0x31, 0xaa, 0x2c, 0x07, 0x6d, 0x9c, 0x09, 0xf2, 0xdb, 0xe2, 0xfd, 0xf3, 0x34, 0x16, 0xe6, 0x5d, - 0xb4, 0xa4, 0x7a, 0x35, 0x07, 0x5a, 0x70, 0x16, 0x53, 0x41, 0x8e, 0x7c, 0x73, 0xb7, 0xfe, 0xc6, - 0x62, 0xb1, 0x4b, 0x7d, 0xd1, 0x9d, 0xef, 0xb7, 0x76, 0x17, 0x9c, 0xf5, 0xa4, 0x52, 0x3f, 0xf2, - 0x85, 0xf5, 0x3b, 0xd4, 0xa9, 0x01, 0x9a, 0xeb, 0x68, 0xbe, 0xc4, 0x9a, 0xa7, 0xbe, 0xf9, 0x10, - 0x6d, 0x55, 0x40, 0x4d, 0xba, 0xcf, 0x10, 0xdb, 0xce, 0xbd, 0x52, 0xa0, 0xc1, 0xf8, 0xc2, 0x7a, - 0x8a, 0x36, 0x8f, 0x2a, 0x72, 0x29, 0x87, 0x49, 0x23, 0x42, 0xa3, 0x39, 0x8c, 0xb7, 0x51, 0xbb, - 0xfc, 0x91, 0xd0, 0xd1, 0x2f, 0x38, 0xd5, 0x86, 0x15, 0xa2, 0x5b, 0x67, 0x82, 0x9c, 0x40, 0xe4, - 0x57, 0x60, 0x37, 0x5c, 0xc0, 0xe1, 0x65, 0xa0, 0x99, 0x1f, 0xaa, 0x95, 0xb9, 0x3f, 0x1b, 0xa8, - 0x7b, 0x0c, 0xd3, 0x03, 0x21, 0xe8, 0x38, 0x0a, 0x21, 0x92, 0x8a, 0x2c, 0x30, 0x01, 0xf5, 0x69, - 0xbe, 0x8b, 0xd6, 0xca, 0x46, 0x2b, 0xfb, 0x6b, 0xd5, 0x59, 0x2d, 0x36, 0x75, 0x63, 0x3d, 0x44, - 0x28, 0xe6, 0x90, 0xba, 0xc4, 0x3d, 0x87, 0x69, 0xee, 0xc6, 0x76, 0x7d, 0xd6, 0x64, 0xff, 0x29, - 0xf6, 0x28, 0xf1, 0x02, 0x4a, 0x8e, 0x61, 0xea, 0xac, 0x28, 0xf9, 0xe1, 0x31, 0x4c, 0xd5, 0xdb, - 0x21, 0x66, 0x2f, 0x81, 0xeb, 0x01, 0xd1, 0x72, 0xb2, 0x85, 0xf5, 0x17, 0x03, 0xdd, 0x3b, 0xc3, - 0x01, 0xf5, 0xb1, 0x64, 0xbc, 0xb8, 0xef, 0x51, 0xe2, 0x29, 0x8d, 0x37, 0xdc, 0xeb, 0x15, 0x6f, - 0xe7, 0xaf, 0xf1, 0xf6, 0x63, 0xb4, 0x5a, 0x66, 0x58, 0xf9, 0xdb, 0x9a, 0xc1, 0xdf, 0x4e, 0xa1, + 0xd6, 0xbf, 0x0d, 0x74, 0xeb, 0x93, 0x80, 0x79, 0x38, 0x38, 0x09, 0xb0, 0x98, 0xa8, 0xe4, 0x4d, + 0x55, 0xd4, 0x1c, 0xf2, 0xae, 0xd1, 0xde, 0xcd, 0x1c, 0xb5, 0x52, 0xd3, 0x7d, 0xfc, 0x11, 0xba, + 0x5d, 0xd6, 0x71, 0x79, 0xb9, 0x3a, 0x98, 0xc3, 0x3b, 0x17, 0xdf, 0xed, 0x6c, 0x14, 0x39, 0x1c, + 0xea, 0x8b, 0x7e, 0xec, 0x6c, 0x90, 0xc6, 0x86, 0x6f, 0xf6, 0x50, 0x87, 0x7a, 0xc4, 0x15, 0xf0, + 0xd2, 0x8d, 0x92, 0x50, 0xe7, 0x65, 0xc1, 0x69, 0x53, 0x8f, 0x9c, 0xc0, 0xcb, 0xcf, 0x93, 0xd0, + 0x7c, 0x88, 0xde, 0x29, 0x06, 0x91, 0x9b, 0xe2, 0xc0, 0x55, 0xfa, 0x2e, 0xf6, 0x7d, 0xae, 0xd3, + 0xb4, 0xea, 0xdc, 0x29, 0x4e, 0xcf, 0x70, 0xa0, 0x8c, 0x1d, 0xf8, 0x3e, 0xb7, 0xfe, 0xb5, 0x88, + 0x96, 0x46, 0x98, 0xe3, 0x50, 0x98, 0xa7, 0x68, 0x43, 0x42, 0x18, 0x07, 0x58, 0x82, 0x9b, 0x71, + 0x64, 0x1e, 0xe9, 0xfb, 0x9a, 0x3b, 0xeb, 0xb3, 0xc5, 0xae, 0x4d, 0x93, 0x74, 0xcf, 0x1e, 0xea, + 0xdd, 0x13, 0x89, 0x25, 0x38, 0xeb, 0x05, 0x46, 0xb6, 0x69, 0xfe, 0x0a, 0x75, 0x25, 0x4f, 0x84, + 0xac, 0xd8, 0xab, 0x6a, 0xdb, 0x2c, 0x95, 0xef, 0x14, 0xe7, 0x59, 0xc3, 0x97, 0xed, 0x7a, 0x3d, + 0x51, 0xb5, 0xfe, 0x17, 0xa2, 0x3a, 0x41, 0x77, 0x14, 0xcb, 0x5f, 0xc6, 0x5c, 0x98, 0x1d, 0xf3, + 0xb6, 0xd2, 0x6f, 0x82, 0x7e, 0x81, 0xcc, 0x54, 0x90, 0xcb, 0x98, 0x8b, 0x6f, 0xe1, 0x67, 0x2a, + 0x48, 0x13, 0xd2, 0x47, 0xdb, 0x42, 0x15, 0x9f, 0x1b, 0x82, 0xd4, 0xb4, 0x17, 0x07, 0x10, 0x51, + 0x31, 0x29, 0xc0, 0x97, 0x66, 0x07, 0xdf, 0xd2, 0x40, 0x9f, 0x29, 0x1c, 0xa7, 0x80, 0xc9, 0xad, + 0x0c, 0x51, 0xef, 0x7a, 0x2b, 0x65, 0x82, 0x96, 0x75, 0x82, 0x7e, 0x72, 0x0d, 0x44, 0x99, 0xa5, + 0x7d, 0x74, 0x37, 0xc4, 0xaf, 0x5d, 0x39, 0xe1, 0x4c, 0xca, 0x00, 0x7c, 0x37, 0xc6, 0xe4, 0x1c, + 0xa4, 0xd0, 0x33, 0xaa, 0xe5, 0xdc, 0x09, 0xf1, 0xeb, 0xd3, 0xe2, 0x6c, 0x94, 0x1d, 0x99, 0x02, + 0xbd, 0x57, 0xa3, 0xf4, 0x57, 0x98, 0xfb, 0xae, 0x0f, 0x11, 0x0b, 0x5d, 0x0e, 0x63, 0xc5, 0x7b, + 0x38, 0x63, 0x77, 0x80, 0x72, 0x2c, 0xe5, 0x8d, 0xac, 0x5e, 0x19, 0x65, 0x13, 0x0f, 0x19, 0x8d, + 0xf2, 0xd9, 0x6d, 0x55, 0xcc, 0xaf, 0xd0, 0x1e, 0x2b, 0x30, 0xa7, 0x86, 0xf5, 0x04, 0xc0, 0xf2, + 0xd0, 0xed, 0xa7, 0x38, 0xf2, 0xc5, 0x04, 0x9f, 0xc3, 0x67, 0x20, 0xb1, 0x8f, 0x25, 0x6e, 0xf4, + 0xcc, 0x0b, 0x00, 0x37, 0x66, 0x2c, 0xc8, 0x7a, 0x26, 0xa3, 0xa0, 0xb2, 0x67, 0x9e, 0x00, 0x8c, + 0x18, 0x0b, 0x54, 0xcf, 0x98, 0x5d, 0xb4, 0x9c, 0x02, 0x17, 0x55, 0x05, 0x17, 0x4b, 0xeb, 0x17, + 0xa8, 0xad, 0x49, 0xe3, 0x80, 0x9c, 0x0b, 0x73, 0x1b, 0xb5, 0x15, 0x12, 0x08, 0x01, 0xa2, 0x6b, + 0xf4, 0x5b, 0xbb, 0x6d, 0xa7, 0xda, 0xb0, 0x24, 0xda, 0xba, 0xe9, 0x5d, 0x24, 0xcc, 0xe7, 0x68, + 0x39, 0x06, 0x3d, 0xb4, 0xb5, 0x62, 0x67, 0xff, 0x43, 0x7b, 0x86, 0xb7, 0xa7, 0x7d, 0x13, 0xa0, + 0x53, 0xa0, 0x59, 0xbc, 0x7a, 0x8d, 0x5d, 0x9a, 0x15, 0xc2, 0x3c, 0xbb, 0x6c, 0xf4, 0xd7, 0x6f, + 0x65, 0xf4, 0x12, 0x5e, 0x65, 0xf3, 0x7d, 0xd4, 0x39, 0xc8, 0xc2, 0xfe, 0x0d, 0x15, 0xf2, 0xea, + 0xb5, 0xac, 0xd6, 0xaf, 0xe5, 0x53, 0xb4, 0x9e, 0x8f, 0xb8, 0x53, 0xa6, 0x89, 0xcf, 0xfc, 0x29, + 0x42, 0xf9, 0x6c, 0x54, 0x84, 0x99, 0xa5, 0xa5, 0x9d, 0xef, 0x1c, 0xf9, 0x8d, 0x51, 0x35, 0xdf, + 0x18, 0x55, 0x96, 0x83, 0x36, 0xce, 0x04, 0xf9, 0x6d, 0xf1, 0xfe, 0x79, 0x16, 0x0b, 0xf3, 0x2e, + 0x5a, 0x52, 0xbd, 0x9a, 0x03, 0x2d, 0x38, 0x8b, 0xa9, 0x20, 0x47, 0xbe, 0xb9, 0x5b, 0x7f, 0x63, + 0xb1, 0xd8, 0xa5, 0xbe, 0xe8, 0xce, 0xf7, 0x5b, 0xbb, 0x0b, 0xce, 0x7a, 0x52, 0xa9, 0x1f, 0xf9, + 0xc2, 0xfa, 0x1d, 0xea, 0xd4, 0x00, 0xcd, 0x75, 0x34, 0x5f, 0x62, 0xcd, 0x53, 0xdf, 0x7c, 0x84, + 0xb6, 0x2a, 0xa0, 0x26, 0xdd, 0x67, 0x88, 0x6d, 0xe7, 0x5e, 0x29, 0xd0, 0x60, 0x7c, 0x61, 0x3d, + 0x43, 0x9b, 0x47, 0x15, 0xb9, 0x94, 0xc3, 0xa4, 0x11, 0xa1, 0xd1, 0x1c, 0xc6, 0xdb, 0xa8, 0x5d, + 0xfe, 0x48, 0xe8, 0xe8, 0x17, 0x9c, 0x6a, 0xc3, 0x0a, 0xd1, 0xad, 0x33, 0x41, 0x4e, 0x20, 0xf2, + 0x2b, 0xb0, 0x1b, 0x2e, 0xe0, 0xf0, 0x32, 0xd0, 0xcc, 0x0f, 0xd5, 0xca, 0xdc, 0x9f, 0x0d, 0xd4, + 0x3d, 0x86, 0xe9, 0x81, 0x10, 0x74, 0x1c, 0x85, 0x10, 0x49, 0x45, 0x16, 0x98, 0x80, 0xfa, 0x34, + 0xdf, 0x45, 0x6b, 0x65, 0xa3, 0x95, 0xfd, 0xb5, 0xea, 0xac, 0x16, 0x9b, 0xba, 0xb1, 0x1e, 0x21, + 0x14, 0x73, 0x48, 0x5d, 0xe2, 0x9e, 0xc3, 0x34, 0x77, 0x63, 0xbb, 0x3e, 0x6b, 0xb2, 0xff, 0x14, + 0x7b, 0x94, 0x78, 0x01, 0x25, 0xc7, 0x30, 0x75, 0x56, 0x94, 0xfc, 0xf0, 0x18, 0xa6, 0xea, 0xed, + 0x10, 0xb3, 0x57, 0xc0, 0xf5, 0x80, 0x68, 0x39, 0xd9, 0xc2, 0xfa, 0x8b, 0x81, 0xee, 0x9d, 0xe1, + 0x80, 0xfa, 0x58, 0x32, 0x5e, 0xdc, 0xf7, 0x28, 0xf1, 0x94, 0xc6, 0x0f, 0xdc, 0xeb, 0x15, 0x6f, + 0xe7, 0xaf, 0xf1, 0xf6, 0x23, 0xb4, 0x5a, 0x66, 0x58, 0xf9, 0xdb, 0x9a, 0xc1, 0xdf, 0x4e, 0xa1, 0x71, 0x0c, 0x53, 0xeb, 0x8f, 0x35, 0xdf, 0x0e, 0xa7, 0xb5, 0xe6, 0xe5, 0xff, 0xc5, 0xb7, 0xd2, 0x6c, 0xdd, 0x37, 0x52, 0xd7, 0xbf, 0x12, 0x40, 0xeb, 0x6a, 0x00, 0xd6, 0xdf, 0x0c, 0xb4, 0x59, - 0xb7, 0x2a, 0x4e, 0xd9, 0x88, 0x27, 0x11, 0xbc, 0xc9, 0x7a, 0x55, 0x3f, 0xf3, 0xf5, 0xfa, 0x79, - 0x86, 0xd6, 0x1b, 0x4e, 0x89, 0xfc, 0x36, 0x7e, 0x39, 0x13, 0x85, 0xd4, 0xe8, 0xc1, 0x59, 0xab, - 0xc7, 0x21, 0x0e, 0x9f, 0x7d, 0x7b, 0xd1, 0x33, 0xbe, 0xbb, 0xe8, 0x19, 0xff, 0xbc, 0xe8, 0x19, - 0x5f, 0xbd, 0xee, 0xcd, 0x7d, 0xf7, 0xba, 0x37, 0xf7, 0x8f, 0xd7, 0xbd, 0xb9, 0xdf, 0x7f, 0x34, - 0xa6, 0x72, 0x92, 0x78, 0x36, 0x61, 0xe1, 0x20, 0xff, 0x09, 0xad, 0x6c, 0x7d, 0x50, 0xfe, 0xd3, - 0xa7, 0xfb, 0x83, 0x57, 0xcd, 0x1f, 0x7b, 0x39, 0x8d, 0x41, 0x78, 0x4b, 0xba, 0xac, 0x3f, 0xfc, - 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7b, 0x4c, 0xb0, 0x24, 0x09, 0x10, 0x00, 0x00, + 0xb7, 0x2a, 0x4e, 0xd9, 0x88, 0x27, 0x11, 0xfc, 0x90, 0xf5, 0xaa, 0x7e, 0xe6, 0xeb, 0xf5, 0xf3, + 0x1c, 0xad, 0x37, 0x9c, 0x12, 0xf9, 0x6d, 0xfc, 0x72, 0x26, 0x0a, 0xa9, 0xd1, 0x83, 0xb3, 0x56, + 0x8f, 0x43, 0x1c, 0x3e, 0xff, 0xe6, 0xa2, 0x67, 0x7c, 0x7b, 0xd1, 0x33, 0xfe, 0x79, 0xd1, 0x33, + 0xbe, 0x7c, 0xd3, 0x9b, 0xfb, 0xf6, 0x4d, 0x6f, 0xee, 0x1f, 0x6f, 0x7a, 0x73, 0xbf, 0xff, 0x70, + 0x4c, 0xe5, 0x24, 0xf1, 0x6c, 0xc2, 0xc2, 0x41, 0xfe, 0x13, 0x5a, 0xd9, 0xfa, 0xa0, 0xfc, 0xa7, + 0x4f, 0x1f, 0x0e, 0x5e, 0x37, 0x7f, 0xec, 0xe5, 0x34, 0x06, 0xe1, 0x2d, 0xe9, 0xb2, 0x7e, 0xf8, + 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x73, 0xaf, 0xd0, 0x18, 0x09, 0x10, 0x00, 0x00, } func (m *ConsumerAdditionProposal) Marshal() (dAtA []byte, err error) { diff --git a/x/ccv/provider/types/query.pb.go b/x/ccv/provider/types/query.pb.go index f8a4f04d23..f82376da05 100644 --- a/x/ccv/provider/types/query.pb.go +++ b/x/ccv/provider/types/query.pb.go @@ -1150,9 +1150,9 @@ var fileDescriptor_422512d7b7586cd7 = []byte{ 0x2c, 0xc3, 0xc5, 0xc1, 0x76, 0xf8, 0x4d, 0xc4, 0x96, 0x23, 0x3e, 0xc7, 0x34, 0xa2, 0x78, 0x52, 0xbd, 0xf3, 0x78, 0x37, 0x2f, 0x3d, 0xd9, 0xcd, 0x4b, 0x7f, 0xee, 0xe6, 0xa5, 0x87, 0x7b, 0xf9, 0xcc, 0x93, 0xbd, 0x7c, 0xe6, 0xd9, 0x5e, 0x3e, 0xf3, 0xd1, 0x7c, 0xcd, 0x66, 0x5b, 0x8d, 0x4d, - 0xd5, 0x24, 0x75, 0xcd, 0x24, 0xb4, 0x4e, 0x68, 0x5b, 0xbf, 0x77, 0x9a, 0xfd, 0x82, 0x92, 0x76, - 0x7f, 0xdf, 0xfc, 0xed, 0x78, 0x98, 0x6e, 0x4e, 0xf0, 0xaf, 0x95, 0xcb, 0xff, 0x07, 0x00, 0x00, - 0xff, 0xff, 0xb7, 0x37, 0x44, 0xeb, 0x42, 0x13, 0x00, 0x00, + 0xd5, 0x24, 0x75, 0xcd, 0x24, 0xb4, 0x4e, 0x68, 0x5b, 0xbf, 0x77, 0x9a, 0xfd, 0x82, 0xcb, 0xda, + 0xfd, 0x7d, 0xf3, 0xb7, 0xe3, 0x61, 0xba, 0x39, 0xc1, 0xbf, 0x56, 0x2e, 0xff, 0x1f, 0x00, 0x00, + 0xff, 0xff, 0xbf, 0xd4, 0x24, 0xd7, 0x42, 0x13, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/x/ccv/provider/types/tx.pb.go b/x/ccv/provider/types/tx.pb.go index 746f92b417..32bca37998 100644 --- a/x/ccv/provider/types/tx.pb.go +++ b/x/ccv/provider/types/tx.pb.go @@ -207,7 +207,7 @@ var fileDescriptor_43221a4391e9fbf4 = []byte{ // 453 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x93, 0x3d, 0x6b, 0x14, 0x41, 0x18, 0xc7, 0x77, 0x13, 0xd4, 0x64, 0x8c, 0x82, 0xc3, 0x15, 0x97, 0xf3, 0xd8, 0xd3, 0x15, 0x24, - 0x85, 0xee, 0x90, 0x58, 0x88, 0x01, 0x8b, 0x4b, 0x6c, 0x24, 0x5c, 0xb3, 0x8d, 0x60, 0xe1, 0xb1, + 0x85, 0xee, 0x10, 0x53, 0x88, 0x01, 0x8b, 0x4b, 0x6c, 0x24, 0x5c, 0xb3, 0x8d, 0x60, 0xe1, 0xb1, 0x37, 0x33, 0x4e, 0x06, 0xb3, 0xf3, 0x2c, 0xf3, 0xcc, 0xad, 0xd9, 0x6f, 0x60, 0xa9, 0x95, 0x6d, 0xbe, 0x81, 0x5f, 0x43, 0xb0, 0x49, 0x69, 0x25, 0x72, 0xd7, 0x58, 0xfb, 0x09, 0x64, 0xdf, 0x3c, 0xc5, 0xe3, 0x08, 0x92, 0xee, 0x79, 0xdb, 0xff, 0xff, 0xb7, 0x33, 0xf3, 0x90, 0x07, 0xda, 0x38, @@ -226,14 +226,14 @@ var fileDescriptor_43221a4391e9fbf4 = []byte{ 0x91, 0x60, 0x84, 0x2a, 0x96, 0x4a, 0xa3, 0x93, 0xb6, 0x9d, 0x88, 0xe5, 0xdb, 0xc4, 0x8a, 0x67, 0xd2, 0x40, 0x4a, 0x3b, 0xe4, 0x8a, 0x28, 0x83, 0x86, 0xbf, 0x4e, 0x68, 0x9f, 0x6c, 0x0a, 0x99, 0x01, 0x6a, 0x07, 0x0d, 0x79, 0xbc, 0x28, 0xfc, 0xe1, 0xbf, 0x43, 0xee, 0xaf, 0xd6, 0x6f, 0x49, - 0xf6, 0xbe, 0xac, 0x91, 0xf5, 0x11, 0x2a, 0xfa, 0xc1, 0x27, 0xb7, 0xfe, 0x3d, 0xc8, 0x27, 0xd1, - 0x05, 0x6e, 0x3c, 0x5a, 0xf6, 0xab, 0xbd, 0xe1, 0x7f, 0x7f, 0xda, 0xb2, 0xd1, 0x4f, 0x3e, 0xb9, - 0xbd, 0xea, 0x8c, 0x0e, 0x2f, 0x6a, 0xb1, 0x42, 0xa4, 0x77, 0x74, 0x09, 0x22, 0x2d, 0xf1, 0xc1, - 0x8b, 0xcf, 0xb3, 0xc0, 0x3f, 0x9f, 0x05, 0xfe, 0xf7, 0x59, 0xe0, 0xbf, 0x9f, 0x07, 0xde, 0xf9, - 0x3c, 0xf0, 0xbe, 0xce, 0x03, 0xef, 0xe5, 0x53, 0xa5, 0xdd, 0xf1, 0x74, 0x12, 0x71, 0x48, 0x9b, - 0xf7, 0xcd, 0x16, 0xbe, 0x0f, 0x7f, 0xaf, 0x5e, 0xbe, 0xc7, 0x4e, 0xff, 0xde, 0x3f, 0x57, 0x64, - 0x12, 0x27, 0x57, 0xab, 0x17, 0xff, 0xe8, 0x57, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7a, 0x53, 0xb5, - 0xb8, 0xb0, 0x03, 0x00, 0x00, + 0x1e, 0x7d, 0x59, 0x23, 0xeb, 0x23, 0x54, 0xf4, 0x83, 0x4f, 0x6e, 0xfd, 0x7b, 0x90, 0x4f, 0xa2, + 0x0b, 0xdc, 0x78, 0xb4, 0xec, 0x57, 0x7b, 0xc3, 0xff, 0xfe, 0xb4, 0x65, 0xa3, 0x9f, 0x7c, 0x72, + 0x7b, 0xd5, 0x19, 0x1d, 0x5e, 0xd4, 0x62, 0x85, 0x48, 0xef, 0xe8, 0x12, 0x44, 0x5a, 0xe2, 0x83, + 0x17, 0x9f, 0x67, 0x81, 0x7f, 0x3e, 0x0b, 0xfc, 0xef, 0xb3, 0xc0, 0x7f, 0x3f, 0x0f, 0xbc, 0xf3, + 0x79, 0xe0, 0x7d, 0x9d, 0x07, 0xde, 0xcb, 0xa7, 0x4a, 0xbb, 0xe3, 0xe9, 0x24, 0xe2, 0x90, 0x36, + 0xef, 0x9b, 0x2d, 0x7c, 0x1f, 0xfe, 0x5e, 0xbd, 0x7c, 0x8f, 0x9d, 0xfe, 0xbd, 0x7f, 0xae, 0xc8, + 0x24, 0x4e, 0xae, 0x56, 0x2f, 0x7e, 0xef, 0x57, 0x00, 0x00, 0x00, 0xff, 0xff, 0x72, 0xb0, 0xd5, + 0x84, 0xb0, 0x03, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/x/ccv/types/ccv.pb.go b/x/ccv/types/ccv.pb.go index ea2d38dc84..21d0b32f0b 100644 --- a/x/ccv/types/ccv.pb.go +++ b/x/ccv/types/ccv.pb.go @@ -524,9 +524,9 @@ var fileDescriptor_68bd5f3242e6f29c = []byte{ 0x48, 0x1d, 0x88, 0xc8, 0x89, 0x4b, 0x72, 0xee, 0xec, 0x5c, 0x15, 0x4f, 0x66, 0x68, 0xc9, 0xc2, 0xd7, 0xef, 0x0a, 0x57, 0x3a, 0xbc, 0xb8, 0x51, 0xf8, 0xcb, 0x1b, 0x85, 0xff, 0x7d, 0xa3, 0xf0, 0xdf, 0x6e, 0x15, 0xee, 0xf2, 0x56, 0xe1, 0xae, 0x6e, 0x15, 0xee, 0xf3, 0xeb, 0x16, 0x66, 0xed, - 0x41, 0x53, 0x77, 0x49, 0xcf, 0x48, 0x56, 0xeb, 0x1d, 0xaa, 0x97, 0x93, 0x1d, 0x1d, 0x9a, 0xc6, - 0x97, 0x78, 0x51, 0xc7, 0x2b, 0xb3, 0xb9, 0x1c, 0xef, 0xcc, 0xed, 0xbf, 0x01, 0x00, 0x00, 0xff, - 0xff, 0x5e, 0x61, 0xe5, 0xc6, 0xd0, 0x05, 0x00, 0x00, + 0x41, 0x53, 0x77, 0x49, 0xcf, 0x48, 0x56, 0xeb, 0x1d, 0xaa, 0x97, 0x93, 0x1d, 0x1d, 0x6e, 0x1b, + 0x5f, 0xe2, 0x45, 0x1d, 0xaf, 0xcc, 0xe6, 0x72, 0xbc, 0x33, 0xb7, 0xff, 0x06, 0x00, 0x00, 0xff, + 0xff, 0xc0, 0xe2, 0x3f, 0x59, 0xd0, 0x05, 0x00, 0x00, } func (m *ValidatorSetChangePacketData) Marshal() (dAtA []byte, err error) { From 0339832b68b8e66d7edcc947bf7aeff920a69804 Mon Sep 17 00:00:00 2001 From: MSalopek Date: Fri, 23 Jun 2023 10:06:52 +0200 Subject: [PATCH 031/134] tests: fix broken sovereign app.go (#1068) * fix: fix broken sovereign app.go * chore: fix upgrade proposals for sovereign * chore: fix sovereign app.go * chore: re-enable all tests * fix: update democ and throttle tests --- app/consumer-democracy/app.go | 3 -- app/consumer/app.go | 2 -- app/provider/app.go | 3 -- app/sovereign/app.go | 28 +++++++++++++++---- go.sum | 1 + tests/e2e/actions.go | 5 ++-- tests/e2e/actions_sovereign_chain.go | 10 ++++--- tests/e2e/config.go | 8 +++--- tests/e2e/main.go | 4 +-- tests/e2e/state.go | 4 +-- tests/e2e/steps_democracy.go | 2 +- tests/e2e/steps_reward_denom.go | 4 +-- tests/e2e/steps_sovereign_changeover.go | 2 +- .../testnet-scripts/sovereign-genesis.json | 24 ++++++++++++---- 14 files changed, 64 insertions(+), 36 deletions(-) diff --git a/app/consumer-democracy/app.go b/app/consumer-democracy/app.go index 298087262d..6b3078212b 100644 --- a/app/consumer-democracy/app.go +++ b/app/consumer-democracy/app.go @@ -116,9 +116,6 @@ import ( consumer "github.com/cosmos/interchain-security/v3/x/ccv/consumer" consumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" - - // unnamed import of statik for swagger UI support - _ "github.com/cosmos/cosmos-sdk/client/docs/statik" ) const ( diff --git a/app/consumer/app.go b/app/consumer/app.go index 20b6695dfa..17c15c2c86 100644 --- a/app/consumer/app.go +++ b/app/consumer/app.go @@ -91,8 +91,6 @@ import ( ibcconsumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" ibcconsumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" - // unnamed import of statik for swagger UI support - _ "github.com/cosmos/cosmos-sdk/client/docs/statik" testutil "github.com/cosmos/interchain-security/v3/testutil/integration" ) diff --git a/app/provider/app.go b/app/provider/app.go index 3fefd34daa..d810ff360f 100644 --- a/app/provider/app.go +++ b/app/provider/app.go @@ -109,9 +109,6 @@ import ( providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" testutil "github.com/cosmos/interchain-security/v3/testutil/integration" - - // unnamed import of statik for swagger UI support - _ "github.com/cosmos/cosmos-sdk/client/docs/statik" ) const ( diff --git a/app/sovereign/app.go b/app/sovereign/app.go index e616b92514..b1049255f9 100644 --- a/app/sovereign/app.go +++ b/app/sovereign/app.go @@ -7,6 +7,9 @@ import ( "os" "path/filepath" + autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" + reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" + runtimeservices "github.com/cosmos/cosmos-sdk/runtime/services" appparams "github.com/cosmos/interchain-security/v3/app/params" "github.com/cosmos/cosmos-sdk/baseapp" @@ -27,8 +30,12 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/version" - "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/consensus" + consensusparamkeeper "github.com/cosmos/cosmos-sdk/x/consensus/keeper" + consensusparamtypes "github.com/cosmos/cosmos-sdk/x/consensus/types" + + "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth/ante" authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" @@ -44,7 +51,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/capability" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - consensusparamkeeper "github.com/cosmos/cosmos-sdk/x/consensus/keeper" "github.com/cosmos/cosmos-sdk/x/crisis" crisiskeeper "github.com/cosmos/cosmos-sdk/x/crisis/keeper" crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types" @@ -108,6 +114,7 @@ import ( minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" paramproposal "github.com/cosmos/cosmos-sdk/x/params/types/proposal" + tendermint "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" ) const ( @@ -125,7 +132,7 @@ var ( // and genesis verification. ModuleBasics = module.NewBasicManager( auth.AppModuleBasic{}, - genutil.AppModuleBasic{}, + genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator), bank.AppModuleBasic{}, capability.AppModuleBasic{}, sdkstaking.AppModuleBasic{}, @@ -148,6 +155,8 @@ var ( evidence.AppModuleBasic{}, transfer.AppModuleBasic{}, vesting.AppModuleBasic{}, + tendermint.AppModuleBasic{}, + consensus.AppModuleBasic{}, ) // module account permissions @@ -246,11 +255,11 @@ func New( bApp.SetInterfaceRegistry(interfaceRegistry) keys := sdk.NewKVStoreKeys( - authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, + authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, crisistypes.StoreKey, minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey, govtypes.StoreKey, paramstypes.StoreKey, ibchost.StoreKey, upgradetypes.StoreKey, feegrant.StoreKey, evidencetypes.StoreKey, ibctransfertypes.StoreKey, - capabilitytypes.StoreKey, authzkeeper.StoreKey, + capabilitytypes.StoreKey, authzkeeper.StoreKey, consensusparamtypes.StoreKey, ) tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey) memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey) @@ -263,6 +272,7 @@ func New( keys: keys, tkeys: tkeys, memKeys: memKeys, + txConfig: encodingConfig.TxConfig, } app.ParamsKeeper = initParamsKeeper( @@ -623,6 +633,14 @@ func New( app.ScopedIBCKeeper = scopedIBCKeeper app.ScopedTransferKeeper = scopedTransferKeeper + autocliv1.RegisterQueryServer(app.GRPCQueryRouter(), runtimeservices.NewAutoCLIQueryService(app.MM.Modules)) + + reflectionSvc, err := runtimeservices.NewReflectionService() + if err != nil { + panic(err) + } + reflectionv1.RegisterReflectionServiceServer(app.GRPCQueryRouter(), reflectionSvc) + return app } diff --git a/go.sum b/go.sum index b79f6784cb..cafdd80e8c 100644 --- a/go.sum +++ b/go.sum @@ -1129,6 +1129,7 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1 github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/tyler-smith/go-bip39 v1.0.2/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= +github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index 2e8cd38a9b..719e5d7517 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -1395,7 +1395,7 @@ func (tr TestRun) delegateTokens( } // wait for inclusion in a block -> '--broadcast-mode block' is deprecated - tr.waitBlocks(action.chain, 1, 10*time.Second) + tr.waitBlocks(action.chain, 2, 10*time.Second) } type unbondTokensAction struct { @@ -1760,7 +1760,6 @@ func (tr TestRun) registerConsumerRewardDenom(action registerConsumerRewardDenom `--node`, tr.getValidatorNode(action.chain, action.from), `--gas`, "9000000", `--keyring-backend`, `test`, - `-b`, `block`, `-y`, ).CombinedOutput() @@ -1771,6 +1770,8 @@ func (tr TestRun) registerConsumerRewardDenom(action registerConsumerRewardDenom if err != nil { log.Fatal(err, "\n", string(bz)) } + + tr.waitBlocks(action.chain, 2, 10*time.Second) } // Creates an additional node on selected chain diff --git a/tests/e2e/actions_sovereign_chain.go b/tests/e2e/actions_sovereign_chain.go index c61a2a9a38..cf2d6288e8 100644 --- a/tests/e2e/actions_sovereign_chain.go +++ b/tests/e2e/actions_sovereign_chain.go @@ -105,16 +105,16 @@ func (tr TestRun) startSovereignChain( }, verbose) } -type UpgradeProposalAction struct { +type LegacyUpgradeProposalAction struct { chainID chainID upgradeTitle string proposer validatorID upgradeHeight uint64 } -func (tr *TestRun) submitUpgradeProposal(action UpgradeProposalAction, verbose bool) { +func (tr *TestRun) submitLegacyUpgradeProposal(action LegacyUpgradeProposalAction, verbose bool) { submit := fmt.Sprintf( - `%s tx gov submit-proposal software-upgrade %s \ + `%s tx gov submit-legacy-proposal software-upgrade %s \ --title %s \ --deposit 10000000stake \ --upgrade-height %s \ @@ -126,7 +126,7 @@ func (tr *TestRun) submitUpgradeProposal(action UpgradeProposalAction, verbose b --chain-id %s \ --home %s \ --node %s \ - -b block \ + --no-validate \ -y`, tr.chainConfigs[chainID("sover")].binaryName, action.upgradeTitle, @@ -152,6 +152,8 @@ func (tr *TestRun) submitUpgradeProposal(action UpgradeProposalAction, verbose b if err != nil { log.Fatal(err, "\n", string(bz)) } + + tr.waitBlocks(action.chainID, 1, 15*time.Second) } type waitUntilBlockAction struct { diff --git a/tests/e2e/config.go b/tests/e2e/config.go index df54cbd4f4..373281162d 100644 --- a/tests/e2e/config.go +++ b/tests/e2e/config.go @@ -364,12 +364,12 @@ func ChangeoverTestRun() TestRun { binaryName: "interchain-security-pd", ipPrefix: "7.7.7", votingWaitTime: 20, - genesisChanges: ".app_state.gov.voting_params.voting_period = \"20s\" | " + + genesisChanges: ".app_state.gov.params.voting_period = \"20s\" | " + // Custom slashing parameters for testing validator downtime functionality // See https://docs.cosmos.network/main/modules/slashing/04_begin_block.html#uptime-tracking ".app_state.slashing.params.signed_blocks_window = \"10\" | " + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + - ".app_state.slashing.params.downtime_jail_duration = \"2s\" | " + + ".app_state.slashing.params.downtime_jail_duration = \"60s\" | " + ".app_state.slashing.params.slash_fraction_downtime = \"0.010000000000000000\" | " + ".app_state.provider.params.slash_meter_replenish_fraction = \"1.0\" | " + // This disables slash packet throttling ".app_state.provider.params.slash_meter_replenish_period = \"3s\"", @@ -380,10 +380,10 @@ func ChangeoverTestRun() TestRun { upgradeBinary: "interchain-security-cdd", ipPrefix: "7.7.8", votingWaitTime: 20, - genesisChanges: ".app_state.gov.voting_params.voting_period = \"20s\" | " + + genesisChanges: ".app_state.gov.params.voting_period = \"20s\" | " + ".app_state.slashing.params.signed_blocks_window = \"15\" | " + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + - ".app_state.slashing.params.downtime_jail_duration = \"2s\" | " + + ".app_state.slashing.params.downtime_jail_duration = \"60s\" | " + ".app_state.slashing.params.slash_fraction_downtime = \"0.010000000000000000\" | " + ".app_state.staking.params.unbonding_time = \"1728000s\"", // making the genesis unbonding time equal to unbonding time in the consumer addition proposal }, diff --git a/tests/e2e/main.go b/tests/e2e/main.go index 00967dfcac..9943d6f9bd 100644 --- a/tests/e2e/main.go +++ b/tests/e2e/main.go @@ -115,8 +115,8 @@ func (tr *TestRun) runStep(step Step, verbose bool) { tr.startChain(action, verbose) case StartSovereignChainAction: tr.startSovereignChain(action, verbose) - case UpgradeProposalAction: - tr.submitUpgradeProposal(action, verbose) + case LegacyUpgradeProposalAction: + tr.submitLegacyUpgradeProposal(action, verbose) case waitUntilBlockAction: tr.waitUntilBlockOnChain(action) case ChangeoverChainAction: diff --git a/tests/e2e/state.go b/tests/e2e/state.go index 0c2573574f..5464b291ac 100644 --- a/tests/e2e/state.go +++ b/tests/e2e/state.go @@ -426,8 +426,8 @@ func (tr TestRun) getProposal(chain chainID, proposal uint) Proposal { }, } case "/cosmos.upgrade.v1beta1.SoftwareUpgradeProposal": - height := gjson.Get(string(bz), `content.plan.height`).Uint() - title := gjson.Get(string(bz), `content.plan.name`).String() + height := gjson.Get(string(bz), `messages.0.content.plan.height`).Uint() + title := gjson.Get(string(bz), `messages.0.content.plan.name`).String() return UpgradeProposal{ Deposit: uint(deposit), Status: status, diff --git a/tests/e2e/steps_democracy.go b/tests/e2e/steps_democracy.go index 3c80818a24..7264c44341 100644 --- a/tests/e2e/steps_democracy.go +++ b/tests/e2e/steps_democracy.go @@ -100,7 +100,7 @@ func stepsDemocracy(consumerName string) []Step { state: State{ chainID(consumerName): ChainState{ ValBalances: &map[validatorID]uint{ - validatorID("alice"): 9899999999, + validatorID("alice"): 9889999998, validatorID("bob"): 9960000001, }, // Check that the parameter is changed on gov-consumer chain diff --git a/tests/e2e/steps_reward_denom.go b/tests/e2e/steps_reward_denom.go index cb557f0471..9aad8ec7a8 100644 --- a/tests/e2e/steps_reward_denom.go +++ b/tests/e2e/steps_reward_denom.go @@ -98,11 +98,11 @@ func stepsRewardDenomConsumer(consumerName string) []Step { state: State{ chainID(consumerName): ChainState{ ValBalances: &map[validatorID]uint{ - validatorID("alice"): 9899999999, + validatorID("alice"): 9889999998, validatorID("bob"): 9960000001, }, // Check that the parameter is changed on gov-consumer chain - Params: &([]Param{{Subspace: "staking", Key: "MaxValidators", Value: "105"}}), + Params: &([]Param{{Subspace: "transfer", Key: "SendEnabled", Value: "true"}}), }, }, }, diff --git a/tests/e2e/steps_sovereign_changeover.go b/tests/e2e/steps_sovereign_changeover.go index 71daad684b..c02b2c4d43 100644 --- a/tests/e2e/steps_sovereign_changeover.go +++ b/tests/e2e/steps_sovereign_changeover.go @@ -192,7 +192,7 @@ func stepRunSovereignChain() []Step { func stepsUpgradeChain() []Step { return []Step{ { - action: UpgradeProposalAction{ + action: LegacyUpgradeProposalAction{ chainID: chainID("sover"), upgradeTitle: "sovereign-changeover", proposer: validatorID("alice"), diff --git a/tests/e2e/testnet-scripts/sovereign-genesis.json b/tests/e2e/testnet-scripts/sovereign-genesis.json index 6c34a0ec1c..c3ae9da36c 100644 --- a/tests/e2e/testnet-scripts/sovereign-genesis.json +++ b/tests/e2e/testnet-scripts/sovereign-genesis.json @@ -1,5 +1,5 @@ { - "genesis_time": "2023-06-19T21:06:09.696739416Z", + "genesis_time": "2023-06-22T15:55:00.982713586Z", "chain_id": "sover", "initial_height": "1", "consensus_params": { @@ -35,13 +35,16 @@ "accounts": [ { "@type": "/cosmos.auth.v1beta1.BaseAccount", - "address": "cosmos1dkas8mu4kyhl5jrh4nzvm65qz588hy9qcz08la", + "address": "cosmos19pe9pg5dv9k5fzgzmsrgnw9rl9asf7ddwhu7lm", "pub_key": null, "account_number": "0", "sequence": "0" } ] }, + "authz": { + "authorization": [] + }, "bank": { "params": { "send_enabled": [], @@ -99,6 +102,9 @@ "evidence": { "evidence": [] }, + "feegrant": { + "allowances": [] + }, "genutil": { "gen_txs": [ { @@ -160,7 +166,7 @@ "tip": null }, "signatures": [ - "D06i2qqq2HathlT7cy+PDLTDuYKAmzw5Ne+Ehvzr9bVy3jpm2h8deDGeSXTSrhdP04UpFXerSn+zIPth5TKNrg==" + "c7aD9dWzb85fn+Aq0ijMdhyJNJSOsOcFLvJt8ctvdxAAbwdrzKPVFbq9IYf1qCwKmfmQUrlFy40qiuQeXaZ8pg==" ] } ] @@ -199,7 +205,8 @@ "params": { "allowed_clients": [ "06-solomachine", - "07-tendermint" + "07-tendermint", + "09-localhost" ] }, "create_localhost": false, @@ -239,6 +246,12 @@ } }, "params": null, + "provider": { + "params": { + "slash_meter_replenish_fraction": "1.0", + "slash_meter_replenish_period": "3s" + } + }, "slashing": { "params": { "signed_blocks_window": "10", @@ -273,7 +286,8 @@ "params": { "send_enabled": true, "receive_enabled": true - } + }, + "total_escrowed": [] }, "upgrade": {}, "vesting": {} From 6e3164cb695de004207b54fa36878f0b2f8412aa Mon Sep 17 00:00:00 2001 From: Marius Poke Date: Fri, 23 Jun 2023 22:32:59 +0200 Subject: [PATCH 032/134] ci: add lint and check-breakage to gh actions (#1066) add lint and check-breakage to gh actions Co-authored-by: MSalopek Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> --- .github/workflows/proto.yml | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .github/workflows/proto.yml diff --git a/.github/workflows/proto.yml b/.github/workflows/proto.yml new file mode 100644 index 0000000000..601310a793 --- /dev/null +++ b/.github/workflows/proto.yml @@ -0,0 +1,31 @@ +name: Protobuf +# Protobuf runs buf (https://buf.build/) lint and check-breakage +# This workflow is only run when a .proto file has been changed +on: + pull_request: + paths: + - "proto/**" + +permissions: + contents: read + +jobs: + lint: + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@v3 + - uses: bufbuild/buf-setup-action@v1.9.0 + - uses: bufbuild/buf-lint-action@v1 + with: + input: "proto" + + break-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: bufbuild/buf-setup-action@v1.9.0 + - uses: bufbuild/buf-breaking-action@v1 + with: + input: "proto" + against: "https://github.com/${{ github.repository }}.git#branch=${{ github.event.pull_request.base.ref }},ref=HEAD~1,subdir=proto" From fcb1ff43a83b55d29ebd47c758d26cdba6b0b992 Mon Sep 17 00:00:00 2001 From: Marius Poke Date: Tue, 27 Jun 2023 11:03:06 +0200 Subject: [PATCH 033/134] docs: release notes template (#1064) * add release notes template * add upgrading info * add gh action to push proto files to buf.build --------- Co-authored-by: MSalopek Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> --- .github/workflows/proto-registry.yml | 20 ++++++++ RELEASE_NOTES.md | 27 ++++++++++ UPGRADING.md | 73 ++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+) create mode 100644 .github/workflows/proto-registry.yml create mode 100644 RELEASE_NOTES.md create mode 100644 UPGRADING.md diff --git a/.github/workflows/proto-registry.yml b/.github/workflows/proto-registry.yml new file mode 100644 index 0000000000..bc620edbdc --- /dev/null +++ b/.github/workflows/proto-registry.yml @@ -0,0 +1,20 @@ +name: Buf-Push +# Protobuf runs buf (https://buf.build/) push updated proto files to https://buf.build/cosmos/interchain-security +# This workflow is only run when a .proto file has been changed +on: + push: + branches: + - main + paths: + - "proto/**" + +jobs: + push: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: bufbuild/buf-setup-action@v1.9.0 + - uses: bufbuild/buf-push-action@v1 + with: + input: "proto" + buf_token: ${{ secrets.BUF_TOKEN }} diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md new file mode 100644 index 0000000000..62704ea9c6 --- /dev/null +++ b/RELEASE_NOTES.md @@ -0,0 +1,27 @@ + + +# Replicated Security Release Notes + +## 📝 Changelog + +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 ``. + +## 🚀 Highlights + + + +## ❤️ 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! \ No newline at end of file diff --git a/UPGRADING.md b/UPGRADING.md new file mode 100644 index 0000000000..588a135bdb --- /dev/null +++ b/UPGRADING.md @@ -0,0 +1,73 @@ +# Upgrading Replicated Security + +This guide provides instructions for upgrading to specific versions of Replicated Security. + +## [v3.0.x](https://github.com/cosmos/interchain-security/releases/tag/v3.0.0-rc0) + +### Upgrading to Cosmos SDK 0.47 + +The following should be considered as complementary to [Cosmos SDK v0.47 UPGRADING.md](https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc2/UPGRADING.md). + +#### Protobuf + +Protobuf code generation, linting and formatting have been updated to leverage the `ghcr.io/cosmos/proto-builder:0.11.5` docker container. Replicated Security protobuf definitions are now packaged and published to [buf.build/cosmos/interchain-security](buf.build/cosmos/interchain-security) via CI workflows. The `third_party/proto` directory has been removed in favour of dependency management using [buf.build](https://docs.buf.build/introduction). + +#### App modules + +Legacy APIs of the `AppModule` interface have been removed from ccv modules. For example, for + +```diff +- // Route implements the AppModule interface +- func (am AppModule) Route() sdk.Route { +- return sdk.Route{} +- } +- +- // QuerierRoute implements the AppModule interface +- func (AppModule) QuerierRoute() string { +- return types.QuerierRoute +- } +- +- // LegacyQuerierHandler implements the AppModule interface +- func (am AppModule) LegacyQuerierHandler(*codec.LegacyAmino) sdk.Querier { +- return nil +- } +- +- // ProposalContents doesn't return any content functions for governance proposals. +- func (AppModule) ProposalContents(_ module.SimulationState) []simtypes.WeightedProposalContent { +- return nil +- } +``` + +#### Imports + +Imports for ics23 have been updated as the repository have been migrated from confio to cosmos. + +```diff +import ( + // ... +- ics23 "github.com/confio/ics23/go" ++ ics23 "github.com/cosmos/ics23/go" + // ... +) +``` + +Imports for gogoproto have been updated. + +```diff +import ( + // ... +- "github.com/gogo/protobuf/proto" ++ "github.com/cosmos/gogoproto/proto" + // ... +) +``` + +## [v2.0.x](https://github.com/cosmos/interchain-security/releases/tag/v2.0.0) + +### Provider + +Upgrading a provider from `v1.1.0-multiden` to `v2.0.0` will require state migrations. See [migration.go](./x/ccv/provider/keeper/migration.go). See the provider module's `ConsensusVersion` in [module](./x/ccv/provider/module.go). + +### Consumer + +Upgrading a consumer from `v1.2.0-multiden` to `v2.0.0` will NOT require state migrations. See the consumer module's `ConsensusVersion` in [module](./x/ccv/consumer/module.go). \ No newline at end of file From 1c9652038b47baa6c32fbde0aee06fcc153bb06f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 27 Jun 2023 15:20:07 -0700 Subject: [PATCH 034/134] build(deps): bump bufbuild/buf-setup-action from 1.9.0 to 1.22.0 (#1082) Bumps [bufbuild/buf-setup-action](https://github.com/bufbuild/buf-setup-action) from 1.9.0 to 1.22.0. - [Release notes](https://github.com/bufbuild/buf-setup-action/releases) - [Commits](https://github.com/bufbuild/buf-setup-action/compare/v1.9.0...v1.22.0) --- updated-dependencies: - dependency-name: bufbuild/buf-setup-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/proto-registry.yml | 2 +- .github/workflows/proto.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/proto-registry.yml b/.github/workflows/proto-registry.yml index bc620edbdc..483fab06c1 100644 --- a/.github/workflows/proto-registry.yml +++ b/.github/workflows/proto-registry.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: bufbuild/buf-setup-action@v1.9.0 + - uses: bufbuild/buf-setup-action@v1.22.0 - uses: bufbuild/buf-push-action@v1 with: input: "proto" diff --git a/.github/workflows/proto.yml b/.github/workflows/proto.yml index 601310a793..c1c302a60f 100644 --- a/.github/workflows/proto.yml +++ b/.github/workflows/proto.yml @@ -15,7 +15,7 @@ jobs: timeout-minutes: 5 steps: - uses: actions/checkout@v3 - - uses: bufbuild/buf-setup-action@v1.9.0 + - uses: bufbuild/buf-setup-action@v1.22.0 - uses: bufbuild/buf-lint-action@v1 with: input: "proto" @@ -24,7 +24,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: bufbuild/buf-setup-action@v1.9.0 + - uses: bufbuild/buf-setup-action@v1.22.0 - uses: bufbuild/buf-breaking-action@v1 with: input: "proto" From e88e2b2a770aca3d2fbe9b624413b9abeaf2282a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 27 Jun 2023 15:41:49 -0700 Subject: [PATCH 035/134] build(deps): bump google.golang.org/grpc from 1.55.0 to 1.56.1 (#1083) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.55.0 to 1.56.1. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.55.0...v1.56.1) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> --- go.mod | 14 +++++++------- go.sum | 28 ++++++++++++++-------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/go.mod b/go.mod index ee1c62d762..4513716d93 100644 --- a/go.mod +++ b/go.mod @@ -26,17 +26,17 @@ require ( golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc golang.org/x/net v0.9.0 // indirect golang.org/x/sys v0.7.0 // indirect - google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 - google.golang.org/grpc v1.55.0 + google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 + google.golang.org/grpc v1.56.1 google.golang.org/protobuf v1.30.0 gopkg.in/yaml.v2 v2.4.0 ) require ( cloud.google.com/go v0.110.0 // indirect - cloud.google.com/go/compute v1.18.0 // indirect + cloud.google.com/go/compute v1.19.1 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/iam v0.12.0 // indirect + cloud.google.com/go/iam v0.13.0 // indirect cloud.google.com/go/storage v1.29.0 // indirect cosmossdk.io/api v0.3.1 cosmossdk.io/core v0.5.1 // indirect @@ -92,7 +92,7 @@ require ( github.com/google/orderedcode v0.0.1 // indirect github.com/google/uuid v1.3.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect - github.com/googleapis/gax-go/v2 v2.7.0 // indirect + github.com/googleapis/gax-go/v2 v2.7.1 // indirect github.com/gorilla/handlers v1.5.1 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect @@ -152,11 +152,11 @@ require ( github.com/zondax/ledger-go v0.14.1 // indirect go.etcd.io/bbolt v1.3.7 // indirect go.opencensus.io v0.24.0 // indirect - golang.org/x/oauth2 v0.6.0 // indirect + golang.org/x/oauth2 v0.7.0 // indirect golang.org/x/term v0.7.0 // indirect golang.org/x/text v0.9.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect - google.golang.org/api v0.110.0 // indirect + google.golang.org/api v0.114.0 // indirect google.golang.org/appengine v1.6.7 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index cafdd80e8c..d58b95ebb4 100644 --- a/go.sum +++ b/go.sum @@ -73,8 +73,8 @@ cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= -cloud.google.com/go/compute v1.18.0 h1:FEigFqoDbys2cvFkZ9Fjq4gnHBP55anJ0yQyau2f9oY= -cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute v1.19.1 h1:am86mquDUgjGNWxiGn+5PGLbmgiWXlE/yNWpIpNvuXY= +cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= @@ -114,8 +114,8 @@ cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y97 cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= -cloud.google.com/go/iam v0.12.0 h1:DRtTY29b75ciH6Ov1PHb4/iat2CLCvrOm40Q0a6DFpE= -cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iam v0.13.0 h1:+CmB+K0J/33d0zSQ9SlFWUeCCEn5XJA0ZMZ3pHE9u8k= +cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= @@ -665,8 +665,8 @@ github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99 github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= -github.com/googleapis/gax-go/v2 v2.7.0 h1:IcsPKeInNvYi7eqSaDjiZqDDKu5rsmunY0Y1YupQSSQ= -github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= +github.com/googleapis/gax-go/v2 v2.7.1 h1:gF4c0zjUP2H/s/hEGyLA3I0fA2ZWjzYiONAD6cvPr8A= +github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -1346,8 +1346,8 @@ golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= -golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= -golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= +golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= +golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1626,8 +1626,8 @@ google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= -google.golang.org/api v0.110.0 h1:l+rh0KYUooe9JGbGVx71tbFo4SMbMTXK3I3ia2QSEeU= -google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= +google.golang.org/api v0.114.0 h1:1xQPji6cO2E2vLiI+C/XiFAnsn1WV3mjaEwGLhi3grE= +google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1747,8 +1747,8 @@ google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqw google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= -google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= @@ -1790,8 +1790,8 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= -google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= +google.golang.org/grpc v1.56.1 h1:z0dNfjIl0VpaZ9iSVjA6daGatAYwPGstTjt5vkRMFkQ= +google.golang.org/grpc v1.56.1/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= From ce7bedbd0230954e66d61d8ecc61ede42bf8a2fa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 28 Jun 2023 07:18:42 -0700 Subject: [PATCH 036/134] build(deps): bump google.golang.org/protobuf from 1.30.0 to 1.31.0 (#1084) Bumps google.golang.org/protobuf from 1.30.0 to 1.31.0. --- updated-dependencies: - dependency-name: google.golang.org/protobuf dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 4513716d93..b487f32ab9 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( golang.org/x/sys v0.7.0 // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 google.golang.org/grpc v1.56.1 - google.golang.org/protobuf v1.30.0 + google.golang.org/protobuf v1.31.0 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index d58b95ebb4..6e22b529cf 100644 --- a/go.sum +++ b/go.sum @@ -1808,8 +1808,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 07302ffb6692fe849f5f5d393de5db6395e74a53 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Wed, 28 Jun 2023 08:17:04 -0700 Subject: [PATCH 037/134] refactor: log when constructing IBC err ack (#1090) * log with err ack * linter --- tests/integration/slashing.go | 7 +++---- x/ccv/consumer/ibc_module.go | 2 +- x/ccv/consumer/keeper/relay_test.go | 2 +- x/ccv/provider/ibc_module.go | 4 ++-- x/ccv/provider/keeper/relay.go | 6 +++--- x/ccv/types/utils.go | 5 +++++ 6 files changed, 15 insertions(+), 11 deletions(-) diff --git a/tests/integration/slashing.go b/tests/integration/slashing.go index d4e960a9cd..68b632efe1 100644 --- a/tests/integration/slashing.go +++ b/tests/integration/slashing.go @@ -255,7 +255,7 @@ func (s *CCVTestSuite) TestSlashPacketAcknowledgement() { err := consumerKeeper.OnAcknowledgementPacket(s.consumerCtx(), packet, channeltypes.NewResultAcknowledgement(ack.Acknowledgement())) s.Require().NoError(err) - err = consumerKeeper.OnAcknowledgementPacket(s.consumerCtx(), packet, channeltypes.NewErrorAcknowledgement(fmt.Errorf("another error"))) + err = consumerKeeper.OnAcknowledgementPacket(s.consumerCtx(), packet, ccv.NewErrorAcknowledgementWithLog(s.consumerCtx(), fmt.Errorf("another error"))) s.Require().Error(err) } @@ -330,7 +330,8 @@ func (suite *CCVTestSuite) TestOnRecvSlashPacketErrors() { errAck := providerKeeper.OnRecvSlashPacket(ctx, packet, packetData) suite.Require().False(errAck.Success()) errAckCast := errAck.(channeltypes.Acknowledgement) - // TODO: see if there's a way to get error reason like before + // Error strings in err acks are now thrown out by IBC core to prevent app hash. + // Hence a generic error string is expected. suite.Require().Equal("ABCI code: 1: error handling packet: see events for details", errAckCast.GetError()) // Restore init chain height @@ -341,7 +342,6 @@ func (suite *CCVTestSuite) TestOnRecvSlashPacketErrors() { errAck = providerKeeper.OnRecvSlashPacket(ctx, packet, packetData) suite.Require().False(errAck.Success()) errAckCast = errAck.(channeltypes.Acknowledgement) - // TODO: see if there's a way to get error reason like before suite.Require().Equal("ABCI code: 1: error handling packet: see events for details", errAckCast.GetError()) // save current VSC ID @@ -357,7 +357,6 @@ func (suite *CCVTestSuite) TestOnRecvSlashPacketErrors() { errAck = providerKeeper.OnRecvSlashPacket(ctx, packet, packetData) suite.Require().False(errAck.Success()) errAckCast = errAck.(channeltypes.Acknowledgement) - // TODO: see if there's a way to get error reason like before suite.Require().Equal("ABCI code: 1: error handling packet: see events for details", errAckCast.GetError()) // construct slashing packet with non existing validator diff --git a/x/ccv/consumer/ibc_module.go b/x/ccv/consumer/ibc_module.go index d55a1998af..0ca0b29370 100644 --- a/x/ccv/consumer/ibc_module.go +++ b/x/ccv/consumer/ibc_module.go @@ -231,7 +231,7 @@ func (am AppModule) OnRecvPacket( data types.ValidatorSetChangePacketData ) if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { - errAck := channeltypes.NewErrorAcknowledgement(fmt.Errorf("cannot unmarshal CCV packet data")) + errAck := types.NewErrorAcknowledgementWithLog(ctx, fmt.Errorf("cannot unmarshal CCV packet data")) ack = &errAck } else { ack = am.keeper.OnRecvVSCPacket(ctx, packet, data) diff --git a/x/ccv/consumer/keeper/relay_test.go b/x/ccv/consumer/keeper/relay_test.go index 299d316d21..1c2ba5152f 100644 --- a/x/ccv/consumer/keeper/relay_test.go +++ b/x/ccv/consumer/keeper/relay_test.go @@ -279,7 +279,7 @@ func TestOnAcknowledgementPacket(t *testing.T) { ).Return(nil).Times(1), ) - ack = channeltypes.NewErrorAcknowledgement(fmt.Errorf("error")) + ack = types.NewErrorAcknowledgementWithLog(ctx, fmt.Errorf("error")) err = consumerKeeper.OnAcknowledgementPacket(ctx, packet, ack) require.Nil(t, err) } diff --git a/x/ccv/provider/ibc_module.go b/x/ccv/provider/ibc_module.go index b543c8927e..df0f6066a3 100644 --- a/x/ccv/provider/ibc_module.go +++ b/x/ccv/provider/ibc_module.go @@ -180,7 +180,7 @@ func (am AppModule) OnRecvPacket( ) // unmarshall consumer packet if err := ccv.ModuleCdc.UnmarshalJSON(packet.GetData(), &consumerPacket); err != nil { - errAck := channeltypes.NewErrorAcknowledgement(fmt.Errorf("cannot unmarshal CCV packet data")) + errAck := ccv.NewErrorAcknowledgementWithLog(ctx, fmt.Errorf("cannot unmarshal CCV packet data")) ack = &errAck } else { // TODO: call ValidateBasic method on consumer packet data @@ -194,7 +194,7 @@ func (am AppModule) OnRecvPacket( // handle SlashPacket ack = am.keeper.OnRecvSlashPacket(ctx, packet, *consumerPacket.GetSlashPacketData()) default: - errAck := channeltypes.NewErrorAcknowledgement(fmt.Errorf("invalid consumer packet type: %q", consumerPacket.Type)) + errAck := ccv.NewErrorAcknowledgementWithLog(ctx, fmt.Errorf("invalid consumer packet type: %q", consumerPacket.Type)) ack = &errAck } } diff --git a/x/ccv/provider/keeper/relay.go b/x/ccv/provider/keeper/relay.go index 1aa0858da6..350bc968d4 100644 --- a/x/ccv/provider/keeper/relay.go +++ b/x/ccv/provider/keeper/relay.go @@ -33,7 +33,7 @@ func (k Keeper) OnRecvVSCMaturedPacket( } if err := k.QueueThrottledVSCMaturedPacketData(ctx, chainID, packet.Sequence, data); err != nil { - return channeltypes.NewErrorAcknowledgement(fmt.Errorf( + return ccv.NewErrorAcknowledgementWithLog(ctx, fmt.Errorf( "failed to queue VSCMatured packet data: %s", err.Error())) } @@ -330,7 +330,7 @@ func (k Keeper) OnRecvSlashPacket(ctx sdk.Context, packet channeltypes.Packet, d "vscID", data.ValsetUpdateId, "infractionType", data.Infraction, ) - return channeltypes.NewErrorAcknowledgement(err) + return ccv.NewErrorAcknowledgementWithLog(ctx, err) } // The slash packet validator address may be known only on the consumer chain, @@ -366,7 +366,7 @@ func (k Keeper) OnRecvSlashPacket(ctx sdk.Context, packet channeltypes.Packet, d // Queue slash packet data in the same (consumer chain specific) queue as vsc matured packet data, // to enforce order of handling between the two packet data types. if err := k.QueueThrottledSlashPacketData(ctx, chainID, packet.Sequence, data); err != nil { - return channeltypes.NewErrorAcknowledgement(fmt.Errorf("failed to queue slash packet data: %s", err.Error())) + return ccv.NewErrorAcknowledgementWithLog(ctx, fmt.Errorf("failed to queue slash packet data: %s", err.Error())) } k.Logger(ctx).Info("slash packet received and enqueued", diff --git a/x/ccv/types/utils.go b/x/ccv/types/utils.go index f27dab2b04..524725a532 100644 --- a/x/ccv/types/utils.go +++ b/x/ccv/types/utils.go @@ -85,6 +85,11 @@ func SendIBCPacket( return err } +func NewErrorAcknowledgementWithLog(ctx sdk.Context, err error) channeltypes.Acknowledgement { + ctx.Logger().Error("IBC ErrorAcknowledgement constructed", "error", err) + return channeltypes.NewErrorAcknowledgement(err) +} + // AppendMany appends a variable number of byte slices together func AppendMany(byteses ...[]byte) (out []byte) { for _, bytes := range byteses { From 4add79c928e6ee58588e39ea6acbac489d0797e2 Mon Sep 17 00:00:00 2001 From: MSalopek Date: Wed, 28 Jun 2023 19:21:32 +0200 Subject: [PATCH 038/134] chore: remove noisy proto linter (#1100) --- .github/workflows/proto.yml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/.github/workflows/proto.yml b/.github/workflows/proto.yml index c1c302a60f..4f2b512e97 100644 --- a/.github/workflows/proto.yml +++ b/.github/workflows/proto.yml @@ -10,16 +10,6 @@ permissions: contents: read jobs: - lint: - runs-on: ubuntu-latest - timeout-minutes: 5 - steps: - - uses: actions/checkout@v3 - - uses: bufbuild/buf-setup-action@v1.22.0 - - uses: bufbuild/buf-lint-action@v1 - with: - input: "proto" - break-check: runs-on: ubuntu-latest steps: From 7a33cb0ae9ddfc58bd819dba8656dfd0cc423402 Mon Sep 17 00:00:00 2001 From: MSalopek Date: Fri, 30 Jun 2023 11:05:29 +0200 Subject: [PATCH 039/134] fix: make SlashPacketData backward compatible when sending data over the wire (#1093) * fix: use v1 slash types on consumer side * fix: update provider ibc_module to also handle v1 slash packets * chore: update linter * fix problematic packet handling on provider * rm unused function * refactor/test: 1093 continued (#1104) * UnmarshalConsumerPacket func, use it in tests * added test * format --------- Co-authored-by: Marius Poke Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> --- proto/interchain_security/ccv/v1/ccv.proto | 40 +- tests/integration/throttle.go | 37 +- x/ccv/provider/ibc_module.go | 68 +- x/ccv/provider/ibc_module_test.go | 60 ++ x/ccv/provider/proposal_handler_test.go | 3 +- x/ccv/types/ccv.go | 61 +- x/ccv/types/ccv.pb.go | 743 +++++++++++++++++++-- 7 files changed, 919 insertions(+), 93 deletions(-) diff --git a/proto/interchain_security/ccv/v1/ccv.proto b/proto/interchain_security/ccv/v1/ccv.proto index ffae373aa6..1f3722a234 100644 --- a/proto/interchain_security/ccv/v1/ccv.proto +++ b/proto/interchain_security/ccv/v1/ccv.proto @@ -84,4 +84,42 @@ enum ConsumerPacketDataType { // VSCMatured packet CONSUMER_PACKET_TYPE_VSCM = 2 [ (gogoproto.enumvalue_customname) = "VscMaturedPacket" ]; -} \ No newline at end of file +} + +// ConsumerPacketData contains a consumer packet data and a type tag +// that is compatible with ICS v1 and v2 over the wire. It is not used for internal storage. +message ConsumerPacketDataV1 { + ConsumerPacketDataType type = 1; + + oneof data { + SlashPacketDataV1 slashPacketData = 2; + VSCMaturedPacketData vscMaturedPacketData = 3; + } +} + +// This packet is sent from the consumer chain to the provider chain +// It is backward compatible with the ICS v1 and v2 version of the packet. +message SlashPacketDataV1 { + tendermint.abci.Validator validator = 1 [ + (gogoproto.nullable) = false, + (gogoproto.moretags) = "yaml:\"validator\"" + ]; + // map to the infraction block height on the provider + uint64 valset_update_id = 2; + // tell if the slashing is for a downtime or a double-signing infraction + InfractionType infraction = 3; +} + +// InfractionType indicates the infraction type a validator commited. +// NOTE: ccv.InfractionType to maintain compatibility between ICS versions +// using different versions of the cosmos-sdk and ibc-go modules. +enum InfractionType { + option (gogoproto.goproto_enum_prefix) = false; + + // UNSPECIFIED defines an empty infraction type. + INFRACTION_TYPE_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "InfractionEmpty"]; + // DOUBLE_SIGN defines a validator that double-signs a block. + INFRACTION_TYPE_DOUBLE_SIGN = 1 [(gogoproto.enumvalue_customname) = "DoubleSign"]; + // DOWNTIME defines a validator that missed signing too many blocks. + INFRACTION_TYPE_DOWNTIME = 2 [(gogoproto.enumvalue_customname) = "Downtime"]; +} diff --git a/tests/integration/throttle.go b/tests/integration/throttle.go index 92800cd1bb..0620bdd6b6 100644 --- a/tests/integration/throttle.go +++ b/tests/integration/throttle.go @@ -9,6 +9,7 @@ import ( channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" icstestingutils "github.com/cosmos/interchain-security/v3/testutil/ibc_testing" + "github.com/cosmos/interchain-security/v3/x/ccv/provider" providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) @@ -314,8 +315,8 @@ func (s *CCVTestSuite) TestPacketSpam() { // Recv 500 packets from consumer to provider in same block for _, packet := range packets { - consumerPacketData := ccvtypes.ConsumerPacketData{} - ccvtypes.ModuleCdc.MustUnmarshalJSON(packet.GetData(), &consumerPacketData) + consumerPacketData, err := provider.UnmarshalConsumerPacket(packet) // Same func used by provider's OnRecvPacket + s.Require().NoError(err) providerKeeper.OnRecvSlashPacket(s.providerCtx(), packet, *consumerPacketData.GetSlashPacketData()) } @@ -368,8 +369,8 @@ func (s *CCVTestSuite) TestDoubleSignDoesNotAffectThrottling() { // Recv 500 packets from consumer to provider in same block for _, packet := range packets { - consumerPacketData := ccvtypes.ConsumerPacketData{} - ccvtypes.ModuleCdc.MustUnmarshalJSON(packet.GetData(), &consumerPacketData) + consumerPacketData, err := provider.UnmarshalConsumerPacket(packet) // Same func used by provider's OnRecvPacket + s.Require().NoError(err) providerKeeper.OnRecvSlashPacket(s.providerCtx(), packet, *consumerPacketData.GetSlashPacketData()) } @@ -464,8 +465,10 @@ func (s *CCVTestSuite) TestQueueOrdering() { // Recv 500 packets from consumer to provider in same block for i, packet := range packets { - consumerPacketData := ccvtypes.ConsumerPacketData{} - ccvtypes.ModuleCdc.MustUnmarshalJSON(packet.GetData(), &consumerPacketData) + + consumerPacketData, err := provider.UnmarshalConsumerPacket(packet) // Same func used by provider's OnRecvPacket + s.Require().NoError(err) + // Type depends on index packets were appended from above if (i+5)%10 == 0 { vscMaturedPacketData := consumerPacketData.GetVscMaturedPacketData() @@ -678,8 +681,8 @@ func (s *CCVTestSuite) TestSlashSameValidator() { // Recv and queue all slash packets. for _, packet := range packets { - consumerPacketData := ccvtypes.ConsumerPacketData{} - ccvtypes.ModuleCdc.MustUnmarshalJSON(packet.GetData(), &consumerPacketData) + consumerPacketData, err := provider.UnmarshalConsumerPacket(packet) // Same func used by provider's OnRecvPacket + s.Require().NoError(err) providerKeeper.OnRecvSlashPacket(s.providerCtx(), packet, *consumerPacketData.GetSlashPacketData()) } @@ -739,8 +742,8 @@ func (s CCVTestSuite) TestSlashAllValidators() { //nolint:govet // this is a tes // Recv and queue all slash packets. for _, packet := range packets { - consumerPacketData := ccvtypes.ConsumerPacketData{} - ccvtypes.ModuleCdc.MustUnmarshalJSON(packet.GetData(), &consumerPacketData) + consumerPacketData, err := provider.UnmarshalConsumerPacket(packet) // Same func used by provider's OnRecvPacket + s.Require().NoError(err) providerKeeper.OnRecvSlashPacket(s.providerCtx(), packet, *consumerPacketData.GetSlashPacketData()) } @@ -786,10 +789,9 @@ func (s *CCVTestSuite) TestLeadingVSCMaturedAreDequeued() { ibcSeqNum := uint64(i) packet := s.constructSlashPacketFromConsumer(*bundle, *s.providerChain.Vals.Validators[0], stakingtypes.Infraction_INFRACTION_DOWNTIME, ibcSeqNum) - packetData := ccvtypes.ConsumerPacketData{} - ccvtypes.ModuleCdc.MustUnmarshalJSON(packet.GetData(), &packetData) - providerKeeper.OnRecvSlashPacket(s.providerCtx(), - packet, *packetData.GetSlashPacketData()) + consumerPacketData, err := provider.UnmarshalConsumerPacket(packet) // Same func used by provider's OnRecvPacket + s.Require().NoError(err) + providerKeeper.OnRecvSlashPacket(s.providerCtx(), packet, *consumerPacketData.GetSlashPacketData()) } } @@ -877,10 +879,9 @@ func (s *CCVTestSuite) TestVscMaturedHandledPerBlockLimit() { ibcSeqNum := uint64(i) packet := s.constructSlashPacketFromConsumer(*bundle, *s.providerChain.Vals.Validators[0], stakingtypes.Infraction_INFRACTION_DOWNTIME, ibcSeqNum) - packetData := ccvtypes.ConsumerPacketData{} - ccvtypes.ModuleCdc.MustUnmarshalJSON(packet.GetData(), &packetData) - providerKeeper.OnRecvSlashPacket(s.providerCtx(), - packet, *packetData.GetSlashPacketData()) + consumerPacketData, err := provider.UnmarshalConsumerPacket(packet) // Same func used by provider's OnRecvPacket + s.Require().NoError(err) + providerKeeper.OnRecvSlashPacket(s.providerCtx(), packet, *consumerPacketData.GetSlashPacketData()) } } diff --git a/x/ccv/provider/ibc_module.go b/x/ccv/provider/ibc_module.go index df0f6066a3..698d37385b 100644 --- a/x/ccv/provider/ibc_module.go +++ b/x/ccv/provider/ibc_module.go @@ -174,29 +174,26 @@ func (am AppModule) OnRecvPacket( packet channeltypes.Packet, _ sdk.AccAddress, ) ibcexported.Acknowledgement { - var ( - ack ibcexported.Acknowledgement - consumerPacket ccv.ConsumerPacketData - ) - // unmarshall consumer packet - if err := ccv.ModuleCdc.UnmarshalJSON(packet.GetData(), &consumerPacket); err != nil { - errAck := ccv.NewErrorAcknowledgementWithLog(ctx, fmt.Errorf("cannot unmarshal CCV packet data")) + consumerPacket, err := UnmarshalConsumerPacket(packet) + if err != nil { + errAck := ccv.NewErrorAcknowledgementWithLog(ctx, err) + return &errAck + } + + // TODO: call ValidateBasic method on consumer packet data + // See: https://github.com/cosmos/interchain-security/issues/634 + + var ack ibcexported.Acknowledgement + switch consumerPacket.Type { + case ccv.VscMaturedPacket: + // handle VSCMaturedPacket + ack = am.keeper.OnRecvVSCMaturedPacket(ctx, packet, *consumerPacket.GetVscMaturedPacketData()) + case ccv.SlashPacket: + // handle SlashPacket + ack = am.keeper.OnRecvSlashPacket(ctx, packet, *consumerPacket.GetSlashPacketData()) + default: + errAck := ccv.NewErrorAcknowledgementWithLog(ctx, fmt.Errorf("invalid consumer packet type: %q", consumerPacket.Type)) ack = &errAck - } else { - // TODO: call ValidateBasic method on consumer packet data - // See: https://github.com/cosmos/interchain-security/issues/634 - - switch consumerPacket.Type { - case ccv.VscMaturedPacket: - // handle VSCMaturedPacket - ack = am.keeper.OnRecvVSCMaturedPacket(ctx, packet, *consumerPacket.GetVscMaturedPacketData()) - case ccv.SlashPacket: - // handle SlashPacket - ack = am.keeper.OnRecvSlashPacket(ctx, packet, *consumerPacket.GetSlashPacketData()) - default: - errAck := ccv.NewErrorAcknowledgementWithLog(ctx, fmt.Errorf("invalid consumer packet type: %q", consumerPacket.Type)) - ack = &errAck - } } ctx.EventManager().EmitEvent( @@ -210,6 +207,33 @@ func (am AppModule) OnRecvPacket( return ack } +func UnmarshalConsumerPacket(packet channeltypes.Packet) (consumerPacket ccv.ConsumerPacketData, err error) { + // First try unmarshaling into ccv.ConsumerPacketData type + if err := ccv.ModuleCdc.UnmarshalJSON(packet.GetData(), &consumerPacket); err != nil { + // If failed, packet should be a v1 slash packet, retry for ConsumerPacketDataV1 packet type + var v1Packet ccv.ConsumerPacketDataV1 + errV1 := ccv.ModuleCdc.UnmarshalJSON(packet.GetData(), &v1Packet) + if errV1 != nil { + // If neither worked, return error + return ccv.ConsumerPacketData{}, errV1 + } + + // VSC matured packets should not be unmarshaled as v1 packets + if v1Packet.Type == ccv.VscMaturedPacket { + return ccv.ConsumerPacketData{}, fmt.Errorf("VSC matured packets should be correctly unmarshaled") + } + + // Convert from v1 packet type + consumerPacket = ccv.ConsumerPacketData{ + Type: v1Packet.Type, + Data: &ccv.ConsumerPacketData_SlashPacketData{ + SlashPacketData: v1Packet.GetSlashPacketData().FromV1(), + }, + } + } + return consumerPacket, nil +} + // OnAcknowledgementPacket implements the IBCModule interface func (am AppModule) OnAcknowledgementPacket( ctx sdk.Context, diff --git a/x/ccv/provider/ibc_module_test.go b/x/ccv/provider/ibc_module_test.go index 42279fbb73..96e0eb97d1 100644 --- a/x/ccv/provider/ibc_module_test.go +++ b/x/ccv/provider/ibc_module_test.go @@ -7,6 +7,7 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + "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" host "github.com/cosmos/ibc-go/v7/modules/core/24-host" @@ -338,3 +339,62 @@ func TestOnChanOpenConfirm(t *testing.T) { ctrl.Finish() } } + +func TestUnmarshalConsumerPacket(t *testing.T) { + testCases := []struct { + name string + packet channeltypes.Packet + expectedPacketData ccv.ConsumerPacketData + }{ + { + name: "vsc matured", + packet: channeltypes.NewPacket( + ccv.ConsumerPacketData{ + Type: ccv.VscMaturedPacket, + Data: &ccv.ConsumerPacketData_VscMaturedPacketData{ + VscMaturedPacketData: &ccv.VSCMaturedPacketData{ + ValsetUpdateId: 420, + }, + }, + }.GetBytes(), + 342, "sourcePort", "sourceChannel", "destinationPort", "destinationChannel", types.Height{}, 0, + ), + expectedPacketData: ccv.ConsumerPacketData{ + Type: ccv.VscMaturedPacket, + Data: &ccv.ConsumerPacketData_VscMaturedPacketData{ + VscMaturedPacketData: &ccv.VSCMaturedPacketData{ + ValsetUpdateId: 420, + }, + }, + }, + }, + { + name: "slash packet", + packet: channeltypes.NewPacket( + ccv.ConsumerPacketData{ + Type: ccv.SlashPacket, + Data: &ccv.ConsumerPacketData_SlashPacketData{ + SlashPacketData: &ccv.SlashPacketData{ + ValsetUpdateId: 789, + }, + }, + }.GetBytes(), // Note packet data is converted to v1 bytes here + 342, "sourcePort", "sourceChannel", "destinationPort", "destinationChannel", types.Height{}, 0, + ), + expectedPacketData: ccv.ConsumerPacketData{ + Type: ccv.SlashPacket, + Data: &ccv.ConsumerPacketData_SlashPacketData{ + SlashPacketData: &ccv.SlashPacketData{ + ValsetUpdateId: 789, + }, + }, + }, + }, + } + + for _, tc := range testCases { + actualConsumerPacketData, err := provider.UnmarshalConsumerPacket(tc.packet) + require.NoError(t, err) + require.Equal(t, tc.expectedPacketData, actualConsumerPacketData) + } +} diff --git a/x/ccv/provider/proposal_handler_test.go b/x/ccv/provider/proposal_handler_test.go index 4f78695935..a85853a246 100644 --- a/x/ccv/provider/proposal_handler_test.go +++ b/x/ccv/provider/proposal_handler_test.go @@ -81,7 +81,8 @@ 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{ // nolint:staticcheck + // nolint:staticcheck + content: &distributiontypes.CommunityPoolSpendProposal{ Title: "title", Description: "desc", Recipient: "", diff --git a/x/ccv/types/ccv.go b/x/ccv/types/ccv.go index 62111a7b65..e7739b4c2f 100644 --- a/x/ccv/types/ccv.go +++ b/x/ccv/types/ccv.go @@ -59,6 +59,23 @@ func NewSlashPacketData(validator abci.Validator, valUpdateId uint64, infraction } } +// NewSlashPacketDataV1 creates a new SlashPacketDataV1 that uses ccv.InfractionTypes to maintain backward compatibility. +func NewSlashPacketDataV1(validator abci.Validator, valUpdateId uint64, infractionType stakingtypes.Infraction) *SlashPacketDataV1 { + v1Type := InfractionEmpty + switch infractionType { + case stakingtypes.Infraction_INFRACTION_DOWNTIME: + v1Type = Downtime + case stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN: + v1Type = DoubleSign + } + + return &SlashPacketDataV1{ + Validator: validator, + ValsetUpdateId: valUpdateId, + Infraction: v1Type, + } +} + func (vdt SlashPacketData) ValidateBasic() error { if len(vdt.Validator.Address) == 0 || vdt.Validator.Power == 0 { return errorsmod.Wrap(ErrInvalidPacketData, "validator fields cannot be empty") @@ -76,6 +93,10 @@ func (vdt SlashPacketData) GetBytes() []byte { return valDowntimeBytes } +func (vdt SlashPacketData) ToV1() *SlashPacketDataV1 { + return NewSlashPacketDataV1(vdt.Validator, vdt.ValsetUpdateId, vdt.Infraction) +} + func (cp ConsumerPacketData) ValidateBasic() (err error) { switch cp.Type { case VscMaturedPacket: @@ -99,7 +120,45 @@ func (cp ConsumerPacketData) ValidateBasic() (err error) { return } +// Convert to bytes while maintaining over the wire compatibility with previous versions. func (cp ConsumerPacketData) GetBytes() []byte { - bytes := ModuleCdc.MustMarshalJSON(&cp) + return cp.ToV1Bytes() +} + +// ToV1Bytes converts the ConsumerPacketData to JSON byte array compatible +// with the format used by ICS versions using cosmos-sdk v45 (ICS v1 and ICS v2). +func (cp ConsumerPacketData) ToV1Bytes() []byte { + if cp.Type != SlashPacket { + bytes := ModuleCdc.MustMarshalJSON(&cp) + return bytes + } + + sp := cp.GetSlashPacketData() + spdv1 := NewSlashPacketDataV1(sp.Validator, sp.ValsetUpdateId, sp.Infraction) + cpv1 := ConsumerPacketDataV1{ + Type: cp.Type, + Data: &ConsumerPacketDataV1_SlashPacketData{ + SlashPacketData: spdv1, + }, + } + bytes := ModuleCdc.MustMarshalJSON(&cpv1) return bytes } + +// FromV1 converts SlashPacketDataV1 to SlashPacketData. +// Provider must handle both V1 and later versions of the SlashPacketData. +func (vdt1 SlashPacketDataV1) FromV1() *SlashPacketData { + newType := stakingtypes.Infraction_INFRACTION_UNSPECIFIED + switch vdt1.Infraction { + case Downtime: + newType = stakingtypes.Infraction_INFRACTION_DOWNTIME + case DoubleSign: + newType = stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN + } + + return &SlashPacketData{ + Validator: vdt1.Validator, + ValsetUpdateId: vdt1.ValsetUpdateId, + Infraction: newType, + } +} diff --git a/x/ccv/types/ccv.pb.go b/x/ccv/types/ccv.pb.go index 21d0b32f0b..c2f0bd3ecc 100644 --- a/x/ccv/types/ccv.pb.go +++ b/x/ccv/types/ccv.pb.go @@ -57,6 +57,40 @@ func (ConsumerPacketDataType) EnumDescriptor() ([]byte, []int) { return fileDescriptor_68bd5f3242e6f29c, []int{0} } +// InfractionType indicates the infraction type a validator commited. +// NOTE: ccv.InfractionType to maintain compatibility between ICS versions +// using different versions of the cosmos-sdk and ibc-go modules. +type InfractionType int32 + +const ( + // UNSPECIFIED defines an empty infraction type. + InfractionEmpty InfractionType = 0 + // DOUBLE_SIGN defines a validator that double-signs a block. + DoubleSign InfractionType = 1 + // DOWNTIME defines a validator that missed signing too many blocks. + Downtime InfractionType = 2 +) + +var InfractionType_name = map[int32]string{ + 0: "INFRACTION_TYPE_UNSPECIFIED", + 1: "INFRACTION_TYPE_DOUBLE_SIGN", + 2: "INFRACTION_TYPE_DOWNTIME", +} + +var InfractionType_value = map[string]int32{ + "INFRACTION_TYPE_UNSPECIFIED": 0, + "INFRACTION_TYPE_DOUBLE_SIGN": 1, + "INFRACTION_TYPE_DOWNTIME": 2, +} + +func (x InfractionType) String() string { + return proto.EnumName(InfractionType_name, int32(x)) +} + +func (InfractionType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_68bd5f3242e6f29c, []int{1} +} + // This packet is sent from provider chain to consumer chain if the validator // set for consumer chain changes (due to new bonding/unbonding messages or // slashing events) A VSCMatured packet from consumer chain will be sent @@ -466,8 +500,168 @@ func (m *ConsumerPacketDataList) GetList() []ConsumerPacketData { return nil } +// ConsumerPacketData contains a consumer packet data and a type tag +// that is compatible with ICS v1 and v2 over the wire. It is not used for internal storage. +type ConsumerPacketDataV1 struct { + Type ConsumerPacketDataType `protobuf:"varint,1,opt,name=type,proto3,enum=interchain_security.ccv.v1.ConsumerPacketDataType" json:"type,omitempty"` + // Types that are valid to be assigned to Data: + // *ConsumerPacketDataV1_SlashPacketData + // *ConsumerPacketDataV1_VscMaturedPacketData + Data isConsumerPacketDataV1_Data `protobuf_oneof:"data"` +} + +func (m *ConsumerPacketDataV1) Reset() { *m = ConsumerPacketDataV1{} } +func (m *ConsumerPacketDataV1) String() string { return proto.CompactTextString(m) } +func (*ConsumerPacketDataV1) ProtoMessage() {} +func (*ConsumerPacketDataV1) Descriptor() ([]byte, []int) { + return fileDescriptor_68bd5f3242e6f29c, []int{7} +} +func (m *ConsumerPacketDataV1) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ConsumerPacketDataV1) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ConsumerPacketDataV1.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 *ConsumerPacketDataV1) XXX_Merge(src proto.Message) { + xxx_messageInfo_ConsumerPacketDataV1.Merge(m, src) +} +func (m *ConsumerPacketDataV1) XXX_Size() int { + return m.Size() +} +func (m *ConsumerPacketDataV1) XXX_DiscardUnknown() { + xxx_messageInfo_ConsumerPacketDataV1.DiscardUnknown(m) +} + +var xxx_messageInfo_ConsumerPacketDataV1 proto.InternalMessageInfo + +type isConsumerPacketDataV1_Data interface { + isConsumerPacketDataV1_Data() + MarshalTo([]byte) (int, error) + Size() int +} + +type ConsumerPacketDataV1_SlashPacketData struct { + SlashPacketData *SlashPacketDataV1 `protobuf:"bytes,2,opt,name=slashPacketData,proto3,oneof" json:"slashPacketData,omitempty"` +} +type ConsumerPacketDataV1_VscMaturedPacketData struct { + VscMaturedPacketData *VSCMaturedPacketData `protobuf:"bytes,3,opt,name=vscMaturedPacketData,proto3,oneof" json:"vscMaturedPacketData,omitempty"` +} + +func (*ConsumerPacketDataV1_SlashPacketData) isConsumerPacketDataV1_Data() {} +func (*ConsumerPacketDataV1_VscMaturedPacketData) isConsumerPacketDataV1_Data() {} + +func (m *ConsumerPacketDataV1) GetData() isConsumerPacketDataV1_Data { + if m != nil { + return m.Data + } + return nil +} + +func (m *ConsumerPacketDataV1) GetType() ConsumerPacketDataType { + if m != nil { + return m.Type + } + return UnspecifiedPacket +} + +func (m *ConsumerPacketDataV1) GetSlashPacketData() *SlashPacketDataV1 { + if x, ok := m.GetData().(*ConsumerPacketDataV1_SlashPacketData); ok { + return x.SlashPacketData + } + return nil +} + +func (m *ConsumerPacketDataV1) GetVscMaturedPacketData() *VSCMaturedPacketData { + if x, ok := m.GetData().(*ConsumerPacketDataV1_VscMaturedPacketData); ok { + return x.VscMaturedPacketData + } + return nil +} + +// XXX_OneofWrappers is for the internal use of the proto package. +func (*ConsumerPacketDataV1) XXX_OneofWrappers() []interface{} { + return []interface{}{ + (*ConsumerPacketDataV1_SlashPacketData)(nil), + (*ConsumerPacketDataV1_VscMaturedPacketData)(nil), + } +} + +// This packet is sent from the consumer chain to the provider chain +// It is backward compatible with the ICS v1 and v2 version of the packet. +type SlashPacketDataV1 struct { + Validator types.Validator `protobuf:"bytes,1,opt,name=validator,proto3" json:"validator" yaml:"validator"` + // map to the infraction block height on the provider + ValsetUpdateId uint64 `protobuf:"varint,2,opt,name=valset_update_id,json=valsetUpdateId,proto3" json:"valset_update_id,omitempty"` + // tell if the slashing is for a downtime or a double-signing infraction + Infraction InfractionType `protobuf:"varint,3,opt,name=infraction,proto3,enum=interchain_security.ccv.v1.InfractionType" json:"infraction,omitempty"` +} + +func (m *SlashPacketDataV1) Reset() { *m = SlashPacketDataV1{} } +func (m *SlashPacketDataV1) String() string { return proto.CompactTextString(m) } +func (*SlashPacketDataV1) ProtoMessage() {} +func (*SlashPacketDataV1) Descriptor() ([]byte, []int) { + return fileDescriptor_68bd5f3242e6f29c, []int{8} +} +func (m *SlashPacketDataV1) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SlashPacketDataV1) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_SlashPacketDataV1.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 *SlashPacketDataV1) XXX_Merge(src proto.Message) { + xxx_messageInfo_SlashPacketDataV1.Merge(m, src) +} +func (m *SlashPacketDataV1) XXX_Size() int { + return m.Size() +} +func (m *SlashPacketDataV1) XXX_DiscardUnknown() { + xxx_messageInfo_SlashPacketDataV1.DiscardUnknown(m) +} + +var xxx_messageInfo_SlashPacketDataV1 proto.InternalMessageInfo + +func (m *SlashPacketDataV1) GetValidator() types.Validator { + if m != nil { + return m.Validator + } + return types.Validator{} +} + +func (m *SlashPacketDataV1) GetValsetUpdateId() uint64 { + if m != nil { + return m.ValsetUpdateId + } + return 0 +} + +func (m *SlashPacketDataV1) GetInfraction() InfractionType { + if m != nil { + return m.Infraction + } + return InfractionEmpty +} + func init() { proto.RegisterEnum("interchain_security.ccv.v1.ConsumerPacketDataType", ConsumerPacketDataType_name, ConsumerPacketDataType_value) + proto.RegisterEnum("interchain_security.ccv.v1.InfractionType", InfractionType_name, InfractionType_value) proto.RegisterType((*ValidatorSetChangePacketData)(nil), "interchain_security.ccv.v1.ValidatorSetChangePacketData") proto.RegisterType((*ValidatorSetChangePackets)(nil), "interchain_security.ccv.v1.ValidatorSetChangePackets") proto.RegisterType((*VSCMaturedPacketData)(nil), "interchain_security.ccv.v1.VSCMaturedPacketData") @@ -475,6 +669,8 @@ func init() { proto.RegisterType((*MaturedUnbondingOps)(nil), "interchain_security.ccv.v1.MaturedUnbondingOps") proto.RegisterType((*ConsumerPacketData)(nil), "interchain_security.ccv.v1.ConsumerPacketData") proto.RegisterType((*ConsumerPacketDataList)(nil), "interchain_security.ccv.v1.ConsumerPacketDataList") + proto.RegisterType((*ConsumerPacketDataV1)(nil), "interchain_security.ccv.v1.ConsumerPacketDataV1") + proto.RegisterType((*SlashPacketDataV1)(nil), "interchain_security.ccv.v1.SlashPacketDataV1") } func init() { @@ -482,51 +678,60 @@ func init() { } var fileDescriptor_68bd5f3242e6f29c = []byte{ - // 697 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x94, 0xcf, 0x6a, 0xdb, 0x4a, - 0x14, 0xc6, 0xa5, 0x58, 0x04, 0x32, 0x86, 0x44, 0xd1, 0xf5, 0xbd, 0x38, 0xba, 0xad, 0x22, 0x44, - 0xa0, 0xa6, 0xa5, 0x52, 0xad, 0x74, 0x51, 0xda, 0x4d, 0x63, 0xc7, 0xc1, 0xa6, 0xf9, 0x63, 0xa4, - 0x38, 0xa5, 0xdd, 0x88, 0xb1, 0x34, 0xb1, 0x07, 0xdb, 0x1a, 0xa3, 0x19, 0x8b, 0xfa, 0x0d, 0x4a, - 0x56, 0x7d, 0x81, 0xac, 0x4a, 0x1f, 0xa4, 0xbb, 0x2c, 0x03, 0xdd, 0x64, 0x15, 0x4a, 0xf2, 0x06, - 0x7d, 0x82, 0x22, 0x59, 0x76, 0x1c, 0x5b, 0x31, 0x64, 0xe5, 0xf1, 0x99, 0x73, 0x3e, 0xf1, 0xfd, - 0xe6, 0xe3, 0x80, 0x2d, 0xec, 0x33, 0x14, 0xb8, 0x6d, 0x88, 0x7d, 0x87, 0x22, 0x77, 0x10, 0x60, - 0x36, 0x34, 0x5c, 0x37, 0x34, 0xc2, 0x62, 0xf4, 0xa3, 0xf7, 0x03, 0xc2, 0x88, 0x24, 0xa7, 0x74, - 0xe9, 0xd1, 0x75, 0x58, 0x94, 0xb7, 0x5c, 0x42, 0x7b, 0x84, 0x1a, 0x94, 0xc1, 0x0e, 0xf6, 0x5b, - 0x46, 0x58, 0x6c, 0x22, 0x06, 0x8b, 0xe3, 0xff, 0x23, 0x05, 0x39, 0xd7, 0x22, 0x2d, 0x12, 0x1f, - 0x8d, 0xe8, 0x94, 0x54, 0xff, 0x67, 0xc8, 0xf7, 0x50, 0xd0, 0xc3, 0x3e, 0x33, 0x60, 0xd3, 0xc5, - 0x06, 0x1b, 0xf6, 0x11, 0x1d, 0x5d, 0x6a, 0x57, 0x3c, 0x78, 0x72, 0x02, 0xbb, 0xd8, 0x83, 0x8c, - 0x04, 0x36, 0x62, 0xe5, 0x36, 0xf4, 0x5b, 0xa8, 0x0e, 0xdd, 0x0e, 0x62, 0xbb, 0x90, 0x41, 0x89, - 0x80, 0xf5, 0x70, 0x7c, 0xef, 0x0c, 0xfa, 0x1e, 0x64, 0x88, 0xe6, 0x79, 0x35, 0x53, 0xc8, 0x9a, - 0xaa, 0x7e, 0xa7, 0xac, 0x47, 0xca, 0xfa, 0x44, 0xa9, 0x11, 0x37, 0x96, 0xd4, 0x8b, 0xeb, 0x4d, - 0xee, 0xcf, 0xf5, 0x66, 0x7e, 0x08, 0x7b, 0xdd, 0xb7, 0xda, 0x9c, 0x90, 0x66, 0x89, 0xe1, 0xfd, - 0x11, 0x2a, 0x15, 0x40, 0x54, 0xa3, 0x88, 0x25, 0x4d, 0x0e, 0xf6, 0xf2, 0x4b, 0x2a, 0x5f, 0x10, - 0xac, 0xd5, 0x51, 0x7d, 0xd4, 0x58, 0xf3, 0xa4, 0xa7, 0x00, 0xd0, 0x2e, 0xa4, 0x6d, 0x07, 0xba, - 0x1d, 0x9a, 0xcf, 0xa8, 0x99, 0xc2, 0x8a, 0xb5, 0x12, 0x57, 0x76, 0xdc, 0x0e, 0xd5, 0x08, 0xd8, - 0x78, 0xc8, 0x19, 0x95, 0x2c, 0x20, 0x74, 0x31, 0x65, 0x89, 0x93, 0x37, 0xfa, 0xc3, 0xec, 0xf5, - 0x45, 0x78, 0x4a, 0x42, 0xe4, 0xd0, 0x8a, 0xb5, 0xb4, 0xf7, 0x20, 0x77, 0x62, 0x97, 0x0f, 0x20, - 0x1b, 0x04, 0xc8, 0x9b, 0x42, 0x98, 0xe6, 0x88, 0x4f, 0x73, 0xa4, 0xfd, 0xe2, 0xc1, 0x9a, 0x1d, - 0x19, 0x98, 0x9a, 0xb6, 0xc0, 0xca, 0x84, 0x51, 0x3c, 0x96, 0x35, 0xe5, 0x87, 0xc1, 0x97, 0xf2, - 0x09, 0x72, 0x71, 0x06, 0xb9, 0x66, 0xdd, 0xc9, 0x3c, 0x82, 0x71, 0x09, 0x00, 0xec, 0x9f, 0x06, - 0xd0, 0x65, 0x98, 0xf8, 0xf9, 0x8c, 0xca, 0x17, 0x56, 0x4d, 0x4d, 0x1f, 0xa5, 0x51, 0x1f, 0xa7, - 0x2f, 0x49, 0xa3, 0x5e, 0x9b, 0x74, 0x5a, 0x53, 0x53, 0xda, 0x33, 0xf0, 0x4f, 0x02, 0xa5, 0xe1, - 0x37, 0x89, 0xef, 0x61, 0xbf, 0x75, 0xd4, 0xa7, 0x92, 0x08, 0x32, 0xd8, 0x1b, 0x65, 0x49, 0xb0, - 0xa2, 0xa3, 0xf6, 0x63, 0x09, 0x48, 0x65, 0xe2, 0xd3, 0x41, 0x0f, 0x05, 0x53, 0x04, 0xf6, 0x80, - 0x10, 0x45, 0x36, 0x36, 0xbf, 0x6a, 0x9a, 0x8b, 0xde, 0x6a, 0x7e, 0xfa, 0x78, 0xd8, 0x47, 0x56, - 0x3c, 0x2f, 0x7d, 0x04, 0x6b, 0xf4, 0x3e, 0xdc, 0xd8, 0x74, 0xd6, 0x7c, 0xb1, 0x48, 0x72, 0xe6, - 0x3d, 0xaa, 0x9c, 0x35, 0xab, 0x22, 0x9d, 0x82, 0x5c, 0x48, 0xdd, 0xb9, 0x87, 0x8f, 0x71, 0x65, - 0xcd, 0x57, 0x0b, 0xc3, 0x95, 0x12, 0x98, 0x2a, 0x67, 0xa5, 0xea, 0x95, 0x96, 0x81, 0xe0, 0x41, - 0x06, 0xb5, 0x26, 0xf8, 0x6f, 0xde, 0xe8, 0x3e, 0xa6, 0x4c, 0xaa, 0xde, 0x8b, 0xb5, 0xfe, 0x38, - 0x54, 0xd3, 0x61, 0x7e, 0xfe, 0x93, 0x4f, 0xfb, 0x48, 0x44, 0x53, 0x7a, 0x07, 0xd4, 0xf2, 0xd1, - 0xa1, 0xdd, 0x38, 0xa8, 0x58, 0x4e, 0x7d, 0xa7, 0xfc, 0xa1, 0x72, 0xec, 0x1c, 0x7f, 0xaa, 0x57, - 0x9c, 0xc6, 0xa1, 0x5d, 0xaf, 0x94, 0x6b, 0x7b, 0xb5, 0xca, 0xae, 0xc8, 0xc9, 0xff, 0x9e, 0x9d, - 0xab, 0xeb, 0x0d, 0x9f, 0xf6, 0x91, 0x8b, 0x4f, 0xf1, 0xd8, 0x87, 0x64, 0x00, 0x39, 0x75, 0xd8, - 0xde, 0xdf, 0xb1, 0xab, 0x22, 0x2f, 0xaf, 0x9d, 0x9d, 0xab, 0xd9, 0x29, 0xe6, 0xd2, 0x36, 0xd8, - 0x48, 0x1d, 0x88, 0xc8, 0x89, 0x4b, 0x72, 0xee, 0xec, 0x5c, 0x15, 0x4f, 0x66, 0x68, 0xc9, 0xc2, - 0xd7, 0xef, 0x0a, 0x57, 0x3a, 0xbc, 0xb8, 0x51, 0xf8, 0xcb, 0x1b, 0x85, 0xff, 0x7d, 0xa3, 0xf0, - 0xdf, 0x6e, 0x15, 0xee, 0xf2, 0x56, 0xe1, 0xae, 0x6e, 0x15, 0xee, 0xf3, 0xeb, 0x16, 0x66, 0xed, - 0x41, 0x53, 0x77, 0x49, 0xcf, 0x48, 0x56, 0xeb, 0x1d, 0xaa, 0x97, 0x93, 0x1d, 0x1d, 0x6e, 0x1b, - 0x5f, 0xe2, 0x45, 0x1d, 0xaf, 0xcc, 0xe6, 0x72, 0xbc, 0x33, 0xb7, 0xff, 0x06, 0x00, 0x00, 0xff, - 0xff, 0xc0, 0xe2, 0x3f, 0x59, 0xd0, 0x05, 0x00, 0x00, + // 836 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x56, 0xcf, 0x6e, 0xe2, 0x46, + 0x1c, 0xb6, 0x01, 0xad, 0x9a, 0xa1, 0x22, 0xce, 0x2c, 0xad, 0x58, 0x6f, 0xcb, 0x5a, 0xd6, 0x4a, + 0x45, 0xa9, 0xd6, 0x2e, 0x64, 0x0f, 0x55, 0x7b, 0x69, 0x00, 0xa7, 0x71, 0x9b, 0x90, 0xc8, 0x06, + 0x56, 0xdb, 0x8b, 0x35, 0xd8, 0x13, 0x32, 0x0a, 0xd8, 0xc8, 0x33, 0xb8, 0xe5, 0x0d, 0x2a, 0x4e, + 0x7d, 0x01, 0x4e, 0x55, 0x0f, 0xfb, 0x18, 0xbd, 0xed, 0x71, 0xa5, 0x5e, 0xf6, 0xd2, 0xa8, 0x4a, + 0xde, 0xa0, 0x4f, 0x50, 0xd9, 0xfc, 0xc7, 0x06, 0x29, 0x52, 0xa5, 0xf6, 0x84, 0x19, 0xff, 0xbe, + 0x4f, 0xf3, 0xfd, 0x19, 0x79, 0xc0, 0x73, 0xe2, 0x32, 0xec, 0xdb, 0xd7, 0x88, 0xb8, 0x16, 0xc5, + 0xf6, 0xd0, 0x27, 0x6c, 0xa4, 0xda, 0x76, 0xa0, 0x06, 0xe5, 0xf0, 0x47, 0x19, 0xf8, 0x1e, 0xf3, + 0xa0, 0x98, 0x30, 0xa5, 0x84, 0xaf, 0x83, 0xb2, 0xf8, 0xdc, 0xf6, 0x68, 0xdf, 0xa3, 0x2a, 0x65, + 0xe8, 0x86, 0xb8, 0x5d, 0x35, 0x28, 0x77, 0x30, 0x43, 0xe5, 0xf9, 0xff, 0x29, 0x83, 0x98, 0xef, + 0x7a, 0x5d, 0x2f, 0x7a, 0x54, 0xc3, 0xa7, 0xd9, 0xea, 0x53, 0x86, 0x5d, 0x07, 0xfb, 0x7d, 0xe2, + 0x32, 0x15, 0x75, 0x6c, 0xa2, 0xb2, 0xd1, 0x00, 0xd3, 0xe9, 0x4b, 0xf9, 0x3d, 0x0f, 0x3e, 0x69, + 0xa3, 0x1e, 0x71, 0x10, 0xf3, 0x7c, 0x13, 0xb3, 0xda, 0x35, 0x72, 0xbb, 0xf8, 0x12, 0xd9, 0x37, + 0x98, 0xd5, 0x11, 0x43, 0xd0, 0x03, 0x07, 0xc1, 0xfc, 0xbd, 0x35, 0x1c, 0x38, 0x88, 0x61, 0x5a, + 0xe0, 0xa5, 0x74, 0x29, 0x5b, 0x91, 0x94, 0x25, 0xb3, 0x12, 0x32, 0x2b, 0x0b, 0xa6, 0x56, 0x34, + 0x58, 0x95, 0xde, 0xde, 0x3e, 0xe3, 0xfe, 0xbe, 0x7d, 0x56, 0x18, 0xa1, 0x7e, 0xef, 0x2b, 0x39, + 0x46, 0x24, 0x1b, 0x42, 0xb0, 0x0e, 0xa1, 0xb0, 0x04, 0xc2, 0x35, 0x8a, 0xd9, 0x6c, 0xc8, 0x22, + 0x4e, 0x21, 0x25, 0xf1, 0xa5, 0x8c, 0x91, 0x9b, 0xae, 0x4f, 0x07, 0x75, 0x07, 0x7e, 0x0a, 0x00, + 0xed, 0x21, 0x7a, 0x6d, 0x21, 0xfb, 0x86, 0x16, 0xd2, 0x52, 0xba, 0xb4, 0x67, 0xec, 0x45, 0x2b, + 0xc7, 0xf6, 0x0d, 0x95, 0x3d, 0xf0, 0x64, 0x9b, 0x32, 0x0a, 0x0d, 0x90, 0xe9, 0x11, 0xca, 0x66, + 0x4a, 0xbe, 0x54, 0xb6, 0x7b, 0xaf, 0xec, 0xb2, 0xa7, 0x9a, 0x09, 0x15, 0x1a, 0x11, 0x97, 0xfc, + 0x0d, 0xc8, 0xb7, 0xcd, 0xda, 0x39, 0x62, 0x43, 0x1f, 0x3b, 0x2b, 0x16, 0x26, 0x29, 0xe2, 0x93, + 0x14, 0xc9, 0x7f, 0xf0, 0x60, 0xdf, 0x0c, 0x05, 0xac, 0xa0, 0x0d, 0xb0, 0xb7, 0xf0, 0x28, 0x82, + 0x65, 0x2b, 0xe2, 0x76, 0xe3, 0xab, 0x85, 0x99, 0xe5, 0xc2, 0x86, 0xe5, 0xb2, 0xb1, 0xa4, 0x79, + 0x80, 0xc7, 0x55, 0x00, 0x88, 0x7b, 0xe5, 0x23, 0x9b, 0x11, 0xcf, 0x2d, 0xa4, 0x25, 0xbe, 0x94, + 0xab, 0xc8, 0xca, 0xb4, 0x8d, 0xca, 0xbc, 0x7d, 0xb3, 0x36, 0x2a, 0xfa, 0x62, 0xd2, 0x58, 0x41, + 0xc9, 0x9f, 0x81, 0xc7, 0x33, 0x53, 0x5a, 0x6e, 0xc7, 0x73, 0x1d, 0xe2, 0x76, 0x2f, 0x06, 0x14, + 0x0a, 0x20, 0x4d, 0x9c, 0x69, 0x97, 0x32, 0x46, 0xf8, 0x28, 0xff, 0x96, 0x02, 0xb0, 0xe6, 0xb9, + 0x74, 0xd8, 0xc7, 0xfe, 0x8a, 0x03, 0x27, 0x20, 0x13, 0x56, 0x36, 0x12, 0x9f, 0xab, 0x54, 0x76, + 0x65, 0x15, 0x47, 0x37, 0x47, 0x03, 0x6c, 0x44, 0x78, 0xf8, 0x0a, 0xec, 0xd3, 0x75, 0x73, 0x23, + 0xd1, 0xd9, 0xca, 0xe7, 0xbb, 0x28, 0x37, 0xf2, 0x38, 0xe5, 0x8c, 0x4d, 0x16, 0x78, 0x05, 0xf2, + 0x01, 0xb5, 0x63, 0xc1, 0x47, 0x76, 0x65, 0x2b, 0x5f, 0xec, 0x2c, 0x57, 0x42, 0x61, 0x4e, 0x39, + 0x23, 0x91, 0xaf, 0xfa, 0x08, 0x64, 0x1c, 0xc4, 0x90, 0xdc, 0x01, 0x1f, 0xc7, 0x85, 0x9e, 0x11, + 0xca, 0xe0, 0xe9, 0x5a, 0xad, 0x95, 0x87, 0x59, 0xb5, 0x56, 0xe6, 0x37, 0x29, 0x90, 0x8f, 0x8f, + 0xb4, 0xcb, 0xff, 0x5a, 0x1a, 0xaf, 0xb7, 0xa5, 0xf1, 0xe2, 0x01, 0x69, 0xb4, 0xcb, 0xff, 0x87, + 0x3c, 0xfe, 0xe4, 0xc1, 0x41, 0x6c, 0x63, 0xff, 0xf1, 0xc1, 0xfd, 0x2e, 0xe1, 0xe0, 0x1e, 0xee, + 0x52, 0xbe, 0x3c, 0xbc, 0x51, 0x48, 0x2b, 0xe8, 0xc3, 0xdf, 0xf9, 0xa4, 0xc2, 0x85, 0x63, 0xf0, + 0x6b, 0x20, 0xd5, 0x2e, 0x1a, 0x66, 0xeb, 0x5c, 0x33, 0xac, 0xcb, 0xe3, 0xda, 0xf7, 0x5a, 0xd3, + 0x6a, 0xbe, 0xbe, 0xd4, 0xac, 0x56, 0xc3, 0xbc, 0xd4, 0x6a, 0xfa, 0x89, 0xae, 0xd5, 0x05, 0x4e, + 0xfc, 0x68, 0x3c, 0x91, 0x0e, 0x5a, 0x2e, 0x1d, 0x60, 0x9b, 0x5c, 0x91, 0xb9, 0x87, 0x50, 0x05, + 0x62, 0x22, 0xd8, 0x3c, 0x3b, 0x36, 0x4f, 0x05, 0x5e, 0xdc, 0x1f, 0x4f, 0xa4, 0xec, 0x8a, 0xb1, + 0xf0, 0x08, 0x3c, 0x49, 0x04, 0x84, 0xa9, 0x09, 0x29, 0x31, 0x3f, 0x9e, 0x48, 0x42, 0x7b, 0x23, + 0x29, 0x31, 0xf3, 0xf3, 0xaf, 0x45, 0xee, 0xf0, 0x0d, 0x0f, 0x72, 0xeb, 0x12, 0xe1, 0x4b, 0xf0, + 0x54, 0x6f, 0x9c, 0x18, 0xc7, 0xb5, 0xa6, 0x7e, 0xd1, 0x48, 0xda, 0xf6, 0xe3, 0xf1, 0x44, 0xda, + 0x5f, 0x82, 0xb4, 0xfe, 0x80, 0x8d, 0xa0, 0x1a, 0x47, 0xd5, 0x2f, 0x5a, 0xd5, 0x33, 0xcd, 0x32, + 0xf5, 0x6f, 0x1b, 0x02, 0x2f, 0xe6, 0xc6, 0x13, 0x09, 0xd4, 0xbd, 0x61, 0xa7, 0x87, 0x4d, 0xd2, + 0x75, 0xe1, 0x21, 0x28, 0xc4, 0x01, 0xaf, 0x1a, 0x4d, 0xfd, 0x5c, 0x13, 0x52, 0xe2, 0x87, 0xe3, + 0x89, 0xf4, 0x41, 0xdd, 0xfb, 0xd1, 0x65, 0xa4, 0x8f, 0xa7, 0x7b, 0xad, 0x36, 0xde, 0xde, 0x15, + 0xf9, 0x77, 0x77, 0x45, 0xfe, 0xaf, 0xbb, 0x22, 0xff, 0xcb, 0x7d, 0x91, 0x7b, 0x77, 0x5f, 0xe4, + 0xde, 0xdf, 0x17, 0xb9, 0x1f, 0x5e, 0x76, 0x09, 0xbb, 0x1e, 0x76, 0x14, 0xdb, 0xeb, 0xab, 0xb3, + 0x2b, 0xc1, 0x32, 0xd2, 0x17, 0x8b, 0xbb, 0x45, 0x70, 0xa4, 0xfe, 0x14, 0x5d, 0x30, 0xa2, 0x4f, + 0x7d, 0xe7, 0x51, 0xf4, 0xad, 0x3f, 0xfa, 0x27, 0x00, 0x00, 0xff, 0xff, 0x8f, 0xbf, 0xfc, 0xd2, + 0x88, 0x08, 0x00, 0x00, } func (m *ValidatorSetChangePacketData) Marshal() (dAtA []byte, err error) { @@ -845,6 +1050,128 @@ func (m *ConsumerPacketDataList) MarshalToSizedBuffer(dAtA []byte) (int, error) return len(dAtA) - i, nil } +func (m *ConsumerPacketDataV1) 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 *ConsumerPacketDataV1) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ConsumerPacketDataV1) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Data != nil { + { + size := m.Data.Size() + i -= size + if _, err := m.Data.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + } + } + if m.Type != 0 { + i = encodeVarintCcv(dAtA, i, uint64(m.Type)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *ConsumerPacketDataV1_SlashPacketData) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ConsumerPacketDataV1_SlashPacketData) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.SlashPacketData != nil { + { + size, err := m.SlashPacketData.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCcv(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + return len(dAtA) - i, nil +} +func (m *ConsumerPacketDataV1_VscMaturedPacketData) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ConsumerPacketDataV1_VscMaturedPacketData) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.VscMaturedPacketData != nil { + { + size, err := m.VscMaturedPacketData.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCcv(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + return len(dAtA) - i, nil +} +func (m *SlashPacketDataV1) 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 *SlashPacketDataV1) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SlashPacketDataV1) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Infraction != 0 { + i = encodeVarintCcv(dAtA, i, uint64(m.Infraction)) + i-- + dAtA[i] = 0x18 + } + if m.ValsetUpdateId != 0 { + i = encodeVarintCcv(dAtA, i, uint64(m.ValsetUpdateId)) + i-- + dAtA[i] = 0x10 + } + { + size, err := m.Validator.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCcv(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func encodeVarintCcv(dAtA []byte, offset int, v uint64) int { offset -= sovCcv(v) base := offset @@ -994,13 +1321,69 @@ func (m *ConsumerPacketDataList) Size() (n int) { return n } -func sovCcv(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 +func (m *ConsumerPacketDataV1) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Type != 0 { + n += 1 + sovCcv(uint64(m.Type)) + } + if m.Data != nil { + n += m.Data.Size() + } + return n } -func sozCcv(x uint64) (n int) { - return sovCcv(uint64((x << 1) ^ uint64((int64(x) >> 63)))) + +func (m *ConsumerPacketDataV1_SlashPacketData) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.SlashPacketData != nil { + l = m.SlashPacketData.Size() + n += 1 + l + sovCcv(uint64(l)) + } + return n } -func (m *ValidatorSetChangePacketData) Unmarshal(dAtA []byte) error { +func (m *ConsumerPacketDataV1_VscMaturedPacketData) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.VscMaturedPacketData != nil { + l = m.VscMaturedPacketData.Size() + n += 1 + l + sovCcv(uint64(l)) + } + return n +} +func (m *SlashPacketDataV1) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Validator.Size() + n += 1 + l + sovCcv(uint64(l)) + if m.ValsetUpdateId != 0 { + n += 1 + sovCcv(uint64(m.ValsetUpdateId)) + } + if m.Infraction != 0 { + n += 1 + sovCcv(uint64(m.Infraction)) + } + return n +} + +func sovCcv(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozCcv(x uint64) (n int) { + return sovCcv(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *ValidatorSetChangePacketData) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1758,6 +2141,266 @@ func (m *ConsumerPacketDataList) Unmarshal(dAtA []byte) error { } return nil } +func (m *ConsumerPacketDataV1) 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 ErrIntOverflowCcv + } + 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: ConsumerPacketDataV1: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ConsumerPacketDataV1: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType) + } + m.Type = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCcv + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Type |= ConsumerPacketDataType(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SlashPacketData", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCcv + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCcv + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCcv + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &SlashPacketDataV1{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Data = &ConsumerPacketDataV1_SlashPacketData{v} + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field VscMaturedPacketData", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCcv + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCcv + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCcv + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &VSCMaturedPacketData{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Data = &ConsumerPacketDataV1_VscMaturedPacketData{v} + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCcv(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCcv + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SlashPacketDataV1) 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 ErrIntOverflowCcv + } + 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: SlashPacketDataV1: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SlashPacketDataV1: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Validator", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCcv + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCcv + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCcv + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Validator.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ValsetUpdateId", wireType) + } + m.ValsetUpdateId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCcv + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ValsetUpdateId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Infraction", wireType) + } + m.Infraction = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCcv + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Infraction |= InfractionType(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipCcv(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCcv + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipCcv(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 From bcb2b27e8085cdd129a846fd76ef3217ec1bc8ee Mon Sep 17 00:00:00 2001 From: MSalopek Date: Fri, 30 Jun 2023 13:26:08 +0200 Subject: [PATCH 040/134] chore: update CHANGELOG.md for v3 (#1108) * chore: update CHANGELOG.md for v3 Update changelog to include note about fixing SlashPacket compatibility over the Wire * Update CHANGELOG.md --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c7cb03404c..c07c612136 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,8 +8,9 @@ Add an entry to the unreleased section whenever merging a PR to main that is not Date: June 21st, 2023 -Interchain Security v3 uses SDK 0.47 and IBC 7. +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). From d16c7669b4f23380a50c8dedfaf6d25f50ca0edd Mon Sep 17 00:00:00 2001 From: yaruwangway <69694322+yaruwangway@users.noreply.github.com> Date: Wed, 5 Jul 2023 14:33:34 +0200 Subject: [PATCH 041/134] fix: `AttributeDistributionTotal` in event emit (#1097) * fix: emitted distribution events * docs: update changelog * fix: lint --------- Co-authored-by: MSalopek --- CHANGELOG.md | 2 ++ x/ccv/consumer/keeper/distribution.go | 9 ++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c07c612136..7f6893544e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ Add an entry to the unreleased section whenever merging a PR to main that is not targeted at a specific release. These entries will eventually be included in a release. +* (fix) [#720](https://github.com/cosmos/interchain-security/issues/720) Fix the attribute `AttributeDistributionTotal` value in `FeeDistribution` event emit. + ## v3.0.0 Date: June 21st, 2023 diff --git a/x/ccv/consumer/keeper/distribution.go b/x/ccv/consumer/keeper/distribution.go index e2c8d2a403..9d59be2f89 100644 --- a/x/ccv/consumer/keeper/distribution.go +++ b/x/ccv/consumer/keeper/distribution.go @@ -113,10 +113,12 @@ func (k Keeper) SendRewardsToProvider(ctx sdk.Context) error { timeoutTimestamp := uint64(ctx.BlockTime().Add(transferTimeoutPeriod).UnixNano()) sentCoins := sdk.NewCoins() + var allBalances sdk.Coins // iterate over all whitelisted reward denoms for _, denom := range k.AllowedRewardDenoms(ctx) { // get the balance of the denom in the toSendToProviderTokens address balance := k.bankKeeper.GetBalance(ctx, tstProviderAddr, denom) + allBalances = allBalances.Add(balance) // if the balance is not zero, if !balance.IsZero() { @@ -138,11 +140,8 @@ func (k Keeper) SendRewardsToProvider(ctx sdk.Context) error { } } - consumerFeePoolAddr := k.authKeeper.GetModuleAccount(ctx, k.feeCollectorName).GetAddress() - fpTokens := k.bankKeeper.GetAllBalances(ctx, consumerFeePoolAddr) - k.Logger(ctx).Info("sent block rewards to provider", - "total fee pool", fpTokens.String(), + "total fee pool", allBalances.String(), "sent", sentCoins.String(), ) currentHeight := ctx.BlockHeight() @@ -153,7 +152,7 @@ func (k Keeper) SendRewardsToProvider(ctx sdk.Context) error { sdk.NewAttribute(ccv.AttributeDistributionCurrentHeight, strconv.Itoa(int(currentHeight))), sdk.NewAttribute(ccv.AttributeDistributionNextHeight, strconv.Itoa(int(currentHeight+k.GetBlocksPerDistributionTransmission(ctx)))), sdk.NewAttribute(ccv.AttributeDistributionFraction, (k.GetConsumerRedistributionFrac(ctx))), - sdk.NewAttribute(ccv.AttributeDistributionTotal, fpTokens.String()), + sdk.NewAttribute(ccv.AttributeDistributionTotal, allBalances.String()), sdk.NewAttribute(ccv.AttributeDistributionToProvider, sentCoins.String()), ), ) From 21b2650741c7d9310d88a5ec82dacc2b47415a3e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Jul 2023 07:05:51 -0700 Subject: [PATCH 042/134] build(deps): bump github.com/cometbft/cometbft from 0.37.1 to 0.37.2 (#1116) Bumps [github.com/cometbft/cometbft](https://github.com/cometbft/cometbft) from 0.37.1 to 0.37.2. - [Release notes](https://github.com/cometbft/cometbft/releases) - [Changelog](https://github.com/cometbft/cometbft/blob/main/CHANGELOG.md) - [Commits](https://github.com/cometbft/cometbft/compare/v0.37.1...v0.37.2) --- updated-dependencies: - dependency-name: github.com/cometbft/cometbft dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index b487f32ab9..036c4d4c46 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.20 require ( cosmossdk.io/errors v1.0.0-beta.7 cosmossdk.io/math v1.0.1 - github.com/cometbft/cometbft v0.37.1 + github.com/cometbft/cometbft v0.37.2 github.com/cometbft/cometbft-db v0.8.0 github.com/cosmos/cosmos-sdk v0.47.3 github.com/cosmos/gogoproto v1.4.10 diff --git a/go.sum b/go.sum index 6e22b529cf..6ef711918b 100644 --- a/go.sum +++ b/go.sum @@ -360,8 +360,8 @@ github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE github.com/coinbase/kryptology v1.8.0/go.mod h1:RYXOAPdzOGUe3qlSFkMGn58i3xUA8hmxYHksuq+8ciI= github.com/coinbase/rosetta-sdk-go v0.7.9 h1:lqllBjMnazTjIqYrOGv8h8jxjg9+hJazIGZr9ZvoCcA= github.com/coinbase/rosetta-sdk-go v0.7.9/go.mod h1:0/knutI7XGVqXmmH4OQD8OckFrbQ8yMsUZTG7FXCR2M= -github.com/cometbft/cometbft v0.37.1 h1:KLxkQTK2hICXYq21U2hn1W5hOVYUdQgDQ1uB+90xPIg= -github.com/cometbft/cometbft v0.37.1/go.mod h1:Y2MMMN//O5K4YKd8ze4r9jmk4Y7h0ajqILXbH5JQFVs= +github.com/cometbft/cometbft v0.37.2 h1:XB0yyHGT0lwmJlFmM4+rsRnczPlHoAKFX6K8Zgc2/Jc= +github.com/cometbft/cometbft v0.37.2/go.mod h1:Y2MMMN//O5K4YKd8ze4r9jmk4Y7h0ajqILXbH5JQFVs= github.com/cometbft/cometbft-db v0.8.0 h1:vUMDaH3ApkX8m0KZvOFFy9b5DZHBAjsnEuo9AKVZpjo= github.com/cometbft/cometbft-db v0.8.0/go.mod h1:6ASCP4pfhmrCBpfk01/9E1SI29nD3HfVHrY4PG8x5c0= github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4= From 7fcdf7ea6ae5048b4cd3dec7b7852871983bcc3d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Jul 2023 07:38:23 -0700 Subject: [PATCH 043/134] build(deps): bump bufbuild/buf-setup-action from 1.22.0 to 1.23.1 (#1112) Bumps [bufbuild/buf-setup-action](https://github.com/bufbuild/buf-setup-action) from 1.22.0 to 1.23.1. - [Release notes](https://github.com/bufbuild/buf-setup-action/releases) - [Commits](https://github.com/bufbuild/buf-setup-action/compare/v1.22.0...v1.23.1) --- updated-dependencies: - dependency-name: bufbuild/buf-setup-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> --- .github/workflows/proto-registry.yml | 2 +- .github/workflows/proto.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/proto-registry.yml b/.github/workflows/proto-registry.yml index 483fab06c1..08748fe079 100644 --- a/.github/workflows/proto-registry.yml +++ b/.github/workflows/proto-registry.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: bufbuild/buf-setup-action@v1.22.0 + - uses: bufbuild/buf-setup-action@v1.23.1 - uses: bufbuild/buf-push-action@v1 with: input: "proto" diff --git a/.github/workflows/proto.yml b/.github/workflows/proto.yml index 4f2b512e97..0049c05d20 100644 --- a/.github/workflows/proto.yml +++ b/.github/workflows/proto.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: bufbuild/buf-setup-action@v1.22.0 + - uses: bufbuild/buf-setup-action@v1.23.1 - uses: bufbuild/buf-breaking-action@v1 with: input: "proto" From 30f37f7de67a03df8cab95798584646eda53a626 Mon Sep 17 00:00:00 2001 From: Jacob Gadikian Date: Mon, 10 Jul 2023 16:46:00 +0800 Subject: [PATCH 044/134] refactor: sort imports with gci (#1034) apply gci linter --- .golangci.yml | 13 ++- .../ante/forbidden_proposals_ante.go | 1 - .../ante/forbidden_proposals_ante_test.go | 7 +- app/consumer-democracy/ante_handler.go | 7 +- app/consumer-democracy/app.go | 94 +++++++++---------- app/consumer-democracy/export.go | 6 +- .../proposals_whitelisting.go | 3 +- .../proposals_whitelisting_test.go | 3 +- .../ante/disabled_modules_ante_test.go | 6 +- app/consumer/ante/msg_filter_ante_test.go | 6 +- app/consumer/ante_handler.go | 6 +- app/consumer/app.go | 42 ++++----- app/consumer/export.go | 6 +- app/provider/ante_handler.go | 6 +- app/provider/app.go | 47 +++++----- app/provider/export.go | 4 +- app/sovereign/ante_handler.go | 6 +- app/sovereign/app.go | 86 ++++++++--------- app/sovereign/export.go | 4 +- cmd/interchain-security-cd/cmd/root.go | 13 ++- cmd/interchain-security-cd/main.go | 1 + cmd/interchain-security-cdd/cmd/root.go | 10 +- cmd/interchain-security-cdd/main.go | 1 + cmd/interchain-security-pd/cmd/root.go | 11 ++- cmd/interchain-security-pd/main.go | 1 + cmd/interchain-security-sd/cmd/root.go | 11 ++- cmd/interchain-security-sd/main.go | 1 + tests/difference/core/driver/common.go | 5 +- tests/difference/core/driver/core_test.go | 14 ++- .../core/driver/seed_gen_fuzzy_test.go | 7 +- tests/difference/core/driver/setup.go | 34 ++++--- tests/e2e/actions.go | 5 +- tests/integration/common.go | 20 ++-- tests/integration/democracy.go | 10 +- tests/integration/distribution.go | 3 +- tests/integration/expired_client.go | 10 +- tests/integration/instance_test.go | 3 +- tests/integration/key_assignment.go | 8 +- tests/integration/normal_operations.go | 4 +- tests/integration/setup.go | 18 ++-- tests/integration/slashing.go | 12 ++- tests/integration/stop_consumer.go | 6 +- tests/integration/throttle.go | 6 +- tests/integration/unbonding.go | 1 + tests/integration/valset_update.go | 9 +- x/ccv/consumer/client/cli/query.go | 1 + x/ccv/consumer/ibc_module.go | 12 +-- x/ccv/consumer/ibc_module_test.go | 11 ++- x/ccv/consumer/keeper/changeover.go | 3 +- x/ccv/consumer/keeper/changeover_test.go | 9 +- x/ccv/consumer/keeper/distribution.go | 7 +- x/ccv/consumer/keeper/distribution_test.go | 5 +- x/ccv/consumer/keeper/genesis.go | 5 +- x/ccv/consumer/keeper/genesis_test.go | 20 ++-- x/ccv/consumer/keeper/grpc_query.go | 6 +- x/ccv/consumer/keeper/hooks.go | 1 + x/ccv/consumer/keeper/keeper.go | 15 +-- x/ccv/consumer/keeper/keeper_test.go | 14 +-- x/ccv/consumer/keeper/params_test.go | 3 +- x/ccv/consumer/keeper/relay.go | 11 ++- x/ccv/consumer/keeper/relay_test.go | 16 ++-- x/ccv/consumer/keeper/soft_opt_out.go | 1 + x/ccv/consumer/keeper/soft_opt_out_test.go | 4 +- x/ccv/consumer/keeper/validators.go | 6 +- x/ccv/consumer/keeper/validators_test.go | 12 ++- x/ccv/consumer/module.go | 9 +- x/ccv/consumer/types/genesis.go | 4 +- x/ccv/consumer/types/genesis_test.go | 12 +-- x/ccv/consumer/types/keys.go | 1 + x/ccv/consumer/types/params.go | 1 + x/ccv/consumer/types/validator.go | 1 + x/ccv/democracy/distribution/module.go | 8 +- x/ccv/democracy/governance/module.go | 4 +- x/ccv/democracy/staking/module.go | 3 +- x/ccv/provider/client/cli/tx.go | 2 +- x/ccv/provider/client/proposal_handler.go | 6 +- x/ccv/provider/handler.go | 2 + x/ccv/provider/handler_test.go | 4 +- x/ccv/provider/ibc_module.go | 11 ++- x/ccv/provider/ibc_module_test.go | 13 ++- x/ccv/provider/keeper/distribution.go | 1 + x/ccv/provider/keeper/distribution_test.go | 6 +- x/ccv/provider/keeper/genesis.go | 1 + x/ccv/provider/keeper/genesis_test.go | 9 +- x/ccv/provider/keeper/grpc_query.go | 7 +- x/ccv/provider/keeper/hooks.go | 2 +- x/ccv/provider/keeper/hooks_test.go | 4 +- x/ccv/provider/keeper/keeper.go | 17 ++-- x/ccv/provider/keeper/keeper_test.go | 7 +- x/ccv/provider/keeper/key_assignment.go | 7 +- x/ccv/provider/keeper/key_assignment_test.go | 12 ++- x/ccv/provider/keeper/msg_server.go | 6 +- x/ccv/provider/keeper/params.go | 4 +- x/ccv/provider/keeper/params_test.go | 5 +- x/ccv/provider/keeper/proposal.go | 12 ++- x/ccv/provider/keeper/proposal_test.go | 9 +- x/ccv/provider/keeper/relay.go | 8 +- x/ccv/provider/keeper/relay_test.go | 15 +-- x/ccv/provider/keeper/throttle.go | 4 +- x/ccv/provider/keeper/throttle_test.go | 9 +- x/ccv/provider/module.go | 12 +-- x/ccv/provider/module_test.go | 11 +-- x/ccv/provider/proposal_handler.go | 5 +- x/ccv/provider/proposal_handler_test.go | 9 +- x/ccv/provider/types/genesis.go | 4 +- x/ccv/provider/types/genesis_test.go | 11 ++- x/ccv/provider/types/key_assignment.go | 2 + x/ccv/provider/types/keys_test.go | 4 +- x/ccv/provider/types/params.go | 6 +- x/ccv/provider/types/params_test.go | 7 +- x/ccv/provider/types/proposal.go | 4 +- x/ccv/provider/types/proposal_test.go | 8 +- x/ccv/types/ccv.go | 4 +- x/ccv/types/ccv_test.go | 7 +- x/ccv/types/expected_keepers.go | 12 ++- x/ccv/types/shared_params.go | 3 +- x/ccv/types/utils.go | 13 ++- x/ccv/types/utils_test.go | 7 +- 118 files changed, 612 insertions(+), 482 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 430440a76f..5a3b555a6d 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -10,9 +10,9 @@ run: linters: disable-all: true enable: - - depguard - dogsled - exportloopref + - gci - goconst - gocritic - gofumpt @@ -60,6 +60,17 @@ issues: max-same-issues: 10000 linters-settings: + gci: + sections: + - standard # Standard section: captures all standard packages. + - default # Default section: contains all imports that could not be matched to another section type. + - blank # blank imports + - dot # dot imports + - prefix(cosmossdk.io) + - prefix(github.com/cosmos/cosmos-sdk) + - prefix(github.com/cometbft/cometbft) + - prefix(github.com/cosmos/interchain-security) + custom-order: true gofumpt: # Choose whether to use the extra rules. # Default: false diff --git a/app/consumer-democracy/ante/forbidden_proposals_ante.go b/app/consumer-democracy/ante/forbidden_proposals_ante.go index f8acfd8bc5..2856aa4e5b 100644 --- a/app/consumer-democracy/ante/forbidden_proposals_ante.go +++ b/app/consumer-democracy/ante/forbidden_proposals_ante.go @@ -4,7 +4,6 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" ) diff --git a/app/consumer-democracy/ante/forbidden_proposals_ante_test.go b/app/consumer-democracy/ante/forbidden_proposals_ante_test.go index bbe9f6a5dd..0b17e1a0b7 100644 --- a/app/consumer-democracy/ante/forbidden_proposals_ante_test.go +++ b/app/consumer-democracy/ante/forbidden_proposals_ante_test.go @@ -3,6 +3,9 @@ package ante_test import ( "testing" + ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + "github.com/stretchr/testify/require" + 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" @@ -10,11 +13,9 @@ import ( govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" "github.com/cosmos/cosmos-sdk/x/params/types/proposal" + app "github.com/cosmos/interchain-security/v3/app/consumer-democracy" "github.com/cosmos/interchain-security/v3/app/consumer-democracy/ante" - "github.com/stretchr/testify/require" - - ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" ) // 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 e27986a482..eff1a5b1c7 100644 --- a/app/consumer-democracy/ante_handler.go +++ b/app/consumer-democracy/ante_handler.go @@ -1,12 +1,15 @@ package app import ( + ibcante "github.com/cosmos/ibc-go/v7/modules/core/ante" + ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth/ante" - ibcante "github.com/cosmos/ibc-go/v7/modules/core/ante" - ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" + democracyante "github.com/cosmos/interchain-security/v3/app/consumer-democracy/ante" consumerante "github.com/cosmos/interchain-security/v3/app/consumer/ante" ibcconsumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" diff --git a/app/consumer-democracy/app.go b/app/consumer-democracy/app.go index 6b3078212b..063c5bf427 100644 --- a/app/consumer-democracy/app.go +++ b/app/consumer-democracy/app.go @@ -7,23 +7,29 @@ import ( "os" "path/filepath" - "github.com/cosmos/cosmos-sdk/client/flags" - nodeservice "github.com/cosmos/cosmos-sdk/client/grpc/node" - "github.com/cosmos/cosmos-sdk/runtime" - "github.com/cosmos/cosmos-sdk/x/consensus" - consensusparamkeeper "github.com/cosmos/cosmos-sdk/x/consensus/keeper" - consensusparamtypes "github.com/cosmos/cosmos-sdk/x/consensus/types" - "github.com/cosmos/cosmos-sdk/x/genutil" - genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" - appparams "github.com/cosmos/interchain-security/v3/app/params" + "github.com/cosmos/ibc-go/v7/modules/apps/transfer" + ibctransferkeeper "github.com/cosmos/ibc-go/v7/modules/apps/transfer/keeper" + ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + ibc "github.com/cosmos/ibc-go/v7/modules/core" + ibcconnectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" + porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" + ibchost "github.com/cosmos/ibc-go/v7/modules/core/exported" + ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" + tendermint "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + "github.com/spf13/cast" autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" + "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + nodeservice "github.com/cosmos/cosmos-sdk/client/grpc/node" "github.com/cosmos/cosmos-sdk/client/grpc/tmservice" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/runtime" + runtimeservices "github.com/cosmos/cosmos-sdk/runtime/services" "github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/server/api" "github.com/cosmos/cosmos-sdk/server/config" @@ -45,77 +51,67 @@ import ( authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper" authzmodule "github.com/cosmos/cosmos-sdk/x/authz/module" "github.com/cosmos/cosmos-sdk/x/bank" - - runtimeservices "github.com/cosmos/cosmos-sdk/runtime/services" bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/cosmos/cosmos-sdk/x/capability" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + "github.com/cosmos/cosmos-sdk/x/consensus" + consensusparamkeeper "github.com/cosmos/cosmos-sdk/x/consensus/keeper" + consensusparamtypes "github.com/cosmos/cosmos-sdk/x/consensus/types" "github.com/cosmos/cosmos-sdk/x/crisis" crisiskeeper "github.com/cosmos/cosmos-sdk/x/crisis/keeper" crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types" + distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" "github.com/cosmos/cosmos-sdk/x/evidence" evidencekeeper "github.com/cosmos/cosmos-sdk/x/evidence/keeper" evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" "github.com/cosmos/cosmos-sdk/x/feegrant" feegrantkeeper "github.com/cosmos/cosmos-sdk/x/feegrant/keeper" feegrantmodule "github.com/cosmos/cosmos-sdk/x/feegrant/module" + "github.com/cosmos/cosmos-sdk/x/genutil" + genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" + gov "github.com/cosmos/cosmos-sdk/x/gov" + govclient "github.com/cosmos/cosmos-sdk/x/gov/client" + 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" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" "github.com/cosmos/cosmos-sdk/x/params" paramsclient "github.com/cosmos/cosmos-sdk/x/params/client" paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" + paramproposal "github.com/cosmos/cosmos-sdk/x/params/types/proposal" + "github.com/cosmos/cosmos-sdk/x/slashing" + slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/cosmos/cosmos-sdk/x/upgrade" upgradeclient "github.com/cosmos/cosmos-sdk/x/upgrade/client" + upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" dbm "github.com/cometbft/cometbft-db" abci "github.com/cometbft/cometbft/abci/types" tmjson "github.com/cometbft/cometbft/libs/json" "github.com/cometbft/cometbft/libs/log" tmos "github.com/cometbft/cometbft/libs/os" - "github.com/cosmos/cosmos-sdk/x/slashing" - slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" - slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" - "github.com/cosmos/cosmos-sdk/x/upgrade" - upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" - upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - "github.com/cosmos/ibc-go/v7/modules/apps/transfer" - ibctransferkeeper "github.com/cosmos/ibc-go/v7/modules/apps/transfer/keeper" - ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" - ibc "github.com/cosmos/ibc-go/v7/modules/core" - ibcconnectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" - porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" - ibchost "github.com/cosmos/ibc-go/v7/modules/core/exported" - ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" + + appparams "github.com/cosmos/interchain-security/v3/app/params" ibctestingcore "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/core" ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" - "github.com/spf13/cast" - - distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" - distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" testutil "github.com/cosmos/interchain-security/v3/testutil/integration" - ccvdistr "github.com/cosmos/interchain-security/v3/x/ccv/democracy/distribution" - - stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - ccvstaking "github.com/cosmos/interchain-security/v3/x/ccv/democracy/staking" - - gov "github.com/cosmos/cosmos-sdk/x/gov" - govclient "github.com/cosmos/cosmos-sdk/x/gov/client" - 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" - ccvgov "github.com/cosmos/interchain-security/v3/x/ccv/democracy/governance" - - // add mint - mint "github.com/cosmos/cosmos-sdk/x/mint" - mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper" - minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" - - paramproposal "github.com/cosmos/cosmos-sdk/x/params/types/proposal" - tendermint "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" consumer "github.com/cosmos/interchain-security/v3/x/ccv/consumer" consumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + ccvdistr "github.com/cosmos/interchain-security/v3/x/ccv/democracy/distribution" + ccvgov "github.com/cosmos/interchain-security/v3/x/ccv/democracy/governance" + ccvstaking "github.com/cosmos/interchain-security/v3/x/ccv/democracy/staking" ) const ( diff --git a/app/consumer-democracy/export.go b/app/consumer-democracy/export.go index 6c511d6871..bb710da1c4 100644 --- a/app/consumer-democracy/export.go +++ b/app/consumer-democracy/export.go @@ -4,12 +4,12 @@ import ( "encoding/json" "fmt" - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - - tmtypes "github.com/cometbft/cometbft/types" servertypes "github.com/cosmos/cosmos-sdk/server/types" sdk "github.com/cosmos/cosmos-sdk/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + tmtypes "github.com/cometbft/cometbft/types" ) // ExportAppStateAndValidators exports the state of the application for a genesis diff --git a/app/consumer-democracy/proposals_whitelisting.go b/app/consumer-democracy/proposals_whitelisting.go index ab9114343f..1e9141895c 100644 --- a/app/consumer-democracy/proposals_whitelisting.go +++ b/app/consumer-democracy/proposals_whitelisting.go @@ -1,9 +1,10 @@ package app import ( + ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" "github.com/cosmos/cosmos-sdk/x/params/types/proposal" - ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" ) func IsProposalWhitelisted(content v1beta1.Content) bool { diff --git a/app/consumer-democracy/proposals_whitelisting_test.go b/app/consumer-democracy/proposals_whitelisting_test.go index a51709ae4a..127ec82ec5 100644 --- a/app/consumer-democracy/proposals_whitelisting_test.go +++ b/app/consumer-democracy/proposals_whitelisting_test.go @@ -3,10 +3,11 @@ package app_test import ( "testing" + "github.com/stretchr/testify/require" + appConsumer "github.com/cosmos/interchain-security/v3/app/consumer-democracy" ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" icstestingutils "github.com/cosmos/interchain-security/v3/testutil/ibc_testing" - "github.com/stretchr/testify/require" ) 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 dd58e8b79e..1fa114f00c 100644 --- a/app/consumer/ante/disabled_modules_ante_test.go +++ b/app/consumer/ante/disabled_modules_ante_test.go @@ -3,14 +3,16 @@ package ante_test import ( "testing" + ibcclienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + "github.com/stretchr/testify/require" + sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" - ibcclienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + "github.com/cosmos/interchain-security/v3/app/consumer/ante" "github.com/cosmos/interchain-security/v3/app/params" - "github.com/stretchr/testify/require" ) 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 76b3dec604..04bc838a8a 100644 --- a/app/consumer/ante/msg_filter_ante_test.go +++ b/app/consumer/ante/msg_filter_ante_test.go @@ -3,12 +3,14 @@ package ante_test import ( "testing" + ibcclienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + "github.com/stretchr/testify/require" + sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - ibcclienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + "github.com/cosmos/interchain-security/v3/app/consumer/ante" "github.com/cosmos/interchain-security/v3/app/params" - "github.com/stretchr/testify/require" ) type consumerKeeper struct { diff --git a/app/consumer/ante_handler.go b/app/consumer/ante_handler.go index f963150626..d251966685 100644 --- a/app/consumer/ante_handler.go +++ b/app/consumer/ante_handler.go @@ -1,12 +1,14 @@ package app import ( + ibcante "github.com/cosmos/ibc-go/v7/modules/core/ante" + ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth/ante" - ibcante "github.com/cosmos/ibc-go/v7/modules/core/ante" - ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" consumerante "github.com/cosmos/interchain-security/v3/app/consumer/ante" ibcconsumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" diff --git a/app/consumer/app.go b/app/consumer/app.go index 17c15c2c86..c65447e244 100644 --- a/app/consumer/app.go +++ b/app/consumer/app.go @@ -7,14 +7,20 @@ import ( "os" "path/filepath" + "github.com/cosmos/ibc-go/v7/modules/apps/transfer" + ibctransferkeeper "github.com/cosmos/ibc-go/v7/modules/apps/transfer/keeper" + ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + ibc "github.com/cosmos/ibc-go/v7/modules/core" + ibcconnectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" + porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" + ibchost "github.com/cosmos/ibc-go/v7/modules/core/exported" + ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" + tendermint "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + "github.com/spf13/cast" + autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" - dbm "github.com/cometbft/cometbft-db" - abci "github.com/cometbft/cometbft/abci/types" - tmjson "github.com/cometbft/cometbft/libs/json" - "github.com/cometbft/cometbft/libs/log" - tmos "github.com/cometbft/cometbft/libs/os" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" @@ -35,9 +41,6 @@ import ( "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth/ante" - "github.com/cosmos/cosmos-sdk/x/genutil" - genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" - authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation" authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" @@ -63,6 +66,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/feegrant" feegrantkeeper "github.com/cosmos/cosmos-sdk/x/feegrant/keeper" feegrantmodule "github.com/cosmos/cosmos-sdk/x/feegrant/module" + "github.com/cosmos/cosmos-sdk/x/genutil" + genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/cosmos/cosmos-sdk/x/params" paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" @@ -73,25 +78,20 @@ import ( "github.com/cosmos/cosmos-sdk/x/upgrade" upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - "github.com/cosmos/ibc-go/v7/modules/apps/transfer" - ibctransferkeeper "github.com/cosmos/ibc-go/v7/modules/apps/transfer/keeper" - ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" - ibc "github.com/cosmos/ibc-go/v7/modules/core" - ibcconnectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" - porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" - ibchost "github.com/cosmos/ibc-go/v7/modules/core/exported" - ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" + + dbm "github.com/cometbft/cometbft-db" + abci "github.com/cometbft/cometbft/abci/types" + tmjson "github.com/cometbft/cometbft/libs/json" + "github.com/cometbft/cometbft/libs/log" + tmos "github.com/cometbft/cometbft/libs/os" + appparams "github.com/cosmos/interchain-security/v3/app/params" ibctestingcore "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/core" ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" - "github.com/spf13/cast" - - tendermint "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + testutil "github.com/cosmos/interchain-security/v3/testutil/integration" ibcconsumer "github.com/cosmos/interchain-security/v3/x/ccv/consumer" ibcconsumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" ibcconsumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" - - testutil "github.com/cosmos/interchain-security/v3/testutil/integration" ) const ( diff --git a/app/consumer/export.go b/app/consumer/export.go index 168e5385a1..4260efda92 100644 --- a/app/consumer/export.go +++ b/app/consumer/export.go @@ -4,12 +4,12 @@ import ( "encoding/json" "fmt" - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - - tmtypes "github.com/cometbft/cometbft/types" servertypes "github.com/cosmos/cosmos-sdk/server/types" sdk "github.com/cosmos/cosmos-sdk/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + tmtypes "github.com/cometbft/cometbft/types" ) // ExportAppStateAndValidators implements the simapp app interface diff --git a/app/provider/ante_handler.go b/app/provider/ante_handler.go index 0a71573b07..9ba33d3264 100644 --- a/app/provider/ante_handler.go +++ b/app/provider/ante_handler.go @@ -1,12 +1,14 @@ package app import ( + ibcante "github.com/cosmos/ibc-go/v7/modules/core/ante" + ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth/ante" - ibcante "github.com/cosmos/ibc-go/v7/modules/core/ante" - ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" ) // HandlerOptions extend the SDK's AnteHandler options by requiring the IBC diff --git a/app/provider/app.go b/app/provider/app.go index d810ff360f..a25e3f4ab6 100644 --- a/app/provider/app.go +++ b/app/provider/app.go @@ -7,22 +7,33 @@ import ( "os" "path/filepath" - "github.com/cosmos/cosmos-sdk/client/flags" - nodeservice "github.com/cosmos/cosmos-sdk/client/grpc/node" - "github.com/cosmos/cosmos-sdk/runtime" - "github.com/cosmos/cosmos-sdk/server" + "github.com/cosmos/ibc-go/v7/modules/apps/transfer" + ibctransferkeeper "github.com/cosmos/ibc-go/v7/modules/apps/transfer/keeper" + ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + ibc "github.com/cosmos/ibc-go/v7/modules/core" + ibcclient "github.com/cosmos/ibc-go/v7/modules/core/02-client" + ibcclientclient "github.com/cosmos/ibc-go/v7/modules/core/02-client/client" + ibcclienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + ibcconnectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" + porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" + ibchost "github.com/cosmos/ibc-go/v7/modules/core/exported" + ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" + tendermint "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + "github.com/spf13/cast" autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" - appparams "github.com/cosmos/interchain-security/v3/app/params" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + nodeservice "github.com/cosmos/cosmos-sdk/client/grpc/node" "github.com/cosmos/cosmos-sdk/client/grpc/tmservice" "github.com/cosmos/cosmos-sdk/codec" - runtimeservices "github.com/cosmos/cosmos-sdk/runtime/services" - "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/runtime" + runtimeservices "github.com/cosmos/cosmos-sdk/runtime/services" + "github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/server/api" "github.com/cosmos/cosmos-sdk/server/config" servertypes "github.com/cosmos/cosmos-sdk/server/types" @@ -80,35 +91,21 @@ import ( upgradeclient "github.com/cosmos/cosmos-sdk/x/upgrade/client" upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - "github.com/cosmos/ibc-go/v7/modules/apps/transfer" - ibctransferkeeper "github.com/cosmos/ibc-go/v7/modules/apps/transfer/keeper" - ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" - ibc "github.com/cosmos/ibc-go/v7/modules/core" - ibcclient "github.com/cosmos/ibc-go/v7/modules/core/02-client" - ibcclientclient "github.com/cosmos/ibc-go/v7/modules/core/02-client/client" - ibcclienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" - ibcconnectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" - porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" - ibchost "github.com/cosmos/ibc-go/v7/modules/core/exported" - ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" - tendermint "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - - ibctestingcore "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/core" - ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" dbm "github.com/cometbft/cometbft-db" abci "github.com/cometbft/cometbft/abci/types" tmjson "github.com/cometbft/cometbft/libs/json" "github.com/cometbft/cometbft/libs/log" tmos "github.com/cometbft/cometbft/libs/os" - "github.com/spf13/cast" + appparams "github.com/cosmos/interchain-security/v3/app/params" + ibctestingcore "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/core" + ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" + testutil "github.com/cosmos/interchain-security/v3/testutil/integration" ibcprovider "github.com/cosmos/interchain-security/v3/x/ccv/provider" ibcproviderclient "github.com/cosmos/interchain-security/v3/x/ccv/provider/client" ibcproviderkeeper "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" - - testutil "github.com/cosmos/interchain-security/v3/testutil/integration" ) const ( diff --git a/app/provider/export.go b/app/provider/export.go index 3865026b01..74faed0657 100644 --- a/app/provider/export.go +++ b/app/provider/export.go @@ -4,13 +4,13 @@ import ( "encoding/json" "log" - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - servertypes "github.com/cosmos/cosmos-sdk/server/types" sdk "github.com/cosmos/cosmos-sdk/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" "github.com/cosmos/cosmos-sdk/x/staking" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" ) // ExportAppStateAndValidators exports the state of the application for a genesis diff --git a/app/sovereign/ante_handler.go b/app/sovereign/ante_handler.go index 0a71573b07..9ba33d3264 100644 --- a/app/sovereign/ante_handler.go +++ b/app/sovereign/ante_handler.go @@ -1,12 +1,14 @@ package app import ( + ibcante "github.com/cosmos/ibc-go/v7/modules/core/ante" + ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth/ante" - ibcante "github.com/cosmos/ibc-go/v7/modules/core/ante" - ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" ) // HandlerOptions extend the SDK's AnteHandler options by requiring the IBC diff --git a/app/sovereign/app.go b/app/sovereign/app.go index b1049255f9..1693cb1b60 100644 --- a/app/sovereign/app.go +++ b/app/sovereign/app.go @@ -7,10 +7,19 @@ import ( "os" "path/filepath" + "github.com/cosmos/ibc-go/v7/modules/apps/transfer" + ibctransferkeeper "github.com/cosmos/ibc-go/v7/modules/apps/transfer/keeper" + ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + ibc "github.com/cosmos/ibc-go/v7/modules/core" + ibcconnectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" + porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" + ibchost "github.com/cosmos/ibc-go/v7/modules/core/exported" + ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" + tendermint "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + "github.com/spf13/cast" + autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" - runtimeservices "github.com/cosmos/cosmos-sdk/runtime/services" - appparams "github.com/cosmos/interchain-security/v3/app/params" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" @@ -20,8 +29,8 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/runtime" + runtimeservices "github.com/cosmos/cosmos-sdk/runtime/services" "github.com/cosmos/cosmos-sdk/server" - "github.com/cosmos/cosmos-sdk/server/api" "github.com/cosmos/cosmos-sdk/server/config" servertypes "github.com/cosmos/cosmos-sdk/server/types" @@ -30,11 +39,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/version" - - "github.com/cosmos/cosmos-sdk/x/consensus" - consensusparamkeeper "github.com/cosmos/cosmos-sdk/x/consensus/keeper" - consensusparamtypes "github.com/cosmos/cosmos-sdk/x/consensus/types" - "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth/ante" authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" @@ -51,70 +55,58 @@ import ( "github.com/cosmos/cosmos-sdk/x/capability" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + "github.com/cosmos/cosmos-sdk/x/consensus" + consensusparamkeeper "github.com/cosmos/cosmos-sdk/x/consensus/keeper" + consensusparamtypes "github.com/cosmos/cosmos-sdk/x/consensus/types" "github.com/cosmos/cosmos-sdk/x/crisis" crisiskeeper "github.com/cosmos/cosmos-sdk/x/crisis/keeper" crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types" + sdkdistr "github.com/cosmos/cosmos-sdk/x/distribution" + distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" "github.com/cosmos/cosmos-sdk/x/evidence" evidencekeeper "github.com/cosmos/cosmos-sdk/x/evidence/keeper" evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" "github.com/cosmos/cosmos-sdk/x/feegrant" feegrantkeeper "github.com/cosmos/cosmos-sdk/x/feegrant/keeper" feegrantmodule "github.com/cosmos/cosmos-sdk/x/feegrant/module" + "github.com/cosmos/cosmos-sdk/x/genutil" + genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" + sdkgov "github.com/cosmos/cosmos-sdk/x/gov" govclient "github.com/cosmos/cosmos-sdk/x/gov/client" + 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" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" "github.com/cosmos/cosmos-sdk/x/params" paramsclient "github.com/cosmos/cosmos-sdk/x/params/client" paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" + paramproposal "github.com/cosmos/cosmos-sdk/x/params/types/proposal" + "github.com/cosmos/cosmos-sdk/x/slashing" + slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + sdkstaking "github.com/cosmos/cosmos-sdk/x/staking" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/cosmos/cosmos-sdk/x/upgrade" upgradeclient "github.com/cosmos/cosmos-sdk/x/upgrade/client" + upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" dbm "github.com/cometbft/cometbft-db" abci "github.com/cometbft/cometbft/abci/types" tmjson "github.com/cometbft/cometbft/libs/json" "github.com/cometbft/cometbft/libs/log" tmos "github.com/cometbft/cometbft/libs/os" - "github.com/cosmos/cosmos-sdk/x/slashing" - slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" - slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" - "github.com/cosmos/cosmos-sdk/x/upgrade" - upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" - upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - "github.com/cosmos/ibc-go/v7/modules/apps/transfer" - ibctransferkeeper "github.com/cosmos/ibc-go/v7/modules/apps/transfer/keeper" - ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" - ibc "github.com/cosmos/ibc-go/v7/modules/core" - ibcconnectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" - porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" - ibchost "github.com/cosmos/ibc-go/v7/modules/core/exported" - ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" + + appparams "github.com/cosmos/interchain-security/v3/app/params" ibctestingcore "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/core" ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" - "github.com/spf13/cast" - - sdkdistr "github.com/cosmos/cosmos-sdk/x/distribution" - distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" - distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" testutil "github.com/cosmos/interchain-security/v3/testutil/integration" - - sdkstaking "github.com/cosmos/cosmos-sdk/x/staking" - stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - - "github.com/cosmos/cosmos-sdk/x/genutil" - genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" - - sdkgov "github.com/cosmos/cosmos-sdk/x/gov" - govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - - // add mint - mint "github.com/cosmos/cosmos-sdk/x/mint" - mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper" - minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" - - paramproposal "github.com/cosmos/cosmos-sdk/x/params/types/proposal" - tendermint "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" ) const ( diff --git a/app/sovereign/export.go b/app/sovereign/export.go index 770d9b540f..93d46bf973 100644 --- a/app/sovereign/export.go +++ b/app/sovereign/export.go @@ -4,13 +4,13 @@ import ( "encoding/json" "log" - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - servertypes "github.com/cosmos/cosmos-sdk/server/types" sdk "github.com/cosmos/cosmos-sdk/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" "github.com/cosmos/cosmos-sdk/x/staking" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" ) // ExportAppStateAndValidators exports the state of the application for a genesis diff --git a/cmd/interchain-security-cd/cmd/root.go b/cmd/interchain-security-cd/cmd/root.go index 5fac172a96..30c032bbea 100644 --- a/cmd/interchain-security-cd/cmd/root.go +++ b/cmd/interchain-security-cd/cmd/root.go @@ -5,15 +5,11 @@ import ( "io" "os" - dbm "github.com/cometbft/cometbft-db" - tmcfg "github.com/cometbft/cometbft/config" - "github.com/cometbft/cometbft/libs/log" - serverconfig "github.com/cosmos/cosmos-sdk/server/config" - simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" "github.com/spf13/cobra" "github.com/spf13/viper" rosettaCmd "cosmossdk.io/tools/rosetta/cmd" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/config" "github.com/cosmos/cosmos-sdk/client/debug" @@ -22,12 +18,19 @@ import ( "github.com/cosmos/cosmos-sdk/client/pruning" "github.com/cosmos/cosmos-sdk/client/rpc" "github.com/cosmos/cosmos-sdk/server" + serverconfig "github.com/cosmos/cosmos-sdk/server/config" servertypes "github.com/cosmos/cosmos-sdk/server/types" + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" sdk "github.com/cosmos/cosmos-sdk/types" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/crisis" genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" + + dbm "github.com/cometbft/cometbft-db" + tmcfg "github.com/cometbft/cometbft/config" + "github.com/cometbft/cometbft/libs/log" + consumer "github.com/cosmos/interchain-security/v3/app/consumer" "github.com/cosmos/interchain-security/v3/app/params" ) diff --git a/cmd/interchain-security-cd/main.go b/cmd/interchain-security-cd/main.go index 012e5c6d44..12afc46e65 100644 --- a/cmd/interchain-security-cd/main.go +++ b/cmd/interchain-security-cd/main.go @@ -5,6 +5,7 @@ import ( "github.com/cosmos/cosmos-sdk/server" svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" + app "github.com/cosmos/interchain-security/v3/app/consumer" "github.com/cosmos/interchain-security/v3/cmd/interchain-security-cd/cmd" ) diff --git a/cmd/interchain-security-cdd/cmd/root.go b/cmd/interchain-security-cdd/cmd/root.go index 1e3f038717..989bb5a462 100644 --- a/cmd/interchain-security-cdd/cmd/root.go +++ b/cmd/interchain-security-cdd/cmd/root.go @@ -5,14 +5,11 @@ import ( "io" "os" - dbm "github.com/cometbft/cometbft-db" - "github.com/cometbft/cometbft/libs/log" - serverconfig "github.com/cosmos/cosmos-sdk/server/config" "github.com/spf13/cobra" "github.com/spf13/viper" rosettaCmd "cosmossdk.io/tools/rosetta/cmd" - tmcfg "github.com/cometbft/cometbft/config" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/config" "github.com/cosmos/cosmos-sdk/client/debug" @@ -21,6 +18,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/pruning" "github.com/cosmos/cosmos-sdk/client/rpc" "github.com/cosmos/cosmos-sdk/server" + serverconfig "github.com/cosmos/cosmos-sdk/server/config" servertypes "github.com/cosmos/cosmos-sdk/server/types" simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" sdk "github.com/cosmos/cosmos-sdk/types" @@ -29,6 +27,10 @@ import ( "github.com/cosmos/cosmos-sdk/x/crisis" genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" + dbm "github.com/cometbft/cometbft-db" + tmcfg "github.com/cometbft/cometbft/config" + "github.com/cometbft/cometbft/libs/log" + cdd "github.com/cosmos/interchain-security/v3/app/consumer-democracy" "github.com/cosmos/interchain-security/v3/app/params" ) diff --git a/cmd/interchain-security-cdd/main.go b/cmd/interchain-security-cdd/main.go index 5d04ea379b..085903425e 100644 --- a/cmd/interchain-security-cdd/main.go +++ b/cmd/interchain-security-cdd/main.go @@ -5,6 +5,7 @@ import ( "github.com/cosmos/cosmos-sdk/server" svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" + app "github.com/cosmos/interchain-security/v3/app/consumer-democracy" "github.com/cosmos/interchain-security/v3/cmd/interchain-security-cdd/cmd" ) diff --git a/cmd/interchain-security-pd/cmd/root.go b/cmd/interchain-security-pd/cmd/root.go index 246e1c182b..745d81127c 100644 --- a/cmd/interchain-security-pd/cmd/root.go +++ b/cmd/interchain-security-pd/cmd/root.go @@ -5,14 +5,11 @@ import ( "io" "os" - dbm "github.com/cometbft/cometbft-db" - "github.com/cometbft/cometbft/libs/log" - serverconfig "github.com/cosmos/cosmos-sdk/server/config" "github.com/spf13/cobra" "github.com/spf13/viper" rosettaCmd "cosmossdk.io/tools/rosetta/cmd" - tmcfg "github.com/cometbft/cometbft/config" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/config" "github.com/cosmos/cosmos-sdk/client/debug" @@ -21,6 +18,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/pruning" "github.com/cosmos/cosmos-sdk/client/rpc" "github.com/cosmos/cosmos-sdk/server" + serverconfig "github.com/cosmos/cosmos-sdk/server/config" servertypes "github.com/cosmos/cosmos-sdk/server/types" simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" sdk "github.com/cosmos/cosmos-sdk/types" @@ -28,6 +26,11 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/crisis" genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" + + dbm "github.com/cometbft/cometbft-db" + tmcfg "github.com/cometbft/cometbft/config" + "github.com/cometbft/cometbft/libs/log" + "github.com/cosmos/interchain-security/v3/app/params" providerApp "github.com/cosmos/interchain-security/v3/app/provider" ) diff --git a/cmd/interchain-security-pd/main.go b/cmd/interchain-security-pd/main.go index 9ad1cd67cc..361c0fb8e1 100644 --- a/cmd/interchain-security-pd/main.go +++ b/cmd/interchain-security-pd/main.go @@ -5,6 +5,7 @@ import ( "github.com/cosmos/cosmos-sdk/server" svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" + app "github.com/cosmos/interchain-security/v3/app/provider" "github.com/cosmos/interchain-security/v3/cmd/interchain-security-pd/cmd" ) diff --git a/cmd/interchain-security-sd/cmd/root.go b/cmd/interchain-security-sd/cmd/root.go index a93c841474..e5264b8735 100644 --- a/cmd/interchain-security-sd/cmd/root.go +++ b/cmd/interchain-security-sd/cmd/root.go @@ -5,14 +5,11 @@ import ( "io" "os" - dbm "github.com/cometbft/cometbft-db" - "github.com/cometbft/cometbft/libs/log" - serverconfig "github.com/cosmos/cosmos-sdk/server/config" "github.com/spf13/cobra" "github.com/spf13/viper" rosettaCmd "cosmossdk.io/tools/rosetta/cmd" - tmcfg "github.com/cometbft/cometbft/config" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/config" "github.com/cosmos/cosmos-sdk/client/debug" @@ -21,6 +18,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/pruning" "github.com/cosmos/cosmos-sdk/client/rpc" "github.com/cosmos/cosmos-sdk/server" + serverconfig "github.com/cosmos/cosmos-sdk/server/config" servertypes "github.com/cosmos/cosmos-sdk/server/types" simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" sdk "github.com/cosmos/cosmos-sdk/types" @@ -28,6 +26,11 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/crisis" genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" + + dbm "github.com/cometbft/cometbft-db" + tmcfg "github.com/cometbft/cometbft/config" + "github.com/cometbft/cometbft/libs/log" + "github.com/cosmos/interchain-security/v3/app/params" sovereignApp "github.com/cosmos/interchain-security/v3/app/sovereign" ) diff --git a/cmd/interchain-security-sd/main.go b/cmd/interchain-security-sd/main.go index 7c4dc35493..9b59188ea5 100644 --- a/cmd/interchain-security-sd/main.go +++ b/cmd/interchain-security-sd/main.go @@ -5,6 +5,7 @@ import ( "github.com/cosmos/cosmos-sdk/server" svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" + app "github.com/cosmos/interchain-security/v3/app/sovereign" "github.com/cosmos/interchain-security/v3/cmd/interchain-security-sd/cmd" ) diff --git a/tests/difference/core/driver/common.go b/tests/difference/core/driver/common.go index bff271e235..8ea1a4cc36 100644 --- a/tests/difference/core/driver/common.go +++ b/tests/difference/core/driver/common.go @@ -3,10 +3,11 @@ package core import ( "time" - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - tmtypes "github.com/cometbft/cometbft/types" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + tmtypes "github.com/cometbft/cometbft/types" ) const ( diff --git a/tests/difference/core/driver/core_test.go b/tests/difference/core/driver/core_test.go index 648955f66d..12192eb8e4 100644 --- a/tests/difference/core/driver/core_test.go +++ b/tests/difference/core/driver/core_test.go @@ -5,21 +5,19 @@ import ( "testing" "time" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/stretchr/testify/suite" - channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" - ibctestingcore "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/core" - ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" + "github.com/stretchr/testify/suite" + sdk "github.com/cosmos/cosmos-sdk/types" + slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + appConsumer "github.com/cosmos/interchain-security/v3/app/consumer" appProvider "github.com/cosmos/interchain-security/v3/app/provider" - + ibctestingcore "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/core" + ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" simibc "github.com/cosmos/interchain-security/v3/testutil/simibc" - - slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" consumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" ) diff --git a/tests/difference/core/driver/seed_gen_fuzzy_test.go b/tests/difference/core/driver/seed_gen_fuzzy_test.go index 0ea051c63b..610d31e40e 100644 --- a/tests/difference/core/driver/seed_gen_fuzzy_test.go +++ b/tests/difference/core/driver/seed_gen_fuzzy_test.go @@ -2,15 +2,16 @@ package core_test import ( "bytes" + cryptoEd25519 "crypto/ed25519" "testing" - cryptoEd25519 "crypto/ed25519" + mock "github.com/cosmos/ibc-go/v7/testing/mock" - tmtypes "github.com/cometbft/cometbft/types" cosmosEd25519 "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - mock "github.com/cosmos/ibc-go/v7/testing/mock" + + tmtypes "github.com/cometbft/cometbft/types" ) func GetPV(seed []byte) mock.PV { diff --git a/tests/difference/core/driver/setup.go b/tests/difference/core/driver/setup.go index ff42784bc5..fb5bf6a611 100644 --- a/tests/difference/core/driver/setup.go +++ b/tests/difference/core/driver/setup.go @@ -6,41 +6,39 @@ import ( "encoding/json" "time" - abci "github.com/cometbft/cometbft/abci/types" - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - tmtypes "github.com/cometbft/cometbft/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" + commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + "github.com/cosmos/ibc-go/v7/testing/mock" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + "github.com/cosmos/cosmos-sdk/baseapp" codectypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" cosmosEd25519 "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" 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" - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" - - ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" - - cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/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" - commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" - ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - "github.com/cosmos/ibc-go/v7/testing/mock" - slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + abci "github.com/cometbft/cometbft/abci/types" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + tmtypes "github.com/cometbft/cometbft/types" + appConsumer "github.com/cosmos/interchain-security/v3/app/consumer" appProvider "github.com/cosmos/interchain-security/v3/app/provider" + ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" icstestingutils "github.com/cosmos/interchain-security/v3/testutil/ibc_testing" simibc "github.com/cosmos/interchain-security/v3/testutil/simibc" consumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" providerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" - ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index 719e5d7517..3dd8fb704e 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -12,13 +12,14 @@ import ( "sync" "time" - evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + "github.com/tidwall/gjson" + + evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" "github.com/cosmos/interchain-security/v3/x/ccv/provider/client" "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" - "github.com/tidwall/gjson" ) type SendTokensAction struct { diff --git a/tests/integration/common.go b/tests/integration/common.go index d387760724..7d5175d5d7 100644 --- a/tests/integration/common.go +++ b/tests/integration/common.go @@ -4,24 +4,28 @@ import ( "fmt" "time" - "cosmossdk.io/math" - abci "github.com/cometbft/cometbft/abci/types" - tmtypes "github.com/cometbft/cometbft/types" - cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/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" commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" "github.com/cosmos/ibc-go/v7/modules/core/exported" ibctm "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + "github.com/stretchr/testify/require" + + "cosmossdk.io/math" + + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + abci "github.com/cometbft/cometbft/abci/types" + tmtypes "github.com/cometbft/cometbft/types" + ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" icstestingutils "github.com/cosmos/interchain-security/v3/testutil/ibc_testing" testutil "github.com/cosmos/interchain-security/v3/testutil/integration" providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" - "github.com/stretchr/testify/require" ) // ChainType defines the type of chain (either provider or consumer) diff --git a/tests/integration/democracy.go b/tests/integration/democracy.go index f914d581d7..461cfec3b3 100644 --- a/tests/integration/democracy.go +++ b/tests/integration/democracy.go @@ -4,18 +4,20 @@ import ( "testing" "time" + "github.com/stretchr/testify/suite" + "cosmossdk.io/math" - sdk "github.com/cosmos/cosmos-sdk/types" - ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" - icstestingutils "github.com/cosmos/interchain-security/v3/testutil/ibc_testing" + sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + + ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" + icstestingutils "github.com/cosmos/interchain-security/v3/testutil/ibc_testing" testutil "github.com/cosmos/interchain-security/v3/testutil/integration" consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" - "github.com/stretchr/testify/suite" ) type ConsumerDemocracyTestSuite struct { diff --git a/tests/integration/distribution.go b/tests/integration/distribution.go index 8ba2a8756b..a896a6f22b 100644 --- a/tests/integration/distribution.go +++ b/tests/integration/distribution.go @@ -3,10 +3,11 @@ package integration import ( "strings" + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" diff --git a/tests/integration/expired_client.go b/tests/integration/expired_client.go index 89c8280b33..38d2a3ab5e 100644 --- a/tests/integration/expired_client.go +++ b/tests/integration/expired_client.go @@ -3,14 +3,16 @@ package integration import ( "time" - abci "github.com/cometbft/cometbft/abci/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" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" ibctm "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + abci "github.com/cometbft/cometbft/abci/types" + ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) diff --git a/tests/integration/instance_test.go b/tests/integration/instance_test.go index 7602f02c5e..3c2f018807 100644 --- a/tests/integration/instance_test.go +++ b/tests/integration/instance_test.go @@ -3,12 +3,13 @@ package integration_test import ( "testing" + "github.com/stretchr/testify/suite" + appConsumer "github.com/cosmos/interchain-security/v3/app/consumer" appConsumerDemocracy "github.com/cosmos/interchain-security/v3/app/consumer-democracy" appProvider "github.com/cosmos/interchain-security/v3/app/provider" intg "github.com/cosmos/interchain-security/v3/tests/integration" icstestingutils "github.com/cosmos/interchain-security/v3/testutil/ibc_testing" - "github.com/stretchr/testify/suite" ) // 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 5ffabbeab4..fbe6430c67 100644 --- a/tests/integration/key_assignment.go +++ b/tests/integration/key_assignment.go @@ -1,11 +1,13 @@ package integration import ( - tmencoding "github.com/cometbft/cometbft/crypto/encoding" - tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" + "github.com/cosmos/ibc-go/v7/testing/mock" + sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/cosmos/ibc-go/v7/testing/mock" + + tmencoding "github.com/cometbft/cometbft/crypto/encoding" + tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" providerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" diff --git a/tests/integration/normal_operations.go b/tests/integration/normal_operations.go index af2137e5dc..b676689e89 100644 --- a/tests/integration/normal_operations.go +++ b/tests/integration/normal_operations.go @@ -1,8 +1,10 @@ package integration import ( - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" ) diff --git a/tests/integration/setup.go b/tests/integration/setup.go index 07987ce0d7..a18ff551e4 100644 --- a/tests/integration/setup.go +++ b/tests/integration/setup.go @@ -3,21 +3,21 @@ package integration import ( "testing" - tmencoding "github.com/cometbft/cometbft/crypto/encoding" - sdk "github.com/cosmos/cosmos-sdk/types" + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/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" "github.com/cosmos/ibc-go/v7/testing/mock" - testutil "github.com/cosmos/interchain-security/v3/testutil/integration" + "github.com/stretchr/testify/suite" + + sdk "github.com/cosmos/cosmos-sdk/types" + + tmencoding "github.com/cometbft/cometbft/crypto/encoding" + ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" icstestingutils "github.com/cosmos/interchain-security/v3/testutil/ibc_testing" + testutil "github.com/cosmos/interchain-security/v3/testutil/integration" consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" - - transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" - channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" - ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" - - "github.com/stretchr/testify/suite" ) // Callback for instantiating a new coordinator with a provider test chains diff --git a/tests/integration/slashing.go b/tests/integration/slashing.go index 68b632efe1..28ae9da958 100644 --- a/tests/integration/slashing.go +++ b/tests/integration/slashing.go @@ -4,20 +4,22 @@ import ( "fmt" "time" - abci "github.com/cometbft/cometbft/abci/types" - "github.com/cometbft/cometbft/crypto/ed25519" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" sdk "github.com/cosmos/cosmos-sdk/types" evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/crypto/ed25519" tmtypes "github.com/cometbft/cometbft/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" + keepertestutil "github.com/cosmos/interchain-security/v3/testutil/keeper" providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) // TestRelayAndApplyDowntimePacket tests that downtime slash packets can be properly relayed diff --git a/tests/integration/stop_consumer.go b/tests/integration/stop_consumer.go index f6e0d77d59..43ecaf9e33 100644 --- a/tests/integration/stop_consumer.go +++ b/tests/integration/stop_consumer.go @@ -1,10 +1,12 @@ package integration import ( - abci "github.com/cometbft/cometbft/abci/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + sdk "github.com/cosmos/cosmos-sdk/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/v3/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" diff --git a/tests/integration/throttle.go b/tests/integration/throttle.go index 0620bdd6b6..0505d6257a 100644 --- a/tests/integration/throttle.go +++ b/tests/integration/throttle.go @@ -3,10 +3,12 @@ package integration import ( "time" - tmtypes "github.com/cometbft/cometbft/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + + tmtypes "github.com/cometbft/cometbft/types" icstestingutils "github.com/cosmos/interchain-security/v3/testutil/ibc_testing" "github.com/cosmos/interchain-security/v3/x/ccv/provider" diff --git a/tests/integration/unbonding.go b/tests/integration/unbonding.go index 87454be324..7693c782e5 100644 --- a/tests/integration/unbonding.go +++ b/tests/integration/unbonding.go @@ -4,6 +4,7 @@ import ( "time" "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" providerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" diff --git a/tests/integration/valset_update.go b/tests/integration/valset_update.go index e1c0d920ea..955261aa79 100644 --- a/tests/integration/valset_update.go +++ b/tests/integration/valset_update.go @@ -3,11 +3,14 @@ package integration import ( "time" - abci "github.com/cometbft/cometbft/abci/types" - cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" - sdk "github.com/cosmos/cosmos-sdk/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" + + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + + abci "github.com/cometbft/cometbft/abci/types" + ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) diff --git a/x/ccv/consumer/client/cli/query.go b/x/ccv/consumer/client/cli/query.go index dc88aaf9d9..a961b9642c 100644 --- a/x/ccv/consumer/client/cli/query.go +++ b/x/ccv/consumer/client/cli/query.go @@ -5,6 +5,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" ) diff --git a/x/ccv/consumer/ibc_module.go b/x/ccv/consumer/ibc_module.go index 0ca0b29370..74c4cff27c 100644 --- a/x/ccv/consumer/ibc_module.go +++ b/x/ccv/consumer/ibc_module.go @@ -4,18 +4,18 @@ import ( "fmt" "strings" - errorsmod "cosmossdk.io/errors" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - sdk "github.com/cosmos/cosmos-sdk/types" - capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/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" host "github.com/cosmos/ibc-go/v7/modules/core/24-host" ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" + errorsmod "cosmossdk.io/errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" diff --git a/x/ccv/consumer/ibc_module_test.go b/x/ccv/consumer/ibc_module_test.go index 9e326bcbe6..a451625230 100644 --- a/x/ccv/consumer/ibc_module_test.go +++ b/x/ccv/consumer/ibc_module_test.go @@ -3,20 +3,21 @@ package consumer_test import ( "testing" - sdk "github.com/cosmos/cosmos-sdk/types" - capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/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" host "github.com/cosmos/ibc-go/v7/modules/core/24-host" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" "github.com/cosmos/interchain-security/v3/x/ccv/consumer" consumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" - - "github.com/golang/mock/gomock" - "github.com/stretchr/testify/require" ) // TestOnChanOpenInit validates the consumer's OnChanOpenInit implementation against the spec. diff --git a/x/ccv/consumer/keeper/changeover.go b/x/ccv/consumer/keeper/changeover.go index 1221792d3c..74276d1253 100644 --- a/x/ccv/consumer/keeper/changeover.go +++ b/x/ccv/consumer/keeper/changeover.go @@ -1,8 +1,9 @@ package keeper import ( - abci "github.com/cometbft/cometbft/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" + + abci "github.com/cometbft/cometbft/abci/types" ) // ChangeoverIsComplete returns whether the standalone to consumer changeover process is complete. diff --git a/x/ccv/consumer/keeper/changeover_test.go b/x/ccv/consumer/keeper/changeover_test.go index 4009890b52..fcd9a70459 100644 --- a/x/ccv/consumer/keeper/changeover_test.go +++ b/x/ccv/consumer/keeper/changeover_test.go @@ -3,13 +3,16 @@ package keeper_test import ( "testing" - abci "github.com/cometbft/cometbft/abci/types" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" + sdkcryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cosmos/interchain-security/v3/testutil/crypto" uthelpers "github.com/cosmos/interchain-security/v3/testutil/keeper" - "github.com/golang/mock/gomock" - "github.com/stretchr/testify/require" ) func TestChangeoverToConsumer(t *testing.T) { diff --git a/x/ccv/consumer/keeper/distribution.go b/x/ccv/consumer/keeper/distribution.go index 9d59be2f89..48f1c5a1eb 100644 --- a/x/ccv/consumer/keeper/distribution.go +++ b/x/ccv/consumer/keeper/distribution.go @@ -4,13 +4,14 @@ import ( "fmt" "strconv" - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/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" + errorsmod "cosmossdk.io/errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) diff --git a/x/ccv/consumer/keeper/distribution_test.go b/x/ccv/consumer/keeper/distribution_test.go index 07f49b5b8c..71df5fd93d 100644 --- a/x/ccv/consumer/keeper/distribution_test.go +++ b/x/ccv/consumer/keeper/distribution_test.go @@ -4,13 +4,14 @@ import ( "strings" "testing" - sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" + sdk "github.com/cosmos/cosmos-sdk/types" authTypes "github.com/cosmos/cosmos-sdk/x/auth/types" + testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" - "github.com/golang/mock/gomock" ) // TestGetEstimatedNextFeeDistribution tests next fee distribution parameters. diff --git a/x/ccv/consumer/keeper/genesis.go b/x/ccv/consumer/keeper/genesis.go index d9e905bbd8..45ea54f49c 100644 --- a/x/ccv/consumer/keeper/genesis.go +++ b/x/ccv/consumer/keeper/genesis.go @@ -4,10 +4,11 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" - ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" abci "github.com/cometbft/cometbft/abci/types" + + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + ccv "github.com/cosmos/interchain-security/v3/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 a2c0f6a88b..47d834f8a8 100644 --- a/x/ccv/consumer/keeper/genesis_test.go +++ b/x/ccv/consumer/keeper/genesis_test.go @@ -4,25 +4,25 @@ import ( "testing" "time" - abci "github.com/cometbft/cometbft/abci/types" - tmtypes "github.com/cometbft/cometbft/types" - sdk "github.com/cosmos/cosmos-sdk/types" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - "github.com/cosmos/interchain-security/v3/testutil/crypto" - testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" - consumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" - ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + abci "github.com/cometbft/cometbft/abci/types" + tmtypes "github.com/cometbft/cometbft/types" + + "github.com/cosmos/interchain-security/v3/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" + consumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + ccv "github.com/cosmos/interchain-security/v3/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 299e485faf..174f591497 100644 --- a/x/ccv/consumer/keeper/grpc_query.go +++ b/x/ccv/consumer/keeper/grpc_query.go @@ -3,10 +3,12 @@ package keeper import ( "context" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" ) var _ types.QueryServer = Keeper{} diff --git a/x/ccv/consumer/keeper/hooks.go b/x/ccv/consumer/keeper/hooks.go index da3058555b..7f03896e55 100644 --- a/x/ccv/consumer/keeper/hooks.go +++ b/x/ccv/consumer/keeper/hooks.go @@ -2,6 +2,7 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" + ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) diff --git a/x/ccv/consumer/keeper/keeper.go b/x/ccv/consumer/keeper/keeper.go index 24a1234065..7da13ab433 100644 --- a/x/ccv/consumer/keeper/keeper.go +++ b/x/ccv/consumer/keeper/keeper.go @@ -6,21 +6,22 @@ import ( "reflect" "time" + 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" + host "github.com/cosmos/ibc-go/v7/modules/core/24-host" + errorsmod "cosmossdk.io/errors" + "github.com/cosmos/cosmos-sdk/codec" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/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" - host "github.com/cosmos/ibc-go/v7/modules/core/24-host" - tmtypes "github.com/cometbft/cometbft/abci/types" "github.com/cometbft/cometbft/libs/log" - storetypes "github.com/cosmos/cosmos-sdk/store/types" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" diff --git a/x/ccv/consumer/keeper/keeper_test.go b/x/ccv/consumer/keeper/keeper_test.go index 7b23c777c5..662a776cef 100644 --- a/x/ccv/consumer/keeper/keeper_test.go +++ b/x/ccv/consumer/keeper/keeper_test.go @@ -6,21 +6,21 @@ import ( "testing" "time" - abci "github.com/cometbft/cometbft/abci/types" + conntypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" + + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - conntypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cosmos/interchain-security/v3/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" - - "github.com/golang/mock/gomock" - "github.com/stretchr/testify/require" - - cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" ) // TestProviderClientID tests getter and setter functionality for the client ID stored on consumer keeper diff --git a/x/ccv/consumer/keeper/params_test.go b/x/ccv/consumer/keeper/params_test.go index 7573613199..ac6b112aa8 100644 --- a/x/ccv/consumer/keeper/params_test.go +++ b/x/ccv/consumer/keeper/params_test.go @@ -4,10 +4,11 @@ import ( "testing" "time" + "github.com/stretchr/testify/require" + testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" - "github.com/stretchr/testify/require" ) // TestParams tests getters/setters for consumer params diff --git a/x/ccv/consumer/keeper/relay.go b/x/ccv/consumer/keeper/relay.go index d9e922ed3d..cd5105421e 100644 --- a/x/ccv/consumer/keeper/relay.go +++ b/x/ccv/consumer/keeper/relay.go @@ -4,14 +4,17 @@ import ( "fmt" "strconv" - errorsmod "cosmossdk.io/errors" - abci "github.com/cometbft/cometbft/abci/types" - sdk "github.com/cosmos/cosmos-sdk/types" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/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" "github.com/cosmos/ibc-go/v7/modules/core/exported" + errorsmod "cosmossdk.io/errors" + + 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/v3/x/ccv/consumer/types" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) diff --git a/x/ccv/consumer/keeper/relay_test.go b/x/ccv/consumer/keeper/relay_test.go index 1c2ba5152f..962fc943bd 100644 --- a/x/ccv/consumer/keeper/relay_test.go +++ b/x/ccv/consumer/keeper/relay_test.go @@ -6,24 +6,24 @@ import ( "testing" "time" - abci "github.com/cometbft/cometbft/abci/types" - "github.com/cometbft/cometbft/libs/bytes" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v7/modules/core/24-host" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/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" - host "github.com/cosmos/ibc-go/v7/modules/core/24-host" + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/libs/bytes" "github.com/cosmos/interchain-security/v3/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" "github.com/cosmos/interchain-security/v3/x/ccv/types" - - "github.com/golang/mock/gomock" - "github.com/stretchr/testify/require" ) // 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 23a27d4b96..09b8a9be79 100644 --- a/x/ccv/consumer/keeper/soft_opt_out.go +++ b/x/ccv/consumer/keeper/soft_opt_out.go @@ -5,6 +5,7 @@ import ( "sort" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" ) diff --git a/x/ccv/consumer/keeper/soft_opt_out_test.go b/x/ccv/consumer/keeper/soft_opt_out_test.go index 34e5570674..c99d418ca6 100644 --- a/x/ccv/consumer/keeper/soft_opt_out_test.go +++ b/x/ccv/consumer/keeper/soft_opt_out_test.go @@ -3,13 +3,13 @@ package keeper_test import ( "testing" + "github.com/stretchr/testify/require" + tmtypes "github.com/cometbft/cometbft/types" "github.com/cosmos/interchain-security/v3/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" - - "github.com/stretchr/testify/require" ) // Tests that UpdateSmallestNonOptOutPower updates the smallest validator power that cannot soft opt out. diff --git a/x/ccv/consumer/keeper/validators.go b/x/ccv/consumer/keeper/validators.go index 068767546b..2233b22d28 100644 --- a/x/ccv/consumer/keeper/validators.go +++ b/x/ccv/consumer/keeper/validators.go @@ -4,11 +4,13 @@ import ( "time" "cosmossdk.io/math" - cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" - abci "github.com/cometbft/cometbft/abci/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/cosmos/interchain-security/v3/x/ccv/consumer/types" ) diff --git a/x/ccv/consumer/keeper/validators_test.go b/x/ccv/consumer/keeper/validators_test.go index 724ce787d0..67ab91f531 100644 --- a/x/ccv/consumer/keeper/validators_test.go +++ b/x/ccv/consumer/keeper/validators_test.go @@ -3,18 +3,22 @@ package keeper_test import ( "testing" + "github.com/stretchr/testify/require" + "cosmossdk.io/math" - abci "github.com/cometbft/cometbft/abci/types" - tmrand "github.com/cometbft/cometbft/libs/rand" - 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" + + abci "github.com/cometbft/cometbft/abci/types" + tmrand "github.com/cometbft/cometbft/libs/rand" + tmtypes "github.com/cometbft/cometbft/types" + "github.com/cosmos/interchain-security/v3/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" - "github.com/stretchr/testify/require" ) // TestApplyCCValidatorChanges tests the ApplyCCValidatorChanges method for a consumer keeper diff --git a/x/ccv/consumer/module.go b/x/ccv/consumer/module.go index 3d80fb1df1..6c05273451 100644 --- a/x/ccv/consumer/module.go +++ b/x/ccv/consumer/module.go @@ -5,9 +5,7 @@ import ( "encoding/json" "fmt" - abci "github.com/cometbft/cometbft/abci/types" - paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - + porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/spf13/cobra" @@ -17,11 +15,12 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + + abci "github.com/cometbft/cometbft/abci/types" "github.com/cosmos/interchain-security/v3/x/ccv/consumer/client/cli" "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" - consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" ) diff --git a/x/ccv/consumer/types/genesis.go b/x/ccv/consumer/types/genesis.go index 82b6e2c1fa..3a8769939b 100644 --- a/x/ccv/consumer/types/genesis.go +++ b/x/ccv/consumer/types/genesis.go @@ -1,9 +1,11 @@ package types import ( + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + errorsmod "cosmossdk.io/errors" + abci "github.com/cometbft/cometbft/abci/types" - ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) diff --git a/x/ccv/consumer/types/genesis_test.go b/x/ccv/consumer/types/genesis_test.go index 9ce1c4927a..2f4b2fa504 100644 --- a/x/ccv/consumer/types/genesis_test.go +++ b/x/ccv/consumer/types/genesis_test.go @@ -4,22 +4,20 @@ import ( "testing" "time" - sdk "github.com/cosmos/cosmos-sdk/types" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - - abci "github.com/cometbft/cometbft/abci/types" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + "github.com/stretchr/testify/require" - "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + abci "github.com/cometbft/cometbft/abci/types" tmtypes "github.com/cometbft/cometbft/types" "github.com/cosmos/interchain-security/v3/testutil/crypto" - + "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" - "github.com/stretchr/testify/require" ) const ( diff --git a/x/ccv/consumer/types/keys.go b/x/ccv/consumer/types/keys.go index 24be1819c6..0ceed2814e 100644 --- a/x/ccv/consumer/types/keys.go +++ b/x/ccv/consumer/types/keys.go @@ -5,6 +5,7 @@ import ( time "time" sdk "github.com/cosmos/cosmos-sdk/types" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) diff --git a/x/ccv/consumer/types/params.go b/x/ccv/consumer/types/params.go index 485bb8fda5..a9b4e61285 100644 --- a/x/ccv/consumer/types/params.go +++ b/x/ccv/consumer/types/params.go @@ -7,6 +7,7 @@ import ( sdktypes "github.com/cosmos/cosmos-sdk/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) diff --git a/x/ccv/consumer/types/validator.go b/x/ccv/consumer/types/validator.go index c546a68440..b134dde078 100644 --- a/x/ccv/consumer/types/validator.go +++ b/x/ccv/consumer/types/validator.go @@ -2,6 +2,7 @@ package types import ( errorsmod "cosmossdk.io/errors" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" diff --git a/x/ccv/democracy/distribution/module.go b/x/ccv/democracy/distribution/module.go index 7f4842314e..60532dde48 100644 --- a/x/ccv/democracy/distribution/module.go +++ b/x/ccv/democracy/distribution/module.go @@ -4,19 +4,19 @@ import ( "time" "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/types/module" - "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" distr "github.com/cosmos/cosmos-sdk/x/distribution" "github.com/cosmos/cosmos-sdk/x/distribution/exported" "github.com/cosmos/cosmos-sdk/x/distribution/keeper" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" abci "github.com/cometbft/cometbft/abci/types" - distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" ) var ( diff --git a/x/ccv/democracy/governance/module.go b/x/ccv/democracy/governance/module.go index c293a9e3e3..3922607766 100644 --- a/x/ccv/democracy/governance/module.go +++ b/x/ccv/democracy/governance/module.go @@ -6,13 +6,13 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" - - abci "github.com/cometbft/cometbft/abci/types" gov "github.com/cosmos/cosmos-sdk/x/gov" govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + + abci "github.com/cometbft/cometbft/abci/types" ) const ( diff --git a/x/ccv/democracy/staking/module.go b/x/ccv/democracy/staking/module.go index 78489a0166..3e176aaa2c 100644 --- a/x/ccv/democracy/staking/module.go +++ b/x/ccv/democracy/staking/module.go @@ -3,7 +3,6 @@ package staking import ( "encoding/json" - abci "github.com/cometbft/cometbft/abci/types" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" @@ -11,6 +10,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking/exported" "github.com/cosmos/cosmos-sdk/x/staking/keeper" "github.com/cosmos/cosmos-sdk/x/staking/types" + + abci "github.com/cometbft/cometbft/abci/types" ) // Note: for a democracy consumer, this "democracy staking" keeper is only for governance capabilities, diff --git a/x/ccv/provider/client/cli/tx.go b/x/ccv/provider/client/cli/tx.go index ca167dbb60..7e0609d74c 100644 --- a/x/ccv/provider/client/cli/tx.go +++ b/x/ccv/provider/client/cli/tx.go @@ -9,9 +9,9 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/tx" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ) diff --git a/x/ccv/provider/client/proposal_handler.go b/x/ccv/provider/client/proposal_handler.go index 9c02dd3c23..8ec6e89bfd 100644 --- a/x/ccv/provider/client/proposal_handler.go +++ b/x/ccv/provider/client/proposal_handler.go @@ -8,6 +8,9 @@ import ( "path/filepath" "time" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + "github.com/spf13/cobra" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/tx" sdk "github.com/cosmos/cosmos-sdk/types" @@ -16,9 +19,8 @@ import ( govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" - "github.com/spf13/cobra" ) var ( diff --git a/x/ccv/provider/handler.go b/x/ccv/provider/handler.go index 6f3bb29092..71da622fce 100644 --- a/x/ccv/provider/handler.go +++ b/x/ccv/provider/handler.go @@ -2,8 +2,10 @@ package provider import ( errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ) diff --git a/x/ccv/provider/handler_test.go b/x/ccv/provider/handler_test.go index 8871d15669..e4835cf14a 100644 --- a/x/ccv/provider/handler_test.go +++ b/x/ccv/provider/handler_test.go @@ -5,13 +5,15 @@ import ( "strings" "testing" - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/testutil/testdata" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + testcrypto "github.com/cosmos/interchain-security/v3/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" "github.com/cosmos/interchain-security/v3/x/ccv/provider" diff --git a/x/ccv/provider/ibc_module.go b/x/ccv/provider/ibc_module.go index 698d37385b..efe113f895 100644 --- a/x/ccv/provider/ibc_module.go +++ b/x/ccv/provider/ibc_module.go @@ -3,16 +3,17 @@ package provider import ( "fmt" - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/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" host "github.com/cosmos/ibc-go/v7/modules/core/24-host" ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" + errorsmod "cosmossdk.io/errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" diff --git a/x/ccv/provider/ibc_module_test.go b/x/ccv/provider/ibc_module_test.go index 96e0eb97d1..8b7c3f985c 100644 --- a/x/ccv/provider/ibc_module_test.go +++ b/x/ccv/provider/ibc_module_test.go @@ -3,24 +3,23 @@ package provider_test import ( "testing" - sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - "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" host "github.com/cosmos/ibc-go/v7/modules/core/24-host" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" "github.com/cosmos/interchain-security/v3/x/ccv/provider" providerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" - - "github.com/golang/mock/gomock" - "github.com/stretchr/testify/require" ) // TestOnChanOpenInit tests the provider's OnChanOpenInit method against spec. diff --git a/x/ccv/provider/keeper/distribution.go b/x/ccv/provider/keeper/distribution.go index ee6070e27b..a1dff6faf4 100644 --- a/x/ccv/provider/keeper/distribution.go +++ b/x/ccv/provider/keeper/distribution.go @@ -2,6 +2,7 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ) diff --git a/x/ccv/provider/keeper/distribution_test.go b/x/ccv/provider/keeper/distribution_test.go index 4188eedaef..a470feea74 100644 --- a/x/ccv/provider/keeper/distribution_test.go +++ b/x/ccv/provider/keeper/distribution_test.go @@ -3,12 +3,14 @@ package keeper_test import ( "testing" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" + sdk "github.com/cosmos/cosmos-sdk/types" + testutil "github.com/cosmos/interchain-security/v3/testutil/keeper" consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" - "github.com/golang/mock/gomock" - "github.com/stretchr/testify/require" ) // TestRegisterConsumerRewardDenom tests the RegisterConsumerRewardDenom method. diff --git a/x/ccv/provider/keeper/genesis.go b/x/ccv/provider/keeper/genesis.go index 996b73d4a5..b3a0a1ef04 100644 --- a/x/ccv/provider/keeper/genesis.go +++ b/x/ccv/provider/keeper/genesis.go @@ -4,6 +4,7 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) diff --git a/x/ccv/provider/keeper/genesis_test.go b/x/ccv/provider/keeper/genesis_test.go index fe666dcc2c..d9147ce98f 100644 --- a/x/ccv/provider/keeper/genesis_test.go +++ b/x/ccv/provider/keeper/genesis_test.go @@ -4,17 +4,18 @@ import ( "testing" "time" - sdk "github.com/cosmos/cosmos-sdk/types" host "github.com/cosmos/ibc-go/v7/modules/core/24-host" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/interchain-security/v3/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" - consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" - "github.com/golang/mock/gomock" - "github.com/stretchr/testify/require" ) // 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 f43761fd0e..2b522ea9ef 100644 --- a/x/ccv/provider/keeper/grpc_query.go +++ b/x/ccv/provider/keeper/grpc_query.go @@ -4,12 +4,15 @@ import ( "context" "fmt" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) var _ types.QueryServer = Keeper{} diff --git a/x/ccv/provider/keeper/hooks.go b/x/ccv/provider/keeper/hooks.go index 2f2cb8ee0b..35c9b96301 100644 --- a/x/ccv/provider/keeper/hooks.go +++ b/x/ccv/provider/keeper/hooks.go @@ -1,9 +1,9 @@ package keeper import ( + sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - sdk "github.com/cosmos/cosmos-sdk/types" providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) diff --git a/x/ccv/provider/keeper/hooks_test.go b/x/ccv/provider/keeper/hooks_test.go index 463ed5fff5..83dbfe9622 100644 --- a/x/ccv/provider/keeper/hooks_test.go +++ b/x/ccv/provider/keeper/hooks_test.go @@ -3,11 +3,13 @@ package keeper_test import ( "testing" + "github.com/golang/mock/gomock" + sdk "github.com/cosmos/cosmos-sdk/types" + cryptotestutil "github.com/cosmos/interchain-security/v3/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" providerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" - "github.com/golang/mock/gomock" ) func TestValidatorConsensusKeyInUse(t *testing.T) { diff --git a/x/ccv/provider/keeper/keeper.go b/x/ccv/provider/keeper/keeper.go index 03caf0aba5..73785f1c17 100644 --- a/x/ccv/provider/keeper/keeper.go +++ b/x/ccv/provider/keeper/keeper.go @@ -6,25 +6,26 @@ import ( "reflect" "time" + 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" + host "github.com/cosmos/ibc-go/v7/modules/core/24-host" + ibchost "github.com/cosmos/ibc-go/v7/modules/core/exported" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + errorsmod "cosmossdk.io/errors" + "github.com/cosmos/cosmos-sdk/codec" storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/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" - host "github.com/cosmos/ibc-go/v7/modules/core/24-host" - ibchost "github.com/cosmos/ibc-go/v7/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + "github.com/cometbft/cometbft/libs/log" consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" - - "github.com/cometbft/cometbft/libs/log" ) // 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 f34bf262a5..364aac5669 100644 --- a/x/ccv/provider/keeper/keeper_test.go +++ b/x/ccv/provider/keeper/keeper_test.go @@ -6,17 +6,18 @@ import ( "testing" "time" + "github.com/stretchr/testify/require" + + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + abci "github.com/cometbft/cometbft/abci/types" tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" - cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" ibcsimapp "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/simapp" cryptotestutil "github.com/cosmos/interchain-security/v3/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" - - "github.com/stretchr/testify/require" ) const consumer = "consumer" diff --git a/x/ccv/provider/keeper/key_assignment.go b/x/ccv/provider/keeper/key_assignment.go index eb4fecd64f..d440848bbf 100644 --- a/x/ccv/provider/keeper/key_assignment.go +++ b/x/ccv/provider/keeper/key_assignment.go @@ -4,14 +4,15 @@ import ( "fmt" 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/v3/x/ccv/provider/types" - ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" - abci "github.com/cometbft/cometbft/abci/types" tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" + + "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) // GetValidatorConsumerPubKey returns a validator's public key assigned for a consumer chain diff --git a/x/ccv/provider/keeper/key_assignment_test.go b/x/ccv/provider/keeper/key_assignment_test.go index 49ef8698cb..8da633a5c9 100644 --- a/x/ccv/provider/keeper/key_assignment_test.go +++ b/x/ccv/provider/keeper/key_assignment_test.go @@ -7,18 +7,20 @@ import ( "testing" "time" - abci "github.com/cometbft/cometbft/abci/types" - tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" + sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + abci "github.com/cometbft/cometbft/abci/types" + tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" + cryptotestutil "github.com/cosmos/interchain-security/v3/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" - "github.com/stretchr/testify/require" - providerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" - "github.com/golang/mock/gomock" ) func TestValidatorConsumerPubKeyCRUD(t *testing.T) { diff --git a/x/ccv/provider/keeper/msg_server.go b/x/ccv/provider/keeper/msg_server.go index d7051cc392..195e2a7215 100644 --- a/x/ccv/provider/keeper/msg_server.go +++ b/x/ccv/provider/keeper/msg_server.go @@ -4,11 +4,13 @@ import ( "context" "encoding/base64" - tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - errorsmod "cosmossdk.io/errors" + tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) diff --git a/x/ccv/provider/keeper/params.go b/x/ccv/provider/keeper/params.go index adfc574ba9..b7b53b245b 100644 --- a/x/ccv/provider/keeper/params.go +++ b/x/ccv/provider/keeper/params.go @@ -3,10 +3,10 @@ package keeper import ( "time" - sdk "github.com/cosmos/cosmos-sdk/types" - ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) diff --git a/x/ccv/provider/keeper/params_test.go b/x/ccv/provider/keeper/params_test.go index cfaec35dc7..05b3964bb7 100644 --- a/x/ccv/provider/keeper/params_test.go +++ b/x/ccv/provider/keeper/params_test.go @@ -4,14 +4,15 @@ import ( "testing" "time" - sdk "github.com/cosmos/cosmos-sdk/types" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" - "github.com/stretchr/testify/require" ) // TestParams tests the getting/setting of provider ccv module params. diff --git a/x/ccv/provider/keeper/proposal.go b/x/ccv/provider/keeper/proposal.go index 0ce71d6efc..11909ad685 100644 --- a/x/ccv/provider/keeper/proposal.go +++ b/x/ccv/provider/keeper/proposal.go @@ -5,17 +5,19 @@ import ( "strconv" "time" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" errorsmod "cosmossdk.io/errors" - abci "github.com/cometbft/cometbft/abci/types" - tmtypes "github.com/cometbft/cometbft/types" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" - ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + + abci "github.com/cometbft/cometbft/abci/types" + tmtypes "github.com/cometbft/cometbft/types" consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" diff --git a/x/ccv/provider/keeper/proposal_test.go b/x/ccv/provider/keeper/proposal_test.go index 1170a0f368..4e9ee3f4ea 100644 --- a/x/ccv/provider/keeper/proposal_test.go +++ b/x/ccv/provider/keeper/proposal_test.go @@ -7,16 +7,17 @@ import ( "testing" "time" - abci "github.com/cometbft/cometbft/abci/types" - sdk "github.com/cosmos/cosmos-sdk/types" - evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" _go "github.com/cosmos/ics23/go" "github.com/golang/mock/gomock" - "github.com/stretchr/testify/require" + sdk "github.com/cosmos/cosmos-sdk/types" + evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" + + abci "github.com/cometbft/cometbft/abci/types" + cryptoutil "github.com/cosmos/interchain-security/v3/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" diff --git a/x/ccv/provider/keeper/relay.go b/x/ccv/provider/keeper/relay.go index 350bc968d4..df4fdb98ce 100644 --- a/x/ccv/provider/keeper/relay.go +++ b/x/ccv/provider/keeper/relay.go @@ -4,13 +4,15 @@ import ( "fmt" "strconv" - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/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" "github.com/cosmos/ibc-go/v7/modules/core/exported" + errorsmod "cosmossdk.io/errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) diff --git a/x/ccv/provider/keeper/relay_test.go b/x/ccv/provider/keeper/relay_test.go index 15305d8eea..b266211a42 100644 --- a/x/ccv/provider/keeper/relay_test.go +++ b/x/ccv/provider/keeper/relay_test.go @@ -4,13 +4,17 @@ import ( "testing" "time" - abci "github.com/cometbft/cometbft/abci/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" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" exported "github.com/cosmos/ibc-go/v7/modules/core/exported" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" + + 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" ibcsimapp "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/simapp" cryptotestutil "github.com/cosmos/interchain-security/v3/testutil/crypto" @@ -18,9 +22,6 @@ import ( "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" - "github.com/golang/mock/gomock" - - "github.com/stretchr/testify/require" ) // TestQueueVSCPackets tests queueing validator set updates. diff --git a/x/ccv/provider/keeper/throttle.go b/x/ccv/provider/keeper/throttle.go index ddfe1b1763..d8be629ee7 100644 --- a/x/ccv/provider/keeper/throttle.go +++ b/x/ccv/provider/keeper/throttle.go @@ -5,9 +5,11 @@ import ( "time" "cosmossdk.io/math" - tmtypes "github.com/cometbft/cometbft/types" + sdktypes "github.com/cosmos/cosmos-sdk/types" + tmtypes "github.com/cometbft/cometbft/types" + providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) diff --git a/x/ccv/provider/keeper/throttle_test.go b/x/ccv/provider/keeper/throttle_test.go index f923c53e98..a5356b0dc0 100644 --- a/x/ccv/provider/keeper/throttle_test.go +++ b/x/ccv/provider/keeper/throttle_test.go @@ -5,14 +5,15 @@ import ( "testing" "time" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" + "golang.org/x/exp/slices" + "cosmossdk.io/math" - tmtypes "github.com/cometbft/cometbft/types" sdktypes "github.com/cosmos/cosmos-sdk/types" - "github.com/golang/mock/gomock" - "github.com/stretchr/testify/require" - "golang.org/x/exp/slices" + tmtypes "github.com/cometbft/cometbft/types" cryptoutil "github.com/cosmos/interchain-security/v3/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" diff --git a/x/ccv/provider/module.go b/x/ccv/provider/module.go index 556cbcfefa..82891c27c7 100644 --- a/x/ccv/provider/module.go +++ b/x/ccv/provider/module.go @@ -5,23 +5,23 @@ import ( "encoding/json" "fmt" - abci "github.com/cometbft/cometbft/abci/types" + porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/spf13/cobra" + "github.com/cosmos/cosmos-sdk/client" "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/module" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" + abci "github.com/cometbft/cometbft/abci/types" - paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" "github.com/cosmos/interchain-security/v3/x/ccv/provider/client/cli" "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" - - "github.com/grpc-ecosystem/grpc-gateway/runtime" - "github.com/spf13/cobra" ) var ( diff --git a/x/ccv/provider/module_test.go b/x/ccv/provider/module_test.go index 0eee81cc1f..f32cb8cc4d 100644 --- a/x/ccv/provider/module_test.go +++ b/x/ccv/provider/module_test.go @@ -3,19 +3,18 @@ package provider_test import ( "testing" + host "github.com/cosmos/ibc-go/v7/modules/core/24-host" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - host "github.com/cosmos/ibc-go/v7/modules/core/24-host" - testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" "github.com/cosmos/interchain-security/v3/x/ccv/provider" "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/golang/mock/gomock" ) // 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 ebebb9c967..137cbecec7 100644 --- a/x/ccv/provider/proposal_handler.go +++ b/x/ccv/provider/proposal_handler.go @@ -1,11 +1,12 @@ package provider import ( - govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" - errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ) diff --git a/x/ccv/provider/proposal_handler_test.go b/x/ccv/provider/proposal_handler_test.go index a85853a246..d3707d8c28 100644 --- a/x/ccv/provider/proposal_handler_test.go +++ b/x/ccv/provider/proposal_handler_test.go @@ -4,14 +4,13 @@ import ( "testing" "time" - sdk "github.com/cosmos/cosmos-sdk/types" - distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" - evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" - clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" - + sdk "github.com/cosmos/cosmos-sdk/types" + distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" diff --git a/x/ccv/provider/types/genesis.go b/x/ccv/provider/types/genesis.go index 5a9358e736..07c135ebfc 100644 --- a/x/ccv/provider/types/genesis.go +++ b/x/ccv/provider/types/genesis.go @@ -3,9 +3,11 @@ package types import ( "fmt" + host "github.com/cosmos/ibc-go/v7/modules/core/24-host" + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" - host "github.com/cosmos/ibc-go/v7/modules/core/24-host" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) diff --git a/x/ccv/provider/types/genesis_test.go b/x/ccv/provider/types/genesis_test.go index de5c77a803..dbff6a1c2f 100644 --- a/x/ccv/provider/types/genesis_test.go +++ b/x/ccv/provider/types/genesis_test.go @@ -4,19 +4,20 @@ import ( "testing" "time" - 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" commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + "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" "github.com/cosmos/interchain-security/v3/testutil/crypto" consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" - - "github.com/stretchr/testify/require" ) // 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 659ca91e83..78e5161a55 100644 --- a/x/ccv/provider/types/key_assignment.go +++ b/x/ccv/provider/types/key_assignment.go @@ -5,7 +5,9 @@ import ( "strings" errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) diff --git a/x/ccv/provider/types/keys_test.go b/x/ccv/provider/types/keys_test.go index 3bb891ddce..9f470f4a82 100644 --- a/x/ccv/provider/types/keys_test.go +++ b/x/ccv/provider/types/keys_test.go @@ -4,10 +4,12 @@ import ( "testing" "time" + "github.com/stretchr/testify/require" + sdk "github.com/cosmos/cosmos-sdk/types" + cryptoutil "github.com/cosmos/interchain-security/v3/testutil/crypto" providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" - "github.com/stretchr/testify/require" ) // Tests that all singular keys, or prefixes to fully resolves keys are non duplicate byte values. diff --git a/x/ccv/provider/types/params.go b/x/ccv/provider/types/params.go index 0495d1a89e..515d8954ec 100644 --- a/x/ccv/provider/types/params.go +++ b/x/ccv/provider/types/params.go @@ -4,13 +4,13 @@ import ( "fmt" "time" - sdk "github.com/cosmos/cosmos-sdk/types" - paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + sdk "github.com/cosmos/cosmos-sdk/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) diff --git a/x/ccv/provider/types/params_test.go b/x/ccv/provider/types/params_test.go index 7a4b9aabf2..0676a15986 100644 --- a/x/ccv/provider/types/params_test.go +++ b/x/ccv/provider/types/params_test.go @@ -4,12 +4,13 @@ import ( "testing" "time" - "github.com/stretchr/testify/require" - - sdk "github.com/cosmos/cosmos-sdk/types" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ) diff --git a/x/ccv/provider/types/proposal.go b/x/ccv/provider/types/proposal.go index 89e8cb9822..c369ec95f1 100644 --- a/x/ccv/provider/types/proposal.go +++ b/x/ccv/provider/types/proposal.go @@ -6,10 +6,12 @@ import ( "strings" time "time" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + errorsmod "cosmossdk.io/errors" + evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" - clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) diff --git a/x/ccv/provider/types/proposal_test.go b/x/ccv/provider/types/proposal_test.go index b3f27e1415..fac4c7fc4b 100644 --- a/x/ccv/provider/types/proposal_test.go +++ b/x/ccv/provider/types/proposal_test.go @@ -5,19 +5,17 @@ import ( "testing" "time" - evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" - + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" "github.com/golang/protobuf/proto" //nolint:staticcheck // see: https://github.com/cosmos/interchain-security/issues/236 "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" + evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" - clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" - ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ) diff --git a/x/ccv/types/ccv.go b/x/ccv/types/ccv.go index e7739b4c2f..f02ed1c450 100644 --- a/x/ccv/types/ccv.go +++ b/x/ccv/types/ccv.go @@ -4,8 +4,10 @@ import ( "fmt" errorsmod "cosmossdk.io/errors" - abci "github.com/cometbft/cometbft/abci/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + abci "github.com/cometbft/cometbft/abci/types" ) func NewValidatorSetChangePacketData(valUpdates []abci.ValidatorUpdate, valUpdateID uint64, slashAcks []string) ValidatorSetChangePacketData { diff --git a/x/ccv/types/ccv_test.go b/x/ccv/types/ccv_test.go index 5aadafe6ec..596967b199 100644 --- a/x/ccv/types/ccv_test.go +++ b/x/ccv/types/ccv_test.go @@ -3,11 +3,14 @@ package types_test import ( "testing" - abci "github.com/cometbft/cometbft/abci/types" + "github.com/stretchr/testify/require" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cosmos/interchain-security/v3/x/ccv/types" - "github.com/stretchr/testify/require" ) func TestPacketDataValidateBasic(t *testing.T) { diff --git a/x/ccv/types/expected_keepers.go b/x/ccv/types/expected_keepers.go index 8176d193b2..2a82561cf0 100644 --- a/x/ccv/types/expected_keepers.go +++ b/x/ccv/types/expected_keepers.go @@ -4,18 +4,20 @@ import ( context "context" "time" + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/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" + ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" + "cosmossdk.io/math" + 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" evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/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" - ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" abci "github.com/cometbft/cometbft/abci/types" ) diff --git a/x/ccv/types/shared_params.go b/x/ccv/types/shared_params.go index 8ff676bded..566737c0b9 100644 --- a/x/ccv/types/shared_params.go +++ b/x/ccv/types/shared_params.go @@ -4,8 +4,9 @@ import ( fmt "fmt" "time" - sdktypes "github.com/cosmos/cosmos-sdk/types" ibchost "github.com/cosmos/ibc-go/v7/modules/core/24-host" + + sdktypes "github.com/cosmos/cosmos-sdk/types" ) const ( diff --git a/x/ccv/types/utils.go b/x/ccv/types/utils.go index 524725a532..f6e7ffc3aa 100644 --- a/x/ccv/types/utils.go +++ b/x/ccv/types/utils.go @@ -5,14 +5,17 @@ import ( "sort" "time" - errorsmod "cosmossdk.io/errors" - abci "github.com/cometbft/cometbft/abci/types" - tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" - cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" - sdk "github.com/cosmos/cosmos-sdk/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" host "github.com/cosmos/ibc-go/v7/modules/core/24-host" + + errorsmod "cosmossdk.io/errors" + + 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" ) func AccumulateChanges(currentChanges, newChanges []abci.ValidatorUpdate) []abci.ValidatorUpdate { diff --git a/x/ccv/types/utils_test.go b/x/ccv/types/utils_test.go index 0182b68306..f43e5449f1 100644 --- a/x/ccv/types/utils_test.go +++ b/x/ccv/types/utils_test.go @@ -3,11 +3,14 @@ package types_test import ( "testing" - abci "github.com/cometbft/cometbft/abci/types" + "github.com/stretchr/testify/require" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + + abci "github.com/cometbft/cometbft/abci/types" + ibcsimapp "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/simapp" "github.com/cosmos/interchain-security/v3/x/ccv/types" - "github.com/stretchr/testify/require" ) func TestAccumulateChanges(t *testing.T) { From a72735bbb96598985541ba80b4b4d9e14acddbe8 Mon Sep 17 00:00:00 2001 From: MSalopek Date: Mon, 10 Jul 2023 12:36:14 +0200 Subject: [PATCH 045/134] chore: add cometbft bump PR info to changelog (#1121) * chore: add cometbft bump PR info to changelog * chore: change styling in changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f6893544e..92dc3b5efb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ Add an entry to the unreleased section whenever merging a PR to main that is not targeted at a specific release. These entries will eventually be included in a release. * (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 From 14129233594bd72e57fa5ac286c79d6c420cce2a Mon Sep 17 00:00:00 2001 From: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Wed, 12 Jul 2023 07:59:13 -0700 Subject: [PATCH 046/134] feat: remove consumer panic when ccv channel is closed (#1127) * rm panic * rm tests * Update CHANGELOG.md * update comment --- CHANGELOG.md | 8 ++++++++ tests/integration/stop_consumer.go | 29 ----------------------------- testutil/integration/debug_test.go | 4 ---- x/ccv/consumer/module.go | 5 +---- 4 files changed, 9 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92dc3b5efb..b984d03c08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,14 @@ Add an entry to the unreleased section whenever merging a PR to main that is not * (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.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. + +* (feat) [#1127](https://github.com/cosmos/interchain-security/pull/1127) Remove consumer panic when ccv channel is closed + ## v3.0.0 Date: June 21st, 2023 diff --git a/tests/integration/stop_consumer.go b/tests/integration/stop_consumer.go index 43ecaf9e33..b3d32ee6a4 100644 --- a/tests/integration/stop_consumer.go +++ b/tests/integration/stop_consumer.go @@ -6,8 +6,6 @@ import ( 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/v3/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) @@ -213,30 +211,3 @@ func (s *CCVTestSuite) checkConsumerChainIsRemoved(chainID string, checkChannel s.Require().Empty(slashData) s.Require().Empty(vscMaturedData) } - -// TestProviderChannelClosed checks that a consumer chain panics -// when the provider channel was established and then closed -func (suite *CCVTestSuite) TestProviderChannelClosed() { - suite.SetupCCVChannel(suite.path) - // establish provider channel with a first VSC packet - suite.SendEmptyVSCPacket() - - consumerKeeper := suite.consumerApp.GetConsumerKeeper() - - channelID, found := consumerKeeper.GetProviderChannel(suite.consumerChain.GetContext()) - suite.Require().True(found) - - // close provider channel - err := consumerKeeper.ChanCloseInit(suite.consumerChain.GetContext(), ccv.ConsumerPortID, channelID) - suite.Require().NoError(err) - suite.Require().True(consumerKeeper.IsChannelClosed(suite.consumerChain.GetContext(), channelID)) - - // assert begin blocker did panics - defer func() { - if r := recover(); r != nil { - return - } - suite.Require().Fail("Begin blocker did not panic with a closed channel") - }() - suite.consumerApp.BeginBlocker(suite.consumerChain.GetContext(), abci.RequestBeginBlock{}) -} diff --git a/testutil/integration/debug_test.go b/testutil/integration/debug_test.go index 3d04c540ee..077f33cde3 100644 --- a/testutil/integration/debug_test.go +++ b/testutil/integration/debug_test.go @@ -157,10 +157,6 @@ func TestStopConsumerOnChannelClosed(t *testing.T) { runCCVTestByName(t, "TestStopConsumerOnChannelClosed") } -func TestProviderChannelClosed(t *testing.T) { - runCCVTestByName(t, "TestProviderChannelClosed") -} - // // Throttle tests // diff --git a/x/ccv/consumer/module.go b/x/ccv/consumer/module.go index 6c05273451..fe9b18a945 100644 --- a/x/ccv/consumer/module.go +++ b/x/ccv/consumer/module.go @@ -143,12 +143,9 @@ func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) { channelID, found := am.keeper.GetProviderChannel(ctx) if found && am.keeper.IsChannelClosed(ctx, channelID) { // The CCV channel was established, but it was then closed; - // the consumer chain is no longer safe, thus it MUST shut down. - // This is achieved by panicking, similar as it's done in the - // x/upgrade module of cosmos-sdk. + // the consumer chain is not secured anymore, but we allow it to run as a POA chain and log an error. channelClosedMsg := fmt.Sprintf("CCV channel %q was closed - shutdown consumer chain since it is not secured anymore", channelID) am.keeper.Logger(ctx).Error(channelClosedMsg) - panic(channelClosedMsg) } // map next block height to the vscID of the current block height From 08e59a85c958ad5020bc241d93d0c4ec7a712970 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Wed, 12 Jul 2023 10:37:24 -0700 Subject: [PATCH 047/134] docs: clean changelog for v3.1.0 (#1138) Update CHANGELOG.md --- CHANGELOG.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b984d03c08..276edd4d12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,16 +4,15 @@ Add an entry to the unreleased section whenever merging a PR to main that is not targeted at a specific release. These entries will eventually be included in a release. -* (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.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. +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 From fd76f45b726f4ef65f817e8032c4f87f986f2d71 Mon Sep 17 00:00:00 2001 From: MSalopek Date: Thu, 13 Jul 2023 15:09:29 +0200 Subject: [PATCH 048/134] docs: update broken md links (#1130) --- docs/docs/features/proposals.md | 2 +- docs/docs/validators/joining-testnet.md | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/docs/features/proposals.md b/docs/docs/features/proposals.md index a34160ecf4..b68fd343d6 100644 --- a/docs/docs/features/proposals.md +++ b/docs/docs/features/proposals.md @@ -48,7 +48,7 @@ Minimal example: "distribution_transmission_channel": "channel-123" } ``` -More examples can be found in the replicated security testnet repository [here](https://github.com/cosmos/testnets/blob/master/replicated-security/baryon-1/proposal-baryon-1.json) and [here](https://github.com/cosmos/testnets/blob/master/replicated-security/noble-1/start-proposal-noble-1.json). +More examples can be found in the replicated security testnet repository [here](https://github.com/cosmos/testnets/blob/master/replicated-security/stopped/baryon-1/proposal-baryon-1.json) and [here](https://github.com/cosmos/testnets/blob/master/replicated-security/stopped/noble-1/start-proposal-noble-1.json). ## `ConsumerRemovalProposal` Proposal type used to suggest removing an existing consumer chain. diff --git a/docs/docs/validators/joining-testnet.md b/docs/docs/validators/joining-testnet.md index 0e99c3710b..5ae9007416 100644 --- a/docs/docs/validators/joining-testnet.md +++ b/docs/docs/validators/joining-testnet.md @@ -180,9 +180,7 @@ gaiad tx provider assign-consensus-key consumer-1 '' --from Date: Thu, 13 Jul 2023 11:18:53 -0700 Subject: [PATCH 049/134] feat!: optimize pending packets storage on consumer + migration (#1037) * wip * tests * tests * update genesis tests * comments * migration and changelog * migration test * lints * merge fixes * clean * Update ccv.pb.go * add to ADR * address some PR comments * comment * Update ccv.pb.go * lint * Update x/ccv/consumer/keeper/keeper.go Co-authored-by: Simon Noetzlin * byte wise --------- Co-authored-by: Simon Noetzlin --- CHANGELOG.md | 2 + docs/docs/adrs/adr-008-throttle-retries.md | 16 +++ proto/interchain_security/ccv/v1/ccv.proto | 5 +- tests/integration/expired_client.go | 5 +- tests/integration/slashing.go | 24 ++-- x/ccv/consumer/keeper/genesis.go | 16 ++- x/ccv/consumer/keeper/genesis_test.go | 27 +++- x/ccv/consumer/keeper/keeper.go | 88 ++++++++----- x/ccv/consumer/keeper/keeper_test.go | 84 +++++++----- x/ccv/consumer/keeper/migration.go | 70 ++++++++++ x/ccv/consumer/keeper/migration_test.go | 68 ++++++++++ x/ccv/consumer/keeper/relay.go | 22 ++-- x/ccv/consumer/keeper/relay_test.go | 8 +- x/ccv/consumer/keeper/validators_test.go | 4 +- x/ccv/consumer/types/keys.go | 22 +++- x/ccv/consumer/types/keys_test.go | 4 +- x/ccv/types/ccv.go | 14 ++ x/ccv/types/ccv.pb.go | 145 +++++++++++++-------- 18 files changed, 465 insertions(+), 159 deletions(-) create mode 100644 x/ccv/consumer/keeper/migration.go create mode 100644 x/ccv/consumer/keeper/migration_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 276edd4d12..1c017fc5b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ Add an entry to the unreleased section whenever merging a PR to main that is not targeted at a specific release. These entries will eventually be included in a release. +* (feat!) optimize pending packets storage on consumer, with migration! [#1037](https://github.com/cosmos/interchain-security/pull/1037) + ## v3.1.0 Date July 11th, 2023 diff --git a/docs/docs/adrs/adr-008-throttle-retries.md b/docs/docs/adrs/adr-008-throttle-retries.md index a8f0d250ce..134214fffb 100644 --- a/docs/docs/adrs/adr-008-throttle-retries.md +++ b/docs/docs/adrs/adr-008-throttle-retries.md @@ -8,6 +8,7 @@ title: Throttle with retries ## Changelog * 6/9/23: Initial draft +* 6/22/23: added note on consumer pending packets storage optimization ## Status @@ -46,6 +47,21 @@ With the behavior described, we maintain very similar behavior to the current th In the normal case, when no or a few slash packets are being sent, the VSCMaturedPackets will not be delayed, and hence unbonding will not be delayed. +### Consumer pending packets storage optimization + +In addition to the mentioned consumer changes above. An optimization will need to be made to the consumer's pending packets storage to properly implement the feature from this ADR. + +The consumer ccv module previously queued "pending packets" to be sent on each endblocker in [SendPackets](https://github.com/cosmos/interchain-security/blob/3bc4e7135066d848aac60b0787364c07157fd36d/x/ccv/consumer/keeper/relay.go#L178). These packets are queued in state with a protobuf list of `ConsumerPacketData`. For a single append operation, the entire list is deserialized, then a packet is appended to that list, and the list is serialized again. See older version of [AppendPendingPacket](https://github.com/cosmos/interchain-security/blob/05c2dae7c6372b1252b9e97215d07c6aa7618f33/x/ccv/consumer/keeper/keeper.go#L606). That is, a single append operation has O(N) complexity, where N is the size of the list. + +This poor append performance isn't a problem when the pending packets list is small. But with this ADR being implemented, the pending packets list could potentially grow to the order of thousands of entries, in the scenario that a slash packet is bouncing. + +We can improve the append time for this queue by converting it from a protobuf-esq list, to a queue implemented with sdk-esq code. The idea is to persist an uint64 index that will be incremented each time you queue up a packet. You can think of this as storing the tail of the queue. Then, packet data will be keyed by that index, making the data naturally ordered byte-wise for sdk's iterator. The index will also be stored in the packet data value bytes, so that the index can later be used to delete certain packets from the queue. + +Two things are achieved with this approach: + +* More efficient packet append/enqueue times +* The ability to delete select packets from the queue (previously all packets were deleted at once) + ### Provider changes The main change needed for the provider is the removal of queuing logic for slash and vsc matured packets upon being received. diff --git a/proto/interchain_security/ccv/v1/ccv.proto b/proto/interchain_security/ccv/v1/ccv.proto index 1f3722a234..b8ad8ee6d0 100644 --- a/proto/interchain_security/ccv/v1/ccv.proto +++ b/proto/interchain_security/ccv/v1/ccv.proto @@ -56,7 +56,7 @@ message SlashPacketData { // unbonding operations. message MaturedUnbondingOps { repeated uint64 ids = 1; } -// ConsumerPacketData contains a consumer packet data and a type tag +// ConsumerPacketData contains a consumer packet data, type tag, and index for storage. message ConsumerPacketData { ConsumerPacketDataType type = 1; @@ -64,9 +64,12 @@ message ConsumerPacketData { SlashPacketData slashPacketData = 2; VSCMaturedPacketData vscMaturedPacketData = 3; } + uint64 idx = 4; } + // ConsumerPacketDataList is a list of consumer packet data packets. +// NOTE: It is only used for exporting / importing state in InitGenesis and ExportGenesis. message ConsumerPacketDataList { repeated ConsumerPacketData list = 1 [ (gogoproto.nullable) = false ]; } diff --git a/tests/integration/expired_client.go b/tests/integration/expired_client.go index 38d2a3ab5e..53863d2881 100644 --- a/tests/integration/expired_client.go +++ b/tests/integration/expired_client.go @@ -125,7 +125,7 @@ func (s *CCVTestSuite) TestConsumerPacketSendExpiredClient() { // check that the packets were added to the list of pending data packets consumerPackets := consumerKeeper.GetPendingPackets(s.consumerCtx()) s.Require().NotEmpty(consumerPackets) - s.Require().Equal(2, len(consumerPackets.GetList()), "unexpected number of pending data packets") + s.Require().Len(consumerPackets, 2, "unexpected number of pending data packets") // try to send slash packet for downtime infraction addr := ed25519.GenPrivKey().PubKey().Address() @@ -139,7 +139,7 @@ func (s *CCVTestSuite) TestConsumerPacketSendExpiredClient() { // check that the packets were added to the list of pending data packets consumerPackets = consumerKeeper.GetPendingPackets(s.consumerCtx()) s.Require().NotEmpty(consumerPackets) - s.Require().Equal(4, len(consumerPackets.GetList()), "unexpected number of pending data packets") + s.Require().Len(consumerPackets, 4, "unexpected number of pending data packets") // upgrade expired client to the consumer upgradeExpiredClient(s, Provider) @@ -150,7 +150,6 @@ func (s *CCVTestSuite) TestConsumerPacketSendExpiredClient() { // check that the list of pending data packets is emptied consumerPackets = consumerKeeper.GetPendingPackets(s.consumerCtx()) s.Require().Empty(consumerPackets) - s.Require().Equal(0, len(consumerPackets.GetList()), "unexpected number of pending data packets") // relay all packet from consumer to provider relayAllCommittedPackets(s, s.consumerChain, s.path, ccv.ConsumerPortID, s.path.EndpointA.ChannelID, 4) diff --git a/tests/integration/slashing.go b/tests/integration/slashing.go index 28ae9da958..2bc960fd03 100644 --- a/tests/integration/slashing.go +++ b/tests/integration/slashing.go @@ -486,15 +486,15 @@ func (suite *CCVTestSuite) TestValidatorDowntime() { // check that slash packet is queued pendingPackets := consumerKeeper.GetPendingPackets(ctx) - suite.Require().NotEmpty(pendingPackets.List, "pending packets empty") - suite.Require().Len(pendingPackets.List, 1, "pending packets len should be 1 is %d", len(pendingPackets.List)) + suite.Require().NotEmpty(pendingPackets, "pending packets empty") + suite.Require().Len(pendingPackets, 1, "pending packets len should be 1 is %d", len(pendingPackets)) // clear queue, commit packets suite.consumerApp.GetConsumerKeeper().SendPackets(ctx) // check queue was cleared pendingPackets = suite.consumerApp.GetConsumerKeeper().GetPendingPackets(ctx) - suite.Require().Empty(pendingPackets.List, "pending packets NOT empty") + suite.Require().Empty(pendingPackets, "pending packets NOT empty") // verify that the slash packet was sent gotCommit := consumerIBCKeeper.ChannelKeeper.GetPacketCommitment(ctx, ccv.ConsumerPortID, channelID, seq) @@ -573,15 +573,15 @@ func (suite *CCVTestSuite) TestValidatorDoubleSigning() { // check slash packet is queued pendingPackets := suite.consumerApp.GetConsumerKeeper().GetPendingPackets(ctx) - suite.Require().NotEmpty(pendingPackets.List, "pending packets empty") - suite.Require().Len(pendingPackets.List, 1, "pending packets len should be 1 is %d", len(pendingPackets.List)) + suite.Require().NotEmpty(pendingPackets, "pending packets empty") + suite.Require().Len(pendingPackets, 1, "pending packets len should be 1 is %d", len(pendingPackets)) // clear queue, commit packets suite.consumerApp.GetConsumerKeeper().SendPackets(ctx) // check queue was cleared pendingPackets = suite.consumerApp.GetConsumerKeeper().GetPendingPackets(ctx) - suite.Require().Empty(pendingPackets.List, "pending packets NOT empty") + suite.Require().Empty(pendingPackets, "pending packets NOT empty") // check slash packet is sent gotCommit := suite.consumerApp.GetIBCKeeper().ChannelKeeper.GetPacketCommitment(ctx, ccv.ConsumerPortID, channelID, seq) @@ -636,7 +636,7 @@ func (suite *CCVTestSuite) TestQueueAndSendSlashPacket() { // the downtime slash request duplicates dataPackets := consumerKeeper.GetPendingPackets(ctx) suite.Require().NotEmpty(dataPackets) - suite.Require().Len(dataPackets.GetList(), 12) + suite.Require().Len(dataPackets, 12) // save consumer next sequence seq, _ := consumerIBCKeeper.ChannelKeeper.GetNextSequenceSend(ctx, ccv.ConsumerPortID, channelID) @@ -663,7 +663,7 @@ func (suite *CCVTestSuite) TestQueueAndSendSlashPacket() { // check that pending data packets got cleared dataPackets = consumerKeeper.GetPendingPackets(ctx) suite.Require().Empty(dataPackets) - suite.Require().Len(dataPackets.GetList(), 0) + suite.Require().Len(dataPackets, 0) } // TestCISBeforeCCVEstablished tests that the consumer chain doesn't panic or @@ -674,14 +674,14 @@ func (suite *CCVTestSuite) TestCISBeforeCCVEstablished() { // Check pending packets is empty pendingPackets := consumerKeeper.GetPendingPackets(suite.consumerCtx()) - suite.Require().Len(pendingPackets.List, 0) + suite.Require().Len(pendingPackets, 0) consumerKeeper.SlashWithInfractionReason(suite.consumerCtx(), []byte{0x01, 0x02, 0x3}, 66, 4324, sdk.MustNewDecFromStr("0.05"), stakingtypes.Infraction_INFRACTION_DOWNTIME) // Check slash packet was queued pendingPackets = consumerKeeper.GetPendingPackets(suite.consumerCtx()) - suite.Require().Len(pendingPackets.List, 1) + suite.Require().Len(pendingPackets, 1) // Pass 5 blocks, confirming the consumer doesn't panic for i := 0; i < 5; i++ { @@ -690,7 +690,7 @@ func (suite *CCVTestSuite) TestCISBeforeCCVEstablished() { // Check packet is still queued pendingPackets = consumerKeeper.GetPendingPackets(suite.consumerCtx()) - suite.Require().Len(pendingPackets.List, 1) + suite.Require().Len(pendingPackets, 1) // establish ccv channel suite.SetupCCVChannel(suite.path) @@ -699,5 +699,5 @@ func (suite *CCVTestSuite) TestCISBeforeCCVEstablished() { // Pass one more block, and confirm the packet is sent now that ccv channel is established suite.consumerChain.NextBlock() pendingPackets = consumerKeeper.GetPendingPackets(suite.consumerCtx()) - suite.Require().Len(pendingPackets.List, 0) + suite.Require().Len(pendingPackets, 0) } diff --git a/x/ccv/consumer/keeper/genesis.go b/x/ccv/consumer/keeper/genesis.go index 45ea54f49c..a55184fd27 100644 --- a/x/ccv/consumer/keeper/genesis.go +++ b/x/ccv/consumer/keeper/genesis.go @@ -90,9 +90,12 @@ func (k Keeper) InitGenesis(ctx sdk.Context, state *consumertypes.GenesisState) k.SetLastTransmissionBlockHeight(ctx, state.LastTransmissionBlockHeight) } - // set pending consumer pending packets + // Set pending consumer packets, using the depreciated ConsumerPacketDataList type + // that exists for genesis. // note that the list includes pending mature VSC packet only if the handshake is completed - k.AppendPendingPacket(ctx, state.PendingConsumerPackets.List...) + for _, packet := range state.PendingConsumerPackets.List { + k.AppendPendingPacket(ctx, packet.Type, packet.Data) + } // set height to valset update id mapping for _, h2v := range state.HeightToValsetUpdateId { @@ -122,6 +125,11 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) (genesis *consumertypes.GenesisSt // export the current validator set valset := k.MustGetCurrentValidatorsAsABCIUpdates(ctx) + // export pending packets using the depreciated ConsumerPacketDataList type + pendingPackets := k.GetPendingPackets(ctx) + pendingPacketsDepreciated := ccv.ConsumerPacketDataList{} + pendingPacketsDepreciated.List = append(pendingPacketsDepreciated.List, pendingPackets...) + // export all the states created after a provider channel got established if channelID, ok := k.GetProviderChannel(ctx); ok { clientID, found := k.GetProviderClientID(ctx) @@ -136,7 +144,7 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) (genesis *consumertypes.GenesisSt k.GetAllPacketMaturityTimes(ctx), valset, k.GetAllHeightToValsetUpdateIDs(ctx), - k.GetPendingPackets(ctx), + pendingPacketsDepreciated, k.GetAllOutstandingDowntimes(ctx), k.GetLastTransmissionBlockHeight(ctx), params, @@ -156,7 +164,7 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) (genesis *consumertypes.GenesisSt nil, valset, k.GetAllHeightToValsetUpdateIDs(ctx), - k.GetPendingPackets(ctx), + pendingPacketsDepreciated, nil, consumertypes.LastTransmissionBlockHeight{}, params, diff --git a/x/ccv/consumer/keeper/genesis_test.go b/x/ccv/consumer/keeper/genesis_test.go index 47d834f8a8..5058f6ff5c 100644 --- a/x/ccv/consumer/keeper/genesis_test.go +++ b/x/ccv/consumer/keeper/genesis_test.go @@ -148,7 +148,12 @@ func TestInitGenesis(t *testing.T) { func(ctx sdk.Context, ck consumerkeeper.Keeper, gs *consumertypes.GenesisState) { assertConsumerPortIsBound(t, ctx, &ck) - require.Equal(t, pendingDataPackets, ck.GetPendingPackets(ctx)) + obtainedPendingPackets := ck.GetPendingPackets(ctx) + for idx, expectedPacketData := range pendingDataPackets.List { + require.Equal(t, expectedPacketData.Type, obtainedPendingPackets[idx].Type) + require.Equal(t, expectedPacketData.Data, obtainedPendingPackets[idx].Data) + } + assertHeightValsetUpdateIDs(t, ctx, &ck, defaultHeightValsetUpdateIDs) assertProviderClientID(t, ctx, &ck, provClientID) require.Equal(t, validator.Address.Bytes(), ck.GetAllCCValidator(ctx)[0].Address) @@ -186,7 +191,12 @@ func TestInitGenesis(t *testing.T) { require.Equal(t, provChannelID, gotChannelID) require.True(t, ck.PacketMaturityTimeExists(ctx, matPackets[0].VscId, matPackets[0].MaturityTime)) - require.Equal(t, pendingDataPackets, ck.GetPendingPackets(ctx)) + + obtainedPendingPackets := ck.GetPendingPackets(ctx) + for idx, expectedPacketData := range pendingDataPackets.List { + require.Equal(t, expectedPacketData.Type, obtainedPendingPackets[idx].Type) + require.Equal(t, expectedPacketData.Data, obtainedPendingPackets[idx].Data) + } require.Equal(t, gs.OutstandingDowntimeSlashing, ck.GetAllOutstandingDowntimes(ctx)) @@ -252,12 +262,16 @@ func TestExportGenesis(t *testing.T) { Data: &ccv.ConsumerPacketData_SlashPacketData{ SlashPacketData: ccv.NewSlashPacketData(abciValidator, vscID, stakingtypes.Infraction_INFRACTION_DOWNTIME), }, + Idx: 0, }, { Type: ccv.VscMaturedPacket, Data: &ccv.ConsumerPacketData_VscMaturedPacketData{ VscMaturedPacketData: ccv.NewVSCMaturedPacketData(vscID), }, + // This idx is a part of the expected genesis state. + // If the keeper is correctly storing consumer packet data, indexes should be populated. + Idx: 1, }, }, } @@ -291,7 +305,10 @@ func TestExportGenesis(t *testing.T) { ck.SetCCValidator(ctx, cVal) ck.SetParams(ctx, params) - ck.AppendPendingPacket(ctx, consPackets.List...) + for _, packet := range consPackets.List { + ck.AppendPendingPacket(ctx, packet.Type, packet.Data) + } + ck.SetHeightValsetUpdateID(ctx, defaultHeightValsetUpdateIDs[0].Height, defaultHeightValsetUpdateIDs[0].ValsetUpdateId) }, consumertypes.NewRestartGenesisState( @@ -321,7 +338,9 @@ func TestExportGenesis(t *testing.T) { ck.SetHeightValsetUpdateID(ctx, updatedHeightValsetUpdateIDs[0].Height, updatedHeightValsetUpdateIDs[0].ValsetUpdateId) ck.SetHeightValsetUpdateID(ctx, updatedHeightValsetUpdateIDs[1].Height, updatedHeightValsetUpdateIDs[1].ValsetUpdateId) - ck.AppendPendingPacket(ctx, consPackets.List...) + for _, packet := range consPackets.List { + ck.AppendPendingPacket(ctx, packet.Type, packet.Data) + } // populate the required states for an established CCV channel ck.SetPacketMaturityTime(ctx, matPackets[0].VscId, matPackets[0].MaturityTime) diff --git a/x/ccv/consumer/keeper/keeper.go b/x/ccv/consumer/keeper/keeper.go index 7da13ab433..cfff31b367 100644 --- a/x/ccv/consumer/keeper/keeper.go +++ b/x/ccv/consumer/keeper/keeper.go @@ -593,48 +593,78 @@ func (k Keeper) GetAllValidators(ctx sdk.Context) (validators []stakingtypes.Val return validators } -// SetPendingPackets sets the pending CCV packets -func (k Keeper) SetPendingPackets(ctx sdk.Context, packets ccv.ConsumerPacketDataList) { +// getAndIncrementPendingPacketsIdx returns the current pending packets index and increments it. +// This index is used for implementing a FIFO queue of pending packets in the KV store. +func (k Keeper) getAndIncrementPendingPacketsIdx(ctx sdk.Context) (toReturn uint64) { store := ctx.KVStore(k.storeKey) - bz, err := packets.Marshal() - if err != nil { - // This should never happen - panic(fmt.Errorf("failed to marshal ConsumerPacketDataList: %w", err)) + bz := store.Get(types.PendingPacketsIndexKey()) + if bz != nil { + toReturn = sdk.BigEndianToUint64(bz) } - store.Set(types.PendingDataPacketsKey(), bz) + toStore := toReturn + 1 + store.Set(types.PendingPacketsIndexKey(), sdk.Uint64ToBigEndian(toStore)) + return toReturn } -// GetPendingPackets returns the pending CCV packets from the store -func (k Keeper) GetPendingPackets(ctx sdk.Context) ccv.ConsumerPacketDataList { - var packets ccv.ConsumerPacketDataList - +// GetPendingPackets returns ALL the pending CCV packets from the store +func (k Keeper) GetPendingPackets(ctx sdk.Context) []ccv.ConsumerPacketData { + var packets []ccv.ConsumerPacketData store := ctx.KVStore(k.storeKey) - bz := store.Get(types.PendingDataPacketsKey()) - if bz == nil { - return packets + // Note: PendingDataPacketsBytePrefix is the correct prefix, NOT PendingDataPacketsByteKey. + // See consistency with PendingDataPacketsKey(). + iterator := sdk.KVStorePrefixIterator(store, []byte{types.PendingDataPacketsBytePrefix}) + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + var packet ccv.ConsumerPacketData + bz := iterator.Value() + err := packet.Unmarshal(bz) + if err != nil { + // An error here would indicate something is very wrong, + panic(fmt.Errorf("failed to unmarshal pending data packet: %w", err)) + } + packets = append(packets, packet) } + return packets +} - err := packets.Unmarshal(bz) - if err != nil { - // An error here would indicate something is very wrong, - // the PendingPackets are assumed to be correctly serialized in SetPendingPackets. - panic(fmt.Errorf("failed to unmarshal pending data packets: %w", err)) +// DeletePendingDataPackets deletes pending data packets with given indexes +func (k Keeper) DeletePendingDataPackets(ctx sdk.Context, idxs ...uint64) { + store := ctx.KVStore(k.storeKey) + for _, idx := range idxs { + store.Delete(types.PendingDataPacketsKey(idx)) } - - return packets } -// DeletePendingDataPackets clears the pending data packets in store -func (k Keeper) DeletePendingDataPackets(ctx sdk.Context) { +func (k Keeper) DeleteAllPendingDataPackets(ctx sdk.Context) { store := ctx.KVStore(k.storeKey) - store.Delete(types.PendingDataPacketsKey()) + // Note: PendingDataPacketsBytePrefix is the correct prefix, NOT PendingDataPacketsByteKey. + // See consistency with PendingDataPacketsKey(). + iterator := sdk.KVStorePrefixIterator(store, []byte{types.PendingDataPacketsBytePrefix}) + keysToDel := [][]byte{} + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + keysToDel = append(keysToDel, iterator.Key()) + } + for _, key := range keysToDel { + store.Delete(key) + } } -// AppendPendingDataPacket appends the given data packet to the pending data packets in store -func (k Keeper) AppendPendingPacket(ctx sdk.Context, packet ...ccv.ConsumerPacketData) { - pending := k.GetPendingPackets(ctx) - list := append(pending.GetList(), packet...) - k.SetPendingPackets(ctx, ccv.ConsumerPacketDataList{List: list}) +// AppendPendingPacket enqueues the given data packet to the end of the pending data packets queue +func (k Keeper) AppendPendingPacket(ctx sdk.Context, packetType ccv.ConsumerPacketDataType, data ccv.ExportedIsConsumerPacketData_Data) { + cpd := ccv.NewConsumerPacketData( + packetType, + data, + k.getAndIncrementPendingPacketsIdx(ctx), + ) + key := types.PendingDataPacketsKey(cpd.Idx) + store := ctx.KVStore(k.storeKey) + bz, err := cpd.Marshal() + if err != nil { + // This should never happen + panic(fmt.Errorf("failed to marshal ConsumerPacketData: %w", err)) + } + store.Set(key, bz) } func (k Keeper) MarkAsPrevStandaloneChain(ctx sdk.Context) { diff --git a/x/ccv/consumer/keeper/keeper_test.go b/x/ccv/consumer/keeper/keeper_test.go index 662a776cef..5802c9d590 100644 --- a/x/ccv/consumer/keeper/keeper_test.go +++ b/x/ccv/consumer/keeper/keeper_test.go @@ -314,23 +314,25 @@ func TestGetAllCCValidator(t *testing.T) { require.Equal(t, result, expectedGetAllOrder) } -func TestSetPendingPackets(t *testing.T) { +func TestPendingPackets(t *testing.T) { consumerKeeper, ctx, ctrl, _ := testkeeper.GetConsumerKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - // prepare test setup - dataPackets := []ccv.ConsumerPacketData{ + // Instantiate some expected packet data + packetData := []ccv.ConsumerPacketData{ { Type: ccv.VscMaturedPacket, Data: &ccv.ConsumerPacketData_VscMaturedPacketData{ VscMaturedPacketData: ccv.NewVSCMaturedPacketData(1), }, + Idx: 0, // Note these are expected idxs, we don't pass this data to the keeper }, { Type: ccv.VscMaturedPacket, Data: &ccv.ConsumerPacketData_VscMaturedPacketData{ VscMaturedPacketData: ccv.NewVSCMaturedPacketData(2), }, + Idx: 1, }, { Type: ccv.SlashPacket, @@ -341,19 +343,24 @@ func TestSetPendingPackets(t *testing.T) { stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN, ), }, + Idx: 2, }, { Type: ccv.VscMaturedPacket, Data: &ccv.ConsumerPacketData_VscMaturedPacketData{ VscMaturedPacketData: ccv.NewVSCMaturedPacketData(3), }, + Idx: 3, }, } - consumerKeeper.SetPendingPackets(ctx, ccv.ConsumerPacketDataList{List: dataPackets}) - storedDataPackets := consumerKeeper.GetPendingPackets(ctx) - require.NotEmpty(t, storedDataPackets) - require.Equal(t, dataPackets, storedDataPackets.List) + // Append all packets to the queue + for _, data := range packetData { + consumerKeeper.AppendPendingPacket(ctx, data.Type, data.Data) + } + storedPacketData := consumerKeeper.GetPendingPackets(ctx) + require.NotEmpty(t, storedPacketData) + require.Equal(t, packetData, storedPacketData) slashPacket := ccv.NewSlashPacketData( abci.Validator{ @@ -363,31 +370,50 @@ func TestSetPendingPackets(t *testing.T) { uint64(4), stakingtypes.Infraction_INFRACTION_DOWNTIME, ) - dataPackets = append(dataPackets, ccv.ConsumerPacketData{ + // Append slash packet to expected packet data + packetData = append(packetData, ccv.ConsumerPacketData{ Type: ccv.SlashPacket, - Data: &ccv.ConsumerPacketData_SlashPacketData{SlashPacketData: slashPacket}, - }, - ) - consumerKeeper.AppendPendingPacket(ctx, dataPackets[len(dataPackets)-1]) - storedDataPackets = consumerKeeper.GetPendingPackets(ctx) - require.NotEmpty(t, storedDataPackets) - require.Equal(t, dataPackets, storedDataPackets.List) + Data: &ccv.ConsumerPacketData_SlashPacketData{ + SlashPacketData: slashPacket, + }, + Idx: 4, + }) - vscMaturedPakcet := ccv.NewVSCMaturedPacketData(4) - dataPackets = append(dataPackets, ccv.ConsumerPacketData{ + toAppend := packetData[len(packetData)-1] + consumerKeeper.AppendPendingPacket(ctx, toAppend.Type, toAppend.Data) + storedPacketData = consumerKeeper.GetPendingPackets(ctx) + require.NotEmpty(t, storedPacketData) + require.Equal(t, packetData, storedPacketData) + + vscMaturedPacket := ccv.NewVSCMaturedPacketData(4) + packetData = append(packetData, ccv.ConsumerPacketData{ Type: ccv.VscMaturedPacket, - Data: &ccv.ConsumerPacketData_VscMaturedPacketData{VscMaturedPacketData: vscMaturedPakcet}, - }, - ) - consumerKeeper.AppendPendingPacket(ctx, dataPackets[len(dataPackets)-1]) - storedDataPackets = consumerKeeper.GetPendingPackets(ctx) - require.NotEmpty(t, storedDataPackets) - require.Equal(t, dataPackets, storedDataPackets.List) - - consumerKeeper.DeletePendingDataPackets(ctx) - storedDataPackets = consumerKeeper.GetPendingPackets(ctx) - require.Empty(t, storedDataPackets) - require.Len(t, storedDataPackets.List, 0) + Data: &ccv.ConsumerPacketData_VscMaturedPacketData{ + VscMaturedPacketData: vscMaturedPacket, + }, + Idx: 5, + }) + toAppend = packetData[len(packetData)-1] + consumerKeeper.AppendPendingPacket(ctx, toAppend.Type, toAppend.Data) + + storedPacketData = consumerKeeper.GetPendingPackets(ctx) + require.NotEmpty(t, storedPacketData) + require.Equal(t, packetData, storedPacketData) + + // Delete packet with idx 5 (final index) + consumerKeeper.DeletePendingDataPackets(ctx, 5) + storedPacketData = consumerKeeper.GetPendingPackets(ctx) + require.Equal(t, packetData[:len(packetData)-1], storedPacketData) + + // Delete packet with idx 0 (first index) + consumerKeeper.DeletePendingDataPackets(ctx, 0) + storedPacketData = consumerKeeper.GetPendingPackets(ctx) + require.Equal(t, packetData[1:len(packetData)-1], storedPacketData) + + // Delete all packets + consumerKeeper.DeleteAllPendingDataPackets(ctx) + storedPacketData = consumerKeeper.GetPendingPackets(ctx) + require.Empty(t, storedPacketData) } // TestVerifyProviderChain tests the VerifyProviderChain method for the consumer keeper diff --git a/x/ccv/consumer/keeper/migration.go b/x/ccv/consumer/keeper/migration.go new file mode 100644 index 0000000000..361bb2a62f --- /dev/null +++ b/x/ccv/consumer/keeper/migration.go @@ -0,0 +1,70 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" +) + +// Migrator is a struct for handling in-place store migrations. +type Migrator struct { + ccvConsumerKeeper Keeper + ccvConsumerParamSpace paramtypes.Subspace +} + +// NewMigrator returns a new Migrator. +func NewMigrator(ccvConsumerKeeper Keeper, ccvConsumerParamSpace paramtypes.Subspace) Migrator { + return Migrator{ccvConsumerKeeper: ccvConsumerKeeper, ccvConsumerParamSpace: ccvConsumerParamSpace} +} + +// MigrateConsumerPacketData migrates consumer packet data according to +// https://github.com/cosmos/interchain-security/pull/1037 +// +// Note an equivalent migration is not required for providers. +func (k Keeper) MigrateConsumerPacketData(ctx sdk.Context) { + // deserialize packet data from old format + var depreciatedType ccvtypes.ConsumerPacketDataList + store := ctx.KVStore(k.storeKey) + bz := store.Get([]byte{consumertypes.PendingDataPacketsBytePrefix}) + if bz == nil { + ctx.Logger().Info("no pending data packets to migrate") + return + } + err := depreciatedType.Unmarshal(bz) + if err != nil { + // An error here would indicate something is very wrong + panic(fmt.Errorf("failed to unmarshal pending data packets: %w", err)) + } + + // Delete old data + store.Delete([]byte{consumertypes.PendingDataPacketsBytePrefix}) + + // re-serialize packet data in new format, with the same key prefix, + // where indexes are added internally to AppendPendingPacket. + for _, data := range depreciatedType.List { + k.AppendPendingPacket(ctx, data.Type, data.Data) + } +} + +// TODO: the following hackyness could be removed if we're able to reference older versions of ICS. +// This would likely require go.mod split, and a testing module that could depend on multiple ICS versions. + +func PendingDataPacketsKeyOnlyForTesting() []byte { + return []byte{consumertypes.PendingDataPacketsBytePrefix} // Assumes keys haven't been shuffled +} + +// Note: a better test of the old functionality would be to directly reference the old ICS version, +// including the version of ccv.ConsumerPacketDataList has a list of ccv.ConsumerPacketData without indexes. +func (k Keeper) SetPendingPacketsOnlyForTesting(ctx sdk.Context, packets ccvtypes.ConsumerPacketDataList) { + store := ctx.KVStore(k.storeKey) + bz, err := packets.Marshal() + if err != nil { + // This should never happen + panic(fmt.Errorf("failed to marshal ConsumerPacketDataList: %w", err)) + } + store.Set(PendingDataPacketsKeyOnlyForTesting(), bz) +} diff --git a/x/ccv/consumer/keeper/migration_test.go b/x/ccv/consumer/keeper/migration_test.go new file mode 100644 index 0000000000..1e7bc54bdf --- /dev/null +++ b/x/ccv/consumer/keeper/migration_test.go @@ -0,0 +1,68 @@ +package keeper_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + testutil "github.com/cosmos/interchain-security/v3/testutil/keeper" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" +) + +func TestMigrateConsumerPacketData(t *testing.T) { + consumerKeeper, ctx, ctrl, _ := testutil.GetConsumerKeeperAndCtx(t, testutil.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + // Set some pending data packets in the old format + packets := ccvtypes.ConsumerPacketDataList{ + List: []ccvtypes.ConsumerPacketData{ + { + Type: ccvtypes.SlashPacket, + Data: &ccvtypes.ConsumerPacketData_SlashPacketData{ + SlashPacketData: &ccvtypes.SlashPacketData{ + ValsetUpdateId: 77, + }, + }, + }, + { + Type: ccvtypes.VscMaturedPacket, + Data: &ccvtypes.ConsumerPacketData_VscMaturedPacketData{ + VscMaturedPacketData: &ccvtypes.VSCMaturedPacketData{ + ValsetUpdateId: 88, + }, + }, + }, + { + Type: ccvtypes.VscMaturedPacket, + Data: &ccvtypes.ConsumerPacketData_VscMaturedPacketData{ + VscMaturedPacketData: &ccvtypes.VSCMaturedPacketData{ + ValsetUpdateId: 99, + }, + }, + }, + }, + } + + // Set old data + consumerKeeper.SetPendingPacketsOnlyForTesting(ctx, packets) + + // Migrate + consumerKeeper.MigrateConsumerPacketData(ctx) + + // Check that the data is migrated properly + obtainedPackets := consumerKeeper.GetPendingPackets(ctx) + require.Len(t, packets.List, 3) + + require.Equal(t, ccvtypes.SlashPacket, obtainedPackets[0].Type) + require.Equal(t, ccvtypes.VscMaturedPacket, obtainedPackets[1].Type) + require.Equal(t, ccvtypes.VscMaturedPacket, obtainedPackets[2].Type) + + require.Equal(t, uint64(77), obtainedPackets[0].GetSlashPacketData().ValsetUpdateId) + require.Equal(t, uint64(88), obtainedPackets[1].GetVscMaturedPacketData().ValsetUpdateId) + require.Equal(t, uint64(99), obtainedPackets[2].GetVscMaturedPacketData().ValsetUpdateId) + + // Check that indexes are populated + require.Equal(t, uint64(0), obtainedPackets[0].Idx) + require.Equal(t, uint64(1), obtainedPackets[1].Idx) + require.Equal(t, uint64(2), obtainedPackets[2].Idx) +} diff --git a/x/ccv/consumer/keeper/relay.go b/x/ccv/consumer/keeper/relay.go index cd5105421e..073a1d3996 100644 --- a/x/ccv/consumer/keeper/relay.go +++ b/x/ccv/consumer/keeper/relay.go @@ -104,10 +104,10 @@ func (k Keeper) QueueVSCMaturedPackets(ctx sdk.Context) { // Append VSCMatured packet to pending packets. // Sending packets is attempted each EndBlock. // Unsent packets remain in the queue until sent. - k.AppendPendingPacket(ctx, ccv.ConsumerPacketData{ - Type: ccv.VscMaturedPacket, - Data: &ccv.ConsumerPacketData_VscMaturedPacketData{VscMaturedPacketData: vscPacket}, - }) + k.AppendPendingPacket(ctx, + ccv.VscMaturedPacket, + &ccv.ConsumerPacketData_VscMaturedPacketData{VscMaturedPacketData: vscPacket}, + ) k.DeletePacketMaturityTimes(ctx, maturityTime.VscId, maturityTime.MaturityTime) @@ -147,12 +147,12 @@ func (k Keeper) QueueSlashPacket(ctx sdk.Context, validator abci.Validator, vals // append the Slash packet data to pending data packets // to be sent once the CCV channel is established - k.AppendPendingPacket(ctx, ccv.ConsumerPacketData{ - Type: ccv.SlashPacket, - Data: &ccv.ConsumerPacketData_SlashPacketData{ + k.AppendPendingPacket(ctx, + ccv.SlashPacket, + &ccv.ConsumerPacketData_SlashPacketData{ SlashPacketData: slashPacket, }, - }) + ) k.Logger(ctx).Info("SlashPacket enqueued", "vscID", slashPacket.ValsetUpdateId, @@ -186,7 +186,8 @@ func (k Keeper) SendPackets(ctx sdk.Context) { } pending := k.GetPendingPackets(ctx) - for _, p := range pending.GetList() { + for _, p := range pending { + // send packet over IBC err := ccv.SendIBCPacket( ctx, @@ -213,8 +214,7 @@ func (k Keeper) SendPackets(ctx sdk.Context) { } } - // clear pending data packets - k.DeletePendingDataPackets(ctx) + k.DeleteAllPendingDataPackets(ctx) } // OnAcknowledgementPacket executes application logic for acknowledgments of sent VSCMatured and Slash packets diff --git a/x/ccv/consumer/keeper/relay_test.go b/x/ccv/consumer/keeper/relay_test.go index 962fc943bd..48ad7f5ab9 100644 --- a/x/ccv/consumer/keeper/relay_test.go +++ b/x/ccv/consumer/keeper/relay_test.go @@ -293,9 +293,9 @@ func TestSendPacketsFailure(t *testing.T) { consumerKeeper.SetParams(ctx, consumertypes.DefaultParams()) // Set some pending packets - consumerKeeper.SetPendingPackets(ctx, types.ConsumerPacketDataList{List: []types.ConsumerPacketData{ - {}, {}, {}, - }}) + consumerKeeper.AppendPendingPacket(ctx, types.VscMaturedPacket, &types.ConsumerPacketData_VscMaturedPacketData{}) + consumerKeeper.AppendPendingPacket(ctx, types.SlashPacket, &types.ConsumerPacketData_SlashPacketData{}) + consumerKeeper.AppendPendingPacket(ctx, types.VscMaturedPacket, &types.ConsumerPacketData_VscMaturedPacketData{}) // Mock the channel keeper to return an error gomock.InOrder( @@ -305,5 +305,5 @@ func TestSendPacketsFailure(t *testing.T) { // No panic should occur, pending packets should not be cleared consumerKeeper.SendPackets(ctx) - require.Equal(t, 3, len(consumerKeeper.GetPendingPackets(ctx).List)) + require.Equal(t, 3, len(consumerKeeper.GetPendingPackets(ctx))) } diff --git a/x/ccv/consumer/keeper/validators_test.go b/x/ccv/consumer/keeper/validators_test.go index 67ab91f531..dda1ebab19 100644 --- a/x/ccv/consumer/keeper/validators_test.go +++ b/x/ccv/consumer/keeper/validators_test.go @@ -154,7 +154,7 @@ func TestSlash(t *testing.T) { // If we call slash with infraction type empty, no slash packet will be queued consumerKeeper.SlashWithInfractionReason(ctx, []byte{0x01, 0x02, 0x03}, 5, 6, sdk.NewDec(9.0), stakingtypes.Infraction_INFRACTION_UNSPECIFIED) pendingPackets := consumerKeeper.GetPendingPackets(ctx) - require.Len(t, pendingPackets.List, 0) + require.Len(t, pendingPackets, 0) // Consumer keeper from test setup should return false for IsPrevStandaloneChain() require.False(t, consumerKeeper.IsPrevStandaloneChain(ctx)) @@ -165,7 +165,7 @@ func TestSlash(t *testing.T) { // Call slash with valid infraction type and confirm 1 slash packet is queued consumerKeeper.SlashWithInfractionReason(ctx, []byte{0x01, 0x02, 0x03}, 5, 6, sdk.NewDec(9.0), stakingtypes.Infraction_INFRACTION_DOWNTIME) pendingPackets = consumerKeeper.GetPendingPackets(ctx) - require.Len(t, pendingPackets.List, 1) + require.Len(t, pendingPackets, 1) // Next, we set a value for the standalone staking keeper, // and mark the consumer keeper as being from a previous standalone chain diff --git a/x/ccv/consumer/types/keys.go b/x/ccv/consumer/types/keys.go index 0ceed2814e..8b792419ef 100644 --- a/x/ccv/consumer/types/keys.go +++ b/x/ccv/consumer/types/keys.go @@ -98,6 +98,10 @@ const ( // PrevStandaloneChainByteKey is the byte storing the flag marking whether this chain was previously standalone PrevStandaloneChainByteKey + // PendingPacketsIndexBytePrefix is the single byte key to the pending packets index. + // This index is used for implementing a FIFO queue of pending packets in the KV store. + PendingPacketsIndexByteKey + // NOTE: DO NOT ADD NEW BYTE PREFIXES HERE WITHOUT ADDING THEM TO getAllKeyPrefixes() IN keys_test.go ) @@ -172,11 +176,13 @@ func CrossChainValidatorKey(addr []byte) []byte { return append([]byte{CrossChainValidatorBytePrefix}, addr...) } -// PendingDataPacketsKey returns the key for storing a list of data packets -// that cannot be sent yet to the provider chain either because the CCV channel -// is not established or because the client is expired. -func PendingDataPacketsKey() []byte { - return []byte{PendingDataPacketsBytePrefix} +// PendingDataPacketsKey returns the key for storing a queue of data packets to be sent to the provider. +// Packets in this queue will not be sent on the next endblocker if: +// - the CCV channel is not yet established +// - the client is expired +// - A slash packet is being bounced between consumer and provider (not yet implemented) +func PendingDataPacketsKey(idx uint64) []byte { + return append([]byte{PendingDataPacketsBytePrefix}, sdk.Uint64ToBigEndian(idx)...) } func PreCCVKey() []byte { @@ -206,6 +212,12 @@ func PrevStandaloneChainKey() []byte { return []byte{PrevStandaloneChainByteKey} } +// PendingPacketsIndexKey returns the key to the pending packets index. +// This index is used for implementing a FIFO queue of pending packets in the KV store. +func PendingPacketsIndexKey() []byte { + return []byte{PendingPacketsIndexByteKey} +} + // NOTE: DO NOT ADD FULLY DEFINED KEY FUNCTIONS WITHOUT ADDING THEM TO getAllFullyDefinedKeys() IN keys_test.go // diff --git a/x/ccv/consumer/types/keys_test.go b/x/ccv/consumer/types/keys_test.go index a63da6f326..5290dd3599 100644 --- a/x/ccv/consumer/types/keys_test.go +++ b/x/ccv/consumer/types/keys_test.go @@ -41,6 +41,7 @@ func getAllKeyPrefixes() []byte { InitGenesisHeightByteKey, StandaloneTransferChannelIDByteKey, PrevStandaloneChainByteKey, + PendingPacketsIndexByteKey, } } @@ -72,10 +73,11 @@ func getAllFullyDefinedKeys() [][]byte { PacketMaturityTimeKey(0, time.Time{}), HeightValsetUpdateIDKey(0), OutstandingDowntimeKey([]byte{}), - PendingDataPacketsKey(), + PendingDataPacketsKey(473289), CrossChainValidatorKey([]byte{}), InitGenesisHeightKey(), StandaloneTransferChannelIDKey(), PrevStandaloneChainKey(), + PendingPacketsIndexKey(), } } diff --git a/x/ccv/types/ccv.go b/x/ccv/types/ccv.go index f02ed1c450..453c55d252 100644 --- a/x/ccv/types/ccv.go +++ b/x/ccv/types/ccv.go @@ -164,3 +164,17 @@ func (vdt1 SlashPacketDataV1) FromV1() *SlashPacketData { Infraction: newType, } } + +// An exported wrapper around the auto generated isConsumerPacketData_Data interface, only for +// AppendPendingPacket to accept the interface as an argument. +type ExportedIsConsumerPacketData_Data interface { + isConsumerPacketData_Data +} + +func NewConsumerPacketData(cpdType ConsumerPacketDataType, data isConsumerPacketData_Data, idx uint64) ConsumerPacketData { + return ConsumerPacketData{ + Type: cpdType, + Data: data, + Idx: idx, + } +} diff --git a/x/ccv/types/ccv.pb.go b/x/ccv/types/ccv.pb.go index c2f0bd3ecc..c5eacc2288 100644 --- a/x/ccv/types/ccv.pb.go +++ b/x/ccv/types/ccv.pb.go @@ -361,13 +361,14 @@ func (m *MaturedUnbondingOps) GetIds() []uint64 { return nil } -// ConsumerPacketData contains a consumer packet data and a type tag +// ConsumerPacketData contains a consumer packet data, type tag, and index for storage. type ConsumerPacketData struct { Type ConsumerPacketDataType `protobuf:"varint,1,opt,name=type,proto3,enum=interchain_security.ccv.v1.ConsumerPacketDataType" json:"type,omitempty"` // Types that are valid to be assigned to Data: // *ConsumerPacketData_SlashPacketData // *ConsumerPacketData_VscMaturedPacketData Data isConsumerPacketData_Data `protobuf_oneof:"data"` + Idx uint64 `protobuf:"varint,4,opt,name=idx,proto3" json:"idx,omitempty"` } func (m *ConsumerPacketData) Reset() { *m = ConsumerPacketData{} } @@ -447,6 +448,13 @@ func (m *ConsumerPacketData) GetVscMaturedPacketData() *VSCMaturedPacketData { return nil } +func (m *ConsumerPacketData) GetIdx() uint64 { + if m != nil { + return m.Idx + } + return 0 +} + // XXX_OneofWrappers is for the internal use of the proto package. func (*ConsumerPacketData) XXX_OneofWrappers() []interface{} { return []interface{}{ @@ -456,6 +464,7 @@ func (*ConsumerPacketData) XXX_OneofWrappers() []interface{} { } // ConsumerPacketDataList is a list of consumer packet data packets. +// NOTE: It is only used for exporting / importing state in InitGenesis and ExportGenesis. type ConsumerPacketDataList struct { List []ConsumerPacketData `protobuf:"bytes,1,rep,name=list,proto3" json:"list"` } @@ -678,60 +687,61 @@ func init() { } var fileDescriptor_68bd5f3242e6f29c = []byte{ - // 836 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x56, 0xcf, 0x6e, 0xe2, 0x46, - 0x1c, 0xb6, 0x01, 0xad, 0x9a, 0xa1, 0x22, 0xce, 0x2c, 0xad, 0x58, 0x6f, 0xcb, 0x5a, 0xd6, 0x4a, + // 849 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x56, 0xcf, 0x6e, 0xe2, 0x46, + 0x1c, 0xc6, 0x80, 0x56, 0xcd, 0x50, 0x11, 0x67, 0x96, 0x56, 0x5e, 0x6f, 0xcb, 0x5a, 0xd6, 0x4a, 0x45, 0xa9, 0xd6, 0x2e, 0x64, 0x0f, 0x55, 0x7b, 0x69, 0x00, 0xa7, 0x71, 0x9b, 0x90, 0xc8, 0x06, - 0x56, 0xdb, 0x8b, 0x35, 0xd8, 0x13, 0x32, 0x0a, 0xd8, 0xc8, 0x33, 0xb8, 0xe5, 0x0d, 0x2a, 0x4e, - 0x7d, 0x01, 0x4e, 0x55, 0x0f, 0xfb, 0x18, 0xbd, 0xed, 0x71, 0xa5, 0x5e, 0xf6, 0xd2, 0xa8, 0x4a, - 0xde, 0xa0, 0x4f, 0x50, 0xd9, 0xfc, 0xc7, 0x06, 0x29, 0x52, 0xa5, 0xf6, 0x84, 0x19, 0xff, 0xbe, - 0x4f, 0xf3, 0xfd, 0x19, 0x79, 0xc0, 0x73, 0xe2, 0x32, 0xec, 0xdb, 0xd7, 0x88, 0xb8, 0x16, 0xc5, - 0xf6, 0xd0, 0x27, 0x6c, 0xa4, 0xda, 0x76, 0xa0, 0x06, 0xe5, 0xf0, 0x47, 0x19, 0xf8, 0x1e, 0xf3, - 0xa0, 0x98, 0x30, 0xa5, 0x84, 0xaf, 0x83, 0xb2, 0xf8, 0xdc, 0xf6, 0x68, 0xdf, 0xa3, 0x2a, 0x65, - 0xe8, 0x86, 0xb8, 0x5d, 0x35, 0x28, 0x77, 0x30, 0x43, 0xe5, 0xf9, 0xff, 0x29, 0x83, 0x98, 0xef, - 0x7a, 0x5d, 0x2f, 0x7a, 0x54, 0xc3, 0xa7, 0xd9, 0xea, 0x53, 0x86, 0x5d, 0x07, 0xfb, 0x7d, 0xe2, - 0x32, 0x15, 0x75, 0x6c, 0xa2, 0xb2, 0xd1, 0x00, 0xd3, 0xe9, 0x4b, 0xf9, 0x3d, 0x0f, 0x3e, 0x69, - 0xa3, 0x1e, 0x71, 0x10, 0xf3, 0x7c, 0x13, 0xb3, 0xda, 0x35, 0x72, 0xbb, 0xf8, 0x12, 0xd9, 0x37, - 0x98, 0xd5, 0x11, 0x43, 0xd0, 0x03, 0x07, 0xc1, 0xfc, 0xbd, 0x35, 0x1c, 0x38, 0x88, 0x61, 0x5a, - 0xe0, 0xa5, 0x74, 0x29, 0x5b, 0x91, 0x94, 0x25, 0xb3, 0x12, 0x32, 0x2b, 0x0b, 0xa6, 0x56, 0x34, - 0x58, 0x95, 0xde, 0xde, 0x3e, 0xe3, 0xfe, 0xbe, 0x7d, 0x56, 0x18, 0xa1, 0x7e, 0xef, 0x2b, 0x39, - 0x46, 0x24, 0x1b, 0x42, 0xb0, 0x0e, 0xa1, 0xb0, 0x04, 0xc2, 0x35, 0x8a, 0xd9, 0x6c, 0xc8, 0x22, - 0x4e, 0x21, 0x25, 0xf1, 0xa5, 0x8c, 0x91, 0x9b, 0xae, 0x4f, 0x07, 0x75, 0x07, 0x7e, 0x0a, 0x00, - 0xed, 0x21, 0x7a, 0x6d, 0x21, 0xfb, 0x86, 0x16, 0xd2, 0x52, 0xba, 0xb4, 0x67, 0xec, 0x45, 0x2b, - 0xc7, 0xf6, 0x0d, 0x95, 0x3d, 0xf0, 0x64, 0x9b, 0x32, 0x0a, 0x0d, 0x90, 0xe9, 0x11, 0xca, 0x66, - 0x4a, 0xbe, 0x54, 0xb6, 0x7b, 0xaf, 0xec, 0xb2, 0xa7, 0x9a, 0x09, 0x15, 0x1a, 0x11, 0x97, 0xfc, - 0x0d, 0xc8, 0xb7, 0xcd, 0xda, 0x39, 0x62, 0x43, 0x1f, 0x3b, 0x2b, 0x16, 0x26, 0x29, 0xe2, 0x93, - 0x14, 0xc9, 0x7f, 0xf0, 0x60, 0xdf, 0x0c, 0x05, 0xac, 0xa0, 0x0d, 0xb0, 0xb7, 0xf0, 0x28, 0x82, - 0x65, 0x2b, 0xe2, 0x76, 0xe3, 0xab, 0x85, 0x99, 0xe5, 0xc2, 0x86, 0xe5, 0xb2, 0xb1, 0xa4, 0x79, - 0x80, 0xc7, 0x55, 0x00, 0x88, 0x7b, 0xe5, 0x23, 0x9b, 0x11, 0xcf, 0x2d, 0xa4, 0x25, 0xbe, 0x94, - 0xab, 0xc8, 0xca, 0xb4, 0x8d, 0xca, 0xbc, 0x7d, 0xb3, 0x36, 0x2a, 0xfa, 0x62, 0xd2, 0x58, 0x41, - 0xc9, 0x9f, 0x81, 0xc7, 0x33, 0x53, 0x5a, 0x6e, 0xc7, 0x73, 0x1d, 0xe2, 0x76, 0x2f, 0x06, 0x14, - 0x0a, 0x20, 0x4d, 0x9c, 0x69, 0x97, 0x32, 0x46, 0xf8, 0x28, 0xff, 0x96, 0x02, 0xb0, 0xe6, 0xb9, - 0x74, 0xd8, 0xc7, 0xfe, 0x8a, 0x03, 0x27, 0x20, 0x13, 0x56, 0x36, 0x12, 0x9f, 0xab, 0x54, 0x76, - 0x65, 0x15, 0x47, 0x37, 0x47, 0x03, 0x6c, 0x44, 0x78, 0xf8, 0x0a, 0xec, 0xd3, 0x75, 0x73, 0x23, - 0xd1, 0xd9, 0xca, 0xe7, 0xbb, 0x28, 0x37, 0xf2, 0x38, 0xe5, 0x8c, 0x4d, 0x16, 0x78, 0x05, 0xf2, - 0x01, 0xb5, 0x63, 0xc1, 0x47, 0x76, 0x65, 0x2b, 0x5f, 0xec, 0x2c, 0x57, 0x42, 0x61, 0x4e, 0x39, - 0x23, 0x91, 0xaf, 0xfa, 0x08, 0x64, 0x1c, 0xc4, 0x90, 0xdc, 0x01, 0x1f, 0xc7, 0x85, 0x9e, 0x11, - 0xca, 0xe0, 0xe9, 0x5a, 0xad, 0x95, 0x87, 0x59, 0xb5, 0x56, 0xe6, 0x37, 0x29, 0x90, 0x8f, 0x8f, - 0xb4, 0xcb, 0xff, 0x5a, 0x1a, 0xaf, 0xb7, 0xa5, 0xf1, 0xe2, 0x01, 0x69, 0xb4, 0xcb, 0xff, 0x87, - 0x3c, 0xfe, 0xe4, 0xc1, 0x41, 0x6c, 0x63, 0xff, 0xf1, 0xc1, 0xfd, 0x2e, 0xe1, 0xe0, 0x1e, 0xee, - 0x52, 0xbe, 0x3c, 0xbc, 0x51, 0x48, 0x2b, 0xe8, 0xc3, 0xdf, 0xf9, 0xa4, 0xc2, 0x85, 0x63, 0xf0, - 0x6b, 0x20, 0xd5, 0x2e, 0x1a, 0x66, 0xeb, 0x5c, 0x33, 0xac, 0xcb, 0xe3, 0xda, 0xf7, 0x5a, 0xd3, - 0x6a, 0xbe, 0xbe, 0xd4, 0xac, 0x56, 0xc3, 0xbc, 0xd4, 0x6a, 0xfa, 0x89, 0xae, 0xd5, 0x05, 0x4e, - 0xfc, 0x68, 0x3c, 0x91, 0x0e, 0x5a, 0x2e, 0x1d, 0x60, 0x9b, 0x5c, 0x91, 0xb9, 0x87, 0x50, 0x05, - 0x62, 0x22, 0xd8, 0x3c, 0x3b, 0x36, 0x4f, 0x05, 0x5e, 0xdc, 0x1f, 0x4f, 0xa4, 0xec, 0x8a, 0xb1, - 0xf0, 0x08, 0x3c, 0x49, 0x04, 0x84, 0xa9, 0x09, 0x29, 0x31, 0x3f, 0x9e, 0x48, 0x42, 0x7b, 0x23, - 0x29, 0x31, 0xf3, 0xf3, 0xaf, 0x45, 0xee, 0xf0, 0x0d, 0x0f, 0x72, 0xeb, 0x12, 0xe1, 0x4b, 0xf0, - 0x54, 0x6f, 0x9c, 0x18, 0xc7, 0xb5, 0xa6, 0x7e, 0xd1, 0x48, 0xda, 0xf6, 0xe3, 0xf1, 0x44, 0xda, - 0x5f, 0x82, 0xb4, 0xfe, 0x80, 0x8d, 0xa0, 0x1a, 0x47, 0xd5, 0x2f, 0x5a, 0xd5, 0x33, 0xcd, 0x32, - 0xf5, 0x6f, 0x1b, 0x02, 0x2f, 0xe6, 0xc6, 0x13, 0x09, 0xd4, 0xbd, 0x61, 0xa7, 0x87, 0x4d, 0xd2, - 0x75, 0xe1, 0x21, 0x28, 0xc4, 0x01, 0xaf, 0x1a, 0x4d, 0xfd, 0x5c, 0x13, 0x52, 0xe2, 0x87, 0xe3, - 0x89, 0xf4, 0x41, 0xdd, 0xfb, 0xd1, 0x65, 0xa4, 0x8f, 0xa7, 0x7b, 0xad, 0x36, 0xde, 0xde, 0x15, - 0xf9, 0x77, 0x77, 0x45, 0xfe, 0xaf, 0xbb, 0x22, 0xff, 0xcb, 0x7d, 0x91, 0x7b, 0x77, 0x5f, 0xe4, - 0xde, 0xdf, 0x17, 0xb9, 0x1f, 0x5e, 0x76, 0x09, 0xbb, 0x1e, 0x76, 0x14, 0xdb, 0xeb, 0xab, 0xb3, - 0x2b, 0xc1, 0x32, 0xd2, 0x17, 0x8b, 0xbb, 0x45, 0x70, 0xa4, 0xfe, 0x14, 0x5d, 0x30, 0xa2, 0x4f, - 0x7d, 0xe7, 0x51, 0xf4, 0xad, 0x3f, 0xfa, 0x27, 0x00, 0x00, 0xff, 0xff, 0x8f, 0xbf, 0xfc, 0xd2, - 0x88, 0x08, 0x00, 0x00, + 0x56, 0xdb, 0x8b, 0x35, 0xd8, 0x13, 0x32, 0x0a, 0xd8, 0xc8, 0x33, 0xb8, 0xcb, 0x1b, 0x54, 0x9c, + 0xfa, 0x02, 0x9c, 0x7a, 0xda, 0x27, 0xe8, 0xb9, 0xb7, 0x3d, 0xae, 0xd4, 0xcb, 0x5e, 0xba, 0xaa, + 0x92, 0x37, 0xe8, 0x13, 0x54, 0xb6, 0x09, 0x7f, 0x62, 0x83, 0x14, 0x69, 0xa5, 0x3d, 0x31, 0x8c, + 0x7f, 0xdf, 0x27, 0x7f, 0x7f, 0x46, 0x1e, 0xf0, 0x94, 0xb8, 0x0c, 0xfb, 0xf6, 0x25, 0x22, 0xae, + 0x45, 0xb1, 0x3d, 0xf6, 0x09, 0x9b, 0xa8, 0xb6, 0x1d, 0xa8, 0x41, 0x35, 0xfc, 0x51, 0x46, 0xbe, + 0xc7, 0x3c, 0x28, 0xa6, 0x4c, 0x29, 0xe1, 0xe3, 0xa0, 0x2a, 0x3e, 0xb5, 0x3d, 0x3a, 0xf4, 0xa8, + 0x4a, 0x19, 0xba, 0x22, 0x6e, 0x5f, 0x0d, 0xaa, 0x3d, 0xcc, 0x50, 0xf5, 0xf6, 0x7f, 0xcc, 0x20, + 0x96, 0xfa, 0x5e, 0xdf, 0x8b, 0x96, 0x6a, 0xb8, 0x9a, 0xef, 0x3e, 0x66, 0xd8, 0x75, 0xb0, 0x3f, + 0x24, 0x2e, 0x53, 0x51, 0xcf, 0x26, 0x2a, 0x9b, 0x8c, 0x30, 0x8d, 0x1f, 0xca, 0xef, 0x38, 0xf0, + 0x45, 0x17, 0x0d, 0x88, 0x83, 0x98, 0xe7, 0x9b, 0x98, 0x35, 0x2e, 0x91, 0xdb, 0xc7, 0xe7, 0xc8, + 0xbe, 0xc2, 0xac, 0x89, 0x18, 0x82, 0x1e, 0xd8, 0x0b, 0x6e, 0x9f, 0x5b, 0xe3, 0x91, 0x83, 0x18, + 0xa6, 0x02, 0x27, 0xe5, 0x2a, 0x85, 0x9a, 0xa4, 0x2c, 0x99, 0x95, 0x90, 0x59, 0x59, 0x30, 0x75, + 0xa2, 0xc1, 0xba, 0xf4, 0xe6, 0xfd, 0x93, 0xcc, 0x7f, 0xef, 0x9f, 0x08, 0x13, 0x34, 0x1c, 0x7c, + 0x27, 0x27, 0x88, 0x64, 0x83, 0x0f, 0xd6, 0x21, 0x14, 0x56, 0x40, 0xb8, 0x47, 0x31, 0x9b, 0x0f, + 0x59, 0xc4, 0x11, 0xb2, 0x12, 0x57, 0xc9, 0x1b, 0xc5, 0x78, 0x3f, 0x1e, 0xd4, 0x1d, 0xf8, 0x25, + 0x00, 0x74, 0x80, 0xe8, 0xa5, 0x85, 0xec, 0x2b, 0x2a, 0xe4, 0xa4, 0x5c, 0x65, 0xc7, 0xd8, 0x89, + 0x76, 0x0e, 0xed, 0x2b, 0x2a, 0x7b, 0xe0, 0xd1, 0x26, 0x65, 0x14, 0x1a, 0x20, 0x3f, 0x20, 0x94, + 0xcd, 0x95, 0x7c, 0xab, 0x6c, 0xf6, 0x5e, 0xd9, 0x66, 0x4f, 0x3d, 0x1f, 0x2a, 0x34, 0x22, 0x2e, + 0xf9, 0x07, 0x50, 0xea, 0x9a, 0x8d, 0x53, 0xc4, 0xc6, 0x3e, 0x76, 0x56, 0x2c, 0x4c, 0x53, 0xc4, + 0xa5, 0x29, 0x92, 0xff, 0xe6, 0xc0, 0xae, 0x19, 0x0a, 0x58, 0x41, 0x1b, 0x60, 0x67, 0xe1, 0x51, + 0x04, 0x2b, 0xd4, 0xc4, 0xcd, 0xc6, 0xd7, 0x85, 0xb9, 0xe5, 0xfc, 0x1d, 0xcb, 0x65, 0x63, 0x49, + 0x73, 0x0f, 0x8f, 0xeb, 0x00, 0x10, 0xf7, 0xc2, 0x47, 0x36, 0x23, 0x9e, 0x2b, 0xe4, 0x24, 0xae, + 0x52, 0xac, 0xc9, 0x4a, 0xdc, 0x46, 0xe5, 0xb6, 0x7d, 0xf3, 0x36, 0x2a, 0xfa, 0x62, 0xd2, 0x58, + 0x41, 0xc9, 0x5f, 0x81, 0x87, 0x73, 0x53, 0x3a, 0x6e, 0xcf, 0x73, 0x1d, 0xe2, 0xf6, 0xcf, 0x46, + 0x14, 0xf2, 0x20, 0x47, 0x9c, 0xb8, 0x4b, 0x79, 0x23, 0x5c, 0xca, 0x7f, 0x66, 0x01, 0x6c, 0x78, + 0x2e, 0x1d, 0x0f, 0xb1, 0xbf, 0xe2, 0xc0, 0x11, 0xc8, 0x87, 0x95, 0x8d, 0xc4, 0x17, 0x6b, 0xb5, + 0x6d, 0x59, 0x25, 0xd1, 0xed, 0xc9, 0x08, 0x1b, 0x11, 0x1e, 0xbe, 0x00, 0xbb, 0x74, 0xdd, 0xdc, + 0x48, 0x74, 0xa1, 0xf6, 0xf5, 0x36, 0xca, 0x3b, 0x79, 0x1c, 0x67, 0x8c, 0xbb, 0x2c, 0xf0, 0x02, + 0x94, 0x02, 0x6a, 0x27, 0x82, 0x8f, 0xec, 0x2a, 0xd4, 0xbe, 0xd9, 0x5a, 0xae, 0x94, 0xc2, 0x1c, + 0x67, 0x8c, 0x54, 0xbe, 0xd8, 0xb1, 0x57, 0x42, 0x3e, 0x4a, 0x2a, 0x5c, 0xd6, 0x1f, 0x80, 0xbc, + 0x83, 0x18, 0x92, 0x7b, 0xe0, 0xf3, 0xa4, 0xf4, 0x13, 0x42, 0x19, 0x3c, 0x5e, 0x2b, 0xba, 0x72, + 0x3f, 0xf3, 0xd6, 0xea, 0xfd, 0x3a, 0x0b, 0x4a, 0xc9, 0x91, 0x6e, 0xf5, 0x83, 0xe5, 0xf3, 0x72, + 0x53, 0x3e, 0xcf, 0xee, 0x91, 0x4f, 0xb7, 0xfa, 0x11, 0x13, 0x5a, 0xe4, 0xf1, 0x0f, 0x07, 0xf6, + 0x12, 0x2f, 0xf6, 0x91, 0x8f, 0xf2, 0x4f, 0x29, 0x47, 0x79, 0x7f, 0x9b, 0xf2, 0xe5, 0x71, 0x8e, + 0x42, 0x5a, 0x41, 0xef, 0xff, 0xc5, 0xa5, 0x15, 0x2e, 0x1c, 0x83, 0xdf, 0x03, 0xa9, 0x71, 0xd6, + 0x32, 0x3b, 0xa7, 0x9a, 0x61, 0x9d, 0x1f, 0x36, 0x7e, 0xd6, 0xda, 0x56, 0xfb, 0xe5, 0xb9, 0x66, + 0x75, 0x5a, 0xe6, 0xb9, 0xd6, 0xd0, 0x8f, 0x74, 0xad, 0xc9, 0x67, 0xc4, 0xcf, 0xa6, 0x33, 0x69, + 0xaf, 0xe3, 0xd2, 0x11, 0xb6, 0xc9, 0x05, 0xb9, 0xf5, 0x10, 0xaa, 0x40, 0x4c, 0x05, 0x9b, 0x27, + 0x87, 0xe6, 0x31, 0xcf, 0x89, 0xbb, 0xd3, 0x99, 0x54, 0x58, 0x31, 0x16, 0x1e, 0x80, 0x47, 0xa9, + 0x80, 0x30, 0x35, 0x3e, 0x2b, 0x96, 0xa6, 0x33, 0x89, 0xef, 0xde, 0x49, 0x4a, 0xcc, 0xff, 0xf6, + 0x47, 0x39, 0xb3, 0xff, 0x9a, 0x03, 0xc5, 0x75, 0x89, 0xf0, 0x39, 0x78, 0xac, 0xb7, 0x8e, 0x8c, + 0xc3, 0x46, 0x5b, 0x3f, 0x6b, 0xa5, 0xbd, 0xf6, 0xc3, 0xe9, 0x4c, 0xda, 0x5d, 0x82, 0xb4, 0xe1, + 0x88, 0x4d, 0xa0, 0x9a, 0x44, 0x35, 0xcf, 0x3a, 0xf5, 0x13, 0xcd, 0x32, 0xf5, 0x1f, 0x5b, 0x3c, + 0x27, 0x16, 0xa7, 0x33, 0x09, 0x34, 0xbd, 0x71, 0x6f, 0x80, 0x4d, 0xd2, 0x77, 0xe1, 0x3e, 0x10, + 0x92, 0x80, 0x17, 0xad, 0xb6, 0x7e, 0xaa, 0xf1, 0x59, 0xf1, 0xd3, 0xe9, 0x4c, 0xfa, 0xa4, 0xe9, + 0xfd, 0xea, 0x32, 0x32, 0xc4, 0xf1, 0xbb, 0xd6, 0x5b, 0x6f, 0xae, 0xcb, 0xdc, 0xdb, 0xeb, 0x32, + 0xf7, 0xef, 0x75, 0x99, 0xfb, 0xfd, 0xa6, 0x9c, 0x79, 0x7b, 0x53, 0xce, 0xbc, 0xbb, 0x29, 0x67, + 0x7e, 0x79, 0xde, 0x27, 0xec, 0x72, 0xdc, 0x53, 0x6c, 0x6f, 0xa8, 0xce, 0x2f, 0x09, 0xcb, 0x48, + 0x9f, 0x2d, 0x6e, 0x1b, 0xc1, 0x81, 0xfa, 0x2a, 0xba, 0x72, 0x44, 0x1f, 0xff, 0xde, 0x83, 0xe8, + 0xeb, 0x7f, 0xf0, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x69, 0x5d, 0x6d, 0x1f, 0x9a, 0x08, 0x00, + 0x00, } func (m *ValidatorSetChangePacketData) Marshal() (dAtA []byte, err error) { @@ -954,6 +964,11 @@ func (m *ConsumerPacketData) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.Idx != 0 { + i = encodeVarintCcv(dAtA, i, uint64(m.Idx)) + i-- + dAtA[i] = 0x20 + } if m.Data != nil { { size := m.Data.Size() @@ -1279,6 +1294,9 @@ func (m *ConsumerPacketData) Size() (n int) { if m.Data != nil { n += m.Data.Size() } + if m.Idx != 0 { + n += 1 + sovCcv(uint64(m.Idx)) + } return n } @@ -2036,6 +2054,25 @@ func (m *ConsumerPacketData) Unmarshal(dAtA []byte) error { } m.Data = &ConsumerPacketData_VscMaturedPacketData{v} iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Idx", wireType) + } + m.Idx = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCcv + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Idx |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipCcv(dAtA[iNdEx:]) From b7a0d1d4806d65265342f21cc23fc73495c055e2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Jul 2023 12:30:31 -0700 Subject: [PATCH 050/134] build(deps): bump google.golang.org/grpc from 1.56.1 to 1.56.2 (#1126) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.56.1 to 1.56.2. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.56.1...v1.56.2) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 036c4d4c46..d639ef5dca 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( golang.org/x/net v0.9.0 // indirect golang.org/x/sys v0.7.0 // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 - google.golang.org/grpc v1.56.1 + google.golang.org/grpc v1.56.2 google.golang.org/protobuf v1.31.0 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index 6ef711918b..5bf7c2d676 100644 --- a/go.sum +++ b/go.sum @@ -1790,8 +1790,8 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.56.1 h1:z0dNfjIl0VpaZ9iSVjA6daGatAYwPGstTjt5vkRMFkQ= -google.golang.org/grpc v1.56.1/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/grpc v1.56.2 h1:fVRFRnXvU+x6C4IlHZewvJOVHoOv1TUuQyoRsYnB4bI= +google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= From efd69b0ff11a15cd5108e27d1f575badefea59a6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Jul 2023 12:59:07 -0700 Subject: [PATCH 051/134] build(deps): bump semver from 6.3.0 to 6.3.1 in /tests/difference/core/model (#1129) build(deps): bump semver in /tests/difference/core/model Bumps [semver](https://github.com/npm/node-semver) from 6.3.0 to 6.3.1. - [Release notes](https://github.com/npm/node-semver/releases) - [Changelog](https://github.com/npm/node-semver/blob/v6.3.1/CHANGELOG.md) - [Commits](https://github.com/npm/node-semver/compare/v6.3.0...v6.3.1) --- updated-dependencies: - dependency-name: semver dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> --- tests/difference/core/model/yarn.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/difference/core/model/yarn.lock b/tests/difference/core/model/yarn.lock index 2f35241e52..a708e2fa11 100644 --- a/tests/difference/core/model/yarn.lock +++ b/tests/difference/core/model/yarn.lock @@ -2498,16 +2498,16 @@ safe-buffer@~5.1.1: integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== semver@7.x, semver@^7.3.5, semver@^7.3.7: - version "7.3.7" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" - integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== dependencies: lru-cache "^6.0.0" semver@^6.0.0, semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== shallow-clone@^3.0.0: version "3.0.1" From 3f3ba9c21fec75c349e0b4f2cfaf652e5966a904 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Jul 2023 13:23:19 -0700 Subject: [PATCH 052/134] build(deps): bump semver from 5.7.1 to 5.7.2 in /docs (#1141) Bumps [semver](https://github.com/npm/node-semver) from 5.7.1 to 5.7.2. - [Release notes](https://github.com/npm/node-semver/releases) - [Changelog](https://github.com/npm/node-semver/blob/v5.7.2/CHANGELOG.md) - [Commits](https://github.com/npm/node-semver/compare/v5.7.1...v5.7.2) --- updated-dependencies: - dependency-name: semver dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> --- docs/package-lock.json | 144 ++++++++++++++++++++--------------------- 1 file changed, 72 insertions(+), 72 deletions(-) diff --git a/docs/package-lock.json b/docs/package-lock.json index 7d86ce0b2e..385c2a96d6 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -236,9 +236,9 @@ } }, "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } @@ -312,9 +312,9 @@ } }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } @@ -372,9 +372,9 @@ } }, "node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } @@ -1624,9 +1624,9 @@ } }, "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } @@ -1836,9 +1836,9 @@ } }, "node_modules/@babel/preset-env/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } @@ -2799,9 +2799,9 @@ } }, "node_modules/@mdx-js/mdx/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "bin": { "semver": "bin/semver" } @@ -4045,9 +4045,9 @@ } }, "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } @@ -7770,9 +7770,9 @@ } }, "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } @@ -8395,9 +8395,9 @@ } }, "node_modules/package-json/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } @@ -10060,9 +10060,9 @@ } }, "node_modules/remark-mdx/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "bin": { "semver": "bin/semver" } @@ -10511,9 +10511,9 @@ } }, "node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -10536,9 +10536,9 @@ } }, "node_modules/semver-diff/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } @@ -12934,9 +12934,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" } } }, @@ -12993,9 +12993,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" } } }, @@ -13037,9 +13037,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" } } }, @@ -13849,9 +13849,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" } } }, @@ -14006,9 +14006,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" } } }, @@ -14733,9 +14733,9 @@ } }, "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" }, "source-map": { "version": "0.5.7", @@ -15706,9 +15706,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" } } }, @@ -18383,9 +18383,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" } } }, @@ -18813,9 +18813,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" } } }, @@ -19957,9 +19957,9 @@ } }, "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" }, "source-map": { "version": "0.5.7", @@ -20272,9 +20272,9 @@ } }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "requires": { "lru-cache": "^6.0.0" }, @@ -20303,9 +20303,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" } } }, From d77fbf4f49c99b102b072fdf95d35e00ebbf0825 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Mon, 17 Jul 2023 09:18:24 -0700 Subject: [PATCH 053/134] fix!: proper deletion of pending packets (#1146) * Update relay.go * expectation func * reg test * Update CHANGELOG.md --- CHANGELOG.md | 1 + testutil/keeper/expectations.go | 19 +++++++++++++++ x/ccv/consumer/keeper/relay.go | 10 ++++---- x/ccv/consumer/keeper/relay_test.go | 36 +++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c017fc5b1..7109f43bbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Add an entry to the unreleased section whenever merging a PR to main that is not targeted at a specific release. These entries will eventually be included in a release. +* (fix!) proper deletion of pending packets [#1146](https://github.com/cosmos/interchain-security/pull/1146) * (feat!) optimize pending packets storage on consumer, with migration! [#1037](https://github.com/cosmos/interchain-security/pull/1037) ## v3.1.0 diff --git a/testutil/keeper/expectations.go b/testutil/keeper/expectations.go index 1e59085d23..8a231f4760 100644 --- a/testutil/keeper/expectations.go +++ b/testutil/keeper/expectations.go @@ -14,6 +14,7 @@ import ( channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + "github.com/cosmos/interchain-security/v3/x/ccv/types" host "github.com/cosmos/ibc-go/v7/modules/core/24-host" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" @@ -139,3 +140,21 @@ func ExpectGetCapabilityMock(ctx sdk.Context, mocks MockedKeepers, times int) *g ctx, host.PortPath(ccv.ConsumerPortID), ).Return(nil, true).Times(times) } + +func GetMocksForSendIBCPacket(ctx sdk.Context, mocks MockedKeepers, channelID string, times int) []*gomock.Call { + return []*gomock.Call{ + mocks.MockChannelKeeper.EXPECT().GetChannel(ctx, types.ConsumerPortID, + "consumerCCVChannelID").Return(channeltypes.Channel{}, true).Times(times), + mocks.MockScopedKeeper.EXPECT().GetCapability(ctx, + host.ChannelCapabilityPath(types.ConsumerPortID, "consumerCCVChannelID")).Return( + capabilitytypes.NewCapability(1), true).Times(times), + mocks.MockChannelKeeper.EXPECT().SendPacket(ctx, + capabilitytypes.NewCapability(1), + types.ConsumerPortID, + "consumerCCVChannelID", + gomock.Any(), + gomock.Any(), + gomock.Any(), + ).Return(uint64(888), nil).Times(times), + } +} diff --git a/x/ccv/consumer/keeper/relay.go b/x/ccv/consumer/keeper/relay.go index 073a1d3996..120c0218c2 100644 --- a/x/ccv/consumer/keeper/relay.go +++ b/x/ccv/consumer/keeper/relay.go @@ -186,6 +186,7 @@ func (k Keeper) SendPackets(ctx sdk.Context) { } pending := k.GetPendingPackets(ctx) + idxsForDeletion := []uint64{} for _, p := range pending { // send packet over IBC @@ -203,18 +204,19 @@ func (k Keeper) SendPackets(ctx sdk.Context) { // IBC client is expired! // leave the packet data stored to be sent once the client is upgraded k.Logger(ctx).Info("IBC client is expired, cannot send IBC packet; leaving packet data stored:", "type", p.Type.String()) - return + break } // Not able to send packet over IBC! // Leave the packet data stored for the sent to be retried in the next block. // Note that if VSCMaturedPackets are not sent for long enough, the provider // will remove the consumer anyway. k.Logger(ctx).Error("cannot send IBC packet; leaving packet data stored:", "type", p.Type.String(), "err", err.Error()) - return + break } + idxsForDeletion = append(idxsForDeletion, p.Idx) } - - k.DeleteAllPendingDataPackets(ctx) + // Delete pending packets that were successfully sent and did not return an error from SendIBCPacket + k.DeletePendingDataPackets(ctx, idxsForDeletion...) } // OnAcknowledgementPacket executes application logic for acknowledgments of sent VSCMatured and Slash packets diff --git a/x/ccv/consumer/keeper/relay_test.go b/x/ccv/consumer/keeper/relay_test.go index 48ad7f5ab9..6dbebe273f 100644 --- a/x/ccv/consumer/keeper/relay_test.go +++ b/x/ccv/consumer/keeper/relay_test.go @@ -307,3 +307,39 @@ func TestSendPacketsFailure(t *testing.T) { consumerKeeper.SendPackets(ctx) require.Equal(t, 3, len(consumerKeeper.GetPendingPackets(ctx))) } + +// Regression test for https://github.com/cosmos/interchain-security/issues/1145 +func TestSendPacketsDeletion(t *testing.T) { + // Keeper setup + consumerKeeper, ctx, ctrl, mocks := testkeeper.GetConsumerKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + consumerKeeper.SetProviderChannel(ctx, "consumerCCVChannelID") + consumerKeeper.SetParams(ctx, consumertypes.DefaultParams()) + + // Queue two pending packets + consumerKeeper.AppendPendingPacket(ctx, types.SlashPacket, &types.ConsumerPacketData_SlashPacketData{ // Slash appears first + SlashPacketData: &types.SlashPacketData{ + Validator: abci.Validator{}, + ValsetUpdateId: 88, + Infraction: stakingtypes.Infraction_INFRACTION_DOWNTIME, + }, + }) + consumerKeeper.AppendPendingPacket(ctx, types.VscMaturedPacket, &types.ConsumerPacketData_VscMaturedPacketData{ + VscMaturedPacketData: &types.VSCMaturedPacketData{ + ValsetUpdateId: 90, + }, + }) + + // Get mocks for a successful SendPacket call that does NOT return an error + expectations := testkeeper.GetMocksForSendIBCPacket(ctx, mocks, "consumerCCVChannelID", 1) + // Append mocks for a failed SendPacket call, which returns an error + expectations = append(expectations, mocks.MockChannelKeeper.EXPECT().GetChannel(ctx, types.ConsumerPortID, + "consumerCCVChannelID").Return(channeltypes.Channel{}, false).Times(1)) + gomock.InOrder(expectations...) + + consumerKeeper.SendPackets(ctx) + + // Expect the first successfully sent packet to be popped from queue + require.Equal(t, 1, len(consumerKeeper.GetPendingPackets(ctx))) + require.Equal(t, types.VscMaturedPacket, consumerKeeper.GetPendingPackets(ctx)[0].Type) +} From d8373547507384e3479fc12ccd2de77ddc74383e Mon Sep 17 00:00:00 2001 From: omahs <73983677+omahs@users.noreply.github.com> Date: Mon, 17 Jul 2023 20:38:25 +0200 Subject: [PATCH 054/134] docs: fix typos (#1144) * Fix: typo * Fix: typo * Fix: typo * Fix: typos * Fix: typo * Fix: typos * Fix: typos --------- Co-authored-by: MSalopek Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> --- docs/docs/adrs/adr-template.md | 2 +- docs/docs/consumer-development/consumer-chain-governance.md | 2 +- docs/docs/consumer-development/onboarding.md | 6 +++--- docs/docs/features/key-assignment.md | 2 +- docs/docs/features/proposals.md | 4 ++-- docs/docs/features/slashing.md | 4 ++-- docs/docs/introduction/terminology.md | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/docs/adrs/adr-template.md b/docs/docs/adrs/adr-template.md index 2e085330df..b9e3af1678 100644 --- a/docs/docs/adrs/adr-template.md +++ b/docs/docs/adrs/adr-template.md @@ -36,6 +36,6 @@ If the proposed change will be large, please also indicate a way to do the chang ## References -> Are there any relevant PR comments, issues that led up to this, or articles referrenced for why we made the given design choice? If so link them here! +> Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here! * {reference link} diff --git a/docs/docs/consumer-development/consumer-chain-governance.md b/docs/docs/consumer-development/consumer-chain-governance.md index ca99286d93..c8586efe3a 100644 --- a/docs/docs/consumer-development/consumer-chain-governance.md +++ b/docs/docs/consumer-development/consumer-chain-governance.md @@ -16,7 +16,7 @@ For an example, see the [Democracy Consumer](https://github.com/cosmos/interchai ## CosmWasm -There several great DAO and governance frameworks written as CosmWasm contracts. These can be used as the main governance system for a consumer chain. Actions triggered by the CosmWasm governance contracts are able to affect parameters and trigger actions on the consumer chain. +There are several great DAO and governance frameworks written as CosmWasm contracts. These can be used as the main governance system for a consumer chain. Actions triggered by the CosmWasm governance contracts are able to affect parameters and trigger actions on the consumer chain. For an example, see [Neutron](https://github.com/neutron-org/neutron/). diff --git a/docs/docs/consumer-development/onboarding.md b/docs/docs/consumer-development/onboarding.md index 89c5f32dc5..dc870b76de 100644 --- a/docs/docs/consumer-development/onboarding.md +++ b/docs/docs/consumer-development/onboarding.md @@ -20,7 +20,7 @@ To help validators and other node runners onboard onto your chain, please prepar This should include (at minimum): -- [ ] genesis.json witout CCV data (before the propsal passes) +- [ ] genesis.json without CCV data (before the proposal passes) - [ ] genesis.json with CCV data (after spawn time passes) - [ ] information about relevant seed/peer nodes you are running - [ ] relayer information (compatible versions) @@ -73,7 +73,7 @@ Example of a consumer chain addition proposal. // will be responsible for starting their consumer chain validator node. "spawn_time": "2023-02-28T20:40:00.000000Z", // Unbonding period for the consumer chain. - // It should should be smaller than that of the provider. + // It should be smaller than that of the provider. "unbonding_period": 86400000000000, // Timeout period for CCV related IBC packets. // Packets are considered timed-out after this interval elapses. @@ -96,7 +96,7 @@ Example of a consumer chain addition proposal. // channel is created on top of the same connection as the CCV channel. // Note that transfer_channel_id is the ID of the channel end on the consumer chain. // it is most relevant for chains performing a sovereign to consumer changeover - // in order to maintan the existing ibc transfer channel + // in order to maintain the existing ibc transfer channel "distribution_transmission_channel": "channel-123" } ``` diff --git a/docs/docs/features/key-assignment.md b/docs/docs/features/key-assignment.md index c68343255c..a44ed8a32a 100644 --- a/docs/docs/features/key-assignment.md +++ b/docs/docs/features/key-assignment.md @@ -49,7 +49,7 @@ gaiad tx provider assign-consensus-key '' --from "}` -Check that the key was assigned correcly by querying the provider: +Check that the key was assigned correctly by querying the provider: ```bash gaiad query provider validator-consumer-key cosmosvalcons1e....3xsj3ayzf4uv6 diff --git a/docs/docs/features/proposals.md b/docs/docs/features/proposals.md index b68fd343d6..25664bfc1e 100644 --- a/docs/docs/features/proposals.md +++ b/docs/docs/features/proposals.md @@ -32,7 +32,7 @@ Minimal example: "revision_number": 1, }, // Unbonding period for the consumer chain. - // It should should be smaller than that of the provider. + // It should be smaller than that of the provider. "unbonding_period": 86400000000000, // Timeout period for CCV related IBC packets. // Packets are considered timed-out after this interval elapses. @@ -44,7 +44,7 @@ Minimal example: "genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0", "binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1" // relevant for chains performing a sovereign to consumer changeover - // in order to maintan the existing ibc transfer channel + // in order to maintain the existing ibc transfer channel "distribution_transmission_channel": "channel-123" } ``` diff --git a/docs/docs/features/slashing.md b/docs/docs/features/slashing.md index a28b16e8c2..4c74153b15 100644 --- a/docs/docs/features/slashing.md +++ b/docs/docs/features/slashing.md @@ -3,7 +3,7 @@ sidebar_position: 4 --- # Consumer Initiated Slashing -A consumer chain is essentially a regular Cosmos-SDK based chain that uses the interchain security module to achieve economic security by stake deposited on the provider chain, instead of it's own chain. +A consumer chain is essentially a regular Cosmos-SDK based chain that uses the interchain security module to achieve economic security by stake deposited on the provider chain, instead of its own chain. In essence, provider chain and consumer chains are different networks (different infrastructures) that are bound together by the provider's validator set. By being bound to the provider's validator set, a consumer chain inherits the economic security guarantees of the provider chain (in terms of total stake). To maintain the proof of stake model, the consumer chain is able to send evidence of infractions (double signing and downtime) to the provider chain so the offending validators can be penalized. @@ -17,7 +17,7 @@ reported by consumer chains are acted upon on the provider as soon as the provid Instead of slashing, the provider will only jail offending validator for the duration of time established in the chain parameters. :::info -Slash throttling (sometimes called jail throttling) mechanism insures that only a fraction of the validator set can be jailed at any one time to prevent malicious consumer chains from harming the provider. +Slash throttling (sometimes called jail throttling) mechanism ensures that only a fraction of the validator set can be jailed at any one time to prevent malicious consumer chains from harming the provider. ::: ## Double-signing (equivocation) diff --git a/docs/docs/introduction/terminology.md b/docs/docs/introduction/terminology.md index 5f6722fbd9..59994353cf 100644 --- a/docs/docs/introduction/terminology.md +++ b/docs/docs/introduction/terminology.md @@ -8,7 +8,7 @@ You may have heard of one or multiple buzzwords thrown around in the cosmos and ## Shared Security -Shared security is a family of technologies that include optimistic rollups, zk-rollups, sharding and Interchain Security. Ie. any protocol or technology that can allow one blockchain to lend/share it's proof-of-stake security with another blockchain or off-chain process. +Shared security is a family of technologies that include optimistic rollups, zk-rollups, sharding and Interchain Security. Ie. any protocol or technology that can allow one blockchain to lend/share its proof-of-stake security with another blockchain or off-chain process. ## Interchain Security From d67d1bca18440733982bd0680193f31eac2bd59d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Jul 2023 14:33:45 -0700 Subject: [PATCH 055/134] build(deps): bump bufbuild/buf-setup-action from 1.23.1 to 1.24.0 (#1151) Bumps [bufbuild/buf-setup-action](https://github.com/bufbuild/buf-setup-action) from 1.23.1 to 1.24.0. - [Release notes](https://github.com/bufbuild/buf-setup-action/releases) - [Commits](https://github.com/bufbuild/buf-setup-action/compare/v1.23.1...v1.24.0) --- updated-dependencies: - dependency-name: bufbuild/buf-setup-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> --- .github/workflows/proto-registry.yml | 2 +- .github/workflows/proto.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/proto-registry.yml b/.github/workflows/proto-registry.yml index 08748fe079..d79db5af70 100644 --- a/.github/workflows/proto-registry.yml +++ b/.github/workflows/proto-registry.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: bufbuild/buf-setup-action@v1.23.1 + - uses: bufbuild/buf-setup-action@v1.24.0 - uses: bufbuild/buf-push-action@v1 with: input: "proto" diff --git a/.github/workflows/proto.yml b/.github/workflows/proto.yml index 0049c05d20..9791a871c0 100644 --- a/.github/workflows/proto.yml +++ b/.github/workflows/proto.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: bufbuild/buf-setup-action@v1.23.1 + - uses: bufbuild/buf-setup-action@v1.24.0 - uses: bufbuild/buf-breaking-action@v1 with: input: "proto" From 781eefb267882e70574be86d2f7f4d6f5abcf75f Mon Sep 17 00:00:00 2001 From: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Mon, 17 Jul 2023 14:57:28 -0700 Subject: [PATCH 056/134] chore: add release/v3.1.x targets for bots (#1140) update Co-authored-by: MSalopek --- .github/dependabot.yml | 10 ++++++++++ .mergify.yml | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index ec9119084e..65ff156753 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -37,3 +37,13 @@ updates: open-pull-requests-limit: 0 labels: - dependencies + + - package-ecosystem: gomod + directory: "/" + schedule: + interval: daily + target-branch: "release/v3.1.x" + # Only allow automated security-related dependency updates on release branches. + open-pull-requests-limit: 0 + labels: + - dependencies diff --git a/.mergify.yml b/.mergify.yml index 63b8b61550..e08625bf28 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -26,3 +26,11 @@ pull_request_rules: backport: branches: - release/v3.0.x + - name: Backport patches to the release/v3.1.x branch + conditions: + - base=main + - label=A:backport/v3.1.x + actions: + backport: + branches: + - release/v3.1.x From 13468a94ae53d310d1620ecfa79076710af24e34 Mon Sep 17 00:00:00 2001 From: MSalopek Date: Tue, 18 Jul 2023 15:40:55 +0200 Subject: [PATCH 057/134] fix: update broken .dependabot.yml (#1156) --- .github/dependabot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 65ff156753..647408015a 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -38,7 +38,7 @@ updates: labels: - dependencies - - package-ecosystem: gomod + - package-ecosystem: gomod directory: "/" schedule: interval: daily From 82cdd910d92dd9b09a597b484e83e6a7f033e743 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Tue, 18 Jul 2023 08:05:01 -0700 Subject: [PATCH 058/134] docs: ADR for standalone to consumer changeover (#1111) * Create adr-010-standalone-changeover.md * Update adr-010-standalone-changeover.md * Update adr-010-standalone-changeover.md * change order * permalinks --------- Co-authored-by: MSalopek --- .../adrs/adr-010-standalone-changeover.md | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 docs/docs/adrs/adr-010-standalone-changeover.md diff --git a/docs/docs/adrs/adr-010-standalone-changeover.md b/docs/docs/adrs/adr-010-standalone-changeover.md new file mode 100644 index 0000000000..17c192d1fe --- /dev/null +++ b/docs/docs/adrs/adr-010-standalone-changeover.md @@ -0,0 +1,55 @@ +--- +sidebar_position: 11 +title: Standalone to Consumer Changeover +--- +## ADR 010: Standalone to Consumer Changeover + +## Changelog + +* 6/30/23: Feature completed, first draft of ADR. + +## Status + +Implemented + +## Context + +[Stride](https://github.com/Stride-Labs/stride) will be the first consumer to "changeover" from a standalone cosmos blockchain, to a consumer chain secured by the Cosmos Hub. This document will outline the changes made to the replicated security protocol to support this changeover process. + +## Decision + +### Process + +Prior to the changeover, the consumer chain will have an existing staking keeper and validator set, these may be referred to as the "standalone staking keeper" and "standalone validator set" respectively. + +The first step in the changeover process is to submit a ConsumerAdditionProposal. If the proposal passes, the provider will create a new IBC client for the consumer at spawn time, with the provider's validator set. A consumer genesis will also be constructed by the provider for validators to query. Within this consumer genesis contains the initial validator set for the consumer to apply after the changeover. + +Next, the standalone consumer chain runs an upgrade which adds the CCV module, and is properly setup to execute changeover logic. + +The consumer upgrade height must be reached after the provider has created the new IBC client. Any replicated security validators who will run the consumer, but are not a part of the sovereign validator set, must sync up a full node before the consumer upgrade height is reached. The disc state of said full node will be used to run the consumer chain after the changeover has completed. + +The meat of the changeover logic is that the consumer chain validator set is updated to that which was specified by the provider via the queried consumer genesis. Validators which were a part of the old set, but not the new set, are given zero voting power. Once these validator updates are given to Comet, the set is committed, and in effect 2 blocks later (see [FirstConsumerHeight](https://github.com/cosmos/interchain-security/blob/f10e780df182158d95a30f7cf94588b2d0479309/x/ccv/consumer/keeper/changeover.go#L19)). + +A relayer then establishes the new IBC connection between the provider and consumer. The CCV channel handshake is started on top of this connection. Once the CCV channel is established and VSC packets are being relayed, the consumer chain is secured by the provider. + +### Changes to CCV Protocol + +* Consumer Genesis state is updated to include a `PreCCV` boolean. When this boolean is set true in the consumer genesis JSON, [special logic](https://github.com/cosmos/interchain-security/blob/f10e780df182158d95a30f7cf94588b2d0479309/x/ccv/consumer/keeper/changeover.go) is executed on InitGenesis to trigger the changeover process on the consumer's first endblocker after the upgrade which adds the CCV module. Note that InitGenesis is not automatically called during chain upgrades, so the consumer must manually call the consumer's InitGenesis method in an upgrade handler. +* The `ConsumerAdditionProposal` type is updated to include a `DistributionTransmissionChannel` field. This field allows the consumer to use an existing IBC transfer channel to send rewards as a part of the CCV protocol. Consumers that're not changing over from a standalone chain will leave this field blank, indicating that a new transfer channel should be created on top of the same connection as the CCV channel. +* The CCV consumer keeper is updated to contain an optional reference to the standalone staking keeper. The standalone staking keeper is used to slash for infractions that happened before the changeover was completed. Ie. any infraction from a block height before the changeover, that is submitted after the changeover, will call the standalone staking keeper's slash method. Note that a changeover consumer's standalone staking keeper becomes a democracy module keeper, so it is possible for a governance token to be slashed. + +## Consequences + +### Positive + +* Existing cosmos chains are now able to onboard over to a consumer chain secured by a provider. +* The previous staking keepers for such chains can be transitioned to democracy staking module keepers. + +### Negative + +* The delineation between different types of consumers in this repo becomes less clear. Ie. there is code in the [democracy consumer's app.go](https://github.com/cosmos/interchain-security/blob/f10e780df182158d95a30f7cf94588b2d0479309/app/consumer-democracy/app.go) that only applies to a previously standalone chain, but that file also serves as the base for a normal democracy consumer launched with RS from genesis. + +## References + +* EPIC: Standalone to Consumer Changeover [#756](https://github.com/cosmos/interchain-security/issues/756) +* [Changeover diagram from Stride](https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt) From 3bb50053673ddfbd1a72be0ade92ac2069534312 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Jul 2023 08:32:51 -0700 Subject: [PATCH 059/134] build(deps): bump cosmossdk.io/errors from 1.0.0-beta.7 to 1.0.0 (#1154) Bumps [cosmossdk.io/errors](https://github.com/cosmos/cosmos-sdk) from 1.0.0-beta.7 to 1.0.0. - [Release notes](https://github.com/cosmos/cosmos-sdk/releases) - [Changelog](https://github.com/cosmos/cosmos-sdk/blob/main/CHANGELOG.md) - [Commits](https://github.com/cosmos/cosmos-sdk/compare/errors/v1.0.0-beta.7...log/v1.0.0) --- updated-dependencies: - dependency-name: cosmossdk.io/errors dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Co-authored-by: Marius Poke --- go.mod | 12 ++++++------ go.sum | 24 ++++++++++++------------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index d639ef5dca..7947a36e66 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/cosmos/interchain-security/v3 go 1.20 require ( - cosmossdk.io/errors v1.0.0-beta.7 + cosmossdk.io/errors v1.0.0 cosmossdk.io/math v1.0.1 github.com/cometbft/cometbft v0.37.2 github.com/cometbft/cometbft-db v0.8.0 @@ -22,10 +22,10 @@ require ( github.com/spf13/cobra v1.6.1 github.com/stretchr/testify v1.8.4 github.com/tidwall/gjson v1.14.4 - golang.org/x/crypto v0.8.0 // indirect + golang.org/x/crypto v0.11.0 // indirect golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc - golang.org/x/net v0.9.0 // indirect - golang.org/x/sys v0.7.0 // indirect + golang.org/x/net v0.12.0 // indirect + golang.org/x/sys v0.10.0 // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 google.golang.org/grpc v1.56.2 google.golang.org/protobuf v1.31.0 @@ -153,8 +153,8 @@ require ( go.etcd.io/bbolt v1.3.7 // indirect go.opencensus.io v0.24.0 // indirect golang.org/x/oauth2 v0.7.0 // indirect - golang.org/x/term v0.7.0 // indirect - golang.org/x/text v0.9.0 // indirect + golang.org/x/term v0.10.0 // indirect + golang.org/x/text v0.11.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/api v0.114.0 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index 5bf7c2d676..26ceadb4ea 100644 --- a/go.sum +++ b/go.sum @@ -198,8 +198,8 @@ cosmossdk.io/core v0.5.1 h1:vQVtFrIYOQJDV3f7rw4pjjVqc1id4+mE0L9hHP66pyI= cosmossdk.io/core v0.5.1/go.mod h1:KZtwHCLjcFuo0nmDc24Xy6CRNEL9Vl/MeimQ2aC7NLE= cosmossdk.io/depinject v1.0.0-alpha.3 h1:6evFIgj//Y3w09bqOUOzEpFj5tsxBqdc5CfkO7z+zfw= cosmossdk.io/depinject v1.0.0-alpha.3/go.mod h1:eRbcdQ7MRpIPEM5YUJh8k97nxHpYbc3sMUnEtt8HPWU= -cosmossdk.io/errors v1.0.0-beta.7 h1:gypHW76pTQGVnHKo6QBkb4yFOJjC+sUGRc5Al3Odj1w= -cosmossdk.io/errors v1.0.0-beta.7/go.mod h1:mz6FQMJRku4bY7aqS/Gwfcmr/ue91roMEKAmDUDpBfE= +cosmossdk.io/errors v1.0.0 h1:nxF07lmlBbB8NKQhtJ+sJm6ef5uV1XkvPXG2bUntb04= +cosmossdk.io/errors v1.0.0/go.mod h1:+hJZLuhdDE0pYN8HkOrVNwrIOYvUGnn6+4fjnJs/oV0= cosmossdk.io/log v1.1.0 h1:v0ogPHYeTzPcBTcPR1A3j1hkei4pZama8kz8LKlCMv0= cosmossdk.io/log v1.1.0/go.mod h1:6zjroETlcDs+mm62gd8Ig7mZ+N+fVOZS91V17H+M4N4= cosmossdk.io/math v1.0.1 h1:Qx3ifyOPaMLNH/89WeZFH268yCvU4xEcnPLu3sJqPPg= @@ -1208,8 +1208,8 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= -golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= +golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1319,8 +1319,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= -golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= +golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1470,14 +1470,14 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= -golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ= -golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= +golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1488,8 +1488,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= From 9cac44e9caec97fa04b2ee1526aeec3e5c54b93b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Jul 2023 09:49:16 -0700 Subject: [PATCH 060/134] build(deps): bump JamesIves/github-pages-deploy-action from 4.4.2 to 4.4.3 (#1152) build(deps): bump JamesIves/github-pages-deploy-action Bumps [JamesIves/github-pages-deploy-action](https://github.com/jamesives/github-pages-deploy-action) from 4.4.2 to 4.4.3. - [Release notes](https://github.com/jamesives/github-pages-deploy-action/releases) - [Commits](https://github.com/jamesives/github-pages-deploy-action/compare/v4.4.2...v4.4.3) --- updated-dependencies: - dependency-name: JamesIves/github-pages-deploy-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Co-authored-by: Marius Poke --- .github/workflows/deploy-docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index 87b4ced180..0c7dff60c5 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -40,7 +40,7 @@ jobs: make build-docs - name: Deploy 🚀 - uses: JamesIves/github-pages-deploy-action@v4.4.2 + uses: JamesIves/github-pages-deploy-action@v4.4.3 with: branch: gh-pages folder: ~/output From 2f62e7d914ffafad2070cc8774c2e19269b57f97 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Tue, 18 Jul 2023 10:10:58 -0700 Subject: [PATCH 061/134] fix!: revert recent consumer packet data changes (#1150) * revert changes * lint * Update CHANGELOG.md * wrapper type --- CHANGELOG.md | 1 + proto/interchain_security/ccv/v1/ccv.proto | 1 - x/ccv/consumer/keeper/genesis_test.go | 4 - x/ccv/consumer/keeper/keeper.go | 40 ++++-- x/ccv/consumer/keeper/keeper_test.go | 11 +- x/ccv/consumer/keeper/migration_test.go | 5 - x/ccv/consumer/keeper/relay.go | 2 +- x/ccv/types/ccv.go | 3 +- x/ccv/types/ccv.pb.go | 142 ++++++++------------- 9 files changed, 92 insertions(+), 117 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7109f43bbf..2a5c14c6e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Add an entry to the unreleased section whenever merging a PR to main that is not targeted at a specific release. These entries will eventually be included in a release. +* (fix!) revert consumer packet data changes from #1037 [#1150](https://github.com/cosmos/interchain-security/pull/1150) * (fix!) proper deletion of pending packets [#1146](https://github.com/cosmos/interchain-security/pull/1146) * (feat!) optimize pending packets storage on consumer, with migration! [#1037](https://github.com/cosmos/interchain-security/pull/1037) diff --git a/proto/interchain_security/ccv/v1/ccv.proto b/proto/interchain_security/ccv/v1/ccv.proto index b8ad8ee6d0..adf8f418de 100644 --- a/proto/interchain_security/ccv/v1/ccv.proto +++ b/proto/interchain_security/ccv/v1/ccv.proto @@ -64,7 +64,6 @@ message ConsumerPacketData { SlashPacketData slashPacketData = 2; VSCMaturedPacketData vscMaturedPacketData = 3; } - uint64 idx = 4; } diff --git a/x/ccv/consumer/keeper/genesis_test.go b/x/ccv/consumer/keeper/genesis_test.go index 5058f6ff5c..649505da0c 100644 --- a/x/ccv/consumer/keeper/genesis_test.go +++ b/x/ccv/consumer/keeper/genesis_test.go @@ -262,16 +262,12 @@ func TestExportGenesis(t *testing.T) { Data: &ccv.ConsumerPacketData_SlashPacketData{ SlashPacketData: ccv.NewSlashPacketData(abciValidator, vscID, stakingtypes.Infraction_INFRACTION_DOWNTIME), }, - Idx: 0, }, { Type: ccv.VscMaturedPacket, Data: &ccv.ConsumerPacketData_VscMaturedPacketData{ VscMaturedPacketData: ccv.NewVSCMaturedPacketData(vscID), }, - // This idx is a part of the expected genesis state. - // If the keeper is correctly storing consumer packet data, indexes should be populated. - Idx: 1, }, }, } diff --git a/x/ccv/consumer/keeper/keeper.go b/x/ccv/consumer/keeper/keeper.go index cfff31b367..e8b1cb793e 100644 --- a/x/ccv/consumer/keeper/keeper.go +++ b/x/ccv/consumer/keeper/keeper.go @@ -606,9 +606,29 @@ func (k Keeper) getAndIncrementPendingPacketsIdx(ctx sdk.Context) (toReturn uint return toReturn } -// GetPendingPackets returns ALL the pending CCV packets from the store +// GetPendingPackets returns ALL the pending CCV packets from the store without indexes. func (k Keeper) GetPendingPackets(ctx sdk.Context) []ccv.ConsumerPacketData { - var packets []ccv.ConsumerPacketData + ppWithIndexes := k.GetAllPendingPacketsWithIdx(ctx) + var ppList []ccv.ConsumerPacketData + for _, ppWithIndex := range ppWithIndexes { + ppList = append(ppList, ppWithIndex.ConsumerPacketData) + } + return ppList +} + +// ConsumerPacketDataWithIdx is a wrapper around ConsumerPacketData +// that also stores the index of the packet in the pending packets queue. +// +// Note this type is a shim to avoid changing the schema of ConsumerPacketData and breaking the wire. +type ConsumerPacketDataWithIdx struct { + ccv.ConsumerPacketData // Struct embedding + Idx uint64 +} + +// GetAllPendingPacketsWithIdx returns ALL pending consumer packet data from the store +// with indexes relevant to the pending packets queue. +func (k Keeper) GetAllPendingPacketsWithIdx(ctx sdk.Context) []ConsumerPacketDataWithIdx { + packets := []ConsumerPacketDataWithIdx{} store := ctx.KVStore(k.storeKey) // Note: PendingDataPacketsBytePrefix is the correct prefix, NOT PendingDataPacketsByteKey. // See consistency with PendingDataPacketsKey(). @@ -622,7 +642,12 @@ func (k Keeper) GetPendingPackets(ctx sdk.Context) []ccv.ConsumerPacketData { // An error here would indicate something is very wrong, panic(fmt.Errorf("failed to unmarshal pending data packet: %w", err)) } - packets = append(packets, packet) + packetWithIdx := ConsumerPacketDataWithIdx{ + ConsumerPacketData: packet, + // index stored in key after prefix, see PendingDataPacketsKey() + Idx: sdk.BigEndianToUint64(iterator.Key()[1:]), + } + packets = append(packets, packetWithIdx) } return packets } @@ -652,13 +677,10 @@ func (k Keeper) DeleteAllPendingDataPackets(ctx sdk.Context) { // AppendPendingPacket enqueues the given data packet to the end of the pending data packets queue func (k Keeper) AppendPendingPacket(ctx sdk.Context, packetType ccv.ConsumerPacketDataType, data ccv.ExportedIsConsumerPacketData_Data) { - cpd := ccv.NewConsumerPacketData( - packetType, - data, - k.getAndIncrementPendingPacketsIdx(ctx), - ) - key := types.PendingDataPacketsKey(cpd.Idx) + idx := k.getAndIncrementPendingPacketsIdx(ctx) // for FIFO queue + key := types.PendingDataPacketsKey(idx) store := ctx.KVStore(k.storeKey) + cpd := ccv.NewConsumerPacketData(packetType, data) bz, err := cpd.Marshal() if err != nil { // This should never happen diff --git a/x/ccv/consumer/keeper/keeper_test.go b/x/ccv/consumer/keeper/keeper_test.go index 5802c9d590..269c60d9c5 100644 --- a/x/ccv/consumer/keeper/keeper_test.go +++ b/x/ccv/consumer/keeper/keeper_test.go @@ -325,14 +325,12 @@ func TestPendingPackets(t *testing.T) { Data: &ccv.ConsumerPacketData_VscMaturedPacketData{ VscMaturedPacketData: ccv.NewVSCMaturedPacketData(1), }, - Idx: 0, // Note these are expected idxs, we don't pass this data to the keeper }, { Type: ccv.VscMaturedPacket, Data: &ccv.ConsumerPacketData_VscMaturedPacketData{ VscMaturedPacketData: ccv.NewVSCMaturedPacketData(2), }, - Idx: 1, }, { Type: ccv.SlashPacket, @@ -343,14 +341,12 @@ func TestPendingPackets(t *testing.T) { stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN, ), }, - Idx: 2, }, { Type: ccv.VscMaturedPacket, Data: &ccv.ConsumerPacketData_VscMaturedPacketData{ VscMaturedPacketData: ccv.NewVSCMaturedPacketData(3), }, - Idx: 3, }, } @@ -376,7 +372,6 @@ func TestPendingPackets(t *testing.T) { Data: &ccv.ConsumerPacketData_SlashPacketData{ SlashPacketData: slashPacket, }, - Idx: 4, }) toAppend := packetData[len(packetData)-1] @@ -391,7 +386,6 @@ func TestPendingPackets(t *testing.T) { Data: &ccv.ConsumerPacketData_VscMaturedPacketData{ VscMaturedPacketData: vscMaturedPacket, }, - Idx: 5, }) toAppend = packetData[len(packetData)-1] consumerKeeper.AppendPendingPacket(ctx, toAppend.Type, toAppend.Data) @@ -404,16 +398,21 @@ func TestPendingPackets(t *testing.T) { consumerKeeper.DeletePendingDataPackets(ctx, 5) storedPacketData = consumerKeeper.GetPendingPackets(ctx) require.Equal(t, packetData[:len(packetData)-1], storedPacketData) + pendingPacketsWithIdx := consumerKeeper.GetAllPendingPacketsWithIdx(ctx) + require.Equal(t, uint64(4), pendingPacketsWithIdx[len(pendingPacketsWithIdx)-1].Idx) // final element should have idx 4 // Delete packet with idx 0 (first index) consumerKeeper.DeletePendingDataPackets(ctx, 0) storedPacketData = consumerKeeper.GetPendingPackets(ctx) require.Equal(t, packetData[1:len(packetData)-1], storedPacketData) + pendingPacketsWithIdx = consumerKeeper.GetAllPendingPacketsWithIdx(ctx) + require.Equal(t, uint64(1), pendingPacketsWithIdx[0].Idx) // first element should have idx 1 // Delete all packets consumerKeeper.DeleteAllPendingDataPackets(ctx) storedPacketData = consumerKeeper.GetPendingPackets(ctx) require.Empty(t, storedPacketData) + require.Empty(t, consumerKeeper.GetAllPendingPacketsWithIdx(ctx)) } // TestVerifyProviderChain tests the VerifyProviderChain method for the consumer keeper diff --git a/x/ccv/consumer/keeper/migration_test.go b/x/ccv/consumer/keeper/migration_test.go index 1e7bc54bdf..7cb87665f0 100644 --- a/x/ccv/consumer/keeper/migration_test.go +++ b/x/ccv/consumer/keeper/migration_test.go @@ -60,9 +60,4 @@ func TestMigrateConsumerPacketData(t *testing.T) { require.Equal(t, uint64(77), obtainedPackets[0].GetSlashPacketData().ValsetUpdateId) require.Equal(t, uint64(88), obtainedPackets[1].GetVscMaturedPacketData().ValsetUpdateId) require.Equal(t, uint64(99), obtainedPackets[2].GetVscMaturedPacketData().ValsetUpdateId) - - // Check that indexes are populated - require.Equal(t, uint64(0), obtainedPackets[0].Idx) - require.Equal(t, uint64(1), obtainedPackets[1].Idx) - require.Equal(t, uint64(2), obtainedPackets[2].Idx) } diff --git a/x/ccv/consumer/keeper/relay.go b/x/ccv/consumer/keeper/relay.go index 120c0218c2..376110f26d 100644 --- a/x/ccv/consumer/keeper/relay.go +++ b/x/ccv/consumer/keeper/relay.go @@ -185,7 +185,7 @@ func (k Keeper) SendPackets(ctx sdk.Context) { return } - pending := k.GetPendingPackets(ctx) + pending := k.GetAllPendingPacketsWithIdx(ctx) idxsForDeletion := []uint64{} for _, p := range pending { diff --git a/x/ccv/types/ccv.go b/x/ccv/types/ccv.go index 453c55d252..91175eab5d 100644 --- a/x/ccv/types/ccv.go +++ b/x/ccv/types/ccv.go @@ -171,10 +171,9 @@ type ExportedIsConsumerPacketData_Data interface { isConsumerPacketData_Data } -func NewConsumerPacketData(cpdType ConsumerPacketDataType, data isConsumerPacketData_Data, idx uint64) ConsumerPacketData { +func NewConsumerPacketData(cpdType ConsumerPacketDataType, data isConsumerPacketData_Data) ConsumerPacketData { return ConsumerPacketData{ Type: cpdType, Data: data, - Idx: idx, } } diff --git a/x/ccv/types/ccv.pb.go b/x/ccv/types/ccv.pb.go index c5eacc2288..aa0f7da10e 100644 --- a/x/ccv/types/ccv.pb.go +++ b/x/ccv/types/ccv.pb.go @@ -368,7 +368,6 @@ type ConsumerPacketData struct { // *ConsumerPacketData_SlashPacketData // *ConsumerPacketData_VscMaturedPacketData Data isConsumerPacketData_Data `protobuf_oneof:"data"` - Idx uint64 `protobuf:"varint,4,opt,name=idx,proto3" json:"idx,omitempty"` } func (m *ConsumerPacketData) Reset() { *m = ConsumerPacketData{} } @@ -448,13 +447,6 @@ func (m *ConsumerPacketData) GetVscMaturedPacketData() *VSCMaturedPacketData { return nil } -func (m *ConsumerPacketData) GetIdx() uint64 { - if m != nil { - return m.Idx - } - return 0 -} - // XXX_OneofWrappers is for the internal use of the proto package. func (*ConsumerPacketData) XXX_OneofWrappers() []interface{} { return []interface{}{ @@ -687,61 +679,60 @@ func init() { } var fileDescriptor_68bd5f3242e6f29c = []byte{ - // 849 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x56, 0xcf, 0x6e, 0xe2, 0x46, - 0x1c, 0xc6, 0x80, 0x56, 0xcd, 0x50, 0x11, 0x67, 0x96, 0x56, 0x5e, 0x6f, 0xcb, 0x5a, 0xd6, 0x4a, + // 836 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x56, 0xcf, 0x6e, 0xe2, 0x46, + 0x1c, 0xb6, 0x01, 0xad, 0x9a, 0xa1, 0x22, 0xce, 0x2c, 0xad, 0x58, 0x6f, 0xcb, 0x5a, 0xd6, 0x4a, 0x45, 0xa9, 0xd6, 0x2e, 0x64, 0x0f, 0x55, 0x7b, 0x69, 0x00, 0xa7, 0x71, 0x9b, 0x90, 0xc8, 0x06, - 0x56, 0xdb, 0x8b, 0x35, 0xd8, 0x13, 0x32, 0x0a, 0xd8, 0xc8, 0x33, 0xb8, 0xcb, 0x1b, 0x54, 0x9c, - 0xfa, 0x02, 0x9c, 0x7a, 0xda, 0x27, 0xe8, 0xb9, 0xb7, 0x3d, 0xae, 0xd4, 0xcb, 0x5e, 0xba, 0xaa, - 0x92, 0x37, 0xe8, 0x13, 0x54, 0xb6, 0x09, 0x7f, 0x62, 0x83, 0x14, 0x69, 0xa5, 0x3d, 0x31, 0x8c, - 0x7f, 0xdf, 0x27, 0x7f, 0x7f, 0x46, 0x1e, 0xf0, 0x94, 0xb8, 0x0c, 0xfb, 0xf6, 0x25, 0x22, 0xae, - 0x45, 0xb1, 0x3d, 0xf6, 0x09, 0x9b, 0xa8, 0xb6, 0x1d, 0xa8, 0x41, 0x35, 0xfc, 0x51, 0x46, 0xbe, - 0xc7, 0x3c, 0x28, 0xa6, 0x4c, 0x29, 0xe1, 0xe3, 0xa0, 0x2a, 0x3e, 0xb5, 0x3d, 0x3a, 0xf4, 0xa8, - 0x4a, 0x19, 0xba, 0x22, 0x6e, 0x5f, 0x0d, 0xaa, 0x3d, 0xcc, 0x50, 0xf5, 0xf6, 0x7f, 0xcc, 0x20, - 0x96, 0xfa, 0x5e, 0xdf, 0x8b, 0x96, 0x6a, 0xb8, 0x9a, 0xef, 0x3e, 0x66, 0xd8, 0x75, 0xb0, 0x3f, - 0x24, 0x2e, 0x53, 0x51, 0xcf, 0x26, 0x2a, 0x9b, 0x8c, 0x30, 0x8d, 0x1f, 0xca, 0xef, 0x38, 0xf0, - 0x45, 0x17, 0x0d, 0x88, 0x83, 0x98, 0xe7, 0x9b, 0x98, 0x35, 0x2e, 0x91, 0xdb, 0xc7, 0xe7, 0xc8, - 0xbe, 0xc2, 0xac, 0x89, 0x18, 0x82, 0x1e, 0xd8, 0x0b, 0x6e, 0x9f, 0x5b, 0xe3, 0x91, 0x83, 0x18, - 0xa6, 0x02, 0x27, 0xe5, 0x2a, 0x85, 0x9a, 0xa4, 0x2c, 0x99, 0x95, 0x90, 0x59, 0x59, 0x30, 0x75, - 0xa2, 0xc1, 0xba, 0xf4, 0xe6, 0xfd, 0x93, 0xcc, 0x7f, 0xef, 0x9f, 0x08, 0x13, 0x34, 0x1c, 0x7c, - 0x27, 0x27, 0x88, 0x64, 0x83, 0x0f, 0xd6, 0x21, 0x14, 0x56, 0x40, 0xb8, 0x47, 0x31, 0x9b, 0x0f, - 0x59, 0xc4, 0x11, 0xb2, 0x12, 0x57, 0xc9, 0x1b, 0xc5, 0x78, 0x3f, 0x1e, 0xd4, 0x1d, 0xf8, 0x25, - 0x00, 0x74, 0x80, 0xe8, 0xa5, 0x85, 0xec, 0x2b, 0x2a, 0xe4, 0xa4, 0x5c, 0x65, 0xc7, 0xd8, 0x89, - 0x76, 0x0e, 0xed, 0x2b, 0x2a, 0x7b, 0xe0, 0xd1, 0x26, 0x65, 0x14, 0x1a, 0x20, 0x3f, 0x20, 0x94, - 0xcd, 0x95, 0x7c, 0xab, 0x6c, 0xf6, 0x5e, 0xd9, 0x66, 0x4f, 0x3d, 0x1f, 0x2a, 0x34, 0x22, 0x2e, - 0xf9, 0x07, 0x50, 0xea, 0x9a, 0x8d, 0x53, 0xc4, 0xc6, 0x3e, 0x76, 0x56, 0x2c, 0x4c, 0x53, 0xc4, - 0xa5, 0x29, 0x92, 0xff, 0xe6, 0xc0, 0xae, 0x19, 0x0a, 0x58, 0x41, 0x1b, 0x60, 0x67, 0xe1, 0x51, - 0x04, 0x2b, 0xd4, 0xc4, 0xcd, 0xc6, 0xd7, 0x85, 0xb9, 0xe5, 0xfc, 0x1d, 0xcb, 0x65, 0x63, 0x49, - 0x73, 0x0f, 0x8f, 0xeb, 0x00, 0x10, 0xf7, 0xc2, 0x47, 0x36, 0x23, 0x9e, 0x2b, 0xe4, 0x24, 0xae, - 0x52, 0xac, 0xc9, 0x4a, 0xdc, 0x46, 0xe5, 0xb6, 0x7d, 0xf3, 0x36, 0x2a, 0xfa, 0x62, 0xd2, 0x58, - 0x41, 0xc9, 0x5f, 0x81, 0x87, 0x73, 0x53, 0x3a, 0x6e, 0xcf, 0x73, 0x1d, 0xe2, 0xf6, 0xcf, 0x46, - 0x14, 0xf2, 0x20, 0x47, 0x9c, 0xb8, 0x4b, 0x79, 0x23, 0x5c, 0xca, 0x7f, 0x66, 0x01, 0x6c, 0x78, - 0x2e, 0x1d, 0x0f, 0xb1, 0xbf, 0xe2, 0xc0, 0x11, 0xc8, 0x87, 0x95, 0x8d, 0xc4, 0x17, 0x6b, 0xb5, - 0x6d, 0x59, 0x25, 0xd1, 0xed, 0xc9, 0x08, 0x1b, 0x11, 0x1e, 0xbe, 0x00, 0xbb, 0x74, 0xdd, 0xdc, - 0x48, 0x74, 0xa1, 0xf6, 0xf5, 0x36, 0xca, 0x3b, 0x79, 0x1c, 0x67, 0x8c, 0xbb, 0x2c, 0xf0, 0x02, - 0x94, 0x02, 0x6a, 0x27, 0x82, 0x8f, 0xec, 0x2a, 0xd4, 0xbe, 0xd9, 0x5a, 0xae, 0x94, 0xc2, 0x1c, - 0x67, 0x8c, 0x54, 0xbe, 0xd8, 0xb1, 0x57, 0x42, 0x3e, 0x4a, 0x2a, 0x5c, 0xd6, 0x1f, 0x80, 0xbc, - 0x83, 0x18, 0x92, 0x7b, 0xe0, 0xf3, 0xa4, 0xf4, 0x13, 0x42, 0x19, 0x3c, 0x5e, 0x2b, 0xba, 0x72, - 0x3f, 0xf3, 0xd6, 0xea, 0xfd, 0x3a, 0x0b, 0x4a, 0xc9, 0x91, 0x6e, 0xf5, 0x83, 0xe5, 0xf3, 0x72, - 0x53, 0x3e, 0xcf, 0xee, 0x91, 0x4f, 0xb7, 0xfa, 0x11, 0x13, 0x5a, 0xe4, 0xf1, 0x0f, 0x07, 0xf6, - 0x12, 0x2f, 0xf6, 0x91, 0x8f, 0xf2, 0x4f, 0x29, 0x47, 0x79, 0x7f, 0x9b, 0xf2, 0xe5, 0x71, 0x8e, - 0x42, 0x5a, 0x41, 0xef, 0xff, 0xc5, 0xa5, 0x15, 0x2e, 0x1c, 0x83, 0xdf, 0x03, 0xa9, 0x71, 0xd6, - 0x32, 0x3b, 0xa7, 0x9a, 0x61, 0x9d, 0x1f, 0x36, 0x7e, 0xd6, 0xda, 0x56, 0xfb, 0xe5, 0xb9, 0x66, - 0x75, 0x5a, 0xe6, 0xb9, 0xd6, 0xd0, 0x8f, 0x74, 0xad, 0xc9, 0x67, 0xc4, 0xcf, 0xa6, 0x33, 0x69, - 0xaf, 0xe3, 0xd2, 0x11, 0xb6, 0xc9, 0x05, 0xb9, 0xf5, 0x10, 0xaa, 0x40, 0x4c, 0x05, 0x9b, 0x27, - 0x87, 0xe6, 0x31, 0xcf, 0x89, 0xbb, 0xd3, 0x99, 0x54, 0x58, 0x31, 0x16, 0x1e, 0x80, 0x47, 0xa9, - 0x80, 0x30, 0x35, 0x3e, 0x2b, 0x96, 0xa6, 0x33, 0x89, 0xef, 0xde, 0x49, 0x4a, 0xcc, 0xff, 0xf6, - 0x47, 0x39, 0xb3, 0xff, 0x9a, 0x03, 0xc5, 0x75, 0x89, 0xf0, 0x39, 0x78, 0xac, 0xb7, 0x8e, 0x8c, - 0xc3, 0x46, 0x5b, 0x3f, 0x6b, 0xa5, 0xbd, 0xf6, 0xc3, 0xe9, 0x4c, 0xda, 0x5d, 0x82, 0xb4, 0xe1, - 0x88, 0x4d, 0xa0, 0x9a, 0x44, 0x35, 0xcf, 0x3a, 0xf5, 0x13, 0xcd, 0x32, 0xf5, 0x1f, 0x5b, 0x3c, - 0x27, 0x16, 0xa7, 0x33, 0x09, 0x34, 0xbd, 0x71, 0x6f, 0x80, 0x4d, 0xd2, 0x77, 0xe1, 0x3e, 0x10, - 0x92, 0x80, 0x17, 0xad, 0xb6, 0x7e, 0xaa, 0xf1, 0x59, 0xf1, 0xd3, 0xe9, 0x4c, 0xfa, 0xa4, 0xe9, - 0xfd, 0xea, 0x32, 0x32, 0xc4, 0xf1, 0xbb, 0xd6, 0x5b, 0x6f, 0xae, 0xcb, 0xdc, 0xdb, 0xeb, 0x32, - 0xf7, 0xef, 0x75, 0x99, 0xfb, 0xfd, 0xa6, 0x9c, 0x79, 0x7b, 0x53, 0xce, 0xbc, 0xbb, 0x29, 0x67, - 0x7e, 0x79, 0xde, 0x27, 0xec, 0x72, 0xdc, 0x53, 0x6c, 0x6f, 0xa8, 0xce, 0x2f, 0x09, 0xcb, 0x48, - 0x9f, 0x2d, 0x6e, 0x1b, 0xc1, 0x81, 0xfa, 0x2a, 0xba, 0x72, 0x44, 0x1f, 0xff, 0xde, 0x83, 0xe8, - 0xeb, 0x7f, 0xf0, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x69, 0x5d, 0x6d, 0x1f, 0x9a, 0x08, 0x00, - 0x00, + 0x56, 0xdb, 0x8b, 0x35, 0xd8, 0x13, 0x32, 0x0a, 0xd8, 0xc8, 0x33, 0xb8, 0xe5, 0x0d, 0x2a, 0x4e, + 0x7d, 0x01, 0x4e, 0x55, 0x0f, 0xfb, 0x18, 0xbd, 0xed, 0x71, 0xa5, 0x5e, 0xf6, 0xd2, 0xa8, 0x4a, + 0xde, 0xa0, 0x4f, 0x50, 0xd9, 0xfc, 0xc7, 0x06, 0x29, 0x52, 0xa5, 0xf6, 0x84, 0x19, 0xff, 0xbe, + 0x4f, 0xf3, 0xfd, 0x19, 0x79, 0xc0, 0x73, 0xe2, 0x32, 0xec, 0xdb, 0xd7, 0x88, 0xb8, 0x16, 0xc5, + 0xf6, 0xd0, 0x27, 0x6c, 0xa4, 0xda, 0x76, 0xa0, 0x06, 0xe5, 0xf0, 0x47, 0x19, 0xf8, 0x1e, 0xf3, + 0xa0, 0x98, 0x30, 0xa5, 0x84, 0xaf, 0x83, 0xb2, 0xf8, 0xdc, 0xf6, 0x68, 0xdf, 0xa3, 0x2a, 0x65, + 0xe8, 0x86, 0xb8, 0x5d, 0x35, 0x28, 0x77, 0x30, 0x43, 0xe5, 0xf9, 0xff, 0x29, 0x83, 0x98, 0xef, + 0x7a, 0x5d, 0x2f, 0x7a, 0x54, 0xc3, 0xa7, 0xd9, 0xea, 0x53, 0x86, 0x5d, 0x07, 0xfb, 0x7d, 0xe2, + 0x32, 0x15, 0x75, 0x6c, 0xa2, 0xb2, 0xd1, 0x00, 0xd3, 0xe9, 0x4b, 0xf9, 0x3d, 0x0f, 0x3e, 0x69, + 0xa3, 0x1e, 0x71, 0x10, 0xf3, 0x7c, 0x13, 0xb3, 0xda, 0x35, 0x72, 0xbb, 0xf8, 0x12, 0xd9, 0x37, + 0x98, 0xd5, 0x11, 0x43, 0xd0, 0x03, 0x07, 0xc1, 0xfc, 0xbd, 0x35, 0x1c, 0x38, 0x88, 0x61, 0x5a, + 0xe0, 0xa5, 0x74, 0x29, 0x5b, 0x91, 0x94, 0x25, 0xb3, 0x12, 0x32, 0x2b, 0x0b, 0xa6, 0x56, 0x34, + 0x58, 0x95, 0xde, 0xde, 0x3e, 0xe3, 0xfe, 0xbe, 0x7d, 0x56, 0x18, 0xa1, 0x7e, 0xef, 0x2b, 0x39, + 0x46, 0x24, 0x1b, 0x42, 0xb0, 0x0e, 0xa1, 0xb0, 0x04, 0xc2, 0x35, 0x8a, 0xd9, 0x6c, 0xc8, 0x22, + 0x4e, 0x21, 0x25, 0xf1, 0xa5, 0x8c, 0x91, 0x9b, 0xae, 0x4f, 0x07, 0x75, 0x07, 0x7e, 0x0a, 0x00, + 0xed, 0x21, 0x7a, 0x6d, 0x21, 0xfb, 0x86, 0x16, 0xd2, 0x52, 0xba, 0xb4, 0x67, 0xec, 0x45, 0x2b, + 0xc7, 0xf6, 0x0d, 0x95, 0x3d, 0xf0, 0x64, 0x9b, 0x32, 0x0a, 0x0d, 0x90, 0xe9, 0x11, 0xca, 0x66, + 0x4a, 0xbe, 0x54, 0xb6, 0x7b, 0xaf, 0xec, 0xb2, 0xa7, 0x9a, 0x09, 0x15, 0x1a, 0x11, 0x97, 0xfc, + 0x0d, 0xc8, 0xb7, 0xcd, 0xda, 0x39, 0x62, 0x43, 0x1f, 0x3b, 0x2b, 0x16, 0x26, 0x29, 0xe2, 0x93, + 0x14, 0xc9, 0x7f, 0xf0, 0x60, 0xdf, 0x0c, 0x05, 0xac, 0xa0, 0x0d, 0xb0, 0xb7, 0xf0, 0x28, 0x82, + 0x65, 0x2b, 0xe2, 0x76, 0xe3, 0xab, 0x85, 0x99, 0xe5, 0xc2, 0x86, 0xe5, 0xb2, 0xb1, 0xa4, 0x79, + 0x80, 0xc7, 0x55, 0x00, 0x88, 0x7b, 0xe5, 0x23, 0x9b, 0x11, 0xcf, 0x2d, 0xa4, 0x25, 0xbe, 0x94, + 0xab, 0xc8, 0xca, 0xb4, 0x8d, 0xca, 0xbc, 0x7d, 0xb3, 0x36, 0x2a, 0xfa, 0x62, 0xd2, 0x58, 0x41, + 0xc9, 0x9f, 0x81, 0xc7, 0x33, 0x53, 0x5a, 0x6e, 0xc7, 0x73, 0x1d, 0xe2, 0x76, 0x2f, 0x06, 0x14, + 0x0a, 0x20, 0x4d, 0x9c, 0x69, 0x97, 0x32, 0x46, 0xf8, 0x28, 0xff, 0x96, 0x02, 0xb0, 0xe6, 0xb9, + 0x74, 0xd8, 0xc7, 0xfe, 0x8a, 0x03, 0x27, 0x20, 0x13, 0x56, 0x36, 0x12, 0x9f, 0xab, 0x54, 0x76, + 0x65, 0x15, 0x47, 0x37, 0x47, 0x03, 0x6c, 0x44, 0x78, 0xf8, 0x0a, 0xec, 0xd3, 0x75, 0x73, 0x23, + 0xd1, 0xd9, 0xca, 0xe7, 0xbb, 0x28, 0x37, 0xf2, 0x38, 0xe5, 0x8c, 0x4d, 0x16, 0x78, 0x05, 0xf2, + 0x01, 0xb5, 0x63, 0xc1, 0x47, 0x76, 0x65, 0x2b, 0x5f, 0xec, 0x2c, 0x57, 0x42, 0x61, 0x4e, 0x39, + 0x23, 0x91, 0xaf, 0xfa, 0x08, 0x64, 0x1c, 0xc4, 0x90, 0xdc, 0x01, 0x1f, 0xc7, 0x85, 0x9e, 0x11, + 0xca, 0xe0, 0xe9, 0x5a, 0xad, 0x95, 0x87, 0x59, 0xb5, 0x56, 0xe6, 0x37, 0x29, 0x90, 0x8f, 0x8f, + 0xb4, 0xcb, 0xff, 0x5a, 0x1a, 0xaf, 0xb7, 0xa5, 0xf1, 0xe2, 0x01, 0x69, 0xb4, 0xcb, 0xff, 0x87, + 0x3c, 0xfe, 0xe4, 0xc1, 0x41, 0x6c, 0x63, 0xff, 0xf1, 0xc1, 0xfd, 0x2e, 0xe1, 0xe0, 0x1e, 0xee, + 0x52, 0xbe, 0x3c, 0xbc, 0x51, 0x48, 0x2b, 0xe8, 0xc3, 0xdf, 0xf9, 0xa4, 0xc2, 0x85, 0x63, 0xf0, + 0x6b, 0x20, 0xd5, 0x2e, 0x1a, 0x66, 0xeb, 0x5c, 0x33, 0xac, 0xcb, 0xe3, 0xda, 0xf7, 0x5a, 0xd3, + 0x6a, 0xbe, 0xbe, 0xd4, 0xac, 0x56, 0xc3, 0xbc, 0xd4, 0x6a, 0xfa, 0x89, 0xae, 0xd5, 0x05, 0x4e, + 0xfc, 0x68, 0x3c, 0x91, 0x0e, 0x5a, 0x2e, 0x1d, 0x60, 0x9b, 0x5c, 0x91, 0xb9, 0x87, 0x50, 0x05, + 0x62, 0x22, 0xd8, 0x3c, 0x3b, 0x36, 0x4f, 0x05, 0x5e, 0xdc, 0x1f, 0x4f, 0xa4, 0xec, 0x8a, 0xb1, + 0xf0, 0x08, 0x3c, 0x49, 0x04, 0x84, 0xa9, 0x09, 0x29, 0x31, 0x3f, 0x9e, 0x48, 0x42, 0x7b, 0x23, + 0x29, 0x31, 0xf3, 0xf3, 0xaf, 0x45, 0xee, 0xf0, 0x0d, 0x0f, 0x72, 0xeb, 0x12, 0xe1, 0x4b, 0xf0, + 0x54, 0x6f, 0x9c, 0x18, 0xc7, 0xb5, 0xa6, 0x7e, 0xd1, 0x48, 0xda, 0xf6, 0xe3, 0xf1, 0x44, 0xda, + 0x5f, 0x82, 0xb4, 0xfe, 0x80, 0x8d, 0xa0, 0x1a, 0x47, 0xd5, 0x2f, 0x5a, 0xd5, 0x33, 0xcd, 0x32, + 0xf5, 0x6f, 0x1b, 0x02, 0x2f, 0xe6, 0xc6, 0x13, 0x09, 0xd4, 0xbd, 0x61, 0xa7, 0x87, 0x4d, 0xd2, + 0x75, 0xe1, 0x21, 0x28, 0xc4, 0x01, 0xaf, 0x1a, 0x4d, 0xfd, 0x5c, 0x13, 0x52, 0xe2, 0x87, 0xe3, + 0x89, 0xf4, 0x41, 0xdd, 0xfb, 0xd1, 0x65, 0xa4, 0x8f, 0xa7, 0x7b, 0xad, 0x36, 0xde, 0xde, 0x15, + 0xf9, 0x77, 0x77, 0x45, 0xfe, 0xaf, 0xbb, 0x22, 0xff, 0xcb, 0x7d, 0x91, 0x7b, 0x77, 0x5f, 0xe4, + 0xde, 0xdf, 0x17, 0xb9, 0x1f, 0x5e, 0x76, 0x09, 0xbb, 0x1e, 0x76, 0x14, 0xdb, 0xeb, 0xab, 0xb3, + 0x2b, 0xc1, 0x32, 0xd2, 0x17, 0x8b, 0xbb, 0x45, 0x70, 0xa4, 0xfe, 0x14, 0x5d, 0x30, 0xa2, 0x4f, + 0x7d, 0xe7, 0x51, 0xf4, 0xad, 0x3f, 0xfa, 0x27, 0x00, 0x00, 0xff, 0xff, 0x8f, 0xbf, 0xfc, 0xd2, + 0x88, 0x08, 0x00, 0x00, } func (m *ValidatorSetChangePacketData) Marshal() (dAtA []byte, err error) { @@ -964,11 +955,6 @@ func (m *ConsumerPacketData) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.Idx != 0 { - i = encodeVarintCcv(dAtA, i, uint64(m.Idx)) - i-- - dAtA[i] = 0x20 - } if m.Data != nil { { size := m.Data.Size() @@ -1294,9 +1280,6 @@ func (m *ConsumerPacketData) Size() (n int) { if m.Data != nil { n += m.Data.Size() } - if m.Idx != 0 { - n += 1 + sovCcv(uint64(m.Idx)) - } return n } @@ -2054,25 +2037,6 @@ func (m *ConsumerPacketData) Unmarshal(dAtA []byte) error { } m.Data = &ConsumerPacketData_VscMaturedPacketData{v} iNdEx = postIndex - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Idx", wireType) - } - m.Idx = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCcv - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Idx |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } default: iNdEx = preIndex skippy, err := skipCcv(dAtA[iNdEx:]) From 1b44d27f8e9220162839f1bdb166ee93106d5a8c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Jul 2023 13:10:17 -0700 Subject: [PATCH 062/134] build(deps): bump bufbuild/buf-setup-action from 1.24.0 to 1.25.0 (#1157) Bumps [bufbuild/buf-setup-action](https://github.com/bufbuild/buf-setup-action) from 1.24.0 to 1.25.0. - [Release notes](https://github.com/bufbuild/buf-setup-action/releases) - [Commits](https://github.com/bufbuild/buf-setup-action/compare/v1.24.0...v1.25.0) --- updated-dependencies: - dependency-name: bufbuild/buf-setup-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Marius Poke --- .github/workflows/proto-registry.yml | 2 +- .github/workflows/proto.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/proto-registry.yml b/.github/workflows/proto-registry.yml index d79db5af70..9764edd806 100644 --- a/.github/workflows/proto-registry.yml +++ b/.github/workflows/proto-registry.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: bufbuild/buf-setup-action@v1.24.0 + - uses: bufbuild/buf-setup-action@v1.25.0 - uses: bufbuild/buf-push-action@v1 with: input: "proto" diff --git a/.github/workflows/proto.yml b/.github/workflows/proto.yml index 9791a871c0..8f80957d92 100644 --- a/.github/workflows/proto.yml +++ b/.github/workflows/proto.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: bufbuild/buf-setup-action@v1.24.0 + - uses: bufbuild/buf-setup-action@v1.25.0 - uses: bufbuild/buf-breaking-action@v1 with: input: "proto" From b03f6f0ce07e4d9293e19e83b8f5dd54194e7da4 Mon Sep 17 00:00:00 2001 From: MSalopek Date: Tue, 18 Jul 2023 23:11:37 +0200 Subject: [PATCH 063/134] docs: add changeover procedure (#1123) * docs: add changeover procedure part-1 * docs: add changeover procedure part-2 - onboarding checklist * docs: update terminoloy; add validator instructions stubs * docs: update validator docs * docs: update changeover docs and validator guide * deps: update docusaurus deps * docs: update changeover docs and validator guide * docs: update changeover docs and validator guide --- .../changeover-procedure.md | 236 +++ .../consumer-chain-upgrade-procedure.md | 5 - docs/docs/consumer-development/offboarding.md | 2 +- docs/docs/consumer-development/onboarding.md | 2 +- docs/docs/frequently-asked-questions.md | 2 +- docs/docs/introduction/terminology.md | 15 + docs/docs/validators/changeover-procedure.md | 88 ++ docs/docs/validators/joining-neutron.md | 15 + docs/docs/validators/joining-stride.md | 20 + docs/docs/validators/joining-testnet.md | 6 - docs/docs/validators/withdraw_rewards.md | 4 + .../ics_changeover_timeline_stride.png | Bin 0 -> 395340 bytes docs/package-lock.json | 1357 +++++++++-------- docs/package.json | 10 +- 14 files changed, 1086 insertions(+), 676 deletions(-) create mode 100644 docs/docs/consumer-development/changeover-procedure.md delete mode 100644 docs/docs/consumer-development/consumer-chain-upgrade-procedure.md create mode 100644 docs/docs/validators/changeover-procedure.md create mode 100644 docs/docs/validators/joining-neutron.md create mode 100644 docs/docs/validators/joining-stride.md create mode 100644 docs/figures/ics_changeover_timeline_stride.png diff --git a/docs/docs/consumer-development/changeover-procedure.md b/docs/docs/consumer-development/changeover-procedure.md new file mode 100644 index 0000000000..825a0bdae4 --- /dev/null +++ b/docs/docs/consumer-development/changeover-procedure.md @@ -0,0 +1,236 @@ +--- +sidebar_position: 5 +--- + +# Changeover Procedure + +Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the **changeover procedure** and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain. + +The relevant protocol specifications are available below: +* [ICS-28 with existing chains](https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/overview_and_basic_concepts.md#channel-initialization-existing-chains). +* [ADR in ICS repo](../adrs/adr-010-standalone-changeover.md) + +## Overview + +Standalone to consumer changeover procedure can rougly be separated into 4 parts: + +### 1. ConsumerAddition proposal submitted to the `provider` chain +The proposal is equivalent to the "normal" ConsumerAddition proposal submitted by new consumer chains. + +However, here are the most important notes and differences between a new consumer chain and a standalone chain performing a changeover: + +* `chain_id` must be equal to the standalone chain id +* `initial_height` field has additional rules to abide by: + +:::caution +``` +{ +... + "initial_height" : { + // must correspond to current revision number of standalone chain + // e.g. stride-1 => "revision_number": 1 + "revision_number": 1, + + // must correspond to a height that is at least 1 block after the upgrade + // that will add the `consumer` module to the standalone chain + // e.g. "upgrade_height": 100 => "revision_height": 101 + "revision_height": 1, + }, +... +} +``` +RevisionNumber: 0, RevisionHeight: 111 +::: + +* `genesis_hash` can be safely ignored because the chain is already running. A hash of the standalone chain's initial genesis may be used + +* `binary_hash` may not be available ahead of time. All chains performing the changeover go through rigorous testing - if bugs are caught and fixed the hash listed in the proposal may not be the most recent one. + +* `spawn_time` listed in the proposal MUST be before the `upgrade_height` listed in the the upgrade proposal on the standalone chain. +:::caution +`spawn_time` must occur before the `upgrade_height` on the standalone chain is reached becasue the `provider` chain must generate the `ConsumerGenesis` that contains the **validator set** that will be used after the changeover. +::: + +* `unbonding_period` must correspond to the value used on the standalone chain. Otherwise, the clients used for the ccv protocol may be incorrectly initialized. + +* `distribution_transmission_channel` **should be set**. + +:::note +Populating `distribution_transmission_channel` will enable the standalone chain to re-use one of the existing channels to the provider for consumer chain rewards distribution. This will preserve the `ibc denom` that may already be in use. + +If the parameter is not set, a new channel will be created. +::: + +* `ccv_timeout_period` has no important notes + +* `transfer_timeout_period` has no important notes + +* `consumer_redistribution_fraction` has no important notes + +* `blocks_per_distribution_transmission` has no important notes + +* `historical_entries` has no important notes + + +### 2. upgrade proposal on standalone chain + +The standalone chain creates an upgrade proposal to include the `interchain-security/x/ccv/consumer` module. + +:::caution +The upgrade height in the proposal should correspond to a height that is after the `spawn_time` in the consumer addition proposal submitted to the `provider` chain. +::: + +Otherwise, the upgrade is indistinguishable from a regular on-chain upgrade proposal. + +### 3. spawn time is reached + +When the `spawn_time` is reached on the `provider` it will generate a `ConsumerGenesis` that contains the validator set that will supercede the `standalone` validator set. + +This `ConsumerGenesis` must be available on the standalone chain during the on-chain upgrade. + +### 4. standalone chain upgrade + +Performing the on-chain upgrade on the standalone chain will add the `ccv/consumer` module and allow the chain to become a `consumer` of replicated security. + +:::caution +The `ConsumerGenesis` must be exported to a file and placed in the correct folder on the standalone chain before the upgade. + +The file must be placed at the exact specified location, otherwise the upgrade will not be executed correctly. + +Usually the file is placed in `$NODE_HOME/config`, but the file name and the exact directory is dictated by the upgrade code on the `standalone` chain. +* please check exact instructions provided by the `standalone` chain team +::: + +After the `genesis.json` file has been made available, the process is equivalent to a normal on-chain upgrade. The standalone validator set will sign the next couple of blocks before transferring control to `provider` validator set. + +The standalone validator set can still be slashed for any infractions if evidence is submitted within the `unboding_period`. + +#### Notes + +The changeover procedure may be updated in the future to create a seamless way of providing the validator set information to the standalone chain. + +## Onboarding Checklist + +This onboarding checklist is slightly different from the one under [Onboarding](./onboarding.md) + +Additionally, you can check the [testnet repo](https://github.com/cosmos/testnets/blob/master/replicated-security/CONSUMER_LAUNCH_GUIDE.md) for a comprehensive guide on preparing and launching consumer chains. + +## 1. Complete testing & integration + +- [ ] test integration with gaia +- [ ] test your protocol with supported relayer versions (minimum hermes 1.4.1) +- [ ] test the changeover procedure +- [ ] reach out to the ICS team if you are facing issues + +## 2. Create an Onboarding Repository + +To help validators and other node runners onboard onto your chain, please prepare a repository with information on how to run your chain. + +This should include (at minimum): + +- [ ] genesis.json with CCV data (after spawn time passes) +- [ ] information about relevant seed/peer nodes you are running +- [ ] relayer information (compatible versions) +- [ ] copy of your governance proposal (as JSON) +- [ ] a script showing how to start your chain and connect to peers (optional) +- [ ] take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable + +Example of such a repository can be found [here](https://github.com/hyphacoop/ics-testnets/tree/main/game-of-chains-2022/sputnik). + +## 3. Submit a ConsumerChainAddition Governance Proposal to the provider + +Before you submit a `ConsumerChainAddition` proposal, please provide a `spawn_time` that is **before** the the `upgrade_height` of the upgrade that will introduce the `ccv module` to your chain. +:::danger +If the `spawn_time` happens after your `upgrade_height` the provider will not be able to communicate the new validator set to be used after the changeover. +::: + +Additionally, reach out to the community via the [forum](https://forum.cosmos.network/) to formalize your intention to become an ICS consumer, gather community support and accept feedback from the community, validators and developers. + +- [ ] determine your chain's spawn time +- [ ] determine consumer chain parameters to be put in the proposal +- [ ] take note to include a link to your onboarding repository + +Example of a consumer chain addition proposal. + +```js +// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain or add a standalone chain. +// If it passes, then all validators on the provider chain are expected to validate the consumer chain at spawn time. +// It is recommended that spawn time occurs after the proposal end time and that it is scheduled to happen before the standalone chain upgrade +// that sill introduce the ccv module. +{ + // Title of the proposal + "title": "Changeover Standalone chain", + // Description of the proposal + // format the text as a .md file and include the file in your onboarding repository + "description": ".md description of your chain and all other relevant information", + // Proposed chain-id of the new consumer chain. + // Must be unique from all other consumer chain ids of the executing provider chain. + "chain_id": "standalone-1", + // Initial height of new consumer chain. + // For a completely new chain, this will be {0,1}. + "initial_height" : { + // must correspond to current revision number of standalone chain + // e.g. standalone-1 => "revision_number": 1 + "revision_number": 1, + + // must correspond to a height that is at least 1 block after the upgrade + // that will add the `consumer` module to the standalone chain + // e.g. "upgrade_height": 100 => "revision_height": 101 + "revision_number": 1, + }, + // Hash of the consumer chain genesis state without the consumer CCV module genesis params. + // => not relevant for changeover procedure + "genesis_hash": "d86d756e10118e66e6805e9cc476949da2e750098fcc7634fd0cc77f57a0b2b0", + // Hash of the consumer chain binary that should be run by validators on standalone chain upgrade + // => not relevant for changeover procedure as it may become stale + "binary_hash": "376cdbd3a222a3d5c730c9637454cd4dd925e2f9e2e0d0f3702fc922928583f1", + // Time on the provider chain at which the consumer chain genesis is finalized and all validators + // will be responsible for starting their consumer chain validator node. + "spawn_time": "2023-02-28T20:40:00.000000Z", + // Unbonding period for the consumer chain. + // It should should be smaller than that of the provider. + "unbonding_period": 86400000000000, + // Timeout period for CCV related IBC packets. + // Packets are considered timed-out after this interval elapses. + "ccv_timeout_period": 259200000000000, + // IBC transfer packets will timeout after this interval elapses. + "transfer_timeout_period": 1800000000000, + // The fraction of tokens allocated to the consumer redistribution address during distribution events. + // The fraction is a string representing a decimal number. For example "0.75" would represent 75%. + // The reward amount distributed to the provider is calculated as: 1 - consumer_redistribution_fraction. + "consumer_redistribution_fraction": "0.75", + // BlocksPerDistributionTransmission is the number of blocks between IBC token transfers from the consumer chain to the provider chain. + // eg. send rewards to the provider every 1000 blocks + "blocks_per_distribution_transmission": 1000, + // The number of historical info entries to persist in store. + // This param is a part of the cosmos sdk staking module. In the case of + // a ccv enabled consumer chain, the ccv module acts as the staking module. + "historical_entries": 10000, + // The ID of a token transfer channel used for the Reward Distribution + // sub-protocol. If DistributionTransmissionChannel == "", a new transfer + // channel is created on top of the same connection as the CCV channel. + // Note that transfer_channel_id is the ID of the channel end on the consumer chain. + // it is most relevant for chains performing a standalone to consumer changeover + // in order to maintan the existing ibc transfer channel + "distribution_transmission_channel": "channel-123" // NOTE: use existing transfer channel if available +} +``` + +## 3. Submit an Upgrade Proposal & Prepare for Changeover + +This proposal should add the ccv `consumer` module to your chain. + +- [ ] proposal `upgrade_height` must happen after `spawn_time` in the `ConsumerAdditionProposal` +- [ ] advise validators about the exact procedure for your chain and point them to your onboarding repository + + +## 4. Upgrade time 🚀 + +- [ ] after `spawn_time`, request `ConsumerGenesis` from the `provider` and place it in `/.sovereign/config/genesis.json` +- [ ] upgrade the binary to the one listed in your `UpgradeProposal` + +The chain starts after at least 66.67% of standalone voting power comes online. The consumer chain is considered interchain secured once the "old" validator set signs a couple of blocks and transfers control to the `provider` validator set. + +- [ ] provide a repo with onboarding instructions for validators (it should already be listed in the proposal) +- [ ] genesis.json after `spawn_time` obtained from `provider` (MUST contain the initial validator set) +- [ ] maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels) diff --git a/docs/docs/consumer-development/consumer-chain-upgrade-procedure.md b/docs/docs/consumer-development/consumer-chain-upgrade-procedure.md deleted file mode 100644 index 4af18552a3..0000000000 --- a/docs/docs/consumer-development/consumer-chain-upgrade-procedure.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -sidebar_position: 3 ---- - -# Upgrading Consumer Chains \ No newline at end of file diff --git a/docs/docs/consumer-development/offboarding.md b/docs/docs/consumer-development/offboarding.md index bbd4cbf35e..7f2ebb0f5e 100644 --- a/docs/docs/consumer-development/offboarding.md +++ b/docs/docs/consumer-development/offboarding.md @@ -1,5 +1,5 @@ --- -sidebar_position: 5 +sidebar_position: 4 title: Offboarding Checklist --- # Consumer Offboarding diff --git a/docs/docs/consumer-development/onboarding.md b/docs/docs/consumer-development/onboarding.md index dc870b76de..c9b503ed66 100644 --- a/docs/docs/consumer-development/onboarding.md +++ b/docs/docs/consumer-development/onboarding.md @@ -1,5 +1,5 @@ --- -sidebar_position: 4 +sidebar_position: 3 title: Onboarding Checklist --- # Consumer Onboarding Checklist diff --git a/docs/docs/frequently-asked-questions.md b/docs/docs/frequently-asked-questions.md index 6cbf364a36..e431ef3f01 100644 --- a/docs/docs/frequently-asked-questions.md +++ b/docs/docs/frequently-asked-questions.md @@ -8,7 +8,7 @@ slug: /faq VSR simply means that the same validator set is used to secure both the provider and consumer chains. VSR is ensured through ICS protocol which keeps consumers up to date with the validator set of the provider. -## What even is a consumer chain? +## What is a consumer chain? Consumer chain is blockchain operated by the same validator operators as the provider chain. The ICS protocol ensures the validator set replication properties (informs consumer chain about the current state of the validator set on the provider) diff --git a/docs/docs/introduction/terminology.md b/docs/docs/introduction/terminology.md index 59994353cf..fd06174f92 100644 --- a/docs/docs/introduction/terminology.md +++ b/docs/docs/introduction/terminology.md @@ -21,3 +21,18 @@ A particular protocol/implementation of Interchain Security that fully replicate ## Mesh security A protocol built on IBC that allows delegators on a cosmos chain to re-delegate their stake to validators in another chain's own validator set, using the original chain's token (which remains bonded on the original chain). For a deeper exploration of mesh security, see [Replicated vs. Mesh Security on the Informal Blog](https://informal.systems/blog/replicated-vs-mesh-security). + +## Consumer Chain + +Chain that is secured by the validator set of the provider, instead of its own. +Replicated security allows the provider chain validator set to validate blocks on the consumer chain. + +## Standalone Chain + +Chain that is secured by its own validator set. This chain does not participate in replicated security. + +Standalone chains may sometimes be called "sovereign" - the terms are synonymous. + +## Changeover Procedure + +Chains that were not initially launched as consumers of replicated security can still participate in the protocol and leverage the economic security of the provider chain. The process where a standalone chain transitions to being a replicated consumer chain is called the **changeover procedure** and is part of the interchain security protocol. After the changeover, the new consumer chain will retain all existing state, including the IBC clients, connections and channels already established by the chain. diff --git a/docs/docs/validators/changeover-procedure.md b/docs/docs/validators/changeover-procedure.md new file mode 100644 index 0000000000..4149d9b412 --- /dev/null +++ b/docs/docs/validators/changeover-procedure.md @@ -0,0 +1,88 @@ +--- +sidebar_position: 4 +--- + +# Validator instructions for Changeover Procedure + +More details available in [Changeover Procedure documentation](../consumer-development/changeover-procedure.md). + +A major difference betwen launching a new consumer chain vs. onboarding a standalone chain to ICS is that there is no consumer genesis available for the standalone chain. Since a standalone chain already exists, its state must be preserved once it transitions to being a consumer chain. + +## Timeline + +Upgrading standalone chains can be best visualised using a timeline, such as the one available [Excalidraw graphic by Stride](https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt). + +There is some flexibility with regards to how the changeover procedure is executed, so please make sure to follow the guides provided by the team doing the changeover. + +![Standalone to consumer transition timeline](../../figures/ics_changeover_timeline_stride.png?raw=true) + +### 1. `ConsumerAdditionProposal` on provider chain + +This step will add the standalone chain to the list of consumer chains secured by the provider. +This step dictates the `spawn_time`. After `spawn_time` the CCV state (initial validator set of the provider) will be available to the consumer. + +To obtain it from the provider use: +```bash +gaiad q provider consumer-genesis stride-1 -o json > ccv-state.json +jq -s '.[0].app_state.ccvconsumer = .[1] | .[0]' genesis.json ccv-state.json > ccv.json +``` + +### 2. `SoftwareUpgradeProposal` on the standalone/consumer chain + +This upgrade proposal will introduce ICS to the standalone chain, making it a consumer. + +### 3. Assigning a consumer key + +After `spawn_time`, make sure to assign a consumer key if you intend to use one. + +Instructions are available [here](../features/key-assignment.md) + +### 4. Perform the software ugprade on standalone chain + +Please use instructions provided by the standalone chain team and make sure to reach out if you are facing issues. +The upgrade preparation depends on your setup, so please make sure you prepare ahead of time. + +:::danger +The `ccv.json` from step 1. must be made available on the machine running the standalone/consumer chain at standalone chain `upgrade_height`. This file contains the initial validator set and parameters required for normal ICS operation. + +Usually, the file is placed in `$NODE_HOME/config` but this is not a strict requirement. The exact details are available in the upgrade code of the standalone/consumer chain. +::: + +**Performing this upgrade will transition the standalone chain to be a consumer chain.** + +After 3 blocks, the standalone chain will stop using the "old" validator set and begin using the `provider` validator set. + +## FAQ + +### Can I reuse the same validator key for the `consumer` chain that I am already using on the `standalone` chain? Will I need to perform a `AssignConsumerKey` tx with this key before spawn time? + +Validators must either assign a key or use the same key as on the `provider`. + +If you are validating both the `standalone` and the `provider`, you **can** use your current `standalone` key with some caveats: +* you must submit an `AssignConsumerKey` tx with your current `standalone` validator key +* it is best to submit `AssignConsumerKey` tx before `spawn_time` +* if you do not submit the Tx, it is assumed that you will be re-using your `provider` key to validate the `standalone/consumer` chain + +### Can I continue using the same node that was validating the `standalone` chain? + +Yes. + +Please assign your consensus key as stated aboce. + +### Can I set up a new node to validate the `standalone/consumer` chain after it transitions to replicated security? + +Yes. + +If you are planning to do this please make sure that the node is synced with `standalone` network and to submit `AssignConsumerKey` tx before `spawn_time`. + + +### What happens to the `standalone` validator set after it after it transitions to replicated security? + +The `standalone` chain validators will stop being validators after the first 3 blocks are created while using replicated security. The `standalone` validators will become **governors** and still can receive delegations if the `consumer` chain is using the `consumer-democracy` module. + +**Governors DO NOT VALIDATE BLOCKS**. + +Instead, they can participate in the governance process and take on other chain-specific roles. + +## Credits +Thank you Stride team for providing detailed instructions about the changeover procedure. diff --git a/docs/docs/validators/joining-neutron.md b/docs/docs/validators/joining-neutron.md new file mode 100644 index 0000000000..a9adbb25f9 --- /dev/null +++ b/docs/docs/validators/joining-neutron.md @@ -0,0 +1,15 @@ +--- +sidebar_position: 5 +--- + +# Joining Neutron + +Neutron is the first consumer chain to implement ICS. + +You can find instructions on joining the mainnet [here](https://docs.neutron.org/neutron/consumer-chain-launch). + + +To join Neutron chain on the replicated security testnet check [here](https://github.com/cosmos/testnets/tree/master/replicated-security/pion-1) + +## Resources +* [Neutron docs](https://docs.neutron.org) diff --git a/docs/docs/validators/joining-stride.md b/docs/docs/validators/joining-stride.md new file mode 100644 index 0000000000..96e32d8fa2 --- /dev/null +++ b/docs/docs/validators/joining-stride.md @@ -0,0 +1,20 @@ +--- +sidebar_position: 6 +--- +# Joining Stride + +Stride is the first consumer chain to perform the standalone to consumer changeover procedure and transition from a standalone validator set to using `cosmoshub-4` validator set. + +`stride-1` network (mainnet) will perform a software upgrade and at height `4616678` that will transition the network to using the Cosmos Hub's (`cosmoshub-4`) validator set. + + You can find instructions about the Stride consumer chain launch and joining the mainnet [here](https://github.com/Stride-Labs/mainnet/tree/main/ics-instructions). + + This [Excalidraw graphic](https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt) explains the timeline of Stride's changeover procedure. + +## Note +Stride re-uses an existing `transfer` channel to send consumer rewards to the provider chain, in order to preserve existing transfer IBC denom between `stride-1` and `cosmoshub-4`. + +## Resources +* [Stride docs](https://docs.stride.zone/docs) +* [Changeover procedure timeline](https://app.excalidraw.com/l/9UFOCMAZLAI/5EVLj0WJcwt) +* [Changeover upgrade docs](https://github.com/Stride-Labs/mainnet/tree/main/ics-instructions) diff --git a/docs/docs/validators/joining-testnet.md b/docs/docs/validators/joining-testnet.md index 5ae9007416..dcf654786d 100644 --- a/docs/docs/validators/joining-testnet.md +++ b/docs/docs/validators/joining-testnet.md @@ -178,9 +178,3 @@ gaiad tx provider assign-consensus-key consumer-1 '' --from Lfo_lmY+ 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 z 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%0Dsst>>d2|`qx!+Bf_XyQ`5 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.14" } }, "node_modules/@algolia/autocomplete-core": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.7.4.tgz", - "integrity": "sha512-daoLpQ3ps/VTMRZDEBfU8ixXd+amZcNJ4QSP3IERGyzqnL5Ch8uSRFt/4G8pUvW9c3o6GA4vtVv4I4lmnkdXyg==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.9.3.tgz", + "integrity": "sha512-009HdfugtGCdC4JdXUbVJClA0q0zh24yyePn+KUGk3rP7j8FEe/m5Yo/z65gn6nP/cM39PxpzqKrL7A6fP6PPw==", + "dependencies": { + "@algolia/autocomplete-plugin-algolia-insights": "1.9.3", + "@algolia/autocomplete-shared": "1.9.3" + } + }, + "node_modules/@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.9.3.tgz", + "integrity": "sha512-a/yTUkcO/Vyy+JffmAnTWbr4/90cLzw+CC3bRbhnULr/EM0fGNvM13oQQ14f2moLMcVDyAx/leczLlAOovhSZg==", "dependencies": { - "@algolia/autocomplete-shared": "1.7.4" + "@algolia/autocomplete-shared": "1.9.3" + }, + "peerDependencies": { + "search-insights": ">= 1 < 3" } }, "node_modules/@algolia/autocomplete-preset-algolia": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.7.4.tgz", - "integrity": "sha512-s37hrvLEIfcmKY8VU9LsAXgm2yfmkdHT3DnA3SgHaY93yjZ2qL57wzb5QweVkYuEBZkT2PIREvRoLXC2sxTbpQ==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.9.3.tgz", + "integrity": "sha512-d4qlt6YmrLMYy95n5TB52wtNDr6EgAIPH81dvvvW8UmuWRgxEtY0NJiPwl/h95JtG2vmRM804M0DSwMCNZlzRA==", "dependencies": { - "@algolia/autocomplete-shared": "1.7.4" + "@algolia/autocomplete-shared": "1.9.3" }, "peerDependencies": { "@algolia/client-search": ">= 4.9.1 < 6", @@ -51,79 +63,83 @@ } }, "node_modules/@algolia/autocomplete-shared": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.7.4.tgz", - "integrity": "sha512-2VGCk7I9tA9Ge73Km99+Qg87w0wzW4tgUruvWAn/gfey1ZXgmxZtyIRBebk35R1O8TbK77wujVtCnpsGpRy1kg==" + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.9.3.tgz", + "integrity": "sha512-Wnm9E4Ye6Rl6sTTqjoymD+l8DjSTHsHboVRYrKgEt8Q7UHm9nYbqhN/i0fhUYA3OAEH7WA8x3jfpnmJm3rKvaQ==", + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } }, "node_modules/@algolia/cache-browser-local-storage": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.14.3.tgz", - "integrity": "sha512-hWH1yCxgG3+R/xZIscmUrWAIBnmBFHH5j30fY/+aPkEZWt90wYILfAHIOZ1/Wxhho5SkPfwFmT7ooX2d9JeQBw==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.18.0.tgz", + "integrity": "sha512-rUAs49NLlO8LVLgGzM4cLkw8NJLKguQLgvFmBEe3DyzlinoqxzQMHfKZs6TSq4LZfw/z8qHvRo8NcTAAUJQLcw==", "dependencies": { - "@algolia/cache-common": "4.14.3" + "@algolia/cache-common": "4.18.0" } }, "node_modules/@algolia/cache-common": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.14.3.tgz", - "integrity": "sha512-oZJofOoD9FQOwiGTzyRnmzvh3ZP8WVTNPBLH5xU5JNF7drDbRT0ocVT0h/xB2rPHYzOeXRrLaQQBwRT/CKom0Q==" + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.18.0.tgz", + "integrity": "sha512-BmxsicMR4doGbeEXQu8yqiGmiyvpNvejYJtQ7rvzttEAMxOPoWEHrWyzBQw4x7LrBY9pMrgv4ZlUaF8PGzewHg==" }, "node_modules/@algolia/cache-in-memory": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.14.3.tgz", - "integrity": "sha512-ES0hHQnzWjeioLQf5Nq+x1AWdZJ50znNPSH3puB/Y4Xsg4Av1bvLmTJe7SY2uqONaeMTvL0OaVcoVtQgJVw0vg==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.18.0.tgz", + "integrity": "sha512-evD4dA1nd5HbFdufBxLqlJoob7E2ozlqJZuV3YlirNx5Na4q1LckIuzjNYZs2ddLzuTc/Xd5O3Ibf7OwPskHxw==", "dependencies": { - "@algolia/cache-common": "4.14.3" + "@algolia/cache-common": "4.18.0" } }, "node_modules/@algolia/client-account": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.14.3.tgz", - "integrity": "sha512-PBcPb0+f5Xbh5UfLZNx2Ow589OdP8WYjB4CnvupfYBrl9JyC1sdH4jcq/ri8osO/mCZYjZrQsKAPIqW/gQmizQ==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.18.0.tgz", + "integrity": "sha512-XsDnlROr3+Z1yjxBJjUMfMazi1V155kVdte6496atvBgOEtwCzTs3A+qdhfsAnGUvaYfBrBkL0ThnhMIBCGcew==", "dependencies": { - "@algolia/client-common": "4.14.3", - "@algolia/client-search": "4.14.3", - "@algolia/transporter": "4.14.3" + "@algolia/client-common": "4.18.0", + "@algolia/client-search": "4.18.0", + "@algolia/transporter": "4.18.0" } }, "node_modules/@algolia/client-analytics": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.14.3.tgz", - "integrity": "sha512-eAwQq0Hb/aauv9NhCH5Dp3Nm29oFx28sayFN2fdOWemwSeJHIl7TmcsxVlRsO50fsD8CtPcDhtGeD3AIFLNvqw==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.18.0.tgz", + "integrity": "sha512-chEUSN4ReqU7uRQ1C8kDm0EiPE+eJeAXiWcBwLhEynfNuTfawN9P93rSZktj7gmExz0C8XmkbBU19IQ05wCNrQ==", "dependencies": { - "@algolia/client-common": "4.14.3", - "@algolia/client-search": "4.14.3", - "@algolia/requester-common": "4.14.3", - "@algolia/transporter": "4.14.3" + "@algolia/client-common": "4.18.0", + "@algolia/client-search": "4.18.0", + "@algolia/requester-common": "4.18.0", + "@algolia/transporter": "4.18.0" } }, "node_modules/@algolia/client-common": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.14.3.tgz", - "integrity": "sha512-jkPPDZdi63IK64Yg4WccdCsAP4pHxSkr4usplkUZM5C1l1oEpZXsy2c579LQ0rvwCs5JFmwfNG4ahOszidfWPw==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.18.0.tgz", + "integrity": "sha512-7N+soJFP4wn8tjTr3MSUT/U+4xVXbz4jmeRfWfVAzdAbxLAQbHa0o/POSdTvQ8/02DjCLelloZ1bb4ZFVKg7Wg==", "dependencies": { - "@algolia/requester-common": "4.14.3", - "@algolia/transporter": "4.14.3" + "@algolia/requester-common": "4.18.0", + "@algolia/transporter": "4.18.0" } }, "node_modules/@algolia/client-personalization": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.14.3.tgz", - "integrity": "sha512-UCX1MtkVNgaOL9f0e22x6tC9e2H3unZQlSUdnVaSKpZ+hdSChXGaRjp2UIT7pxmPqNCyv51F597KEX5WT60jNg==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.18.0.tgz", + "integrity": "sha512-+PeCjODbxtamHcPl+couXMeHEefpUpr7IHftj4Y4Nia1hj8gGq4VlIcqhToAw8YjLeCTfOR7r7xtj3pJcYdP8A==", "dependencies": { - "@algolia/client-common": "4.14.3", - "@algolia/requester-common": "4.14.3", - "@algolia/transporter": "4.14.3" + "@algolia/client-common": "4.18.0", + "@algolia/requester-common": "4.18.0", + "@algolia/transporter": "4.18.0" } }, "node_modules/@algolia/client-search": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.14.3.tgz", - "integrity": "sha512-I2U7xBx5OPFdPLA8AXKUPPxGY3HDxZ4r7+mlZ8ZpLbI8/ri6fnu6B4z3wcL7sgHhDYMwnAE8Xr0AB0h3Hnkp4A==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.18.0.tgz", + "integrity": "sha512-F9xzQXTjm6UuZtnsLIew6KSraXQ0AzS/Ee+OD+mQbtcA/K1sg89tqb8TkwjtiYZ0oij13u3EapB3gPZwm+1Y6g==", "dependencies": { - "@algolia/client-common": "4.14.3", - "@algolia/requester-common": "4.14.3", - "@algolia/transporter": "4.14.3" + "@algolia/client-common": "4.18.0", + "@algolia/requester-common": "4.18.0", + "@algolia/transporter": "4.18.0" } }, "node_modules/@algolia/events": { @@ -132,47 +148,47 @@ "integrity": "sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==" }, "node_modules/@algolia/logger-common": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.14.3.tgz", - "integrity": "sha512-kUEAZaBt/J3RjYi8MEBT2QEexJR2kAE2mtLmezsmqMQZTV502TkHCxYzTwY2dE7OKcUTxi4OFlMuS4GId9CWPw==" + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.18.0.tgz", + "integrity": "sha512-46etYgSlkoKepkMSyaoriSn2JDgcrpc/nkOgou/lm0y17GuMl9oYZxwKKTSviLKI5Irk9nSKGwnBTQYwXOYdRg==" }, "node_modules/@algolia/logger-console": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.14.3.tgz", - "integrity": "sha512-ZWqAlUITktiMN2EiFpQIFCJS10N96A++yrexqC2Z+3hgF/JcKrOxOdT4nSCQoEPvU4Ki9QKbpzbebRDemZt/hw==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.18.0.tgz", + "integrity": "sha512-3P3VUYMl9CyJbi/UU1uUNlf6Z8N2ltW3Oqhq/nR7vH0CjWv32YROq3iGWGxB2xt3aXobdUPXs6P0tHSKRmNA6g==", "dependencies": { - "@algolia/logger-common": "4.14.3" + "@algolia/logger-common": "4.18.0" } }, "node_modules/@algolia/requester-browser-xhr": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.14.3.tgz", - "integrity": "sha512-AZeg2T08WLUPvDncl2XLX2O67W5wIO8MNaT7z5ii5LgBTuk/rU4CikTjCe2xsUleIZeFl++QrPAi4Bdxws6r/Q==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.18.0.tgz", + "integrity": "sha512-/AcWHOBub2U4TE/bPi4Gz1XfuLK6/7dj4HJG+Z2SfQoS1RjNLshZclU3OoKIkFp8D2NC7+BNsPvr9cPLyW8nyQ==", "dependencies": { - "@algolia/requester-common": "4.14.3" + "@algolia/requester-common": "4.18.0" } }, "node_modules/@algolia/requester-common": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.14.3.tgz", - "integrity": "sha512-RrRzqNyKFDP7IkTuV3XvYGF9cDPn9h6qEDl595lXva3YUk9YSS8+MGZnnkOMHvjkrSCKfoLeLbm/T4tmoIeclw==" + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.18.0.tgz", + "integrity": "sha512-xlT8R1qYNRBCi1IYLsx7uhftzdfsLPDGudeQs+xvYB4sQ3ya7+ppolB/8m/a4F2gCkEO6oxpp5AGemM7kD27jA==" }, "node_modules/@algolia/requester-node-http": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.14.3.tgz", - "integrity": "sha512-O5wnPxtDRPuW2U0EaOz9rMMWdlhwP0J0eSL1Z7TtXF8xnUeeUyNJrdhV5uy2CAp6RbhM1VuC3sOJcIR6Av+vbA==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.18.0.tgz", + "integrity": "sha512-TGfwj9aeTVgOUhn5XrqBhwUhUUDnGIKlI0kCBMdR58XfXcfdwomka+CPIgThRbfYw04oQr31A6/95ZH2QVJ9UQ==", "dependencies": { - "@algolia/requester-common": "4.14.3" + "@algolia/requester-common": "4.18.0" } }, "node_modules/@algolia/transporter": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.14.3.tgz", - "integrity": "sha512-2qlKlKsnGJ008exFRb5RTeTOqhLZj0bkMCMVskxoqWejs2Q2QtWmsiH98hDfpw0fmnyhzHEt0Z7lqxBYp8bW2w==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.18.0.tgz", + "integrity": "sha512-xbw3YRUGtXQNG1geYFEDDuFLZt4Z8YNKbamHPkzr3rWc6qp4/BqEeXcI2u/P/oMq2yxtXgMxrCxOPA8lyIe5jw==", "dependencies": { - "@algolia/cache-common": "4.14.3", - "@algolia/logger-common": "4.14.3", - "@algolia/requester-common": "4.14.3" + "@algolia/cache-common": "4.18.0", + "@algolia/logger-common": "4.18.0", + "@algolia/requester-common": "4.18.0" } }, "node_modules/@ampproject/remapping": { @@ -1985,18 +2001,18 @@ } }, "node_modules/@docsearch/css": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.3.3.tgz", - "integrity": "sha512-6SCwI7P8ao+se1TUsdZ7B4XzL+gqeQZnBc+2EONZlcVa0dVrk0NjETxozFKgMv0eEGH8QzP1fkN+A1rH61l4eg==" + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.5.1.tgz", + "integrity": "sha512-2Pu9HDg/uP/IT10rbQ+4OrTQuxIWdKVUEdcw9/w7kZJv9NeHS6skJx1xuRiFyoGKwAzcHXnLp7csE99sj+O1YA==" }, "node_modules/@docsearch/react": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.3.3.tgz", - "integrity": "sha512-pLa0cxnl+G0FuIDuYlW+EBK6Rw2jwLw9B1RHIeS4N4s2VhsfJ/wzeCi3CWcs5yVfxLd5ZK50t//TMA5e79YT7Q==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.5.1.tgz", + "integrity": "sha512-t5mEODdLzZq4PTFAm/dvqcvZFdPDMdfPE5rJS5SC8OUq9mPzxEy6b+9THIqNM9P0ocCb4UC5jqBrxKclnuIbzQ==", "dependencies": { - "@algolia/autocomplete-core": "1.7.4", - "@algolia/autocomplete-preset-algolia": "1.7.4", - "@docsearch/css": "3.3.3", + "@algolia/autocomplete-core": "1.9.3", + "@algolia/autocomplete-preset-algolia": "1.9.3", + "@docsearch/css": "3.5.1", "algoliasearch": "^4.0.0" }, "peerDependencies": { @@ -2017,9 +2033,9 @@ } }, "node_modules/@docusaurus/core": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-2.3.1.tgz", - "integrity": "sha512-0Jd4jtizqnRAr7svWaBbbrCCN8mzBNd2xFLoT/IM7bGfFie5y58oz97KzXliwiLY3zWjqMXjQcuP1a5VgCv2JA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-2.4.1.tgz", + "integrity": "sha512-SNsY7PshK3Ri7vtsLXVeAJGS50nJN3RgF836zkyUfAD01Fq+sAk5EwWgLw+nnm5KVNGDu7PRR2kRGDsWvqpo0g==", "dependencies": { "@babel/core": "^7.18.6", "@babel/generator": "^7.18.7", @@ -2031,13 +2047,13 @@ "@babel/runtime": "^7.18.6", "@babel/runtime-corejs3": "^7.18.6", "@babel/traverse": "^7.18.8", - "@docusaurus/cssnano-preset": "2.3.1", - "@docusaurus/logger": "2.3.1", - "@docusaurus/mdx-loader": "2.3.1", + "@docusaurus/cssnano-preset": "2.4.1", + "@docusaurus/logger": "2.4.1", + "@docusaurus/mdx-loader": "2.4.1", "@docusaurus/react-loadable": "5.5.2", - "@docusaurus/utils": "2.3.1", - "@docusaurus/utils-common": "2.3.1", - "@docusaurus/utils-validation": "2.3.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-common": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "@slorber/static-site-generator-webpack-plugin": "^4.0.7", "@svgr/webpack": "^6.2.1", "autoprefixer": "^10.4.7", @@ -2105,9 +2121,9 @@ } }, "node_modules/@docusaurus/cssnano-preset": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-2.3.1.tgz", - "integrity": "sha512-7mIhAROES6CY1GmCjR4CZkUfjTL6B3u6rKHK0ChQl2d1IevYXq/k/vFgvOrJfcKxiObpMnE9+X6R2Wt1KqxC6w==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-2.4.1.tgz", + "integrity": "sha512-ka+vqXwtcW1NbXxWsh6yA1Ckii1klY9E53cJ4O9J09nkMBgrNX3iEFED1fWdv8wf4mJjvGi5RLZ2p9hJNjsLyQ==", "dependencies": { "cssnano-preset-advanced": "^5.3.8", "postcss": "^8.4.14", @@ -2119,9 +2135,9 @@ } }, "node_modules/@docusaurus/logger": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-2.3.1.tgz", - "integrity": "sha512-2lAV/olKKVr9qJhfHFCaqBIl8FgYjbUFwgUnX76+cULwQYss+42ZQ3grHGFvI0ocN2X55WcYe64ellQXz7suqg==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-2.4.1.tgz", + "integrity": "sha512-5h5ysIIWYIDHyTVd8BjheZmQZmEgWDR54aQ1BX9pjFfpyzFo5puKXKYrYJXbjEHGyVhEzmB9UXwbxGfaZhOjcg==", "dependencies": { "chalk": "^4.1.2", "tslib": "^2.4.0" @@ -2131,14 +2147,14 @@ } }, "node_modules/@docusaurus/mdx-loader": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.3.1.tgz", - "integrity": "sha512-Gzga7OsxQRpt3392K9lv/bW4jGppdLFJh3luKRknCKSAaZrmVkOQv2gvCn8LAOSZ3uRg5No7AgYs/vpL8K94lA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.4.1.tgz", + "integrity": "sha512-4KhUhEavteIAmbBj7LVFnrVYDiU51H5YWW1zY6SmBSte/YLhDutztLTBE0PQl1Grux1jzUJeaSvAzHpTn6JJDQ==", "dependencies": { "@babel/parser": "^7.18.8", "@babel/traverse": "^7.18.8", - "@docusaurus/logger": "2.3.1", - "@docusaurus/utils": "2.3.1", + "@docusaurus/logger": "2.4.1", + "@docusaurus/utils": "2.4.1", "@mdx-js/mdx": "^1.6.22", "escape-html": "^1.0.3", "file-loader": "^6.2.0", @@ -2162,12 +2178,12 @@ } }, "node_modules/@docusaurus/module-type-aliases": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-2.3.1.tgz", - "integrity": "sha512-6KkxfAVOJqIUynTRb/tphYCl+co3cP0PlHiMDbi+SzmYxMdgIrwYqH9yAnGSDoN6Jk2ZE/JY/Azs/8LPgKP48A==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-2.4.1.tgz", + "integrity": "sha512-gLBuIFM8Dp2XOCWffUDSjtxY7jQgKvYujt7Mx5s4FCTfoL5dN1EVbnrn+O2Wvh8b0a77D57qoIDY7ghgmatR1A==", "dependencies": { "@docusaurus/react-loadable": "5.5.2", - "@docusaurus/types": "2.3.1", + "@docusaurus/types": "2.4.1", "@types/history": "^4.7.11", "@types/react": "*", "@types/react-router-config": "*", @@ -2181,15 +2197,15 @@ } }, "node_modules/@docusaurus/plugin-client-redirects": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-client-redirects/-/plugin-client-redirects-2.3.1.tgz", - "integrity": "sha512-Ye0z36/L8685ni0DIxHqPPaHIXFXiSF90QYiYfpODBX6NxvvveUTyylsDBU1GQhPXPn1bd39QgaOuZ+j9gfaog==", - "dependencies": { - "@docusaurus/core": "2.3.1", - "@docusaurus/logger": "2.3.1", - "@docusaurus/utils": "2.3.1", - "@docusaurus/utils-common": "2.3.1", - "@docusaurus/utils-validation": "2.3.1", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-client-redirects/-/plugin-client-redirects-2.4.1.tgz", + "integrity": "sha512-tp0j16gaLIJ4p+IR0P6KDOFsTOGGMY54MNPnmM61Vaqqt5omLqsuKUO8UlCGU1oW/4EIQOhXYy99XYY5MjE+7A==", + "dependencies": { + "@docusaurus/core": "2.4.1", + "@docusaurus/logger": "2.4.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-common": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "eta": "^2.0.0", "fs-extra": "^10.1.0", "lodash": "^4.17.21", @@ -2204,17 +2220,17 @@ } }, "node_modules/@docusaurus/plugin-content-blog": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.3.1.tgz", - "integrity": "sha512-f5LjqX+9WkiLyGiQ41x/KGSJ/9bOjSD8lsVhPvYeUYHCtYpuiDKfhZE07O4EqpHkBx4NQdtQDbp+aptgHSTuiw==", - "dependencies": { - "@docusaurus/core": "2.3.1", - "@docusaurus/logger": "2.3.1", - "@docusaurus/mdx-loader": "2.3.1", - "@docusaurus/types": "2.3.1", - "@docusaurus/utils": "2.3.1", - "@docusaurus/utils-common": "2.3.1", - "@docusaurus/utils-validation": "2.3.1", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.4.1.tgz", + "integrity": "sha512-E2i7Knz5YIbE1XELI6RlTnZnGgS52cUO4BlCiCUCvQHbR+s1xeIWz4C6BtaVnlug0Ccz7nFSksfwDpVlkujg5Q==", + "dependencies": { + "@docusaurus/core": "2.4.1", + "@docusaurus/logger": "2.4.1", + "@docusaurus/mdx-loader": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-common": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "cheerio": "^1.0.0-rc.12", "feed": "^4.2.2", "fs-extra": "^10.1.0", @@ -2234,17 +2250,17 @@ } }, "node_modules/@docusaurus/plugin-content-docs": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.3.1.tgz", - "integrity": "sha512-DxztTOBEruv7qFxqUtbsqXeNcHqcVEIEe+NQoI1oi2DBmKBhW/o0MIal8lt+9gvmpx3oYtlwmLOOGepxZgJGkw==", - "dependencies": { - "@docusaurus/core": "2.3.1", - "@docusaurus/logger": "2.3.1", - "@docusaurus/mdx-loader": "2.3.1", - "@docusaurus/module-type-aliases": "2.3.1", - "@docusaurus/types": "2.3.1", - "@docusaurus/utils": "2.3.1", - "@docusaurus/utils-validation": "2.3.1", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.4.1.tgz", + "integrity": "sha512-Lo7lSIcpswa2Kv4HEeUcGYqaasMUQNpjTXpV0N8G6jXgZaQurqp7E8NGYeGbDXnb48czmHWbzDL4S3+BbK0VzA==", + "dependencies": { + "@docusaurus/core": "2.4.1", + "@docusaurus/logger": "2.4.1", + "@docusaurus/mdx-loader": "2.4.1", + "@docusaurus/module-type-aliases": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "@types/react-router-config": "^5.0.6", "combine-promises": "^1.1.0", "fs-extra": "^10.1.0", @@ -2264,15 +2280,15 @@ } }, "node_modules/@docusaurus/plugin-content-pages": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.3.1.tgz", - "integrity": "sha512-E80UL6hvKm5VVw8Ka8YaVDtO6kWWDVUK4fffGvkpQ/AJQDOg99LwOXKujPoICC22nUFTsZ2Hp70XvpezCsFQaA==", - "dependencies": { - "@docusaurus/core": "2.3.1", - "@docusaurus/mdx-loader": "2.3.1", - "@docusaurus/types": "2.3.1", - "@docusaurus/utils": "2.3.1", - "@docusaurus/utils-validation": "2.3.1", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.4.1.tgz", + "integrity": "sha512-/UjuH/76KLaUlL+o1OvyORynv6FURzjurSjvn2lbWTFc4tpYY2qLYTlKpTCBVPhlLUQsfyFnshEJDLmPneq2oA==", + "dependencies": { + "@docusaurus/core": "2.4.1", + "@docusaurus/mdx-loader": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "fs-extra": "^10.1.0", "tslib": "^2.4.0", "webpack": "^5.73.0" @@ -2286,13 +2302,13 @@ } }, "node_modules/@docusaurus/plugin-debug": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-2.3.1.tgz", - "integrity": "sha512-Ujpml1Ppg4geB/2hyu2diWnO49az9U2bxM9Shen7b6qVcyFisNJTkVG2ocvLC7wM1efTJcUhBO6zAku2vKJGMw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-2.4.1.tgz", + "integrity": "sha512-7Yu9UPzRShlrH/G8btOpR0e6INFZr0EegWplMjOqelIwAcx3PKyR8mgPTxGTxcqiYj6hxSCRN0D8R7YrzImwNA==", "dependencies": { - "@docusaurus/core": "2.3.1", - "@docusaurus/types": "2.3.1", - "@docusaurus/utils": "2.3.1", + "@docusaurus/core": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils": "2.4.1", "fs-extra": "^10.1.0", "react-json-view": "^1.21.3", "tslib": "^2.4.0" @@ -2306,13 +2322,13 @@ } }, "node_modules/@docusaurus/plugin-google-analytics": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.3.1.tgz", - "integrity": "sha512-OHip0GQxKOFU8n7gkt3TM4HOYTXPCFDjqKbMClDD3KaDnyTuMp/Zvd9HSr770lLEscgPWIvzhJByRAClqsUWiQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.4.1.tgz", + "integrity": "sha512-dyZJdJiCoL+rcfnm0RPkLt/o732HvLiEwmtoNzOoz9MSZz117UH2J6U2vUDtzUzwtFLIf32KkeyzisbwUCgcaQ==", "dependencies": { - "@docusaurus/core": "2.3.1", - "@docusaurus/types": "2.3.1", - "@docusaurus/utils-validation": "2.3.1", + "@docusaurus/core": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "tslib": "^2.4.0" }, "engines": { @@ -2324,13 +2340,13 @@ } }, "node_modules/@docusaurus/plugin-google-gtag": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.3.1.tgz", - "integrity": "sha512-uXtDhfu4+Hm+oqWUySr3DNI5cWC/rmP6XJyAk83Heor3dFjZqDwCbkX8yWPywkRiWev3Dk/rVF8lEn0vIGVocA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.4.1.tgz", + "integrity": "sha512-mKIefK+2kGTQBYvloNEKtDmnRD7bxHLsBcxgnbt4oZwzi2nxCGjPX6+9SQO2KCN5HZbNrYmGo5GJfMgoRvy6uA==", "dependencies": { - "@docusaurus/core": "2.3.1", - "@docusaurus/types": "2.3.1", - "@docusaurus/utils-validation": "2.3.1", + "@docusaurus/core": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "tslib": "^2.4.0" }, "engines": { @@ -2342,13 +2358,13 @@ } }, "node_modules/@docusaurus/plugin-google-tag-manager": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-2.3.1.tgz", - "integrity": "sha512-Ww2BPEYSqg8q8tJdLYPFFM3FMDBCVhEM4UUqKzJaiRMx3NEoly3qqDRAoRDGdIhlC//Rf0iJV9cWAoq2m6k3sw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-2.4.1.tgz", + "integrity": "sha512-Zg4Ii9CMOLfpeV2nG74lVTWNtisFaH9QNtEw48R5QE1KIwDBdTVaiSA18G1EujZjrzJJzXN79VhINSbOJO/r3g==", "dependencies": { - "@docusaurus/core": "2.3.1", - "@docusaurus/types": "2.3.1", - "@docusaurus/utils-validation": "2.3.1", + "@docusaurus/core": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "tslib": "^2.4.0" }, "engines": { @@ -2360,16 +2376,16 @@ } }, "node_modules/@docusaurus/plugin-sitemap": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.3.1.tgz", - "integrity": "sha512-8Yxile/v6QGYV9vgFiYL+8d2N4z4Er3pSHsrD08c5XI8bUXxTppMwjarDUTH/TRTfgAWotRbhJ6WZLyajLpozA==", - "dependencies": { - "@docusaurus/core": "2.3.1", - "@docusaurus/logger": "2.3.1", - "@docusaurus/types": "2.3.1", - "@docusaurus/utils": "2.3.1", - "@docusaurus/utils-common": "2.3.1", - "@docusaurus/utils-validation": "2.3.1", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.4.1.tgz", + "integrity": "sha512-lZx+ijt/+atQ3FVE8FOHV/+X3kuok688OydDXrqKRJyXBJZKgGjA2Qa8RjQ4f27V2woaXhtnyrdPop/+OjVMRg==", + "dependencies": { + "@docusaurus/core": "2.4.1", + "@docusaurus/logger": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-common": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "fs-extra": "^10.1.0", "sitemap": "^7.1.1", "tslib": "^2.4.0" @@ -2383,23 +2399,23 @@ } }, "node_modules/@docusaurus/preset-classic": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-2.3.1.tgz", - "integrity": "sha512-OQ5W0AHyfdUk0IldwJ3BlnZ1EqoJuu2L2BMhqLbqwNWdkmzmSUvlFLH1Pe7CZSQgB2YUUC/DnmjbPKk/qQD0lQ==", - "dependencies": { - "@docusaurus/core": "2.3.1", - "@docusaurus/plugin-content-blog": "2.3.1", - "@docusaurus/plugin-content-docs": "2.3.1", - "@docusaurus/plugin-content-pages": "2.3.1", - "@docusaurus/plugin-debug": "2.3.1", - "@docusaurus/plugin-google-analytics": "2.3.1", - "@docusaurus/plugin-google-gtag": "2.3.1", - "@docusaurus/plugin-google-tag-manager": "2.3.1", - "@docusaurus/plugin-sitemap": "2.3.1", - "@docusaurus/theme-classic": "2.3.1", - "@docusaurus/theme-common": "2.3.1", - "@docusaurus/theme-search-algolia": "2.3.1", - "@docusaurus/types": "2.3.1" + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-2.4.1.tgz", + "integrity": "sha512-P4//+I4zDqQJ+UDgoFrjIFaQ1MeS9UD1cvxVQaI6O7iBmiHQm0MGROP1TbE7HlxlDPXFJjZUK3x3cAoK63smGQ==", + "dependencies": { + "@docusaurus/core": "2.4.1", + "@docusaurus/plugin-content-blog": "2.4.1", + "@docusaurus/plugin-content-docs": "2.4.1", + "@docusaurus/plugin-content-pages": "2.4.1", + "@docusaurus/plugin-debug": "2.4.1", + "@docusaurus/plugin-google-analytics": "2.4.1", + "@docusaurus/plugin-google-gtag": "2.4.1", + "@docusaurus/plugin-google-tag-manager": "2.4.1", + "@docusaurus/plugin-sitemap": "2.4.1", + "@docusaurus/theme-classic": "2.4.1", + "@docusaurus/theme-common": "2.4.1", + "@docusaurus/theme-search-algolia": "2.4.1", + "@docusaurus/types": "2.4.1" }, "engines": { "node": ">=16.14" @@ -2422,26 +2438,26 @@ } }, "node_modules/@docusaurus/theme-classic": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-2.3.1.tgz", - "integrity": "sha512-SelSIDvyttb7ZYHj8vEUhqykhAqfOPKk+uP0z85jH72IMC58e7O8DIlcAeBv+CWsLbNIl9/Hcg71X0jazuxJug==", - "dependencies": { - "@docusaurus/core": "2.3.1", - "@docusaurus/mdx-loader": "2.3.1", - "@docusaurus/module-type-aliases": "2.3.1", - "@docusaurus/plugin-content-blog": "2.3.1", - "@docusaurus/plugin-content-docs": "2.3.1", - "@docusaurus/plugin-content-pages": "2.3.1", - "@docusaurus/theme-common": "2.3.1", - "@docusaurus/theme-translations": "2.3.1", - "@docusaurus/types": "2.3.1", - "@docusaurus/utils": "2.3.1", - "@docusaurus/utils-common": "2.3.1", - "@docusaurus/utils-validation": "2.3.1", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-2.4.1.tgz", + "integrity": "sha512-Rz0wKUa+LTW1PLXmwnf8mn85EBzaGSt6qamqtmnh9Hflkc+EqiYMhtUJeLdV+wsgYq4aG0ANc+bpUDpsUhdnwg==", + "dependencies": { + "@docusaurus/core": "2.4.1", + "@docusaurus/mdx-loader": "2.4.1", + "@docusaurus/module-type-aliases": "2.4.1", + "@docusaurus/plugin-content-blog": "2.4.1", + "@docusaurus/plugin-content-docs": "2.4.1", + "@docusaurus/plugin-content-pages": "2.4.1", + "@docusaurus/theme-common": "2.4.1", + "@docusaurus/theme-translations": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-common": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "@mdx-js/react": "^1.6.22", "clsx": "^1.2.1", "copy-text-to-clipboard": "^3.0.1", - "infima": "0.2.0-alpha.42", + "infima": "0.2.0-alpha.43", "lodash": "^4.17.21", "nprogress": "^0.2.0", "postcss": "^8.4.14", @@ -2461,16 +2477,17 @@ } }, "node_modules/@docusaurus/theme-common": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-2.3.1.tgz", - "integrity": "sha512-RYmYl2OR2biO+yhmW1aS5FyEvnrItPINa+0U2dMxcHpah8reSCjQ9eJGRmAgkZFchV1+aIQzXOI1K7LCW38O0g==", - "dependencies": { - "@docusaurus/mdx-loader": "2.3.1", - "@docusaurus/module-type-aliases": "2.3.1", - "@docusaurus/plugin-content-blog": "2.3.1", - "@docusaurus/plugin-content-docs": "2.3.1", - "@docusaurus/plugin-content-pages": "2.3.1", - "@docusaurus/utils": "2.3.1", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-2.4.1.tgz", + "integrity": "sha512-G7Zau1W5rQTaFFB3x3soQoZpkgMbl/SYNG8PfMFIjKa3M3q8n0m/GRf5/H/e5BqOvt8c+ZWIXGCiz+kUCSHovA==", + "dependencies": { + "@docusaurus/mdx-loader": "2.4.1", + "@docusaurus/module-type-aliases": "2.4.1", + "@docusaurus/plugin-content-blog": "2.4.1", + "@docusaurus/plugin-content-docs": "2.4.1", + "@docusaurus/plugin-content-pages": "2.4.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-common": "2.4.1", "@types/history": "^4.7.11", "@types/react": "*", "@types/react-router-config": "*", @@ -2490,18 +2507,18 @@ } }, "node_modules/@docusaurus/theme-search-algolia": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.3.1.tgz", - "integrity": "sha512-JdHaRqRuH1X++g5fEMLnq7OtULSGQdrs9AbhcWRQ428ZB8/HOiaN6mj3hzHvcD3DFgu7koIVtWPQnvnN7iwzHA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.4.1.tgz", + "integrity": "sha512-6BcqW2lnLhZCXuMAvPRezFs1DpmEKzXFKlYjruuas+Xy3AQeFzDJKTJFIm49N77WFCTyxff8d3E4Q9pi/+5McQ==", "dependencies": { "@docsearch/react": "^3.1.1", - "@docusaurus/core": "2.3.1", - "@docusaurus/logger": "2.3.1", - "@docusaurus/plugin-content-docs": "2.3.1", - "@docusaurus/theme-common": "2.3.1", - "@docusaurus/theme-translations": "2.3.1", - "@docusaurus/utils": "2.3.1", - "@docusaurus/utils-validation": "2.3.1", + "@docusaurus/core": "2.4.1", + "@docusaurus/logger": "2.4.1", + "@docusaurus/plugin-content-docs": "2.4.1", + "@docusaurus/theme-common": "2.4.1", + "@docusaurus/theme-translations": "2.4.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "algoliasearch": "^4.13.1", "algoliasearch-helper": "^3.10.0", "clsx": "^1.2.1", @@ -2520,9 +2537,9 @@ } }, "node_modules/@docusaurus/theme-translations": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-2.3.1.tgz", - "integrity": "sha512-BsBZzAewJabVhoGG1Ij2u4pMS3MPW6gZ6sS4pc+Y7czevRpzxoFNJXRtQDVGe7mOpv/MmRmqg4owDK+lcOTCVQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-2.4.1.tgz", + "integrity": "sha512-T1RAGP+f86CA1kfE8ejZ3T3pUU3XcyvrGMfC/zxCtc2BsnoexuNI9Vk2CmuKCb+Tacvhxjv5unhxXce0+NKyvA==", "dependencies": { "fs-extra": "^10.1.0", "tslib": "^2.4.0" @@ -2532,9 +2549,9 @@ } }, "node_modules/@docusaurus/types": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-2.3.1.tgz", - "integrity": "sha512-PREbIRhTaNNY042qmfSE372Jb7djZt+oVTZkoqHJ8eff8vOIc2zqqDqBVc5BhOfpZGPTrE078yy/torUEZy08A==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-2.4.1.tgz", + "integrity": "sha512-0R+cbhpMkhbRXX138UOc/2XZFF8hiZa6ooZAEEJFp5scytzCw4tC1gChMFXrpa3d2tYE6AX8IrOEpSonLmfQuQ==", "dependencies": { "@types/history": "^4.7.11", "@types/react": "*", @@ -2551,11 +2568,11 @@ } }, "node_modules/@docusaurus/utils": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.3.1.tgz", - "integrity": "sha512-9WcQROCV0MmrpOQDXDGhtGMd52DHpSFbKLfkyaYumzbTstrbA5pPOtiGtxK1nqUHkiIv8UwexS54p0Vod2I1lg==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.4.1.tgz", + "integrity": "sha512-1lvEZdAQhKNht9aPXPoh69eeKnV0/62ROhQeFKKxmzd0zkcuE/Oc5Gpnt00y/f5bIsmOsYMY7Pqfm/5rteT5GA==", "dependencies": { - "@docusaurus/logger": "2.3.1", + "@docusaurus/logger": "2.4.1", "@svgr/webpack": "^6.2.1", "escape-string-regexp": "^4.0.0", "file-loader": "^6.2.0", @@ -2585,9 +2602,9 @@ } }, "node_modules/@docusaurus/utils-common": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-2.3.1.tgz", - "integrity": "sha512-pVlRpXkdNcxmKNxAaB1ya2hfCEvVsLDp2joeM6K6uv55Oc5nVIqgyYSgSNKZyMdw66NnvMfsu0RBylcwZQKo9A==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-2.4.1.tgz", + "integrity": "sha512-bCVGdZU+z/qVcIiEQdyx0K13OC5mYwxhSuDUR95oFbKVuXYRrTVrwZIqQljuo1fyJvFTKHiL9L9skQOPokuFNQ==", "dependencies": { "tslib": "^2.4.0" }, @@ -2604,12 +2621,12 @@ } }, "node_modules/@docusaurus/utils-validation": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.3.1.tgz", - "integrity": "sha512-7n0208IG3k1HVTByMHlZoIDjjOFC8sbViHVXJx0r3Q+3Ezrx+VQ1RZ/zjNn6lT+QBCRCXlnlaoJ8ug4HIVgQ3w==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.4.1.tgz", + "integrity": "sha512-unII3hlJlDwZ3w8U+pMO3Lx3RhI4YEbY3YNsQj4yzrkZzlpqZOLuAiZK2JyULnD+TKbceKU0WyWkQXtYbLNDFA==", "dependencies": { - "@docusaurus/logger": "2.3.1", - "@docusaurus/utils": "2.3.1", + "@docusaurus/logger": "2.4.1", + "@docusaurus/utils": "2.4.1", "joi": "^17.6.0", "js-yaml": "^4.1.0", "tslib": "^2.4.0" @@ -3274,11 +3291,11 @@ } }, "node_modules/@types/hast": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz", - "integrity": "sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==", + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.5.tgz", + "integrity": "sha512-SvQi0L/lNpThgPoleH53cdjB3y9zpLlVjRbqB3rH8hx1jiRSBGAhyjV3H+URFjNVRqt2EdYNrbZE5IsGlNfpRg==", "dependencies": { - "@types/unist": "*" + "@types/unist": "^2" } }, "node_modules/@types/history": { @@ -3326,11 +3343,11 @@ "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" }, "node_modules/@types/mdast": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz", - "integrity": "sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==", + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.12.tgz", + "integrity": "sha512-DT+iNIRNX884cx0/Q1ja7NyUPpZuv0KPyL5rGNxm1WC1OtHstl7n4Jb7nk+xacNShQMbczJjt8uFzznpp6kYBg==", "dependencies": { - "@types/unist": "*" + "@types/unist": "^2" } }, "node_modules/@types/mime": { @@ -3451,9 +3468,9 @@ } }, "node_modules/@types/unist": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", - "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==" + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.7.tgz", + "integrity": "sha512-cputDpIbFgLUaGQn6Vqg3/YsJwxUwHLO13v3i5ouxT4lat0khip9AEWxtERujXV9wxIB1EyF97BSJFt6vpdI8g==" }, "node_modules/@types/ws": { "version": "8.5.4", @@ -3789,30 +3806,30 @@ } }, "node_modules/algoliasearch": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.14.3.tgz", - "integrity": "sha512-GZTEuxzfWbP/vr7ZJfGzIl8fOsoxN916Z6FY2Egc9q2TmZ6hvq5KfAxY89pPW01oW/2HDEKA8d30f9iAH9eXYg==", - "dependencies": { - "@algolia/cache-browser-local-storage": "4.14.3", - "@algolia/cache-common": "4.14.3", - "@algolia/cache-in-memory": "4.14.3", - "@algolia/client-account": "4.14.3", - "@algolia/client-analytics": "4.14.3", - "@algolia/client-common": "4.14.3", - "@algolia/client-personalization": "4.14.3", - "@algolia/client-search": "4.14.3", - "@algolia/logger-common": "4.14.3", - "@algolia/logger-console": "4.14.3", - "@algolia/requester-browser-xhr": "4.14.3", - "@algolia/requester-common": "4.14.3", - "@algolia/requester-node-http": "4.14.3", - "@algolia/transporter": "4.14.3" + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.18.0.tgz", + "integrity": "sha512-pCuVxC1SVcpc08ENH32T4sLKSyzoU7TkRIDBMwSLfIiW+fq4znOmWDkAygHZ6pRcO9I1UJdqlfgnV7TRj+MXrA==", + "dependencies": { + "@algolia/cache-browser-local-storage": "4.18.0", + "@algolia/cache-common": "4.18.0", + "@algolia/cache-in-memory": "4.18.0", + "@algolia/client-account": "4.18.0", + "@algolia/client-analytics": "4.18.0", + "@algolia/client-common": "4.18.0", + "@algolia/client-personalization": "4.18.0", + "@algolia/client-search": "4.18.0", + "@algolia/logger-common": "4.18.0", + "@algolia/logger-console": "4.18.0", + "@algolia/requester-browser-xhr": "4.18.0", + "@algolia/requester-common": "4.18.0", + "@algolia/requester-node-http": "4.18.0", + "@algolia/transporter": "4.18.0" } }, "node_modules/algoliasearch-helper": { - "version": "3.11.3", - "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.11.3.tgz", - "integrity": "sha512-TbaEvLwiuGygHQIB8y+OsJKQQ40+JKUua5B91X66tMUHyyhbNHvqyr0lqd3wCoyKx7WybyQrC0WJvzoIeh24Aw==", + "version": "3.13.3", + "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.13.3.tgz", + "integrity": "sha512-jhbbuYZ+fheXpaJlqdJdFa1jOsrTWKmRRTYDM3oVTto5VodZzM7tT+BHzslAotaJf/81CKrm6yLRQn8WIr/K4A==", "dependencies": { "@algolia/events": "^4.0.1" }, @@ -4794,9 +4811,9 @@ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, "node_modules/copy-text-to-clipboard": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.0.1.tgz", - "integrity": "sha512-rvVsHrpFcL4F2P8ihsoLdFHmd404+CMg71S756oRSeQgqk51U3kicGdnvfkrxva0xXH92SjGS62B0XIJsbh+9Q==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.2.0.tgz", + "integrity": "sha512-RnJFp1XR/LOBDckxTib5Qjr/PMfkatD0MUCQgdpqS8MdKiNUzBjAQBEN6oUy+jW7LI93BBG3DtMB2KOOKpGs2Q==", "engines": { "node": ">=12" }, @@ -4969,11 +4986,11 @@ } }, "node_modules/cross-fetch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", - "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", "dependencies": { - "node-fetch": "2.6.7" + "node-fetch": "^2.6.12" } }, "node_modules/cross-spawn": { @@ -5569,13 +5586,13 @@ } }, "node_modules/domutils": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", - "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", - "domhandler": "^5.0.1" + "domhandler": "^5.0.3" }, "funding": { "url": "https://github.com/fb55/domutils?sponsor=1" @@ -6036,9 +6053,9 @@ } }, "node_modules/fbjs": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.4.tgz", - "integrity": "sha512-ucV0tDODnGV3JCnnkmoszb5lf4bNpzjv80K41wd4k798Etq+UYD0y0TIfalLjZoKgjive6/adkRnszwapiDgBQ==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.5.tgz", + "integrity": "sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==", "dependencies": { "cross-fetch": "^3.1.5", "fbjs-css-vars": "^1.0.0", @@ -6046,7 +6063,7 @@ "object-assign": "^4.1.0", "promise": "^7.1.1", "setimmediate": "^1.0.5", - "ua-parser-js": "^0.7.30" + "ua-parser-js": "^1.0.35" } }, "node_modules/fbjs-css-vars": { @@ -6179,9 +6196,9 @@ } }, "node_modules/flux": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/flux/-/flux-4.0.3.tgz", - "integrity": "sha512-yKAbrp7JhZhj6uiT1FTuVMlIAT1J4jqEyBpFApi1kxpGZCvacMVc/t1pMQyotqHhAgvoE3bNvAykhCo2CLjnYw==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/flux/-/flux-4.0.4.tgz", + "integrity": "sha512-NCj3XlayA2UsapRpM7va6wU1+9rE5FIL7qoMcmxWHRzbp0yujihMBm9BBHZ1MDIk5h5o2Bl6eGiCe8rYELAmYw==", "dependencies": { "fbemitter": "^3.0.0", "fbjs": "^3.0.1" @@ -6909,9 +6926,9 @@ } }, "node_modules/htmlparser2": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz", - "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", "funding": [ "https://github.com/fb55/htmlparser2?sponsor=1", { @@ -6921,9 +6938,9 @@ ], "dependencies": { "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", + "domhandler": "^5.0.3", "domutils": "^3.0.1", - "entities": "^4.3.0" + "entities": "^4.4.0" } }, "node_modules/http-cache-semantics": { @@ -7104,9 +7121,9 @@ } }, "node_modules/infima": { - "version": "0.2.0-alpha.42", - "resolved": "https://registry.npmjs.org/infima/-/infima-0.2.0-alpha.42.tgz", - "integrity": "sha512-ift8OXNbQQwtbIt6z16KnSWP7uJ/SysSMFI4F87MNRTicypfl4Pv3E2OGVv6N3nSZFJvA8imYulCBS64iyHYww==", + "version": "0.2.0-alpha.43", + "resolved": "https://registry.npmjs.org/infima/-/infima-0.2.0-alpha.43.tgz", + "integrity": "sha512-2uw57LvUqW0rK/SWYnd/2rRfxNA5DDNOh33jxF7fy46VWoNhGxiUQyVZHbBMjQ33mQem0cjdDVwgWVAmlRfgyQ==", "engines": { "node": ">=12" } @@ -8109,9 +8126,9 @@ } }, "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -9223,9 +9240,9 @@ } }, "node_modules/postcss-sort-media-queries": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-4.3.0.tgz", - "integrity": "sha512-jAl8gJM2DvuIJiI9sL1CuiHtKM4s5aEIomkU8G3LFvbP+p8i7Sz8VV63uieTgoewGqKbi+hxBTiOKJlB35upCg==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-4.4.1.tgz", + "integrity": "sha512-QDESFzDDGKgpiIh4GYXsSy6sek2yAwQx1JASl5AxBtU1Lq2JfKBljIPNdil989NcSKRQX1ToiaKphImtBuhXWw==", "dependencies": { "sort-css-media-queries": "2.1.0" }, @@ -9794,11 +9811,11 @@ } }, "node_modules/react-textarea-autosize": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.4.0.tgz", - "integrity": "sha512-YrTFaEHLgJsi8sJVYHBzYn+mkP3prGkmP2DKb/tm0t7CLJY5t1Rxix8070LAKb0wby7bl/lf2EeHkuMihMZMwQ==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.5.2.tgz", + "integrity": "sha512-uOkyjkEl0ByEK21eCJMHDGBAAd/BoFQBawYK5XItjAmCTeSbjxghd8qnt7nzsLYzidjnoObu6M26xts0YGKsGg==", "dependencies": { - "@babel/runtime": "^7.10.2", + "@babel/runtime": "^7.20.13", "use-composed-ref": "^1.3.0", "use-latest": "^1.2.1" }, @@ -10482,6 +10499,15 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/search-insights": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.7.0.tgz", + "integrity": "sha512-GLbVaGgzYEKMvuJbHRhLi1qoBFnjXZGZ6l4LxOYPCp4lI2jDRB3jPU9/XNhMwv6kvnA9slTreq6pvK+b3o3aqg==", + "peer": true, + "engines": { + "node": ">=8.16.0" + } + }, "node_modules/section-matter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", @@ -11545,9 +11571,9 @@ } }, "node_modules/ua-parser-js": { - "version": "0.7.33", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.33.tgz", - "integrity": "sha512-s8ax/CeZdK9R/56Sui0WM6y9OFREJarMRHqLB2EwkovemBxNQ+Bqu8GAsUnVcXKgphb++ghr/B2BZx4mahujPw==", + "version": "1.0.35", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.35.tgz", + "integrity": "sha512-fKnGuqmTBnIE+/KXSzCn4db8RTigUzw1AN0DmdU6hJovUTbYJKyqj+8Mt1c4VfRDnOVJnENmfYkIPZ946UrSAA==", "funding": [ { "type": "opencollective", @@ -12749,95 +12775,105 @@ }, "dependencies": { "@algolia/autocomplete-core": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.7.4.tgz", - "integrity": "sha512-daoLpQ3ps/VTMRZDEBfU8ixXd+amZcNJ4QSP3IERGyzqnL5Ch8uSRFt/4G8pUvW9c3o6GA4vtVv4I4lmnkdXyg==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.9.3.tgz", + "integrity": "sha512-009HdfugtGCdC4JdXUbVJClA0q0zh24yyePn+KUGk3rP7j8FEe/m5Yo/z65gn6nP/cM39PxpzqKrL7A6fP6PPw==", "requires": { - "@algolia/autocomplete-shared": "1.7.4" + "@algolia/autocomplete-plugin-algolia-insights": "1.9.3", + "@algolia/autocomplete-shared": "1.9.3" + } + }, + "@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.9.3.tgz", + "integrity": "sha512-a/yTUkcO/Vyy+JffmAnTWbr4/90cLzw+CC3bRbhnULr/EM0fGNvM13oQQ14f2moLMcVDyAx/leczLlAOovhSZg==", + "requires": { + "@algolia/autocomplete-shared": "1.9.3" } }, "@algolia/autocomplete-preset-algolia": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.7.4.tgz", - "integrity": "sha512-s37hrvLEIfcmKY8VU9LsAXgm2yfmkdHT3DnA3SgHaY93yjZ2qL57wzb5QweVkYuEBZkT2PIREvRoLXC2sxTbpQ==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.9.3.tgz", + "integrity": "sha512-d4qlt6YmrLMYy95n5TB52wtNDr6EgAIPH81dvvvW8UmuWRgxEtY0NJiPwl/h95JtG2vmRM804M0DSwMCNZlzRA==", "requires": { - "@algolia/autocomplete-shared": "1.7.4" + "@algolia/autocomplete-shared": "1.9.3" } }, "@algolia/autocomplete-shared": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.7.4.tgz", - "integrity": "sha512-2VGCk7I9tA9Ge73Km99+Qg87w0wzW4tgUruvWAn/gfey1ZXgmxZtyIRBebk35R1O8TbK77wujVtCnpsGpRy1kg==" + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.9.3.tgz", + "integrity": "sha512-Wnm9E4Ye6Rl6sTTqjoymD+l8DjSTHsHboVRYrKgEt8Q7UHm9nYbqhN/i0fhUYA3OAEH7WA8x3jfpnmJm3rKvaQ==", + "requires": {} }, "@algolia/cache-browser-local-storage": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.14.3.tgz", - "integrity": "sha512-hWH1yCxgG3+R/xZIscmUrWAIBnmBFHH5j30fY/+aPkEZWt90wYILfAHIOZ1/Wxhho5SkPfwFmT7ooX2d9JeQBw==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.18.0.tgz", + "integrity": "sha512-rUAs49NLlO8LVLgGzM4cLkw8NJLKguQLgvFmBEe3DyzlinoqxzQMHfKZs6TSq4LZfw/z8qHvRo8NcTAAUJQLcw==", "requires": { - "@algolia/cache-common": "4.14.3" + "@algolia/cache-common": "4.18.0" } }, "@algolia/cache-common": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.14.3.tgz", - "integrity": "sha512-oZJofOoD9FQOwiGTzyRnmzvh3ZP8WVTNPBLH5xU5JNF7drDbRT0ocVT0h/xB2rPHYzOeXRrLaQQBwRT/CKom0Q==" + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.18.0.tgz", + "integrity": "sha512-BmxsicMR4doGbeEXQu8yqiGmiyvpNvejYJtQ7rvzttEAMxOPoWEHrWyzBQw4x7LrBY9pMrgv4ZlUaF8PGzewHg==" }, "@algolia/cache-in-memory": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.14.3.tgz", - "integrity": "sha512-ES0hHQnzWjeioLQf5Nq+x1AWdZJ50znNPSH3puB/Y4Xsg4Av1bvLmTJe7SY2uqONaeMTvL0OaVcoVtQgJVw0vg==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.18.0.tgz", + "integrity": "sha512-evD4dA1nd5HbFdufBxLqlJoob7E2ozlqJZuV3YlirNx5Na4q1LckIuzjNYZs2ddLzuTc/Xd5O3Ibf7OwPskHxw==", "requires": { - "@algolia/cache-common": "4.14.3" + "@algolia/cache-common": "4.18.0" } }, "@algolia/client-account": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.14.3.tgz", - "integrity": "sha512-PBcPb0+f5Xbh5UfLZNx2Ow589OdP8WYjB4CnvupfYBrl9JyC1sdH4jcq/ri8osO/mCZYjZrQsKAPIqW/gQmizQ==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.18.0.tgz", + "integrity": "sha512-XsDnlROr3+Z1yjxBJjUMfMazi1V155kVdte6496atvBgOEtwCzTs3A+qdhfsAnGUvaYfBrBkL0ThnhMIBCGcew==", "requires": { - "@algolia/client-common": "4.14.3", - "@algolia/client-search": "4.14.3", - "@algolia/transporter": "4.14.3" + "@algolia/client-common": "4.18.0", + "@algolia/client-search": "4.18.0", + "@algolia/transporter": "4.18.0" } }, "@algolia/client-analytics": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.14.3.tgz", - "integrity": "sha512-eAwQq0Hb/aauv9NhCH5Dp3Nm29oFx28sayFN2fdOWemwSeJHIl7TmcsxVlRsO50fsD8CtPcDhtGeD3AIFLNvqw==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.18.0.tgz", + "integrity": "sha512-chEUSN4ReqU7uRQ1C8kDm0EiPE+eJeAXiWcBwLhEynfNuTfawN9P93rSZktj7gmExz0C8XmkbBU19IQ05wCNrQ==", "requires": { - "@algolia/client-common": "4.14.3", - "@algolia/client-search": "4.14.3", - "@algolia/requester-common": "4.14.3", - "@algolia/transporter": "4.14.3" + "@algolia/client-common": "4.18.0", + "@algolia/client-search": "4.18.0", + "@algolia/requester-common": "4.18.0", + "@algolia/transporter": "4.18.0" } }, "@algolia/client-common": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.14.3.tgz", - "integrity": "sha512-jkPPDZdi63IK64Yg4WccdCsAP4pHxSkr4usplkUZM5C1l1oEpZXsy2c579LQ0rvwCs5JFmwfNG4ahOszidfWPw==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.18.0.tgz", + "integrity": "sha512-7N+soJFP4wn8tjTr3MSUT/U+4xVXbz4jmeRfWfVAzdAbxLAQbHa0o/POSdTvQ8/02DjCLelloZ1bb4ZFVKg7Wg==", "requires": { - "@algolia/requester-common": "4.14.3", - "@algolia/transporter": "4.14.3" + "@algolia/requester-common": "4.18.0", + "@algolia/transporter": "4.18.0" } }, "@algolia/client-personalization": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.14.3.tgz", - "integrity": "sha512-UCX1MtkVNgaOL9f0e22x6tC9e2H3unZQlSUdnVaSKpZ+hdSChXGaRjp2UIT7pxmPqNCyv51F597KEX5WT60jNg==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.18.0.tgz", + "integrity": "sha512-+PeCjODbxtamHcPl+couXMeHEefpUpr7IHftj4Y4Nia1hj8gGq4VlIcqhToAw8YjLeCTfOR7r7xtj3pJcYdP8A==", "requires": { - "@algolia/client-common": "4.14.3", - "@algolia/requester-common": "4.14.3", - "@algolia/transporter": "4.14.3" + "@algolia/client-common": "4.18.0", + "@algolia/requester-common": "4.18.0", + "@algolia/transporter": "4.18.0" } }, "@algolia/client-search": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.14.3.tgz", - "integrity": "sha512-I2U7xBx5OPFdPLA8AXKUPPxGY3HDxZ4r7+mlZ8ZpLbI8/ri6fnu6B4z3wcL7sgHhDYMwnAE8Xr0AB0h3Hnkp4A==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.18.0.tgz", + "integrity": "sha512-F9xzQXTjm6UuZtnsLIew6KSraXQ0AzS/Ee+OD+mQbtcA/K1sg89tqb8TkwjtiYZ0oij13u3EapB3gPZwm+1Y6g==", "requires": { - "@algolia/client-common": "4.14.3", - "@algolia/requester-common": "4.14.3", - "@algolia/transporter": "4.14.3" + "@algolia/client-common": "4.18.0", + "@algolia/requester-common": "4.18.0", + "@algolia/transporter": "4.18.0" } }, "@algolia/events": { @@ -12846,47 +12882,47 @@ "integrity": "sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==" }, "@algolia/logger-common": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.14.3.tgz", - "integrity": "sha512-kUEAZaBt/J3RjYi8MEBT2QEexJR2kAE2mtLmezsmqMQZTV502TkHCxYzTwY2dE7OKcUTxi4OFlMuS4GId9CWPw==" + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.18.0.tgz", + "integrity": "sha512-46etYgSlkoKepkMSyaoriSn2JDgcrpc/nkOgou/lm0y17GuMl9oYZxwKKTSviLKI5Irk9nSKGwnBTQYwXOYdRg==" }, "@algolia/logger-console": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.14.3.tgz", - "integrity": "sha512-ZWqAlUITktiMN2EiFpQIFCJS10N96A++yrexqC2Z+3hgF/JcKrOxOdT4nSCQoEPvU4Ki9QKbpzbebRDemZt/hw==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.18.0.tgz", + "integrity": "sha512-3P3VUYMl9CyJbi/UU1uUNlf6Z8N2ltW3Oqhq/nR7vH0CjWv32YROq3iGWGxB2xt3aXobdUPXs6P0tHSKRmNA6g==", "requires": { - "@algolia/logger-common": "4.14.3" + "@algolia/logger-common": "4.18.0" } }, "@algolia/requester-browser-xhr": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.14.3.tgz", - "integrity": "sha512-AZeg2T08WLUPvDncl2XLX2O67W5wIO8MNaT7z5ii5LgBTuk/rU4CikTjCe2xsUleIZeFl++QrPAi4Bdxws6r/Q==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.18.0.tgz", + "integrity": "sha512-/AcWHOBub2U4TE/bPi4Gz1XfuLK6/7dj4HJG+Z2SfQoS1RjNLshZclU3OoKIkFp8D2NC7+BNsPvr9cPLyW8nyQ==", "requires": { - "@algolia/requester-common": "4.14.3" + "@algolia/requester-common": "4.18.0" } }, "@algolia/requester-common": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.14.3.tgz", - "integrity": "sha512-RrRzqNyKFDP7IkTuV3XvYGF9cDPn9h6qEDl595lXva3YUk9YSS8+MGZnnkOMHvjkrSCKfoLeLbm/T4tmoIeclw==" + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.18.0.tgz", + "integrity": "sha512-xlT8R1qYNRBCi1IYLsx7uhftzdfsLPDGudeQs+xvYB4sQ3ya7+ppolB/8m/a4F2gCkEO6oxpp5AGemM7kD27jA==" }, "@algolia/requester-node-http": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.14.3.tgz", - "integrity": "sha512-O5wnPxtDRPuW2U0EaOz9rMMWdlhwP0J0eSL1Z7TtXF8xnUeeUyNJrdhV5uy2CAp6RbhM1VuC3sOJcIR6Av+vbA==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.18.0.tgz", + "integrity": "sha512-TGfwj9aeTVgOUhn5XrqBhwUhUUDnGIKlI0kCBMdR58XfXcfdwomka+CPIgThRbfYw04oQr31A6/95ZH2QVJ9UQ==", "requires": { - "@algolia/requester-common": "4.14.3" + "@algolia/requester-common": "4.18.0" } }, "@algolia/transporter": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.14.3.tgz", - "integrity": "sha512-2qlKlKsnGJ008exFRb5RTeTOqhLZj0bkMCMVskxoqWejs2Q2QtWmsiH98hDfpw0fmnyhzHEt0Z7lqxBYp8bW2w==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.18.0.tgz", + "integrity": "sha512-xbw3YRUGtXQNG1geYFEDDuFLZt4Z8YNKbamHPkzr3rWc6qp4/BqEeXcI2u/P/oMq2yxtXgMxrCxOPA8lyIe5jw==", "requires": { - "@algolia/cache-common": "4.14.3", - "@algolia/logger-common": "4.14.3", - "@algolia/requester-common": "4.14.3" + "@algolia/cache-common": "4.18.0", + "@algolia/logger-common": "4.18.0", + "@algolia/requester-common": "4.18.0" } }, "@ampproject/remapping": { @@ -14118,25 +14154,25 @@ "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==" }, "@docsearch/css": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.3.3.tgz", - "integrity": "sha512-6SCwI7P8ao+se1TUsdZ7B4XzL+gqeQZnBc+2EONZlcVa0dVrk0NjETxozFKgMv0eEGH8QzP1fkN+A1rH61l4eg==" + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.5.1.tgz", + "integrity": "sha512-2Pu9HDg/uP/IT10rbQ+4OrTQuxIWdKVUEdcw9/w7kZJv9NeHS6skJx1xuRiFyoGKwAzcHXnLp7csE99sj+O1YA==" }, "@docsearch/react": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.3.3.tgz", - "integrity": "sha512-pLa0cxnl+G0FuIDuYlW+EBK6Rw2jwLw9B1RHIeS4N4s2VhsfJ/wzeCi3CWcs5yVfxLd5ZK50t//TMA5e79YT7Q==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.5.1.tgz", + "integrity": "sha512-t5mEODdLzZq4PTFAm/dvqcvZFdPDMdfPE5rJS5SC8OUq9mPzxEy6b+9THIqNM9P0ocCb4UC5jqBrxKclnuIbzQ==", "requires": { - "@algolia/autocomplete-core": "1.7.4", - "@algolia/autocomplete-preset-algolia": "1.7.4", - "@docsearch/css": "3.3.3", + "@algolia/autocomplete-core": "1.9.3", + "@algolia/autocomplete-preset-algolia": "1.9.3", + "@docsearch/css": "3.5.1", "algoliasearch": "^4.0.0" } }, "@docusaurus/core": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-2.3.1.tgz", - "integrity": "sha512-0Jd4jtizqnRAr7svWaBbbrCCN8mzBNd2xFLoT/IM7bGfFie5y58oz97KzXliwiLY3zWjqMXjQcuP1a5VgCv2JA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-2.4.1.tgz", + "integrity": "sha512-SNsY7PshK3Ri7vtsLXVeAJGS50nJN3RgF836zkyUfAD01Fq+sAk5EwWgLw+nnm5KVNGDu7PRR2kRGDsWvqpo0g==", "requires": { "@babel/core": "^7.18.6", "@babel/generator": "^7.18.7", @@ -14148,13 +14184,13 @@ "@babel/runtime": "^7.18.6", "@babel/runtime-corejs3": "^7.18.6", "@babel/traverse": "^7.18.8", - "@docusaurus/cssnano-preset": "2.3.1", - "@docusaurus/logger": "2.3.1", - "@docusaurus/mdx-loader": "2.3.1", + "@docusaurus/cssnano-preset": "2.4.1", + "@docusaurus/logger": "2.4.1", + "@docusaurus/mdx-loader": "2.4.1", "@docusaurus/react-loadable": "5.5.2", - "@docusaurus/utils": "2.3.1", - "@docusaurus/utils-common": "2.3.1", - "@docusaurus/utils-validation": "2.3.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-common": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "@slorber/static-site-generator-webpack-plugin": "^4.0.7", "@svgr/webpack": "^6.2.1", "autoprefixer": "^10.4.7", @@ -14212,9 +14248,9 @@ } }, "@docusaurus/cssnano-preset": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-2.3.1.tgz", - "integrity": "sha512-7mIhAROES6CY1GmCjR4CZkUfjTL6B3u6rKHK0ChQl2d1IevYXq/k/vFgvOrJfcKxiObpMnE9+X6R2Wt1KqxC6w==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-2.4.1.tgz", + "integrity": "sha512-ka+vqXwtcW1NbXxWsh6yA1Ckii1klY9E53cJ4O9J09nkMBgrNX3iEFED1fWdv8wf4mJjvGi5RLZ2p9hJNjsLyQ==", "requires": { "cssnano-preset-advanced": "^5.3.8", "postcss": "^8.4.14", @@ -14223,23 +14259,23 @@ } }, "@docusaurus/logger": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-2.3.1.tgz", - "integrity": "sha512-2lAV/olKKVr9qJhfHFCaqBIl8FgYjbUFwgUnX76+cULwQYss+42ZQ3grHGFvI0ocN2X55WcYe64ellQXz7suqg==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-2.4.1.tgz", + "integrity": "sha512-5h5ysIIWYIDHyTVd8BjheZmQZmEgWDR54aQ1BX9pjFfpyzFo5puKXKYrYJXbjEHGyVhEzmB9UXwbxGfaZhOjcg==", "requires": { "chalk": "^4.1.2", "tslib": "^2.4.0" } }, "@docusaurus/mdx-loader": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.3.1.tgz", - "integrity": "sha512-Gzga7OsxQRpt3392K9lv/bW4jGppdLFJh3luKRknCKSAaZrmVkOQv2gvCn8LAOSZ3uRg5No7AgYs/vpL8K94lA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.4.1.tgz", + "integrity": "sha512-4KhUhEavteIAmbBj7LVFnrVYDiU51H5YWW1zY6SmBSte/YLhDutztLTBE0PQl1Grux1jzUJeaSvAzHpTn6JJDQ==", "requires": { "@babel/parser": "^7.18.8", "@babel/traverse": "^7.18.8", - "@docusaurus/logger": "2.3.1", - "@docusaurus/utils": "2.3.1", + "@docusaurus/logger": "2.4.1", + "@docusaurus/utils": "2.4.1", "@mdx-js/mdx": "^1.6.22", "escape-html": "^1.0.3", "file-loader": "^6.2.0", @@ -14256,12 +14292,12 @@ } }, "@docusaurus/module-type-aliases": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-2.3.1.tgz", - "integrity": "sha512-6KkxfAVOJqIUynTRb/tphYCl+co3cP0PlHiMDbi+SzmYxMdgIrwYqH9yAnGSDoN6Jk2ZE/JY/Azs/8LPgKP48A==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-2.4.1.tgz", + "integrity": "sha512-gLBuIFM8Dp2XOCWffUDSjtxY7jQgKvYujt7Mx5s4FCTfoL5dN1EVbnrn+O2Wvh8b0a77D57qoIDY7ghgmatR1A==", "requires": { "@docusaurus/react-loadable": "5.5.2", - "@docusaurus/types": "2.3.1", + "@docusaurus/types": "2.4.1", "@types/history": "^4.7.11", "@types/react": "*", "@types/react-router-config": "*", @@ -14271,15 +14307,15 @@ } }, "@docusaurus/plugin-client-redirects": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-client-redirects/-/plugin-client-redirects-2.3.1.tgz", - "integrity": "sha512-Ye0z36/L8685ni0DIxHqPPaHIXFXiSF90QYiYfpODBX6NxvvveUTyylsDBU1GQhPXPn1bd39QgaOuZ+j9gfaog==", - "requires": { - "@docusaurus/core": "2.3.1", - "@docusaurus/logger": "2.3.1", - "@docusaurus/utils": "2.3.1", - "@docusaurus/utils-common": "2.3.1", - "@docusaurus/utils-validation": "2.3.1", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-client-redirects/-/plugin-client-redirects-2.4.1.tgz", + "integrity": "sha512-tp0j16gaLIJ4p+IR0P6KDOFsTOGGMY54MNPnmM61Vaqqt5omLqsuKUO8UlCGU1oW/4EIQOhXYy99XYY5MjE+7A==", + "requires": { + "@docusaurus/core": "2.4.1", + "@docusaurus/logger": "2.4.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-common": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "eta": "^2.0.0", "fs-extra": "^10.1.0", "lodash": "^4.17.21", @@ -14287,17 +14323,17 @@ } }, "@docusaurus/plugin-content-blog": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.3.1.tgz", - "integrity": "sha512-f5LjqX+9WkiLyGiQ41x/KGSJ/9bOjSD8lsVhPvYeUYHCtYpuiDKfhZE07O4EqpHkBx4NQdtQDbp+aptgHSTuiw==", - "requires": { - "@docusaurus/core": "2.3.1", - "@docusaurus/logger": "2.3.1", - "@docusaurus/mdx-loader": "2.3.1", - "@docusaurus/types": "2.3.1", - "@docusaurus/utils": "2.3.1", - "@docusaurus/utils-common": "2.3.1", - "@docusaurus/utils-validation": "2.3.1", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.4.1.tgz", + "integrity": "sha512-E2i7Knz5YIbE1XELI6RlTnZnGgS52cUO4BlCiCUCvQHbR+s1xeIWz4C6BtaVnlug0Ccz7nFSksfwDpVlkujg5Q==", + "requires": { + "@docusaurus/core": "2.4.1", + "@docusaurus/logger": "2.4.1", + "@docusaurus/mdx-loader": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-common": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "cheerio": "^1.0.0-rc.12", "feed": "^4.2.2", "fs-extra": "^10.1.0", @@ -14310,17 +14346,17 @@ } }, "@docusaurus/plugin-content-docs": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.3.1.tgz", - "integrity": "sha512-DxztTOBEruv7qFxqUtbsqXeNcHqcVEIEe+NQoI1oi2DBmKBhW/o0MIal8lt+9gvmpx3oYtlwmLOOGepxZgJGkw==", - "requires": { - "@docusaurus/core": "2.3.1", - "@docusaurus/logger": "2.3.1", - "@docusaurus/mdx-loader": "2.3.1", - "@docusaurus/module-type-aliases": "2.3.1", - "@docusaurus/types": "2.3.1", - "@docusaurus/utils": "2.3.1", - "@docusaurus/utils-validation": "2.3.1", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.4.1.tgz", + "integrity": "sha512-Lo7lSIcpswa2Kv4HEeUcGYqaasMUQNpjTXpV0N8G6jXgZaQurqp7E8NGYeGbDXnb48czmHWbzDL4S3+BbK0VzA==", + "requires": { + "@docusaurus/core": "2.4.1", + "@docusaurus/logger": "2.4.1", + "@docusaurus/mdx-loader": "2.4.1", + "@docusaurus/module-type-aliases": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "@types/react-router-config": "^5.0.6", "combine-promises": "^1.1.0", "fs-extra": "^10.1.0", @@ -14333,100 +14369,100 @@ } }, "@docusaurus/plugin-content-pages": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.3.1.tgz", - "integrity": "sha512-E80UL6hvKm5VVw8Ka8YaVDtO6kWWDVUK4fffGvkpQ/AJQDOg99LwOXKujPoICC22nUFTsZ2Hp70XvpezCsFQaA==", - "requires": { - "@docusaurus/core": "2.3.1", - "@docusaurus/mdx-loader": "2.3.1", - "@docusaurus/types": "2.3.1", - "@docusaurus/utils": "2.3.1", - "@docusaurus/utils-validation": "2.3.1", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.4.1.tgz", + "integrity": "sha512-/UjuH/76KLaUlL+o1OvyORynv6FURzjurSjvn2lbWTFc4tpYY2qLYTlKpTCBVPhlLUQsfyFnshEJDLmPneq2oA==", + "requires": { + "@docusaurus/core": "2.4.1", + "@docusaurus/mdx-loader": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "fs-extra": "^10.1.0", "tslib": "^2.4.0", "webpack": "^5.73.0" } }, "@docusaurus/plugin-debug": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-2.3.1.tgz", - "integrity": "sha512-Ujpml1Ppg4geB/2hyu2diWnO49az9U2bxM9Shen7b6qVcyFisNJTkVG2ocvLC7wM1efTJcUhBO6zAku2vKJGMw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-2.4.1.tgz", + "integrity": "sha512-7Yu9UPzRShlrH/G8btOpR0e6INFZr0EegWplMjOqelIwAcx3PKyR8mgPTxGTxcqiYj6hxSCRN0D8R7YrzImwNA==", "requires": { - "@docusaurus/core": "2.3.1", - "@docusaurus/types": "2.3.1", - "@docusaurus/utils": "2.3.1", + "@docusaurus/core": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils": "2.4.1", "fs-extra": "^10.1.0", "react-json-view": "^1.21.3", "tslib": "^2.4.0" } }, "@docusaurus/plugin-google-analytics": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.3.1.tgz", - "integrity": "sha512-OHip0GQxKOFU8n7gkt3TM4HOYTXPCFDjqKbMClDD3KaDnyTuMp/Zvd9HSr770lLEscgPWIvzhJByRAClqsUWiQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.4.1.tgz", + "integrity": "sha512-dyZJdJiCoL+rcfnm0RPkLt/o732HvLiEwmtoNzOoz9MSZz117UH2J6U2vUDtzUzwtFLIf32KkeyzisbwUCgcaQ==", "requires": { - "@docusaurus/core": "2.3.1", - "@docusaurus/types": "2.3.1", - "@docusaurus/utils-validation": "2.3.1", + "@docusaurus/core": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "tslib": "^2.4.0" } }, "@docusaurus/plugin-google-gtag": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.3.1.tgz", - "integrity": "sha512-uXtDhfu4+Hm+oqWUySr3DNI5cWC/rmP6XJyAk83Heor3dFjZqDwCbkX8yWPywkRiWev3Dk/rVF8lEn0vIGVocA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.4.1.tgz", + "integrity": "sha512-mKIefK+2kGTQBYvloNEKtDmnRD7bxHLsBcxgnbt4oZwzi2nxCGjPX6+9SQO2KCN5HZbNrYmGo5GJfMgoRvy6uA==", "requires": { - "@docusaurus/core": "2.3.1", - "@docusaurus/types": "2.3.1", - "@docusaurus/utils-validation": "2.3.1", + "@docusaurus/core": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "tslib": "^2.4.0" } }, "@docusaurus/plugin-google-tag-manager": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-2.3.1.tgz", - "integrity": "sha512-Ww2BPEYSqg8q8tJdLYPFFM3FMDBCVhEM4UUqKzJaiRMx3NEoly3qqDRAoRDGdIhlC//Rf0iJV9cWAoq2m6k3sw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-2.4.1.tgz", + "integrity": "sha512-Zg4Ii9CMOLfpeV2nG74lVTWNtisFaH9QNtEw48R5QE1KIwDBdTVaiSA18G1EujZjrzJJzXN79VhINSbOJO/r3g==", "requires": { - "@docusaurus/core": "2.3.1", - "@docusaurus/types": "2.3.1", - "@docusaurus/utils-validation": "2.3.1", + "@docusaurus/core": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "tslib": "^2.4.0" } }, "@docusaurus/plugin-sitemap": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.3.1.tgz", - "integrity": "sha512-8Yxile/v6QGYV9vgFiYL+8d2N4z4Er3pSHsrD08c5XI8bUXxTppMwjarDUTH/TRTfgAWotRbhJ6WZLyajLpozA==", - "requires": { - "@docusaurus/core": "2.3.1", - "@docusaurus/logger": "2.3.1", - "@docusaurus/types": "2.3.1", - "@docusaurus/utils": "2.3.1", - "@docusaurus/utils-common": "2.3.1", - "@docusaurus/utils-validation": "2.3.1", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.4.1.tgz", + "integrity": "sha512-lZx+ijt/+atQ3FVE8FOHV/+X3kuok688OydDXrqKRJyXBJZKgGjA2Qa8RjQ4f27V2woaXhtnyrdPop/+OjVMRg==", + "requires": { + "@docusaurus/core": "2.4.1", + "@docusaurus/logger": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-common": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "fs-extra": "^10.1.0", "sitemap": "^7.1.1", "tslib": "^2.4.0" } }, "@docusaurus/preset-classic": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-2.3.1.tgz", - "integrity": "sha512-OQ5W0AHyfdUk0IldwJ3BlnZ1EqoJuu2L2BMhqLbqwNWdkmzmSUvlFLH1Pe7CZSQgB2YUUC/DnmjbPKk/qQD0lQ==", - "requires": { - "@docusaurus/core": "2.3.1", - "@docusaurus/plugin-content-blog": "2.3.1", - "@docusaurus/plugin-content-docs": "2.3.1", - "@docusaurus/plugin-content-pages": "2.3.1", - "@docusaurus/plugin-debug": "2.3.1", - "@docusaurus/plugin-google-analytics": "2.3.1", - "@docusaurus/plugin-google-gtag": "2.3.1", - "@docusaurus/plugin-google-tag-manager": "2.3.1", - "@docusaurus/plugin-sitemap": "2.3.1", - "@docusaurus/theme-classic": "2.3.1", - "@docusaurus/theme-common": "2.3.1", - "@docusaurus/theme-search-algolia": "2.3.1", - "@docusaurus/types": "2.3.1" + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-2.4.1.tgz", + "integrity": "sha512-P4//+I4zDqQJ+UDgoFrjIFaQ1MeS9UD1cvxVQaI6O7iBmiHQm0MGROP1TbE7HlxlDPXFJjZUK3x3cAoK63smGQ==", + "requires": { + "@docusaurus/core": "2.4.1", + "@docusaurus/plugin-content-blog": "2.4.1", + "@docusaurus/plugin-content-docs": "2.4.1", + "@docusaurus/plugin-content-pages": "2.4.1", + "@docusaurus/plugin-debug": "2.4.1", + "@docusaurus/plugin-google-analytics": "2.4.1", + "@docusaurus/plugin-google-gtag": "2.4.1", + "@docusaurus/plugin-google-tag-manager": "2.4.1", + "@docusaurus/plugin-sitemap": "2.4.1", + "@docusaurus/theme-classic": "2.4.1", + "@docusaurus/theme-common": "2.4.1", + "@docusaurus/theme-search-algolia": "2.4.1", + "@docusaurus/types": "2.4.1" } }, "@docusaurus/react-loadable": { @@ -14439,26 +14475,26 @@ } }, "@docusaurus/theme-classic": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-2.3.1.tgz", - "integrity": "sha512-SelSIDvyttb7ZYHj8vEUhqykhAqfOPKk+uP0z85jH72IMC58e7O8DIlcAeBv+CWsLbNIl9/Hcg71X0jazuxJug==", - "requires": { - "@docusaurus/core": "2.3.1", - "@docusaurus/mdx-loader": "2.3.1", - "@docusaurus/module-type-aliases": "2.3.1", - "@docusaurus/plugin-content-blog": "2.3.1", - "@docusaurus/plugin-content-docs": "2.3.1", - "@docusaurus/plugin-content-pages": "2.3.1", - "@docusaurus/theme-common": "2.3.1", - "@docusaurus/theme-translations": "2.3.1", - "@docusaurus/types": "2.3.1", - "@docusaurus/utils": "2.3.1", - "@docusaurus/utils-common": "2.3.1", - "@docusaurus/utils-validation": "2.3.1", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-2.4.1.tgz", + "integrity": "sha512-Rz0wKUa+LTW1PLXmwnf8mn85EBzaGSt6qamqtmnh9Hflkc+EqiYMhtUJeLdV+wsgYq4aG0ANc+bpUDpsUhdnwg==", + "requires": { + "@docusaurus/core": "2.4.1", + "@docusaurus/mdx-loader": "2.4.1", + "@docusaurus/module-type-aliases": "2.4.1", + "@docusaurus/plugin-content-blog": "2.4.1", + "@docusaurus/plugin-content-docs": "2.4.1", + "@docusaurus/plugin-content-pages": "2.4.1", + "@docusaurus/theme-common": "2.4.1", + "@docusaurus/theme-translations": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-common": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "@mdx-js/react": "^1.6.22", "clsx": "^1.2.1", "copy-text-to-clipboard": "^3.0.1", - "infima": "0.2.0-alpha.42", + "infima": "0.2.0-alpha.43", "lodash": "^4.17.21", "nprogress": "^0.2.0", "postcss": "^8.4.14", @@ -14471,16 +14507,17 @@ } }, "@docusaurus/theme-common": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-2.3.1.tgz", - "integrity": "sha512-RYmYl2OR2biO+yhmW1aS5FyEvnrItPINa+0U2dMxcHpah8reSCjQ9eJGRmAgkZFchV1+aIQzXOI1K7LCW38O0g==", - "requires": { - "@docusaurus/mdx-loader": "2.3.1", - "@docusaurus/module-type-aliases": "2.3.1", - "@docusaurus/plugin-content-blog": "2.3.1", - "@docusaurus/plugin-content-docs": "2.3.1", - "@docusaurus/plugin-content-pages": "2.3.1", - "@docusaurus/utils": "2.3.1", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-2.4.1.tgz", + "integrity": "sha512-G7Zau1W5rQTaFFB3x3soQoZpkgMbl/SYNG8PfMFIjKa3M3q8n0m/GRf5/H/e5BqOvt8c+ZWIXGCiz+kUCSHovA==", + "requires": { + "@docusaurus/mdx-loader": "2.4.1", + "@docusaurus/module-type-aliases": "2.4.1", + "@docusaurus/plugin-content-blog": "2.4.1", + "@docusaurus/plugin-content-docs": "2.4.1", + "@docusaurus/plugin-content-pages": "2.4.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-common": "2.4.1", "@types/history": "^4.7.11", "@types/react": "*", "@types/react-router-config": "*", @@ -14493,18 +14530,18 @@ } }, "@docusaurus/theme-search-algolia": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.3.1.tgz", - "integrity": "sha512-JdHaRqRuH1X++g5fEMLnq7OtULSGQdrs9AbhcWRQ428ZB8/HOiaN6mj3hzHvcD3DFgu7koIVtWPQnvnN7iwzHA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.4.1.tgz", + "integrity": "sha512-6BcqW2lnLhZCXuMAvPRezFs1DpmEKzXFKlYjruuas+Xy3AQeFzDJKTJFIm49N77WFCTyxff8d3E4Q9pi/+5McQ==", "requires": { "@docsearch/react": "^3.1.1", - "@docusaurus/core": "2.3.1", - "@docusaurus/logger": "2.3.1", - "@docusaurus/plugin-content-docs": "2.3.1", - "@docusaurus/theme-common": "2.3.1", - "@docusaurus/theme-translations": "2.3.1", - "@docusaurus/utils": "2.3.1", - "@docusaurus/utils-validation": "2.3.1", + "@docusaurus/core": "2.4.1", + "@docusaurus/logger": "2.4.1", + "@docusaurus/plugin-content-docs": "2.4.1", + "@docusaurus/theme-common": "2.4.1", + "@docusaurus/theme-translations": "2.4.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "algoliasearch": "^4.13.1", "algoliasearch-helper": "^3.10.0", "clsx": "^1.2.1", @@ -14516,18 +14553,18 @@ } }, "@docusaurus/theme-translations": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-2.3.1.tgz", - "integrity": "sha512-BsBZzAewJabVhoGG1Ij2u4pMS3MPW6gZ6sS4pc+Y7czevRpzxoFNJXRtQDVGe7mOpv/MmRmqg4owDK+lcOTCVQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-2.4.1.tgz", + "integrity": "sha512-T1RAGP+f86CA1kfE8ejZ3T3pUU3XcyvrGMfC/zxCtc2BsnoexuNI9Vk2CmuKCb+Tacvhxjv5unhxXce0+NKyvA==", "requires": { "fs-extra": "^10.1.0", "tslib": "^2.4.0" } }, "@docusaurus/types": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-2.3.1.tgz", - "integrity": "sha512-PREbIRhTaNNY042qmfSE372Jb7djZt+oVTZkoqHJ8eff8vOIc2zqqDqBVc5BhOfpZGPTrE078yy/torUEZy08A==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-2.4.1.tgz", + "integrity": "sha512-0R+cbhpMkhbRXX138UOc/2XZFF8hiZa6ooZAEEJFp5scytzCw4tC1gChMFXrpa3d2tYE6AX8IrOEpSonLmfQuQ==", "requires": { "@types/history": "^4.7.11", "@types/react": "*", @@ -14540,11 +14577,11 @@ } }, "@docusaurus/utils": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.3.1.tgz", - "integrity": "sha512-9WcQROCV0MmrpOQDXDGhtGMd52DHpSFbKLfkyaYumzbTstrbA5pPOtiGtxK1nqUHkiIv8UwexS54p0Vod2I1lg==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.4.1.tgz", + "integrity": "sha512-1lvEZdAQhKNht9aPXPoh69eeKnV0/62ROhQeFKKxmzd0zkcuE/Oc5Gpnt00y/f5bIsmOsYMY7Pqfm/5rteT5GA==", "requires": { - "@docusaurus/logger": "2.3.1", + "@docusaurus/logger": "2.4.1", "@svgr/webpack": "^6.2.1", "escape-string-regexp": "^4.0.0", "file-loader": "^6.2.0", @@ -14563,20 +14600,20 @@ } }, "@docusaurus/utils-common": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-2.3.1.tgz", - "integrity": "sha512-pVlRpXkdNcxmKNxAaB1ya2hfCEvVsLDp2joeM6K6uv55Oc5nVIqgyYSgSNKZyMdw66NnvMfsu0RBylcwZQKo9A==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-2.4.1.tgz", + "integrity": "sha512-bCVGdZU+z/qVcIiEQdyx0K13OC5mYwxhSuDUR95oFbKVuXYRrTVrwZIqQljuo1fyJvFTKHiL9L9skQOPokuFNQ==", "requires": { "tslib": "^2.4.0" } }, "@docusaurus/utils-validation": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.3.1.tgz", - "integrity": "sha512-7n0208IG3k1HVTByMHlZoIDjjOFC8sbViHVXJx0r3Q+3Ezrx+VQ1RZ/zjNn6lT+QBCRCXlnlaoJ8ug4HIVgQ3w==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.4.1.tgz", + "integrity": "sha512-unII3hlJlDwZ3w8U+pMO3Lx3RhI4YEbY3YNsQj4yzrkZzlpqZOLuAiZK2JyULnD+TKbceKU0WyWkQXtYbLNDFA==", "requires": { - "@docusaurus/logger": "2.3.1", - "@docusaurus/utils": "2.3.1", + "@docusaurus/logger": "2.4.1", + "@docusaurus/utils": "2.4.1", "joi": "^17.6.0", "js-yaml": "^4.1.0", "tslib": "^2.4.0" @@ -15046,11 +15083,11 @@ } }, "@types/hast": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz", - "integrity": "sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==", + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.5.tgz", + "integrity": "sha512-SvQi0L/lNpThgPoleH53cdjB3y9zpLlVjRbqB3rH8hx1jiRSBGAhyjV3H+URFjNVRqt2EdYNrbZE5IsGlNfpRg==", "requires": { - "@types/unist": "*" + "@types/unist": "^2" } }, "@types/history": { @@ -15098,11 +15135,11 @@ "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" }, "@types/mdast": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz", - "integrity": "sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==", + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.12.tgz", + "integrity": "sha512-DT+iNIRNX884cx0/Q1ja7NyUPpZuv0KPyL5rGNxm1WC1OtHstl7n4Jb7nk+xacNShQMbczJjt8uFzznpp6kYBg==", "requires": { - "@types/unist": "*" + "@types/unist": "^2" } }, "@types/mime": { @@ -15223,9 +15260,9 @@ } }, "@types/unist": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", - "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==" + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.7.tgz", + "integrity": "sha512-cputDpIbFgLUaGQn6Vqg3/YsJwxUwHLO13v3i5ouxT4lat0khip9AEWxtERujXV9wxIB1EyF97BSJFt6vpdI8g==" }, "@types/ws": { "version": "8.5.4", @@ -15514,30 +15551,30 @@ "requires": {} }, "algoliasearch": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.14.3.tgz", - "integrity": "sha512-GZTEuxzfWbP/vr7ZJfGzIl8fOsoxN916Z6FY2Egc9q2TmZ6hvq5KfAxY89pPW01oW/2HDEKA8d30f9iAH9eXYg==", - "requires": { - "@algolia/cache-browser-local-storage": "4.14.3", - "@algolia/cache-common": "4.14.3", - "@algolia/cache-in-memory": "4.14.3", - "@algolia/client-account": "4.14.3", - "@algolia/client-analytics": "4.14.3", - "@algolia/client-common": "4.14.3", - "@algolia/client-personalization": "4.14.3", - "@algolia/client-search": "4.14.3", - "@algolia/logger-common": "4.14.3", - "@algolia/logger-console": "4.14.3", - "@algolia/requester-browser-xhr": "4.14.3", - "@algolia/requester-common": "4.14.3", - "@algolia/requester-node-http": "4.14.3", - "@algolia/transporter": "4.14.3" + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.18.0.tgz", + "integrity": "sha512-pCuVxC1SVcpc08ENH32T4sLKSyzoU7TkRIDBMwSLfIiW+fq4znOmWDkAygHZ6pRcO9I1UJdqlfgnV7TRj+MXrA==", + "requires": { + "@algolia/cache-browser-local-storage": "4.18.0", + "@algolia/cache-common": "4.18.0", + "@algolia/cache-in-memory": "4.18.0", + "@algolia/client-account": "4.18.0", + "@algolia/client-analytics": "4.18.0", + "@algolia/client-common": "4.18.0", + "@algolia/client-personalization": "4.18.0", + "@algolia/client-search": "4.18.0", + "@algolia/logger-common": "4.18.0", + "@algolia/logger-console": "4.18.0", + "@algolia/requester-browser-xhr": "4.18.0", + "@algolia/requester-common": "4.18.0", + "@algolia/requester-node-http": "4.18.0", + "@algolia/transporter": "4.18.0" } }, "algoliasearch-helper": { - "version": "3.11.3", - "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.11.3.tgz", - "integrity": "sha512-TbaEvLwiuGygHQIB8y+OsJKQQ40+JKUua5B91X66tMUHyyhbNHvqyr0lqd3wCoyKx7WybyQrC0WJvzoIeh24Aw==", + "version": "3.13.3", + "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.13.3.tgz", + "integrity": "sha512-jhbbuYZ+fheXpaJlqdJdFa1jOsrTWKmRRTYDM3oVTto5VodZzM7tT+BHzslAotaJf/81CKrm6yLRQn8WIr/K4A==", "requires": { "@algolia/events": "^4.0.1" } @@ -16249,9 +16286,9 @@ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, "copy-text-to-clipboard": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.0.1.tgz", - "integrity": "sha512-rvVsHrpFcL4F2P8ihsoLdFHmd404+CMg71S756oRSeQgqk51U3kicGdnvfkrxva0xXH92SjGS62B0XIJsbh+9Q==" + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.2.0.tgz", + "integrity": "sha512-RnJFp1XR/LOBDckxTib5Qjr/PMfkatD0MUCQgdpqS8MdKiNUzBjAQBEN6oUy+jW7LI93BBG3DtMB2KOOKpGs2Q==" }, "copy-webpack-plugin": { "version": "11.0.0", @@ -16364,11 +16401,11 @@ } }, "cross-fetch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", - "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", "requires": { - "node-fetch": "2.6.7" + "node-fetch": "^2.6.12" } }, "cross-spawn": { @@ -16768,13 +16805,13 @@ } }, "domutils": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", - "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", "requires": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", - "domhandler": "^5.0.1" + "domhandler": "^5.0.3" } }, "dot-case": { @@ -17136,9 +17173,9 @@ } }, "fbjs": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.4.tgz", - "integrity": "sha512-ucV0tDODnGV3JCnnkmoszb5lf4bNpzjv80K41wd4k798Etq+UYD0y0TIfalLjZoKgjive6/adkRnszwapiDgBQ==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.5.tgz", + "integrity": "sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==", "requires": { "cross-fetch": "^3.1.5", "fbjs-css-vars": "^1.0.0", @@ -17146,7 +17183,7 @@ "object-assign": "^4.1.0", "promise": "^7.1.1", "setimmediate": "^1.0.5", - "ua-parser-js": "^0.7.30" + "ua-parser-js": "^1.0.35" } }, "fbjs-css-vars": { @@ -17245,9 +17282,9 @@ } }, "flux": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/flux/-/flux-4.0.3.tgz", - "integrity": "sha512-yKAbrp7JhZhj6uiT1FTuVMlIAT1J4jqEyBpFApi1kxpGZCvacMVc/t1pMQyotqHhAgvoE3bNvAykhCo2CLjnYw==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/flux/-/flux-4.0.4.tgz", + "integrity": "sha512-NCj3XlayA2UsapRpM7va6wU1+9rE5FIL7qoMcmxWHRzbp0yujihMBm9BBHZ1MDIk5h5o2Bl6eGiCe8rYELAmYw==", "requires": { "fbemitter": "^3.0.0", "fbjs": "^3.0.1" @@ -17781,14 +17818,14 @@ } }, "htmlparser2": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz", - "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", "requires": { "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", + "domhandler": "^5.0.3", "domutils": "^3.0.1", - "entities": "^4.3.0" + "entities": "^4.4.0" } }, "http-cache-semantics": { @@ -17909,9 +17946,9 @@ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" }, "infima": { - "version": "0.2.0-alpha.42", - "resolved": "https://registry.npmjs.org/infima/-/infima-0.2.0-alpha.42.tgz", - "integrity": "sha512-ift8OXNbQQwtbIt6z16KnSWP7uJ/SysSMFI4F87MNRTicypfl4Pv3E2OGVv6N3nSZFJvA8imYulCBS64iyHYww==" + "version": "0.2.0-alpha.43", + "resolved": "https://registry.npmjs.org/infima/-/infima-0.2.0-alpha.43.tgz", + "integrity": "sha512-2uw57LvUqW0rK/SWYnd/2rRfxNA5DDNOh33jxF7fy46VWoNhGxiUQyVZHbBMjQ33mQem0cjdDVwgWVAmlRfgyQ==" }, "inflight": { "version": "1.0.6", @@ -18625,9 +18662,9 @@ } }, "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", "requires": { "whatwg-url": "^5.0.0" } @@ -19326,9 +19363,9 @@ } }, "postcss-sort-media-queries": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-4.3.0.tgz", - "integrity": "sha512-jAl8gJM2DvuIJiI9sL1CuiHtKM4s5aEIomkU8G3LFvbP+p8i7Sz8VV63uieTgoewGqKbi+hxBTiOKJlB35upCg==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-4.4.1.tgz", + "integrity": "sha512-QDESFzDDGKgpiIh4GYXsSy6sek2yAwQx1JASl5AxBtU1Lq2JfKBljIPNdil989NcSKRQX1ToiaKphImtBuhXWw==", "requires": { "sort-css-media-queries": "2.1.0" } @@ -19749,11 +19786,11 @@ } }, "react-textarea-autosize": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.4.0.tgz", - "integrity": "sha512-YrTFaEHLgJsi8sJVYHBzYn+mkP3prGkmP2DKb/tm0t7CLJY5t1Rxix8070LAKb0wby7bl/lf2EeHkuMihMZMwQ==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.5.2.tgz", + "integrity": "sha512-uOkyjkEl0ByEK21eCJMHDGBAAd/BoFQBawYK5XItjAmCTeSbjxghd8qnt7nzsLYzidjnoObu6M26xts0YGKsGg==", "requires": { - "@babel/runtime": "^7.10.2", + "@babel/runtime": "^7.20.13", "use-composed-ref": "^1.3.0", "use-latest": "^1.2.1" } @@ -20249,6 +20286,12 @@ "ajv-keywords": "^3.5.2" } }, + "search-insights": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.7.0.tgz", + "integrity": "sha512-GLbVaGgzYEKMvuJbHRhLi1qoBFnjXZGZ6l4LxOYPCp4lI2jDRB3jPU9/XNhMwv6kvnA9slTreq6pvK+b3o3aqg==", + "peer": true + }, "section-matter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", @@ -21049,9 +21092,9 @@ "peer": true }, "ua-parser-js": { - "version": "0.7.33", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.33.tgz", - "integrity": "sha512-s8ax/CeZdK9R/56Sui0WM6y9OFREJarMRHqLB2EwkovemBxNQ+Bqu8GAsUnVcXKgphb++ghr/B2BZx4mahujPw==" + "version": "1.0.35", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.35.tgz", + "integrity": "sha512-fKnGuqmTBnIE+/KXSzCn4db8RTigUzw1AN0DmdU6hJovUTbYJKyqj+8Mt1c4VfRDnOVJnENmfYkIPZ946UrSAA==" }, "unherit": { "version": "1.1.3", diff --git a/docs/package.json b/docs/package.json index 297cedf242..a2b516536d 100644 --- a/docs/package.json +++ b/docs/package.json @@ -14,10 +14,10 @@ "write-heading-ids": "docusaurus write-heading-ids" }, "dependencies": { - "@docusaurus/core": "2.3.1", - "@docusaurus/plugin-client-redirects": "^2.3.1", - "@docusaurus/plugin-google-analytics": "^2.3.1", - "@docusaurus/preset-classic": "2.3.1", + "@docusaurus/core": "^2.4.1", + "@docusaurus/plugin-client-redirects": "^2.4.1", + "@docusaurus/plugin-google-analytics": "^2.4.1", + "@docusaurus/preset-classic": "^2.4.1", "@mdx-js/react": "^1.6.22", "@you54f/theme-github-codeblock": "^0.1.1", "autoprefixer": "^10.4.13", @@ -30,7 +30,7 @@ "tailwindcss": "^3.2.7" }, "devDependencies": { - "@docusaurus/module-type-aliases": "2.3.1" + "@docusaurus/module-type-aliases": "^2.4.1" }, "browserslist": { "production": [ From 6204bd8ee6a3eb55fd5cf522d71cfb95a1756084 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Wed, 19 Jul 2023 08:05:46 -0700 Subject: [PATCH 064/134] chore: make hardcoded json string for consumer genesis readable (#1161) make readable Co-authored-by: Marius Poke --- x/ccv/provider/keeper/proposal_test.go | 85 +++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 2 deletions(-) diff --git a/x/ccv/provider/keeper/proposal_test.go b/x/ccv/provider/keeper/proposal_test.go index 4e9ee3f4ea..c84369e815 100644 --- a/x/ccv/provider/keeper/proposal_test.go +++ b/x/ccv/provider/keeper/proposal_test.go @@ -852,10 +852,91 @@ func TestMakeConsumerGenesis(t *testing.T) { actualGenesis, _, err := providerKeeper.MakeConsumerGenesis(ctx, &prop) require.NoError(t, err) - jsonString := `{"params":{"enabled":true, "blocks_per_distribution_transmission":1000, "ccv_timeout_period":2419200000000000, "transfer_timeout_period": 3600000000000, "consumer_redistribution_fraction":"0.75", "historical_entries":10000, "unbonding_period": 1728000000000000, "soft_opt_out_threshold": "0.05", "reward_denoms": [], "provider_reward_denoms": []},"new_chain":true,"provider_client_state":{"chain_id":"testchain1","trust_level":{"numerator":1,"denominator":3},"trusting_period":1197504000000000,"unbonding_period":1814400000000000,"max_clock_drift":10000000000,"frozen_height":{},"latest_height":{"revision_height":5},"proof_specs":[{"leaf_spec":{"hash":1,"prehash_value":1,"length":1,"prefix":"AA=="},"inner_spec":{"child_order":[0,1],"child_size":33,"min_prefix_length":4,"max_prefix_length":12,"hash":1}},{"leaf_spec":{"hash":1,"prehash_value":1,"length":1,"prefix":"AA=="},"inner_spec":{"child_order":[0,1],"child_size":32,"min_prefix_length":1,"max_prefix_length":1,"hash":1}}],"upgrade_path":["upgrade","upgradedIBCState"],"allow_update_after_expiry":true,"allow_update_after_misbehaviour":true},"provider_consensus_state":{"timestamp":"2020-01-02T00:00:10Z","root":{"hash":"LpGpeyQVLUo9HpdsgJr12NP2eCICspcULiWa5u9udOA="},"next_validators_hash":"E30CE736441FB9101FADDAF7E578ABBE6DFDB67207112350A9A904D554E1F5BE"},"unbonding_sequences":null,"initial_val_set":[{"pub_key":{"type":"tendermint/PubKeyEd25519","value":"dcASx5/LIKZqagJWN0frOlFtcvz91frYmj/zmoZRWro="},"power":1}]}` + // JSON string with tabs, newlines and spaces for readability + jsonString := `{ + "params": { + "enabled": true, + "blocks_per_distribution_transmission": 1000, + "ccv_timeout_period": 2419200000000000, + "transfer_timeout_period": 3600000000000, + "consumer_redistribution_fraction": "0.75", + "historical_entries": 10000, + "unbonding_period": 1728000000000000, + "soft_opt_out_threshold": "0.05", + "reward_denoms": [], + "provider_reward_denoms": [] + }, + "new_chain": true, + "provider_client_state": { + "chain_id": "testchain1", + "trust_level": { + "numerator": 1, + "denominator": 3 + }, + "trusting_period": 1197504000000000, + "unbonding_period": 1814400000000000, + "max_clock_drift": 10000000000, + "frozen_height": {}, + "latest_height": { + "revision_height": 5 + }, + "proof_specs": [ + { + "leaf_spec": { + "hash": 1, + "prehash_value": 1, + "length": 1, + "prefix": "AA==" + }, + "inner_spec": { + "child_order": [0, 1], + "child_size": 33, + "min_prefix_length": 4, + "max_prefix_length": 12, + "hash": 1 + } + }, + { + "leaf_spec": { + "hash": 1, + "prehash_value": 1, + "length": 1, + "prefix": "AA==" + }, + "inner_spec": { + "child_order": [0, 1], + "child_size": 32, + "min_prefix_length": 1, + "max_prefix_length": 1, + "hash": 1 + } + } + ], + "upgrade_path": ["upgrade", "upgradedIBCState"], + "allow_update_after_expiry": true, + "allow_update_after_misbehaviour": true + }, + "provider_consensus_state": { + "timestamp": "2020-01-02T00:00:10Z", + "root": { + "hash": "LpGpeyQVLUo9HpdsgJr12NP2eCICspcULiWa5u9udOA=" + }, + "next_validators_hash": "E30CE736441FB9101FADDAF7E578ABBE6DFDB67207112350A9A904D554E1F5BE" + }, + "unbonding_sequences": null, + "initial_val_set": [ + { + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "dcASx5/LIKZqagJWN0frOlFtcvz91frYmj/zmoZRWro=" + }, + "power": 1 + } + ] + }` var expectedGenesis consumertypes.GenesisState - err = json.Unmarshal([]byte(jsonString), &expectedGenesis) + err = json.Unmarshal([]byte(jsonString), &expectedGenesis) // ignores tabs, newlines and spaces require.NoError(t, err) // Zeroing out different fields that are challenging to mock From 064c601231b85066bfaf734efec2751a672528a7 Mon Sep 17 00:00:00 2001 From: yaruwangway <69694322+yaruwangway@users.noreply.github.com> Date: Wed, 19 Jul 2023 17:29:59 +0200 Subject: [PATCH 065/134] Fix: export InitTimeoutTimestamps and VscSendTimestamps to genesis (#1076) * fix: add InitTimeoutTimestamps and VscSendTimestamps to genesis * fix: add chainID to vscSendTimestamp * test: fix tests * test: fixgenesis test * test: fix test TestInitAndExportGenesis * feat: add exportedVscSendTimestamps * docs: update changelog * feat: update exportedVscSendTimestamps * fix: lint --- CHANGELOG.md | 1 + .../ccv/consumer/v1/genesis.proto | 2 +- .../ccv/provider/v1/genesis.proto | 6 + .../ccv/provider/v1/provider.proto | 7 + .../ccv/provider/v1/tx.proto | 2 +- x/ccv/provider/keeper/genesis.go | 15 + x/ccv/provider/keeper/genesis_test.go | 47 ++ x/ccv/provider/module_test.go | 2 + x/ccv/provider/types/genesis.go | 4 + x/ccv/provider/types/genesis.pb.go | 241 +++++++--- x/ccv/provider/types/genesis_test.go | 58 +++ x/ccv/provider/types/provider.pb.go | 446 +++++++++++++----- 12 files changed, 668 insertions(+), 163 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a5c14c6e4..818bdca374 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## [Unreleased] Add an entry to the unreleased section whenever merging a PR to main that is not targeted at a specific release. These entries will eventually be included in a release. +* `[x/ccv/provider]` (fix) [#1076](https://github.com/cosmos/interchain-security/pull/1076) Add `InitTimeoutTimestamps` and `ExportedVscSendTimestamps` to exported genesis. * (fix!) revert consumer packet data changes from #1037 [#1150](https://github.com/cosmos/interchain-security/pull/1150) * (fix!) proper deletion of pending packets [#1146](https://github.com/cosmos/interchain-security/pull/1146) diff --git a/proto/interchain_security/ccv/consumer/v1/genesis.proto b/proto/interchain_security/ccv/consumer/v1/genesis.proto index 9c9418ef3c..3511f3f349 100644 --- a/proto/interchain_security/ccv/consumer/v1/genesis.proto +++ b/proto/interchain_security/ccv/consumer/v1/genesis.proto @@ -55,4 +55,4 @@ message HeightToValsetUpdateID { // OutstandingDowntime defines the genesis information for each validator // flagged with an outstanding downtime slashing. -message OutstandingDowntime { string validator_consensus_address = 1; } \ No newline at end of file +message OutstandingDowntime { string validator_consensus_address = 1; } diff --git a/proto/interchain_security/ccv/provider/v1/genesis.proto b/proto/interchain_security/ccv/provider/v1/genesis.proto index e1f6ab2e1a..1bc412262c 100644 --- a/proto/interchain_security/ccv/provider/v1/genesis.proto +++ b/proto/interchain_security/ccv/provider/v1/genesis.proto @@ -44,6 +44,12 @@ message GenesisState { // empty for a new chain repeated ConsumerAddrsToPrune consumer_addrs_to_prune = 11 [ (gogoproto.nullable) = false ]; + + repeated interchain_security.ccv.provider.v1.InitTimeoutTimestamp init_timeout_timestamps = 12 + [ (gogoproto.nullable) = false ]; + + repeated interchain_security.ccv.provider.v1.ExportedVscSendTimestamp exported_vsc_send_timestamps = 13 + [ (gogoproto.nullable) = false ]; } // consumer chain diff --git a/proto/interchain_security/ccv/provider/v1/provider.proto b/proto/interchain_security/ccv/provider/v1/provider.proto index b986255ce5..3c41e01c89 100644 --- a/proto/interchain_security/ccv/provider/v1/provider.proto +++ b/proto/interchain_security/ccv/provider/v1/provider.proto @@ -221,6 +221,13 @@ message VscSendTimestamp { [ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ]; } +// ExportedVscSendTimestamps is VscSendTimestamp with chainID info for exporting to genesis +message ExportedVscSendTimestamp { + string chain_id = 1; + repeated VscSendTimestamp vsc_send_timestamps = 2 + [ (gogoproto.nullable) = false ]; +} + // // Key assignment section // diff --git a/proto/interchain_security/ccv/provider/v1/tx.proto b/proto/interchain_security/ccv/provider/v1/tx.proto index 257ab6e4e4..952ba31c09 100644 --- a/proto/interchain_security/ccv/provider/v1/tx.proto +++ b/proto/interchain_security/ccv/provider/v1/tx.proto @@ -44,4 +44,4 @@ message MsgRegisterConsumerRewardDenom { // MsgRegisterConsumerRewardDenomResponse defines the // Msg/RegisterConsumerRewardDenom response type. -message MsgRegisterConsumerRewardDenomResponse {} \ No newline at end of file +message MsgRegisterConsumerRewardDenomResponse {} diff --git a/x/ccv/provider/keeper/genesis.go b/x/ccv/provider/keeper/genesis.go index b3a0a1ef04..f201e6de50 100644 --- a/x/ccv/provider/keeper/genesis.go +++ b/x/ccv/provider/keeper/genesis.go @@ -91,6 +91,16 @@ func (k Keeper) InitGenesis(ctx sdk.Context, genState *types.GenesisState) { } } + for _, item := range genState.InitTimeoutTimestamps { + k.SetInitTimeoutTimestamp(ctx, item.ChainId, item.Timestamp) + } + + for _, item := range genState.ExportedVscSendTimestamps { + for _, vscSendTimestamp := range item.VscSendTimestamps { + k.SetVscSendTimestamp(ctx, item.ChainId, vscSendTimestamp.VscId, vscSendTimestamp.Timestamp) + } + } + k.SetParams(ctx, genState.Params) k.InitializeSlashMeter(ctx) } @@ -100,6 +110,7 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { // get a list of all registered consumer chains registeredChains := k.GetAllConsumerChains(ctx) + var exportedVscSendTimestamps []types.ExportedVscSendTimestamp // export states for each consumer chains var consumerStates []types.ConsumerState for _, chain := range registeredChains { @@ -130,6 +141,8 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { cs.PendingValsetChanges = k.GetPendingVSCPackets(ctx, chain.ChainId) consumerStates = append(consumerStates, cs) + vscSendTimestamps := k.GetAllVscSendTimestamps(ctx, chain.ChainId) + exportedVscSendTimestamps = append(exportedVscSendTimestamps, types.ExportedVscSendTimestamp{ChainId: chain.ChainId, VscSendTimestamps: vscSendTimestamps}) } // ConsumerAddrsToPrune are added only for registered consumer chains @@ -152,5 +165,7 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { k.GetAllValidatorConsumerPubKeys(ctx, nil), k.GetAllValidatorsByConsumerAddr(ctx, nil), consumerAddrsToPrune, + k.GetAllInitTimeoutTimestamps(ctx), + exportedVscSendTimestamps, ) } diff --git a/x/ccv/provider/keeper/genesis_test.go b/x/ccv/provider/keeper/genesis_test.go index d9147ce98f..01a3845651 100644 --- a/x/ccv/provider/keeper/genesis_test.go +++ b/x/ccv/provider/keeper/genesis_test.go @@ -1,6 +1,7 @@ package keeper_test import ( + "sort" "testing" "time" @@ -36,6 +37,32 @@ func TestInitAndExportGenesis(t *testing.T) { consumerTmPubKey := consumerCryptoId.TMProtoCryptoPublicKey() consumerConsAddr := consumerCryptoId.ConsumerConsAddress() + initTimeoutTimeStamps := []providertypes.InitTimeoutTimestamp{ + {ChainId: cChainIDs[0], Timestamp: uint64(time.Now().UTC().UnixNano()) + 10}, + {ChainId: cChainIDs[1], Timestamp: uint64(time.Now().UTC().UnixNano()) + 15}, + } + + now := time.Now().UTC() + exportedVscSendTimeStampsC0 := providertypes.ExportedVscSendTimestamp{ + ChainId: "c0", + VscSendTimestamps: []providertypes.VscSendTimestamp{ + {VscId: 1, Timestamp: now.Add(time.Hour)}, + {VscId: 2, Timestamp: now.Add(2 * time.Hour)}, + }, + } + + exportedVscSendTimeStampsC1 := providertypes.ExportedVscSendTimestamp{ + ChainId: "c1", + VscSendTimestamps: []providertypes.VscSendTimestamp{ + {VscId: 1, Timestamp: now.Add(-time.Hour)}, + {VscId: 2, Timestamp: now.Add(time.Hour)}, + }, + } + + var exportedVscSendTimeStampsAll []providertypes.ExportedVscSendTimestamp + exportedVscSendTimeStampsAll = append(exportedVscSendTimeStampsAll, exportedVscSendTimeStampsC0) + exportedVscSendTimeStampsAll = append(exportedVscSendTimeStampsAll, exportedVscSendTimeStampsC1) + // create genesis struct provGenesis := providertypes.NewGenesisState(vscID, []providertypes.ValsetUpdateIdToHeight{{ValsetUpdateId: vscID, Height: initHeight}}, @@ -98,6 +125,8 @@ func TestInitAndExportGenesis(t *testing.T) { ConsumerAddrs: &providertypes.AddressList{Addresses: [][]byte{consumerConsAddr.ToSdkConsAddr()}}, }, }, + initTimeoutTimeStamps, + exportedVscSendTimeStampsAll, ) // Instantiate in-mem provider keeper with mocks @@ -164,6 +193,24 @@ func TestInitAndExportGenesis(t *testing.T) { // check the exported genesis require.Equal(t, provGenesis, pk.ExportGenesis(ctx)) + + initTimeoutTimestampInStore := pk.GetAllInitTimeoutTimestamps(ctx) + sort.Slice(initTimeoutTimestampInStore, func(i, j int) bool { + return initTimeoutTimestampInStore[i].Timestamp < initTimeoutTimestampInStore[j].Timestamp + }) + require.Equal(t, initTimeoutTimestampInStore, initTimeoutTimeStamps) + + vscSendTimestampsC0InStore := pk.GetAllVscSendTimestamps(ctx, cChainIDs[0]) + sort.Slice(vscSendTimestampsC0InStore, func(i, j int) bool { + return vscSendTimestampsC0InStore[i].VscId < vscSendTimestampsC0InStore[j].VscId + }) + require.Equal(t, vscSendTimestampsC0InStore, exportedVscSendTimeStampsC0.VscSendTimestamps) + + vscSendTimestampsC1InStore := pk.GetAllVscSendTimestamps(ctx, cChainIDs[1]) + sort.Slice(vscSendTimestampsC1InStore, func(i, j int) bool { + return vscSendTimestampsC1InStore[i].VscId < vscSendTimestampsC1InStore[j].VscId + }) + require.Equal(t, vscSendTimestampsC1InStore, exportedVscSendTimeStampsC1.VscSendTimestamps) } func assertConsumerChainStates(t *testing.T, ctx sdk.Context, pk keeper.Keeper, consumerStates ...providertypes.ConsumerState) { diff --git a/x/ccv/provider/module_test.go b/x/ccv/provider/module_test.go index f32cb8cc4d..bf63f86b40 100644 --- a/x/ccv/provider/module_test.go +++ b/x/ccv/provider/module_test.go @@ -108,6 +108,8 @@ func TestInitGenesis(t *testing.T) { nil, nil, nil, + nil, + nil, ) cdc := keeperParams.Cdc diff --git a/x/ccv/provider/types/genesis.go b/x/ccv/provider/types/genesis.go index 07c135ebfc..2118f3143e 100644 --- a/x/ccv/provider/types/genesis.go +++ b/x/ccv/provider/types/genesis.go @@ -24,6 +24,8 @@ func NewGenesisState( validatorConsumerPubkeys []ValidatorConsumerPubKey, validatorsByConsumerAddr []ValidatorByConsumerAddr, consumerAddrsToPrune []ConsumerAddrsToPrune, + initTimeoutTimestamps []InitTimeoutTimestamp, + exportedVscSendTimestamps []ExportedVscSendTimestamp, ) *GenesisState { return &GenesisState{ ValsetUpdateId: vscID, @@ -37,6 +39,8 @@ func NewGenesisState( ValidatorConsumerPubkeys: validatorConsumerPubkeys, ValidatorsByConsumerAddr: validatorsByConsumerAddr, ConsumerAddrsToPrune: consumerAddrsToPrune, + InitTimeoutTimestamps: initTimeoutTimestamps, + ExportedVscSendTimestamps: exportedVscSendTimestamps, } } diff --git a/x/ccv/provider/types/genesis.pb.go b/x/ccv/provider/types/genesis.pb.go index 0e4e4f2cf3..ddd7d478b6 100644 --- a/x/ccv/provider/types/genesis.pb.go +++ b/x/ccv/provider/types/genesis.pb.go @@ -48,7 +48,9 @@ type GenesisState struct { // empty for a new chain ValidatorsByConsumerAddr []ValidatorByConsumerAddr `protobuf:"bytes,10,rep,name=validators_by_consumer_addr,json=validatorsByConsumerAddr,proto3" json:"validators_by_consumer_addr"` // empty for a new chain - ConsumerAddrsToPrune []ConsumerAddrsToPrune `protobuf:"bytes,11,rep,name=consumer_addrs_to_prune,json=consumerAddrsToPrune,proto3" json:"consumer_addrs_to_prune"` + ConsumerAddrsToPrune []ConsumerAddrsToPrune `protobuf:"bytes,11,rep,name=consumer_addrs_to_prune,json=consumerAddrsToPrune,proto3" json:"consumer_addrs_to_prune"` + InitTimeoutTimestamps []InitTimeoutTimestamp `protobuf:"bytes,12,rep,name=init_timeout_timestamps,json=initTimeoutTimestamps,proto3" json:"init_timeout_timestamps"` + ExportedVscSendTimestamps []ExportedVscSendTimestamp `protobuf:"bytes,13,rep,name=exported_vsc_send_timestamps,json=exportedVscSendTimestamps,proto3" json:"exported_vsc_send_timestamps"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -161,6 +163,20 @@ func (m *GenesisState) GetConsumerAddrsToPrune() []ConsumerAddrsToPrune { return nil } +func (m *GenesisState) GetInitTimeoutTimestamps() []InitTimeoutTimestamp { + if m != nil { + return m.InitTimeoutTimestamps + } + return nil +} + +func (m *GenesisState) GetExportedVscSendTimestamps() []ExportedVscSendTimestamp { + if m != nil { + return m.ExportedVscSendTimestamps + } + return nil +} + // consumer chain type ConsumerState struct { // ChainID defines the chain ID for the consumer chain @@ -336,61 +352,66 @@ func init() { } var fileDescriptor_48411d9c7900d48e = []byte{ - // 856 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xdd, 0x8e, 0xdb, 0x44, - 0x14, 0x5e, 0xef, 0xa6, 0xdb, 0xcd, 0x6c, 0x77, 0x59, 0x86, 0x55, 0x70, 0xb3, 0x90, 0xae, 0x02, - 0x48, 0x91, 0x00, 0x1b, 0xa7, 0x5c, 0xf0, 0xd7, 0x8b, 0xa6, 0x95, 0x20, 0x42, 0x88, 0x28, 0xfd, - 0x41, 0x2a, 0x17, 0xd6, 0x64, 0x3c, 0x4a, 0x86, 0xd8, 0x33, 0xd6, 0xcc, 0xd8, 0xd4, 0x42, 0x48, - 0x54, 0xbc, 0x00, 0x6f, 0x45, 0x2f, 0x7b, 0xc9, 0x55, 0x85, 0x76, 0xdf, 0x80, 0x27, 0x40, 0x1e, - 0x8f, 0x5d, 0x7b, 0x49, 0x20, 0xe1, 0x2e, 0x3e, 0xdf, 0x9c, 0xef, 0x3b, 0x67, 0xce, 0xcc, 0x37, - 0x01, 0x1e, 0x65, 0x8a, 0x08, 0xbc, 0x40, 0x94, 0xf9, 0x92, 0xe0, 0x44, 0x50, 0x95, 0xb9, 0x18, - 0xa7, 0x6e, 0x2c, 0x78, 0x4a, 0x03, 0x22, 0xdc, 0xd4, 0x73, 0xe7, 0x84, 0x11, 0x49, 0xa5, 0x13, - 0x0b, 0xae, 0x38, 0x7c, 0x67, 0x45, 0x8a, 0x83, 0x71, 0xea, 0x94, 0x29, 0x4e, 0xea, 0x75, 0x4f, - 0xe7, 0x7c, 0xce, 0xf5, 0x7a, 0x37, 0xff, 0x55, 0xa4, 0x76, 0xdf, 0x5d, 0xa7, 0x96, 0x7a, 0xae, - 0x61, 0x50, 0xbc, 0x3b, 0xdc, 0xa4, 0xa6, 0x4a, 0xec, 0x3f, 0x72, 0x30, 0x67, 0x32, 0x89, 0x8a, - 0x9c, 0xf2, 0xb7, 0xc9, 0xf1, 0x36, 0xc9, 0x69, 0xf4, 0xde, 0x7d, 0x4b, 0x11, 0x16, 0x10, 0x11, - 0x51, 0xa6, 0x5c, 0x2c, 0xb2, 0x58, 0x71, 0x77, 0x49, 0x32, 0x83, 0xf6, 0x7f, 0x6f, 0x83, 0x1b, - 0x5f, 0x16, 0xeb, 0x1f, 0x28, 0xa4, 0x08, 0x1c, 0x80, 0x93, 0x14, 0x85, 0x92, 0x28, 0x3f, 0x89, - 0x03, 0xa4, 0x88, 0x4f, 0x03, 0xdb, 0x3a, 0xb7, 0x06, 0xad, 0xe9, 0x71, 0x11, 0x7f, 0xa4, 0xc3, - 0xe3, 0x00, 0xfe, 0x04, 0x5e, 0x2b, 0x55, 0x7d, 0x99, 0xe7, 0x4a, 0x7b, 0xf7, 0x7c, 0x6f, 0x70, - 0x38, 0x1c, 0x3a, 0x1b, 0x6c, 0xb7, 0x73, 0xcf, 0xe4, 0x6a, 0xd9, 0x51, 0xef, 0xf9, 0xcb, 0x5b, - 0x3b, 0x7f, 0xbd, 0xbc, 0xd5, 0xc9, 0x50, 0x14, 0x7e, 0xd6, 0xbf, 0x42, 0xdc, 0x9f, 0x1e, 0xe3, - 0xfa, 0x72, 0x09, 0xbf, 0x07, 0x47, 0x09, 0x9b, 0x71, 0x16, 0x50, 0x36, 0xf7, 0x79, 0x2c, 0xed, - 0x3d, 0x2d, 0xfd, 0xd1, 0x46, 0xd2, 0x8f, 0xca, 0xcc, 0x6f, 0xe3, 0x51, 0x2b, 0x17, 0x9e, 0xde, - 0x48, 0x5e, 0x85, 0x24, 0x44, 0xe0, 0x34, 0x42, 0x2a, 0x11, 0xc4, 0x6f, 0x6a, 0xb4, 0xce, 0xad, - 0xc1, 0xe1, 0xd0, 0x5d, 0xab, 0x91, 0x7a, 0xce, 0x37, 0x3a, 0x2f, 0xa8, 0x29, 0xc8, 0x29, 0x2c, - 0xc8, 0xea, 0x31, 0xf8, 0x33, 0xe8, 0x5e, 0xdd, 0x66, 0x5f, 0x71, 0x7f, 0x41, 0xe8, 0x7c, 0xa1, - 0xec, 0x6b, 0xba, 0x99, 0xcf, 0x37, 0x6a, 0xe6, 0x71, 0x63, 0x2a, 0x0f, 0xf9, 0x57, 0x9a, 0xc2, - 0xf4, 0xd5, 0x49, 0x57, 0xa2, 0xf0, 0x57, 0x0b, 0x9c, 0x55, 0x7b, 0x8c, 0x82, 0x80, 0x2a, 0xca, - 0x99, 0x1f, 0x0b, 0x1e, 0x73, 0x89, 0x42, 0x69, 0xef, 0xeb, 0x02, 0xee, 0x6c, 0x35, 0xc8, 0xbb, - 0x86, 0x66, 0x62, 0x58, 0x4c, 0x09, 0x37, 0xf1, 0x1a, 0x5c, 0xc2, 0x5f, 0x2c, 0xd0, 0xad, 0xaa, - 0x10, 0x24, 0xe2, 0x29, 0x0a, 0x6b, 0x45, 0x5c, 0xd7, 0x45, 0x7c, 0xb1, 0x55, 0x11, 0xd3, 0x82, - 0xe5, 0x4a, 0x0d, 0x36, 0x5e, 0x0d, 0x4b, 0x38, 0x06, 0xfb, 0x31, 0x12, 0x28, 0x92, 0xf6, 0x81, - 0x1e, 0xee, 0xfb, 0x1b, 0xa9, 0x4d, 0x74, 0x8a, 0x21, 0x37, 0x04, 0xba, 0x9b, 0x14, 0x85, 0x34, - 0x40, 0x8a, 0x0b, 0xbf, 0xea, 0x2b, 0x4e, 0x66, 0xf9, 0x7d, 0xb3, 0xdb, 0x5b, 0x74, 0xf3, 0xb8, - 0xa4, 0x29, 0xdb, 0x9a, 0x24, 0xb3, 0xaf, 0x49, 0x56, 0x76, 0x93, 0xae, 0x80, 0x73, 0x0d, 0xf8, - 0xcc, 0x02, 0x67, 0x15, 0x28, 0xfd, 0x59, 0xe6, 0xd7, 0x87, 0x2c, 0x6c, 0xf0, 0x7f, 0x6a, 0x18, - 0x65, 0xb5, 0x09, 0x8b, 0x7f, 0xd4, 0x20, 0x9b, 0x38, 0x4c, 0xc1, 0x9b, 0x0d, 0x51, 0x99, 0x9f, - 0xeb, 0x58, 0x24, 0x8c, 0xd8, 0x87, 0x5a, 0xfe, 0xd3, 0x6d, 0x4f, 0x95, 0x90, 0x0f, 0xf9, 0x24, - 0x27, 0x30, 0xda, 0xa7, 0x78, 0x05, 0xd6, 0x7f, 0xd6, 0x02, 0x47, 0x0d, 0x4f, 0x81, 0x37, 0xc1, - 0x41, 0x21, 0x62, 0x2c, 0xac, 0x3d, 0xbd, 0xae, 0xbf, 0xc7, 0x01, 0x7c, 0x1b, 0x00, 0xbc, 0x40, - 0x8c, 0x91, 0x30, 0x07, 0x77, 0x35, 0xd8, 0x36, 0x91, 0x71, 0x00, 0xcf, 0x40, 0x1b, 0x87, 0x94, - 0x30, 0x95, 0xa3, 0x7b, 0x1a, 0x3d, 0x28, 0x02, 0xe3, 0x00, 0xbe, 0x07, 0x8e, 0x29, 0xa3, 0x8a, - 0xa2, 0xb0, 0xbc, 0xae, 0x2d, 0xed, 0x8f, 0x47, 0x26, 0x6a, 0xae, 0xd8, 0x0c, 0x9c, 0x54, 0xfb, - 0x60, 0x1c, 0xd9, 0xbe, 0xa6, 0xcf, 0x98, 0xb7, 0x76, 0x03, 0x2a, 0xb7, 0x4f, 0x3d, 0xa7, 0xee, - 0xca, 0xa6, 0xf1, 0xca, 0x6f, 0x0d, 0x06, 0x15, 0xe8, 0xc4, 0xa4, 0xf0, 0x27, 0xe3, 0x26, 0x79, - 0x0f, 0x73, 0x52, 0x5e, 0xe0, 0x4f, 0xfe, 0xcd, 0xaa, 0xaa, 0x01, 0x3f, 0x20, 0xea, 0x9e, 0x4e, - 0x9b, 0x20, 0xbc, 0x24, 0xea, 0x3e, 0x52, 0xa8, 0xdc, 0x69, 0xc3, 0x5e, 0x78, 0x4c, 0xb1, 0x48, - 0xc2, 0x0f, 0x00, 0x94, 0x21, 0x92, 0x0b, 0x3f, 0xe0, 0x3f, 0x32, 0x45, 0x23, 0xe2, 0x23, 0xbc, - 0xd4, 0xb7, 0xb5, 0x3d, 0x3d, 0xd1, 0xc8, 0x7d, 0x03, 0xdc, 0xc5, 0x4b, 0xf8, 0x03, 0x78, 0xa3, - 0xe1, 0xa2, 0x3e, 0x65, 0x01, 0x79, 0x6a, 0x1f, 0xe8, 0x02, 0x3f, 0xde, 0xec, 0x28, 0x4a, 0x5c, - 0x37, 0x4f, 0x53, 0xdc, 0xeb, 0x75, 0xcf, 0x1e, 0xe7, 0xa4, 0xfd, 0x27, 0xa0, 0xb3, 0xda, 0x0e, - 0xb7, 0x78, 0xd6, 0x3a, 0x60, 0xdf, 0x8c, 0x75, 0x57, 0xe3, 0xe6, 0x6b, 0xf4, 0xdd, 0xf3, 0x8b, - 0x9e, 0xf5, 0xe2, 0xa2, 0x67, 0xfd, 0x79, 0xd1, 0xb3, 0x7e, 0xbb, 0xec, 0xed, 0xbc, 0xb8, 0xec, - 0xed, 0xfc, 0x71, 0xd9, 0xdb, 0x79, 0x72, 0x67, 0x4e, 0xd5, 0x22, 0x99, 0x39, 0x98, 0x47, 0x2e, - 0xe6, 0x32, 0xe2, 0xd2, 0x7d, 0xd5, 0xd5, 0x87, 0xd5, 0x33, 0x9d, 0xde, 0x76, 0x9f, 0x36, 0xff, - 0x13, 0xa8, 0x2c, 0x26, 0x72, 0xb6, 0xaf, 0x5f, 0xe2, 0xdb, 0x7f, 0x07, 0x00, 0x00, 0xff, 0xff, - 0xa6, 0x98, 0xf7, 0xad, 0xd8, 0x08, 0x00, 0x00, + // 930 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xdd, 0x6e, 0x23, 0x35, + 0x14, 0xee, 0xb4, 0xd9, 0x6e, 0xe3, 0xfe, 0x50, 0x4c, 0xc9, 0x4e, 0xd3, 0x25, 0x5b, 0x05, 0x90, + 0x2a, 0x01, 0x33, 0xa4, 0xcb, 0x05, 0x7f, 0x7b, 0xb1, 0xdd, 0x45, 0x10, 0x21, 0x44, 0x94, 0x76, + 0x8b, 0xb4, 0x5c, 0x58, 0x8e, 0x6d, 0x25, 0xa6, 0x33, 0xf6, 0x68, 0xec, 0x99, 0x6d, 0x84, 0x90, + 0x58, 0xc1, 0x03, 0xf0, 0x56, 0xec, 0xe5, 0x5e, 0x72, 0xb5, 0x42, 0xed, 0x1b, 0xf0, 0x04, 0x68, + 0x3c, 0x9e, 0xe9, 0x24, 0x24, 0x90, 0x70, 0x95, 0xcc, 0xf9, 0x7c, 0xbe, 0xef, 0x1c, 0x1f, 0xfb, + 0x1c, 0x83, 0x0e, 0x17, 0x9a, 0xc5, 0x64, 0x84, 0xb9, 0x40, 0x8a, 0x91, 0x24, 0xe6, 0x7a, 0xec, + 0x13, 0x92, 0xfa, 0x51, 0x2c, 0x53, 0x4e, 0x59, 0xec, 0xa7, 0x1d, 0x7f, 0xc8, 0x04, 0x53, 0x5c, + 0x79, 0x51, 0x2c, 0xb5, 0x84, 0x6f, 0xcf, 0x70, 0xf1, 0x08, 0x49, 0xbd, 0xc2, 0xc5, 0x4b, 0x3b, + 0xcd, 0xbd, 0xa1, 0x1c, 0x4a, 0xb3, 0xde, 0xcf, 0xfe, 0xe5, 0xae, 0xcd, 0x77, 0xe6, 0xa9, 0xa5, + 0x1d, 0xdf, 0x32, 0x68, 0xd9, 0x3c, 0x5e, 0x24, 0xa6, 0x52, 0xec, 0x3f, 0x7c, 0x88, 0x14, 0x2a, + 0x09, 0x73, 0x9f, 0xe2, 0xbf, 0xf5, 0xe9, 0x2c, 0xe2, 0x33, 0x91, 0x7b, 0xf3, 0xae, 0x66, 0x82, + 0xb2, 0x38, 0xe4, 0x42, 0xfb, 0x24, 0x1e, 0x47, 0x5a, 0xfa, 0x17, 0x6c, 0x6c, 0xd1, 0xf6, 0xef, + 0x9b, 0x60, 0xeb, 0xcb, 0x7c, 0xfd, 0xa9, 0xc6, 0x9a, 0xc1, 0x23, 0xb0, 0x9b, 0xe2, 0x40, 0x31, + 0x8d, 0x92, 0x88, 0x62, 0xcd, 0x10, 0xa7, 0xae, 0x73, 0xe8, 0x1c, 0xd5, 0xfa, 0x3b, 0xb9, 0xfd, + 0x89, 0x31, 0x77, 0x29, 0xfc, 0x11, 0xbc, 0x56, 0xa8, 0x22, 0x95, 0xf9, 0x2a, 0x77, 0xf5, 0x70, + 0xed, 0x68, 0xf3, 0xf8, 0xd8, 0x5b, 0x60, 0xbb, 0xbd, 0x47, 0xd6, 0xd7, 0xc8, 0x9e, 0xb4, 0x5e, + 0xbc, 0xba, 0xb7, 0xf2, 0xd7, 0xab, 0x7b, 0x8d, 0x31, 0x0e, 0x83, 0x4f, 0xdb, 0x53, 0xc4, 0xed, + 0xfe, 0x0e, 0xa9, 0x2e, 0x57, 0xf0, 0x7b, 0xb0, 0x9d, 0x88, 0x81, 0x14, 0x94, 0x8b, 0x21, 0x92, + 0x91, 0x72, 0xd7, 0x8c, 0xf4, 0x87, 0x0b, 0x49, 0x3f, 0x29, 0x3c, 0xbf, 0x8d, 0x4e, 0x6a, 0x99, + 0x70, 0x7f, 0x2b, 0xb9, 0x31, 0x29, 0x88, 0xc1, 0x5e, 0x88, 0x75, 0x12, 0x33, 0x34, 0xa9, 0x51, + 0x3b, 0x74, 0x8e, 0x36, 0x8f, 0xfd, 0xb9, 0x1a, 0x69, 0xc7, 0xfb, 0xc6, 0xf8, 0xd1, 0x8a, 0x82, + 0xea, 0xc3, 0x9c, 0xac, 0x6a, 0x83, 0x3f, 0x81, 0xe6, 0xf4, 0x36, 0x23, 0x2d, 0xd1, 0x88, 0xf1, + 0xe1, 0x48, 0xbb, 0xb7, 0x4c, 0x32, 0x9f, 0x2d, 0x94, 0xcc, 0xf9, 0x44, 0x55, 0xce, 0xe4, 0x57, + 0x86, 0xc2, 0xe6, 0xd5, 0x48, 0x67, 0xa2, 0xf0, 0x17, 0x07, 0x1c, 0x94, 0x7b, 0x8c, 0x29, 0xe5, + 0x9a, 0x4b, 0x81, 0xa2, 0x58, 0x46, 0x52, 0xe1, 0x40, 0xb9, 0xeb, 0x26, 0x80, 0x07, 0x4b, 0x15, + 0xf2, 0xa1, 0xa5, 0xe9, 0x59, 0x16, 0x1b, 0xc2, 0x3e, 0x99, 0x83, 0x2b, 0xf8, 0xb3, 0x03, 0x9a, + 0x65, 0x14, 0x31, 0x0b, 0x65, 0x8a, 0x83, 0x4a, 0x10, 0xb7, 0x4d, 0x10, 0x9f, 0x2f, 0x15, 0x44, + 0x3f, 0x67, 0x99, 0x8a, 0xc1, 0x25, 0xb3, 0x61, 0x05, 0xbb, 0x60, 0x3d, 0xc2, 0x31, 0x0e, 0x95, + 0xbb, 0x61, 0x8a, 0xfb, 0xde, 0x42, 0x6a, 0x3d, 0xe3, 0x62, 0xc9, 0x2d, 0x81, 0xc9, 0x26, 0xc5, + 0x01, 0xa7, 0x58, 0xcb, 0x18, 0x95, 0x79, 0x45, 0xc9, 0x20, 0xbb, 0x6f, 0x6e, 0x7d, 0x89, 0x6c, + 0xce, 0x0b, 0x9a, 0x22, 0xad, 0x5e, 0x32, 0xf8, 0x9a, 0x8d, 0x8b, 0x6c, 0xd2, 0x19, 0x70, 0xa6, + 0x01, 0x9f, 0x3b, 0xe0, 0xa0, 0x04, 0x15, 0x1a, 0x8c, 0x51, 0xb5, 0xc8, 0xb1, 0x0b, 0xfe, 0x4f, + 0x0c, 0x27, 0xe3, 0x4a, 0x85, 0xe3, 0x7f, 0xc4, 0xa0, 0x26, 0x71, 0x98, 0x82, 0x3b, 0x13, 0xa2, + 0x2a, 0x3b, 0xd7, 0x51, 0x9c, 0x08, 0xe6, 0x6e, 0x1a, 0xf9, 0x4f, 0x96, 0x3d, 0x55, 0xb1, 0x3a, + 0x93, 0xbd, 0x8c, 0xc0, 0x6a, 0xef, 0x91, 0x19, 0x18, 0x7c, 0x06, 0xee, 0x70, 0xc1, 0x35, 0xd2, + 0x3c, 0x64, 0x32, 0xc9, 0x7f, 0x95, 0xc6, 0x61, 0xa4, 0xdc, 0xad, 0x25, 0x74, 0xbb, 0x82, 0xeb, + 0xb3, 0x9c, 0xe2, 0xac, 0x60, 0xb0, 0xba, 0x6f, 0xf2, 0x19, 0x98, 0x82, 0xbf, 0x3a, 0xe0, 0x2e, + 0xbb, 0x8c, 0x64, 0xac, 0x19, 0x45, 0xa9, 0x22, 0x48, 0x31, 0x41, 0xab, 0xf2, 0xdb, 0x4b, 0x5c, + 0xa6, 0x2f, 0x2c, 0xd1, 0xb9, 0x22, 0xa7, 0x4c, 0xd0, 0xe9, 0x10, 0xf6, 0xd9, 0x1c, 0x5c, 0xb5, + 0x9f, 0xd7, 0xc0, 0xf6, 0x44, 0x4f, 0x85, 0xfb, 0x60, 0x23, 0x57, 0xb3, 0x2d, 0xbc, 0xde, 0xbf, + 0x6d, 0xbe, 0xbb, 0x14, 0xbe, 0x05, 0x00, 0x19, 0x61, 0x21, 0x58, 0x90, 0x81, 0xab, 0x06, 0xac, + 0x5b, 0x4b, 0x97, 0xc2, 0x03, 0x50, 0x27, 0x01, 0x67, 0x42, 0x67, 0xe8, 0x9a, 0x41, 0x37, 0x72, + 0x43, 0x97, 0xc2, 0x77, 0xc1, 0x4e, 0xb6, 0x11, 0x1c, 0x07, 0x45, 0xbb, 0xaa, 0x99, 0xf9, 0xb0, + 0x6d, 0xad, 0xb6, 0xc5, 0x0c, 0xc0, 0x6e, 0x79, 0x0e, 0xec, 0x44, 0x72, 0x6f, 0x99, 0x3b, 0xd6, + 0x99, 0xbb, 0x13, 0xe5, 0xb4, 0x4b, 0x3b, 0x5e, 0x75, 0x2a, 0xd9, 0xec, 0xcb, 0x79, 0x63, 0x31, + 0xa8, 0x41, 0x23, 0x62, 0x79, 0x7f, 0xb6, 0xdd, 0x34, 0xcb, 0x61, 0xc8, 0x8a, 0x06, 0xf6, 0xf1, + 0xbf, 0xb5, 0xea, 0xf2, 0x80, 0x9f, 0x32, 0xfd, 0xc8, 0xb8, 0xf5, 0x30, 0xb9, 0x60, 0xfa, 0x31, + 0xd6, 0xb8, 0x38, 0x69, 0x96, 0x3d, 0xef, 0xb1, 0xf9, 0x22, 0x05, 0xdf, 0x07, 0x50, 0x05, 0x58, + 0x8d, 0x10, 0x95, 0xcf, 0x44, 0x56, 0x67, 0x84, 0xc9, 0x85, 0xe9, 0x56, 0xf5, 0xfe, 0xae, 0x41, + 0x1e, 0x5b, 0xe0, 0x21, 0xb9, 0x80, 0x3f, 0x80, 0x37, 0x26, 0xa6, 0x08, 0xe2, 0x82, 0xb2, 0x4b, + 0x77, 0xc3, 0x04, 0xf8, 0xd1, 0x62, 0x57, 0x51, 0x91, 0xea, 0xf0, 0xb0, 0xc1, 0xbd, 0x5e, 0x9d, + 0x59, 0xdd, 0x8c, 0xb4, 0xfd, 0x14, 0x34, 0x66, 0x8f, 0x83, 0x25, 0xc6, 0x7a, 0x03, 0xac, 0xdb, + 0xb2, 0xae, 0x1a, 0xdc, 0x7e, 0x9d, 0x7c, 0xf7, 0xe2, 0xaa, 0xe5, 0xbc, 0xbc, 0x6a, 0x39, 0x7f, + 0x5e, 0xb5, 0x9c, 0xdf, 0xae, 0x5b, 0x2b, 0x2f, 0xaf, 0x5b, 0x2b, 0x7f, 0x5c, 0xb7, 0x56, 0x9e, + 0x3e, 0x18, 0x72, 0x3d, 0x4a, 0x06, 0x1e, 0x91, 0xa1, 0x4f, 0xa4, 0x0a, 0xa5, 0xf2, 0x6f, 0xb2, + 0xfa, 0xa0, 0x7c, 0xa6, 0xa4, 0xf7, 0xfd, 0xcb, 0xc9, 0x37, 0x91, 0x1e, 0x47, 0x4c, 0x0d, 0xd6, + 0xcd, 0x4b, 0xe4, 0xfe, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x4d, 0xe2, 0xfe, 0x45, 0xd8, 0x09, + 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -413,6 +434,34 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.ExportedVscSendTimestamps) > 0 { + for iNdEx := len(m.ExportedVscSendTimestamps) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ExportedVscSendTimestamps[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x6a + } + } + if len(m.InitTimeoutTimestamps) > 0 { + for iNdEx := len(m.InitTimeoutTimestamps) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.InitTimeoutTimestamps[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x62 + } + } if len(m.ConsumerAddrsToPrune) > 0 { for iNdEx := len(m.ConsumerAddrsToPrune) - 1; iNdEx >= 0; iNdEx-- { { @@ -758,6 +807,18 @@ func (m *GenesisState) Size() (n int) { n += 1 + l + sovGenesis(uint64(l)) } } + if len(m.InitTimeoutTimestamps) > 0 { + for _, e := range m.InitTimeoutTimestamps { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.ExportedVscSendTimestamps) > 0 { + for _, e := range m.ExportedVscSendTimestamps { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } return n } @@ -1215,6 +1276,74 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InitTimeoutTimestamps", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.InitTimeoutTimestamps = append(m.InitTimeoutTimestamps, InitTimeoutTimestamp{}) + if err := m.InitTimeoutTimestamps[len(m.InitTimeoutTimestamps)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 13: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ExportedVscSendTimestamps", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ExportedVscSendTimestamps = append(m.ExportedVscSendTimestamps, ExportedVscSendTimestamp{}) + if err := m.ExportedVscSendTimestamps[len(m.ExportedVscSendTimestamps)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) diff --git a/x/ccv/provider/types/genesis_test.go b/x/ccv/provider/types/genesis_test.go index dbff6a1c2f..c4b5002f07 100644 --- a/x/ccv/provider/types/genesis_test.go +++ b/x/ccv/provider/types/genesis_test.go @@ -41,6 +41,8 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, + nil, ), true, }, @@ -63,6 +65,8 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, + nil, ), true, }, @@ -82,6 +86,8 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, + nil, ), true, }, @@ -101,6 +107,8 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, + nil, ), false, }, @@ -120,6 +128,8 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, + nil, ), false, }, @@ -139,6 +149,8 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, + nil, ), false, }, @@ -164,6 +176,8 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, + nil, ), false, }, @@ -189,6 +203,8 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, + nil, ), false, }, @@ -214,6 +230,8 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, + nil, ), false, }, @@ -239,6 +257,8 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, + nil, ), false, }, @@ -264,6 +284,8 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, + nil, ), false, }, @@ -289,6 +311,8 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, + nil, ), false, }, @@ -314,6 +338,8 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, + nil, ), false, }, @@ -339,6 +365,8 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, + nil, ), false, }, @@ -356,6 +384,8 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, + nil, ), false, }, @@ -373,6 +403,8 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, + nil, ), false, }, @@ -390,6 +422,8 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, + nil, ), false, }, @@ -407,6 +441,8 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, + nil, ), false, }, @@ -427,6 +463,8 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, + nil, ), false, }, @@ -448,6 +486,8 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, + nil, ), false, }, @@ -469,6 +509,8 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, + nil, ), false, }, @@ -494,6 +536,8 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, + nil, ), false, }, @@ -519,6 +563,8 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, + nil, ), false, }, @@ -544,6 +590,8 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, + nil, ), false, }, @@ -578,6 +626,8 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, + nil, ), false, }, @@ -624,6 +674,8 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, + nil, ), false, }, @@ -644,6 +696,8 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, + nil, ), false, }, @@ -663,6 +717,8 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, + nil, ), false, }, @@ -682,6 +738,8 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, + nil, ), false, }, diff --git a/x/ccv/provider/types/provider.pb.go b/x/ccv/provider/types/provider.pb.go index e651a5415c..30dba16cdc 100644 --- a/x/ccv/provider/types/provider.pb.go +++ b/x/ccv/provider/types/provider.pb.go @@ -971,6 +971,59 @@ func (m *VscSendTimestamp) GetTimestamp() time.Time { return time.Time{} } +// ExportedVscSendTimestamps is VscSendTimestamp with chainID info for exporting to genesis +type ExportedVscSendTimestamp struct { + ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + VscSendTimestamps []VscSendTimestamp `protobuf:"bytes,2,rep,name=vsc_send_timestamps,json=vscSendTimestamps,proto3" json:"vsc_send_timestamps"` +} + +func (m *ExportedVscSendTimestamp) Reset() { *m = ExportedVscSendTimestamp{} } +func (m *ExportedVscSendTimestamp) String() string { return proto.CompactTextString(m) } +func (*ExportedVscSendTimestamp) ProtoMessage() {} +func (*ExportedVscSendTimestamp) Descriptor() ([]byte, []int) { + return fileDescriptor_f22ec409a72b7b72, []int{15} +} +func (m *ExportedVscSendTimestamp) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ExportedVscSendTimestamp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ExportedVscSendTimestamp.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 *ExportedVscSendTimestamp) XXX_Merge(src proto.Message) { + xxx_messageInfo_ExportedVscSendTimestamp.Merge(m, src) +} +func (m *ExportedVscSendTimestamp) XXX_Size() int { + return m.Size() +} +func (m *ExportedVscSendTimestamp) XXX_DiscardUnknown() { + xxx_messageInfo_ExportedVscSendTimestamp.DiscardUnknown(m) +} + +var xxx_messageInfo_ExportedVscSendTimestamp proto.InternalMessageInfo + +func (m *ExportedVscSendTimestamp) GetChainId() string { + if m != nil { + return m.ChainId + } + return "" +} + +func (m *ExportedVscSendTimestamp) GetVscSendTimestamps() []VscSendTimestamp { + if m != nil { + return m.VscSendTimestamps + } + return nil +} + type KeyAssignmentReplacement struct { ProviderAddr []byte `protobuf:"bytes,1,opt,name=provider_addr,json=providerAddr,proto3" json:"provider_addr,omitempty"` PrevCKey *crypto.PublicKey `protobuf:"bytes,2,opt,name=prev_c_key,json=prevCKey,proto3" json:"prev_c_key,omitempty"` @@ -981,7 +1034,7 @@ func (m *KeyAssignmentReplacement) Reset() { *m = KeyAssignmentReplaceme func (m *KeyAssignmentReplacement) String() string { return proto.CompactTextString(m) } func (*KeyAssignmentReplacement) ProtoMessage() {} func (*KeyAssignmentReplacement) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{15} + return fileDescriptor_f22ec409a72b7b72, []int{16} } func (m *KeyAssignmentReplacement) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1044,7 +1097,7 @@ func (m *ValidatorConsumerPubKey) Reset() { *m = ValidatorConsumerPubKey func (m *ValidatorConsumerPubKey) String() string { return proto.CompactTextString(m) } func (*ValidatorConsumerPubKey) ProtoMessage() {} func (*ValidatorConsumerPubKey) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{16} + return fileDescriptor_f22ec409a72b7b72, []int{17} } func (m *ValidatorConsumerPubKey) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1107,7 +1160,7 @@ func (m *ValidatorByConsumerAddr) Reset() { *m = ValidatorByConsumerAddr func (m *ValidatorByConsumerAddr) String() string { return proto.CompactTextString(m) } func (*ValidatorByConsumerAddr) ProtoMessage() {} func (*ValidatorByConsumerAddr) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{17} + return fileDescriptor_f22ec409a72b7b72, []int{18} } func (m *ValidatorByConsumerAddr) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1169,7 +1222,7 @@ func (m *ConsumerAddrsToPrune) Reset() { *m = ConsumerAddrsToPrune{} } func (m *ConsumerAddrsToPrune) String() string { return proto.CompactTextString(m) } func (*ConsumerAddrsToPrune) ProtoMessage() {} func (*ConsumerAddrsToPrune) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{18} + return fileDescriptor_f22ec409a72b7b72, []int{19} } func (m *ConsumerAddrsToPrune) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1235,6 +1288,7 @@ func init() { proto.RegisterType((*UnbondingOp)(nil), "interchain_security.ccv.provider.v1.UnbondingOp") proto.RegisterType((*InitTimeoutTimestamp)(nil), "interchain_security.ccv.provider.v1.InitTimeoutTimestamp") proto.RegisterType((*VscSendTimestamp)(nil), "interchain_security.ccv.provider.v1.VscSendTimestamp") + proto.RegisterType((*ExportedVscSendTimestamp)(nil), "interchain_security.ccv.provider.v1.ExportedVscSendTimestamp") proto.RegisterType((*KeyAssignmentReplacement)(nil), "interchain_security.ccv.provider.v1.KeyAssignmentReplacement") proto.RegisterType((*ValidatorConsumerPubKey)(nil), "interchain_security.ccv.provider.v1.ValidatorConsumerPubKey") proto.RegisterType((*ValidatorByConsumerAddr)(nil), "interchain_security.ccv.provider.v1.ValidatorByConsumerAddr") @@ -1246,107 +1300,110 @@ func init() { } var fileDescriptor_f22ec409a72b7b72 = []byte{ - // 1598 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0x4b, 0x73, 0xdc, 0xc6, - 0x11, 0x26, 0xb8, 0x7c, 0xed, 0x2c, 0x1f, 0x12, 0x44, 0x59, 0x4b, 0x85, 0x59, 0xae, 0xe0, 0xc4, - 0xc5, 0x94, 0xcb, 0xd8, 0x90, 0xba, 0xa4, 0x54, 0x71, 0xb9, 0xc8, 0x95, 0x65, 0xd1, 0x8c, 0xad, - 0x35, 0xc8, 0x50, 0x95, 0xe4, 0x80, 0x1a, 0x0c, 0x5a, 0xbb, 0x53, 0x04, 0x30, 0xd0, 0xcc, 0x00, - 0xd2, 0x5e, 0x72, 0xce, 0xd1, 0xb9, 0xb9, 0x92, 0x8b, 0xf3, 0x0b, 0xf2, 0x37, 0x7c, 0xf4, 0x31, - 0x27, 0x3b, 0x45, 0x1d, 0x72, 0xc8, 0x9f, 0x48, 0xcd, 0xe0, 0xcd, 0x87, 0xb3, 0xaa, 0xc4, 0x37, - 0xcc, 0x4c, 0xf7, 0xd7, 0xdd, 0xd3, 0xdd, 0x5f, 0x0f, 0xd0, 0x3e, 0x8d, 0x24, 0x70, 0x32, 0xc1, - 0x34, 0x72, 0x05, 0x90, 0x84, 0x53, 0x39, 0x1d, 0x10, 0x92, 0x0e, 0x62, 0xce, 0x52, 0xea, 0x03, - 0x1f, 0xa4, 0x7b, 0xe5, 0xb7, 0x1d, 0x73, 0x26, 0x99, 0xf9, 0xee, 0x35, 0x3a, 0x36, 0x21, 0xa9, - 0x5d, 0xca, 0xa5, 0x7b, 0xf7, 0x37, 0xc7, 0x6c, 0xcc, 0xb4, 0xfc, 0x40, 0x7d, 0x65, 0xaa, 0xf7, - 0x77, 0xc6, 0x8c, 0x8d, 0x03, 0x18, 0xe8, 0x95, 0x97, 0xbc, 0x18, 0x48, 0x1a, 0x82, 0x90, 0x38, - 0x8c, 0x73, 0x81, 0xde, 0x65, 0x01, 0x3f, 0xe1, 0x58, 0x52, 0x16, 0x15, 0x00, 0xd4, 0x23, 0x03, - 0xc2, 0x38, 0x0c, 0x48, 0x40, 0x21, 0x92, 0xca, 0xbd, 0xec, 0x2b, 0x17, 0x18, 0x28, 0x81, 0x80, - 0x8e, 0x27, 0x32, 0xdb, 0x16, 0x03, 0x09, 0x91, 0x0f, 0x3c, 0xa4, 0x99, 0x70, 0xb5, 0xca, 0x15, - 0xb6, 0x6b, 0xe7, 0x84, 0x4f, 0x63, 0xc9, 0x06, 0xe7, 0x30, 0x15, 0xf9, 0xe9, 0x7b, 0x84, 0x89, - 0x90, 0x89, 0x01, 0xa8, 0xc0, 0x22, 0x02, 0x83, 0x74, 0xcf, 0x03, 0x89, 0xf7, 0xca, 0x8d, 0xc2, - 0xef, 0x5c, 0xce, 0xc3, 0xa2, 0x92, 0x21, 0x8c, 0xe6, 0x7e, 0x5b, 0xdf, 0x2f, 0xa1, 0xee, 0x90, - 0x45, 0x22, 0x09, 0x81, 0x1f, 0xf8, 0x3e, 0x55, 0x21, 0x8d, 0x38, 0x8b, 0x99, 0xc0, 0x81, 0xb9, - 0x89, 0x16, 0x25, 0x95, 0x01, 0x74, 0x8d, 0xbe, 0xb1, 0xdb, 0x76, 0xb2, 0x85, 0xd9, 0x47, 0x1d, - 0x1f, 0x04, 0xe1, 0x34, 0x56, 0xc2, 0xdd, 0x79, 0x7d, 0x56, 0xdf, 0x32, 0xb7, 0xd0, 0x4a, 0x96, - 0x05, 0xea, 0x77, 0x5b, 0xfa, 0x78, 0x59, 0xaf, 0x8f, 0x7c, 0xf3, 0x13, 0xb4, 0x4e, 0x23, 0x2a, - 0x29, 0x0e, 0xdc, 0x09, 0xa8, 0xdb, 0xe8, 0x2e, 0xf4, 0x8d, 0xdd, 0xce, 0xfe, 0x7d, 0x9b, 0x7a, - 0xc4, 0x56, 0x17, 0x68, 0xe7, 0xd7, 0x96, 0xee, 0xd9, 0x4f, 0xb5, 0xc4, 0xe1, 0xc2, 0x37, 0xdf, - 0xed, 0xcc, 0x39, 0x6b, 0xb9, 0x5e, 0xb6, 0x69, 0x3e, 0x40, 0xab, 0x63, 0x88, 0x40, 0x50, 0xe1, - 0x4e, 0xb0, 0x98, 0x74, 0x17, 0xfb, 0xc6, 0xee, 0xaa, 0xd3, 0xc9, 0xf7, 0x9e, 0x62, 0x31, 0x31, - 0x77, 0x50, 0xc7, 0xa3, 0x11, 0xe6, 0xd3, 0x4c, 0x62, 0x49, 0x4b, 0xa0, 0x6c, 0x4b, 0x0b, 0x0c, - 0x11, 0x12, 0x31, 0x7e, 0x15, 0xb9, 0x2a, 0xdb, 0xdd, 0xe5, 0xdc, 0x91, 0x2c, 0xd3, 0x76, 0x91, - 0x69, 0xfb, 0xb4, 0x28, 0x85, 0xc3, 0x15, 0xe5, 0xc8, 0x97, 0xdf, 0xef, 0x18, 0x4e, 0x5b, 0xeb, - 0xa9, 0x13, 0xf3, 0x73, 0x74, 0x2b, 0x89, 0x3c, 0x16, 0xf9, 0x34, 0x1a, 0xbb, 0x31, 0x70, 0xca, - 0xfc, 0xee, 0x8a, 0x86, 0xda, 0xba, 0x02, 0xf5, 0x38, 0x2f, 0x9a, 0x0c, 0xe9, 0x2b, 0x85, 0xb4, - 0x51, 0x2a, 0x8f, 0xb4, 0xae, 0xf9, 0x05, 0x32, 0x09, 0x49, 0xb5, 0x4b, 0x2c, 0x91, 0x05, 0x62, - 0x7b, 0x76, 0xc4, 0x5b, 0x84, 0xa4, 0xa7, 0x99, 0x76, 0x0e, 0xf9, 0x07, 0x74, 0x4f, 0x72, 0x1c, - 0x89, 0x17, 0xc0, 0x2f, 0xe3, 0xa2, 0xd9, 0x71, 0xef, 0x16, 0x18, 0x4d, 0xf0, 0xa7, 0xa8, 0x4f, - 0xf2, 0x02, 0x72, 0x39, 0xf8, 0x54, 0x48, 0x4e, 0xbd, 0x44, 0xe9, 0xba, 0x2f, 0x38, 0x26, 0xba, - 0x46, 0x3a, 0xba, 0x08, 0x7a, 0x85, 0x9c, 0xd3, 0x10, 0x7b, 0x92, 0x4b, 0x99, 0xcf, 0xd0, 0xcf, - 0xbc, 0x80, 0x91, 0x73, 0xa1, 0x9c, 0x73, 0x1b, 0x48, 0xda, 0x74, 0x48, 0x85, 0x50, 0x68, 0xab, - 0x7d, 0x63, 0xb7, 0xe5, 0x3c, 0xc8, 0x64, 0x47, 0xc0, 0x1f, 0xd7, 0x24, 0x4f, 0x6b, 0x82, 0xe6, - 0x07, 0xc8, 0x9c, 0x50, 0x21, 0x19, 0xa7, 0x04, 0x07, 0x2e, 0x44, 0x92, 0x53, 0x10, 0xdd, 0x35, - 0xad, 0x7e, 0xbb, 0x3a, 0xf9, 0x38, 0x3b, 0x30, 0x3f, 0x45, 0x0f, 0x6e, 0x34, 0xea, 0x92, 0x09, - 0x8e, 0x22, 0x08, 0xba, 0xeb, 0x3a, 0x94, 0x1d, 0xff, 0x06, 0x9b, 0xc3, 0x4c, 0xec, 0xd1, 0xca, - 0x9f, 0xbe, 0xde, 0x99, 0xfb, 0xea, 0xeb, 0x9d, 0x39, 0xeb, 0xef, 0x06, 0xba, 0x37, 0x2c, 0x03, - 0x0f, 0x59, 0x8a, 0x83, 0x1f, 0xb3, 0xc1, 0x0e, 0x50, 0x5b, 0x48, 0x16, 0x67, 0x25, 0xbd, 0xf0, - 0x16, 0x25, 0xbd, 0xa2, 0xd4, 0xd4, 0x81, 0xf5, 0x57, 0x03, 0x6d, 0x7e, 0xfc, 0x32, 0xa1, 0x29, - 0x23, 0xf8, 0xff, 0xc2, 0x07, 0xc7, 0x68, 0x0d, 0x6a, 0x78, 0xa2, 0xdb, 0xea, 0xb7, 0x76, 0x3b, - 0xfb, 0x3f, 0xb7, 0x33, 0x72, 0xb2, 0x4b, 0xce, 0xca, 0x09, 0xca, 0xae, 0x5b, 0x77, 0x9a, 0xba, - 0xd6, 0xbf, 0x0d, 0x74, 0xeb, 0x93, 0x80, 0x79, 0x38, 0x38, 0x09, 0xb0, 0x98, 0xa8, 0xe4, 0x4d, - 0x55, 0xd4, 0x1c, 0xf2, 0xae, 0xd1, 0xde, 0xcd, 0x1c, 0xb5, 0x52, 0xd3, 0x7d, 0xfc, 0x11, 0xba, - 0x5d, 0xd6, 0x71, 0x79, 0xb9, 0x3a, 0x98, 0xc3, 0x3b, 0x17, 0xdf, 0xed, 0x6c, 0x14, 0x39, 0x1c, - 0xea, 0x8b, 0x7e, 0xec, 0x6c, 0x90, 0xc6, 0x86, 0x6f, 0xf6, 0x50, 0x87, 0x7a, 0xc4, 0x15, 0xf0, - 0xd2, 0x8d, 0x92, 0x50, 0xe7, 0x65, 0xc1, 0x69, 0x53, 0x8f, 0x9c, 0xc0, 0xcb, 0xcf, 0x93, 0xd0, - 0x7c, 0x88, 0xde, 0x29, 0x06, 0x91, 0x9b, 0xe2, 0xc0, 0x55, 0xfa, 0x2e, 0xf6, 0x7d, 0xae, 0xd3, - 0xb4, 0xea, 0xdc, 0x29, 0x4e, 0xcf, 0x70, 0xa0, 0x8c, 0x1d, 0xf8, 0x3e, 0xb7, 0xfe, 0xb5, 0x88, - 0x96, 0x46, 0x98, 0xe3, 0x50, 0x98, 0xa7, 0x68, 0x43, 0x42, 0x18, 0x07, 0x58, 0x82, 0x9b, 0x71, - 0x64, 0x1e, 0xe9, 0xfb, 0x9a, 0x3b, 0xeb, 0xb3, 0xc5, 0xae, 0x4d, 0x93, 0x74, 0xcf, 0x1e, 0xea, - 0xdd, 0x13, 0x89, 0x25, 0x38, 0xeb, 0x05, 0x46, 0xb6, 0x69, 0xfe, 0x0a, 0x75, 0x25, 0x4f, 0x84, - 0xac, 0xd8, 0xab, 0x6a, 0xdb, 0x2c, 0x95, 0xef, 0x14, 0xe7, 0x59, 0xc3, 0x97, 0xed, 0x7a, 0x3d, - 0x51, 0xb5, 0xfe, 0x17, 0xa2, 0x3a, 0x41, 0x77, 0x14, 0xcb, 0x5f, 0xc6, 0x5c, 0x98, 0x1d, 0xf3, - 0xb6, 0xd2, 0x6f, 0x82, 0x7e, 0x81, 0xcc, 0x54, 0x90, 0xcb, 0x98, 0x8b, 0x6f, 0xe1, 0x67, 0x2a, - 0x48, 0x13, 0xd2, 0x47, 0xdb, 0x42, 0x15, 0x9f, 0x1b, 0x82, 0xd4, 0xb4, 0x17, 0x07, 0x10, 0x51, - 0x31, 0x29, 0xc0, 0x97, 0x66, 0x07, 0xdf, 0xd2, 0x40, 0x9f, 0x29, 0x1c, 0xa7, 0x80, 0xc9, 0xad, - 0x0c, 0x51, 0xef, 0x7a, 0x2b, 0x65, 0x82, 0x96, 0x75, 0x82, 0x7e, 0x72, 0x0d, 0x44, 0x99, 0xa5, - 0x7d, 0x74, 0x37, 0xc4, 0xaf, 0x5d, 0x39, 0xe1, 0x4c, 0xca, 0x00, 0x7c, 0x37, 0xc6, 0xe4, 0x1c, - 0xa4, 0xd0, 0x33, 0xaa, 0xe5, 0xdc, 0x09, 0xf1, 0xeb, 0xd3, 0xe2, 0x6c, 0x94, 0x1d, 0x99, 0x02, - 0xbd, 0x57, 0xa3, 0xf4, 0x57, 0x98, 0xfb, 0xae, 0x0f, 0x11, 0x0b, 0x5d, 0x0e, 0x63, 0xc5, 0x7b, - 0x38, 0x63, 0x77, 0x80, 0x72, 0x2c, 0xe5, 0x8d, 0xac, 0x5e, 0x19, 0x65, 0x13, 0x0f, 0x19, 0x8d, - 0xf2, 0xd9, 0x6d, 0x55, 0xcc, 0xaf, 0xd0, 0x1e, 0x2b, 0x30, 0xa7, 0x86, 0xf5, 0x04, 0xc0, 0xf2, - 0xd0, 0xed, 0xa7, 0x38, 0xf2, 0xc5, 0x04, 0x9f, 0xc3, 0x67, 0x20, 0xb1, 0x8f, 0x25, 0x6e, 0xf4, - 0xcc, 0x0b, 0x00, 0x37, 0x66, 0x2c, 0xc8, 0x7a, 0x26, 0xa3, 0xa0, 0xb2, 0x67, 0x9e, 0x00, 0x8c, - 0x18, 0x0b, 0x54, 0xcf, 0x98, 0x5d, 0xb4, 0x9c, 0x02, 0x17, 0x55, 0x05, 0x17, 0x4b, 0xeb, 0x17, - 0xa8, 0xad, 0x49, 0xe3, 0x80, 0x9c, 0x0b, 0x73, 0x1b, 0xb5, 0x15, 0x12, 0x08, 0x01, 0xa2, 0x6b, - 0xf4, 0x5b, 0xbb, 0x6d, 0xa7, 0xda, 0xb0, 0x24, 0xda, 0xba, 0xe9, 0x5d, 0x24, 0xcc, 0xe7, 0x68, - 0x39, 0x06, 0x3d, 0xb4, 0xb5, 0x62, 0x67, 0xff, 0x43, 0x7b, 0x86, 0xb7, 0xa7, 0x7d, 0x13, 0xa0, - 0x53, 0xa0, 0x59, 0xbc, 0x7a, 0x8d, 0x5d, 0x9a, 0x15, 0xc2, 0x3c, 0xbb, 0x6c, 0xf4, 0xd7, 0x6f, - 0x65, 0xf4, 0x12, 0x5e, 0x65, 0xf3, 0x7d, 0xd4, 0x39, 0xc8, 0xc2, 0xfe, 0x0d, 0x15, 0xf2, 0xea, - 0xb5, 0xac, 0xd6, 0xaf, 0xe5, 0x53, 0xb4, 0x9e, 0x8f, 0xb8, 0x53, 0xa6, 0x89, 0xcf, 0xfc, 0x29, - 0x42, 0xf9, 0x6c, 0x54, 0x84, 0x99, 0xa5, 0xa5, 0x9d, 0xef, 0x1c, 0xf9, 0x8d, 0x51, 0x35, 0xdf, - 0x18, 0x55, 0x96, 0x83, 0x36, 0xce, 0x04, 0xf9, 0x6d, 0xf1, 0xfe, 0x79, 0x16, 0x0b, 0xf3, 0x2e, - 0x5a, 0x52, 0xbd, 0x9a, 0x03, 0x2d, 0x38, 0x8b, 0xa9, 0x20, 0x47, 0xbe, 0xb9, 0x5b, 0x7f, 0x63, - 0xb1, 0xd8, 0xa5, 0xbe, 0xe8, 0xce, 0xf7, 0x5b, 0xbb, 0x0b, 0xce, 0x7a, 0x52, 0xa9, 0x1f, 0xf9, - 0xc2, 0xfa, 0x1d, 0xea, 0xd4, 0x00, 0xcd, 0x75, 0x34, 0x5f, 0x62, 0xcd, 0x53, 0xdf, 0x7c, 0x84, - 0xb6, 0x2a, 0xa0, 0x26, 0xdd, 0x67, 0x88, 0x6d, 0xe7, 0x5e, 0x29, 0xd0, 0x60, 0x7c, 0x61, 0x3d, - 0x43, 0x9b, 0x47, 0x15, 0xb9, 0x94, 0xc3, 0xa4, 0x11, 0xa1, 0xd1, 0x1c, 0xc6, 0xdb, 0xa8, 0x5d, - 0xfe, 0x48, 0xe8, 0xe8, 0x17, 0x9c, 0x6a, 0xc3, 0x0a, 0xd1, 0xad, 0x33, 0x41, 0x4e, 0x20, 0xf2, - 0x2b, 0xb0, 0x1b, 0x2e, 0xe0, 0xf0, 0x32, 0xd0, 0xcc, 0x0f, 0xd5, 0xca, 0xdc, 0x9f, 0x0d, 0xd4, - 0x3d, 0x86, 0xe9, 0x81, 0x10, 0x74, 0x1c, 0x85, 0x10, 0x49, 0x45, 0x16, 0x98, 0x80, 0xfa, 0x34, - 0xdf, 0x45, 0x6b, 0x65, 0xa3, 0x95, 0xfd, 0xb5, 0xea, 0xac, 0x16, 0x9b, 0xba, 0xb1, 0x1e, 0x21, - 0x14, 0x73, 0x48, 0x5d, 0xe2, 0x9e, 0xc3, 0x34, 0x77, 0x63, 0xbb, 0x3e, 0x6b, 0xb2, 0xff, 0x14, - 0x7b, 0x94, 0x78, 0x01, 0x25, 0xc7, 0x30, 0x75, 0x56, 0x94, 0xfc, 0xf0, 0x18, 0xa6, 0xea, 0xed, - 0x10, 0xb3, 0x57, 0xc0, 0xf5, 0x80, 0x68, 0x39, 0xd9, 0xc2, 0xfa, 0x8b, 0x81, 0xee, 0x9d, 0xe1, - 0x80, 0xfa, 0x58, 0x32, 0x5e, 0xdc, 0xf7, 0x28, 0xf1, 0x94, 0xc6, 0x0f, 0xdc, 0xeb, 0x15, 0x6f, - 0xe7, 0xaf, 0xf1, 0xf6, 0x23, 0xb4, 0x5a, 0x66, 0x58, 0xf9, 0xdb, 0x9a, 0xc1, 0xdf, 0x4e, 0xa1, - 0x71, 0x0c, 0x53, 0xeb, 0x8f, 0x35, 0xdf, 0x0e, 0xa7, 0xb5, 0xe6, 0xe5, 0xff, 0xc5, 0xb7, 0xd2, - 0x6c, 0xdd, 0x37, 0x52, 0xd7, 0xbf, 0x12, 0x40, 0xeb, 0x6a, 0x00, 0xd6, 0xdf, 0x0c, 0xb4, 0x59, - 0xb7, 0x2a, 0x4e, 0xd9, 0x88, 0x27, 0x11, 0xfc, 0x90, 0xf5, 0xaa, 0x7e, 0xe6, 0xeb, 0xf5, 0xf3, - 0x1c, 0xad, 0x37, 0x9c, 0x12, 0xf9, 0x6d, 0xfc, 0x72, 0x26, 0x0a, 0xa9, 0xd1, 0x83, 0xb3, 0x56, - 0x8f, 0x43, 0x1c, 0x3e, 0xff, 0xe6, 0xa2, 0x67, 0x7c, 0x7b, 0xd1, 0x33, 0xfe, 0x79, 0xd1, 0x33, - 0xbe, 0x7c, 0xd3, 0x9b, 0xfb, 0xf6, 0x4d, 0x6f, 0xee, 0x1f, 0x6f, 0x7a, 0x73, 0xbf, 0xff, 0x70, - 0x4c, 0xe5, 0x24, 0xf1, 0x6c, 0xc2, 0xc2, 0x41, 0xfe, 0x13, 0x5a, 0xd9, 0xfa, 0xa0, 0xfc, 0xa7, - 0x4f, 0x1f, 0x0e, 0x5e, 0x37, 0x7f, 0xec, 0xe5, 0x34, 0x06, 0xe1, 0x2d, 0xe9, 0xb2, 0x7e, 0xf8, - 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x73, 0xaf, 0xd0, 0x18, 0x09, 0x10, 0x00, 0x00, + // 1645 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0x4d, 0x73, 0x1b, 0xc7, + 0xd1, 0xe6, 0x12, 0xfc, 0xc2, 0x80, 0x1f, 0xe2, 0x92, 0xb2, 0x96, 0x7a, 0xf9, 0x82, 0xd0, 0x3a, + 0x71, 0x31, 0xe5, 0xf2, 0x22, 0xa4, 0x2a, 0x55, 0x29, 0x55, 0x5c, 0x2e, 0x12, 0x92, 0x2c, 0x9a, + 0xb1, 0x05, 0x2f, 0x19, 0xaa, 0x92, 0x1c, 0xb6, 0x66, 0x67, 0x5b, 0xc0, 0x14, 0x77, 0x77, 0x56, + 0x33, 0x83, 0x95, 0x70, 0xc9, 0x39, 0x47, 0xe7, 0xe6, 0x4a, 0x2e, 0x4e, 0xfe, 0x40, 0xfe, 0x86, + 0x8f, 0x3e, 0xe6, 0x64, 0xa7, 0xa4, 0x43, 0x0e, 0xf9, 0x13, 0xa9, 0x99, 0xfd, 0x04, 0x48, 0x2a, + 0x50, 0x25, 0xb9, 0xed, 0xf4, 0x74, 0x3f, 0xdd, 0x3d, 0xd3, 0xfd, 0xf4, 0x00, 0xe8, 0x90, 0xc6, + 0x12, 0x38, 0x19, 0x62, 0x1a, 0x7b, 0x02, 0xc8, 0x88, 0x53, 0x39, 0xee, 0x12, 0x92, 0x76, 0x13, + 0xce, 0x52, 0x1a, 0x00, 0xef, 0xa6, 0x07, 0xe5, 0xb7, 0x93, 0x70, 0x26, 0x99, 0xf9, 0xfe, 0x35, + 0x36, 0x0e, 0x21, 0xa9, 0x53, 0xea, 0xa5, 0x07, 0x77, 0xb7, 0x07, 0x6c, 0xc0, 0xb4, 0x7e, 0x57, + 0x7d, 0x65, 0xa6, 0x77, 0xf7, 0x06, 0x8c, 0x0d, 0x42, 0xe8, 0xea, 0x95, 0x3f, 0x7a, 0xde, 0x95, + 0x34, 0x02, 0x21, 0x71, 0x94, 0xe4, 0x0a, 0xed, 0x69, 0x85, 0x60, 0xc4, 0xb1, 0xa4, 0x2c, 0x2e, + 0x00, 0xa8, 0x4f, 0xba, 0x84, 0x71, 0xe8, 0x92, 0x90, 0x42, 0x2c, 0x55, 0x78, 0xd9, 0x57, 0xae, + 0xd0, 0x55, 0x0a, 0x21, 0x1d, 0x0c, 0x65, 0x26, 0x16, 0x5d, 0x09, 0x71, 0x00, 0x3c, 0xa2, 0x99, + 0x72, 0xb5, 0xca, 0x0d, 0x76, 0x6b, 0xfb, 0x84, 0x8f, 0x13, 0xc9, 0xba, 0x97, 0x30, 0x16, 0xf9, + 0xee, 0x07, 0x84, 0x89, 0x88, 0x89, 0x2e, 0xa8, 0xc4, 0x62, 0x02, 0xdd, 0xf4, 0xc0, 0x07, 0x89, + 0x0f, 0x4a, 0x41, 0x11, 0x77, 0xae, 0xe7, 0x63, 0x51, 0xe9, 0x10, 0x46, 0xf3, 0xb8, 0xed, 0x1f, + 0x96, 0x90, 0xd5, 0x63, 0xb1, 0x18, 0x45, 0xc0, 0x8f, 0x82, 0x80, 0xaa, 0x94, 0xfa, 0x9c, 0x25, + 0x4c, 0xe0, 0xd0, 0xdc, 0x46, 0x8b, 0x92, 0xca, 0x10, 0x2c, 0xa3, 0x63, 0xec, 0x37, 0xdd, 0x6c, + 0x61, 0x76, 0x50, 0x2b, 0x00, 0x41, 0x38, 0x4d, 0x94, 0xb2, 0x35, 0xaf, 0xf7, 0xea, 0x22, 0x73, + 0x07, 0xad, 0x64, 0xb7, 0x40, 0x03, 0xab, 0xa1, 0xb7, 0x97, 0xf5, 0xfa, 0x24, 0x30, 0x3f, 0x45, + 0xeb, 0x34, 0xa6, 0x92, 0xe2, 0xd0, 0x1b, 0x82, 0x3a, 0x0d, 0x6b, 0xa1, 0x63, 0xec, 0xb7, 0x0e, + 0xef, 0x3a, 0xd4, 0x27, 0x8e, 0x3a, 0x40, 0x27, 0x3f, 0xb6, 0xf4, 0xc0, 0x79, 0xa2, 0x35, 0x8e, + 0x17, 0xbe, 0xfd, 0x7e, 0x6f, 0xce, 0x5d, 0xcb, 0xed, 0x32, 0xa1, 0x79, 0x0f, 0xad, 0x0e, 0x20, + 0x06, 0x41, 0x85, 0x37, 0xc4, 0x62, 0x68, 0x2d, 0x76, 0x8c, 0xfd, 0x55, 0xb7, 0x95, 0xcb, 0x9e, + 0x60, 0x31, 0x34, 0xf7, 0x50, 0xcb, 0xa7, 0x31, 0xe6, 0xe3, 0x4c, 0x63, 0x49, 0x6b, 0xa0, 0x4c, + 0xa4, 0x15, 0x7a, 0x08, 0x89, 0x04, 0xbf, 0x8c, 0x3d, 0x75, 0xdb, 0xd6, 0x72, 0x1e, 0x48, 0x76, + 0xd3, 0x4e, 0x71, 0xd3, 0xce, 0x79, 0x51, 0x0a, 0xc7, 0x2b, 0x2a, 0x90, 0xaf, 0x7e, 0xd8, 0x33, + 0xdc, 0xa6, 0xb6, 0x53, 0x3b, 0xe6, 0x17, 0xe8, 0xd6, 0x28, 0xf6, 0x59, 0x1c, 0xd0, 0x78, 0xe0, + 0x25, 0xc0, 0x29, 0x0b, 0xac, 0x15, 0x0d, 0xb5, 0x73, 0x05, 0xea, 0x61, 0x5e, 0x34, 0x19, 0xd2, + 0xd7, 0x0a, 0x69, 0xa3, 0x34, 0xee, 0x6b, 0x5b, 0xf3, 0x4b, 0x64, 0x12, 0x92, 0xea, 0x90, 0xd8, + 0x48, 0x16, 0x88, 0xcd, 0xd9, 0x11, 0x6f, 0x11, 0x92, 0x9e, 0x67, 0xd6, 0x39, 0xe4, 0x6f, 0xd1, + 0x1d, 0xc9, 0x71, 0x2c, 0x9e, 0x03, 0x9f, 0xc6, 0x45, 0xb3, 0xe3, 0xde, 0x2e, 0x30, 0x26, 0xc1, + 0x9f, 0xa0, 0x0e, 0xc9, 0x0b, 0xc8, 0xe3, 0x10, 0x50, 0x21, 0x39, 0xf5, 0x47, 0xca, 0xd6, 0x7b, + 0xce, 0x31, 0xd1, 0x35, 0xd2, 0xd2, 0x45, 0xd0, 0x2e, 0xf4, 0xdc, 0x09, 0xb5, 0xc7, 0xb9, 0x96, + 0xf9, 0x14, 0xfd, 0xc8, 0x0f, 0x19, 0xb9, 0x14, 0x2a, 0x38, 0x6f, 0x02, 0x49, 0xbb, 0x8e, 0xa8, + 0x10, 0x0a, 0x6d, 0xb5, 0x63, 0xec, 0x37, 0xdc, 0x7b, 0x99, 0x6e, 0x1f, 0xf8, 0xc3, 0x9a, 0xe6, + 0x79, 0x4d, 0xd1, 0xfc, 0x08, 0x99, 0x43, 0x2a, 0x24, 0xe3, 0x94, 0xe0, 0xd0, 0x83, 0x58, 0x72, + 0x0a, 0xc2, 0x5a, 0xd3, 0xe6, 0x9b, 0xd5, 0xce, 0xa3, 0x6c, 0xc3, 0xfc, 0x0c, 0xdd, 0xbb, 0xd1, + 0xa9, 0x47, 0x86, 0x38, 0x8e, 0x21, 0xb4, 0xd6, 0x75, 0x2a, 0x7b, 0xc1, 0x0d, 0x3e, 0x7b, 0x99, + 0xda, 0x83, 0x95, 0xdf, 0x7f, 0xb3, 0x37, 0xf7, 0xf5, 0x37, 0x7b, 0x73, 0xf6, 0x5f, 0x0d, 0x74, + 0xa7, 0x57, 0x26, 0x1e, 0xb1, 0x14, 0x87, 0xff, 0xcb, 0x06, 0x3b, 0x42, 0x4d, 0x21, 0x59, 0x92, + 0x95, 0xf4, 0xc2, 0x3b, 0x94, 0xf4, 0x8a, 0x32, 0x53, 0x1b, 0xf6, 0x9f, 0x0c, 0xb4, 0xfd, 0xe8, + 0xc5, 0x88, 0xa6, 0x8c, 0xe0, 0xff, 0x0a, 0x1f, 0x9c, 0xa2, 0x35, 0xa8, 0xe1, 0x09, 0xab, 0xd1, + 0x69, 0xec, 0xb7, 0x0e, 0x7f, 0xec, 0x64, 0xe4, 0xe4, 0x94, 0x9c, 0x95, 0x13, 0x94, 0x53, 0xf7, + 0xee, 0x4e, 0xda, 0xda, 0xff, 0x34, 0xd0, 0xad, 0x4f, 0x43, 0xe6, 0xe3, 0xf0, 0x2c, 0xc4, 0x62, + 0xa8, 0x2e, 0x6f, 0xac, 0xb2, 0xe6, 0x90, 0x77, 0x8d, 0x8e, 0x6e, 0xe6, 0xac, 0x95, 0x99, 0xee, + 0xe3, 0x4f, 0xd0, 0x66, 0x59, 0xc7, 0xe5, 0xe1, 0xea, 0x64, 0x8e, 0xb7, 0x5e, 0x7f, 0xbf, 0xb7, + 0x51, 0xdc, 0x61, 0x4f, 0x1f, 0xf4, 0x43, 0x77, 0x83, 0x4c, 0x08, 0x02, 0xb3, 0x8d, 0x5a, 0xd4, + 0x27, 0x9e, 0x80, 0x17, 0x5e, 0x3c, 0x8a, 0xf4, 0xbd, 0x2c, 0xb8, 0x4d, 0xea, 0x93, 0x33, 0x78, + 0xf1, 0xc5, 0x28, 0x32, 0xef, 0xa3, 0xf7, 0x8a, 0x41, 0xe4, 0xa5, 0x38, 0xf4, 0x94, 0xbd, 0x87, + 0x83, 0x80, 0xeb, 0x6b, 0x5a, 0x75, 0xb7, 0x8a, 0xdd, 0x0b, 0x1c, 0x2a, 0x67, 0x47, 0x41, 0xc0, + 0xed, 0x7f, 0x2c, 0xa2, 0xa5, 0x3e, 0xe6, 0x38, 0x12, 0xe6, 0x39, 0xda, 0x90, 0x10, 0x25, 0x21, + 0x96, 0xe0, 0x65, 0x1c, 0x99, 0x67, 0xfa, 0xa1, 0xe6, 0xce, 0xfa, 0x6c, 0x71, 0x6a, 0xd3, 0x24, + 0x3d, 0x70, 0x7a, 0x5a, 0x7a, 0x26, 0xb1, 0x04, 0x77, 0xbd, 0xc0, 0xc8, 0x84, 0xe6, 0xcf, 0x91, + 0x25, 0xf9, 0x48, 0xc8, 0x8a, 0xbd, 0xaa, 0xb6, 0xcd, 0xae, 0xf2, 0xbd, 0x62, 0x3f, 0x6b, 0xf8, + 0xb2, 0x5d, 0xaf, 0x27, 0xaa, 0xc6, 0x7f, 0x42, 0x54, 0x67, 0x68, 0x4b, 0xb1, 0xfc, 0x34, 0xe6, + 0xc2, 0xec, 0x98, 0x9b, 0xca, 0x7e, 0x12, 0xf4, 0x4b, 0x64, 0xa6, 0x82, 0x4c, 0x63, 0x2e, 0xbe, + 0x43, 0x9c, 0xa9, 0x20, 0x93, 0x90, 0x01, 0xda, 0x15, 0xaa, 0xf8, 0xbc, 0x08, 0xa4, 0xa6, 0xbd, + 0x24, 0x84, 0x98, 0x8a, 0x61, 0x01, 0xbe, 0x34, 0x3b, 0xf8, 0x8e, 0x06, 0xfa, 0x5c, 0xe1, 0xb8, + 0x05, 0x4c, 0xee, 0xa5, 0x87, 0xda, 0xd7, 0x7b, 0x29, 0x2f, 0x68, 0x59, 0x5f, 0xd0, 0xff, 0x5d, + 0x03, 0x51, 0xde, 0xd2, 0x21, 0xba, 0x1d, 0xe1, 0x57, 0x9e, 0x1c, 0x72, 0x26, 0x65, 0x08, 0x81, + 0x97, 0x60, 0x72, 0x09, 0x52, 0xe8, 0x19, 0xd5, 0x70, 0xb7, 0x22, 0xfc, 0xea, 0xbc, 0xd8, 0xeb, + 0x67, 0x5b, 0xa6, 0x40, 0x1f, 0xd4, 0x28, 0xfd, 0x25, 0xe6, 0x81, 0x17, 0x40, 0xcc, 0x22, 0x8f, + 0xc3, 0x40, 0xf1, 0x1e, 0xce, 0xd8, 0x1d, 0xa0, 0x1c, 0x4b, 0x79, 0x23, 0xab, 0x57, 0x46, 0xd9, + 0xc4, 0x3d, 0x46, 0xe3, 0x7c, 0x76, 0xdb, 0x15, 0xf3, 0x2b, 0xb4, 0x87, 0x0a, 0xcc, 0xad, 0x61, + 0x3d, 0x06, 0xb0, 0x7d, 0xb4, 0xf9, 0x04, 0xc7, 0x81, 0x18, 0xe2, 0x4b, 0xf8, 0x1c, 0x24, 0x0e, + 0xb0, 0xc4, 0x13, 0x3d, 0xf3, 0x1c, 0xc0, 0x4b, 0x18, 0x0b, 0xb3, 0x9e, 0xc9, 0x28, 0xa8, 0xec, + 0x99, 0xc7, 0x00, 0x7d, 0xc6, 0x42, 0xd5, 0x33, 0xa6, 0x85, 0x96, 0x53, 0xe0, 0xa2, 0xaa, 0xe0, + 0x62, 0x69, 0xff, 0x04, 0x35, 0x35, 0x69, 0x1c, 0x91, 0x4b, 0x61, 0xee, 0xa2, 0xa6, 0x42, 0x02, + 0x21, 0x40, 0x58, 0x46, 0xa7, 0xb1, 0xdf, 0x74, 0x2b, 0x81, 0x2d, 0xd1, 0xce, 0x4d, 0xef, 0x22, + 0x61, 0x3e, 0x43, 0xcb, 0x09, 0xe8, 0xa1, 0xad, 0x0d, 0x5b, 0x87, 0x1f, 0x3b, 0x33, 0xbc, 0x3d, + 0x9d, 0x9b, 0x00, 0xdd, 0x02, 0xcd, 0xe6, 0xd5, 0x6b, 0x6c, 0x6a, 0x56, 0x08, 0xf3, 0x62, 0xda, + 0xe9, 0x2f, 0xde, 0xc9, 0xe9, 0x14, 0x5e, 0xe5, 0xf3, 0x43, 0xd4, 0x3a, 0xca, 0xd2, 0xfe, 0x25, + 0x15, 0xf2, 0xea, 0xb1, 0xac, 0xd6, 0x8f, 0xe5, 0x33, 0xb4, 0x9e, 0x8f, 0xb8, 0x73, 0xa6, 0x89, + 0xcf, 0xfc, 0x7f, 0x84, 0xf2, 0xd9, 0xa8, 0x08, 0x33, 0xbb, 0x96, 0x66, 0x2e, 0x39, 0x09, 0x26, + 0x46, 0xd5, 0xfc, 0xc4, 0xa8, 0xb2, 0x5d, 0xb4, 0x71, 0x21, 0xc8, 0xaf, 0x8a, 0xf7, 0xcf, 0xd3, + 0x44, 0x98, 0xb7, 0xd1, 0x92, 0xea, 0xd5, 0x1c, 0x68, 0xc1, 0x5d, 0x4c, 0x05, 0x39, 0x09, 0xcc, + 0xfd, 0xfa, 0x1b, 0x8b, 0x25, 0x1e, 0x0d, 0x84, 0x35, 0xdf, 0x69, 0xec, 0x2f, 0xb8, 0xeb, 0xa3, + 0xca, 0xfc, 0x24, 0x10, 0xf6, 0xaf, 0x51, 0xab, 0x06, 0x68, 0xae, 0xa3, 0xf9, 0x12, 0x6b, 0x9e, + 0x06, 0xe6, 0x03, 0xb4, 0x53, 0x01, 0x4d, 0xd2, 0x7d, 0x86, 0xd8, 0x74, 0xef, 0x94, 0x0a, 0x13, + 0x8c, 0x2f, 0xec, 0xa7, 0x68, 0xfb, 0xa4, 0x22, 0x97, 0x72, 0x98, 0x4c, 0x64, 0x68, 0x4c, 0x0e, + 0xe3, 0x5d, 0xd4, 0x2c, 0x7f, 0x48, 0xe8, 0xec, 0x17, 0xdc, 0x4a, 0x60, 0x47, 0xe8, 0xd6, 0x85, + 0x20, 0x67, 0x10, 0x07, 0x15, 0xd8, 0x0d, 0x07, 0x70, 0x3c, 0x0d, 0x34, 0xf3, 0x43, 0xb5, 0x72, + 0xf7, 0x17, 0x03, 0x59, 0x8f, 0x5e, 0x25, 0x8c, 0x4b, 0x08, 0xae, 0xf8, 0x7d, 0x4b, 0x12, 0x97, + 0x68, 0x4b, 0x85, 0x24, 0x20, 0x0e, 0xbc, 0x12, 0x2d, 0x3b, 0xad, 0xd6, 0xe1, 0xcf, 0x66, 0xaa, + 0xc1, 0x69, 0x77, 0x39, 0x2d, 0x6c, 0xa6, 0x53, 0x72, 0x61, 0xff, 0xc1, 0x40, 0xd6, 0x29, 0x8c, + 0x8f, 0x84, 0xa0, 0x83, 0x38, 0x82, 0x58, 0x2a, 0x46, 0xc3, 0x04, 0xd4, 0xa7, 0xf9, 0x3e, 0x5a, + 0x2b, 0xd9, 0xa0, 0x24, 0x81, 0x55, 0x77, 0xb5, 0x10, 0xea, 0xee, 0x7f, 0x80, 0x50, 0xc2, 0x21, + 0xf5, 0x88, 0x77, 0x09, 0xe3, 0xfc, 0xac, 0x76, 0xeb, 0x03, 0x31, 0xfb, 0x31, 0xe5, 0xf4, 0x47, + 0x7e, 0x48, 0xc9, 0x29, 0x8c, 0xdd, 0x15, 0xa5, 0xdf, 0x3b, 0x85, 0xb1, 0x7a, 0xe0, 0x24, 0xec, + 0x25, 0x70, 0x3d, 0xc5, 0x1a, 0x6e, 0xb6, 0xb0, 0xff, 0x68, 0xa0, 0x3b, 0x17, 0x38, 0xa4, 0x01, + 0x96, 0x8c, 0x17, 0x45, 0xd1, 0x1f, 0xf9, 0xca, 0xe2, 0x2d, 0xe7, 0x76, 0x25, 0xda, 0xf9, 0x6b, + 0xa2, 0xfd, 0x04, 0xad, 0x96, 0x65, 0xa8, 0xe2, 0x6d, 0xcc, 0x10, 0x6f, 0xab, 0xb0, 0x38, 0x85, + 0xb1, 0xfd, 0xbb, 0x5a, 0x6c, 0xc7, 0xe3, 0x1a, 0xc3, 0xf0, 0x7f, 0x13, 0x5b, 0xe9, 0xb6, 0x1e, + 0x1b, 0xa9, 0xdb, 0x5f, 0x49, 0xa0, 0x71, 0x35, 0x01, 0xfb, 0xcf, 0x06, 0xda, 0xae, 0x7b, 0x15, + 0xe7, 0xac, 0xcf, 0x47, 0x31, 0xbc, 0xcd, 0x7b, 0x55, 0xe4, 0xf3, 0xf5, 0x22, 0x7f, 0x86, 0xd6, + 0x27, 0x82, 0x12, 0xf9, 0x69, 0xfc, 0x74, 0xa6, 0x1a, 0xab, 0x71, 0x98, 0xbb, 0x56, 0xcf, 0x43, + 0x1c, 0x3f, 0xfb, 0xf6, 0x75, 0xdb, 0xf8, 0xee, 0x75, 0xdb, 0xf8, 0xfb, 0xeb, 0xb6, 0xf1, 0xd5, + 0x9b, 0xf6, 0xdc, 0x77, 0x6f, 0xda, 0x73, 0x7f, 0x7b, 0xd3, 0x9e, 0xfb, 0xcd, 0xc7, 0x03, 0x2a, + 0x87, 0x23, 0xdf, 0x21, 0x2c, 0xea, 0xe6, 0xbf, 0x94, 0x2b, 0x5f, 0x1f, 0x95, 0x7f, 0x3c, 0xa4, + 0xf7, 0xbb, 0xaf, 0x26, 0xff, 0x7d, 0x90, 0xe3, 0x04, 0x84, 0xbf, 0xa4, 0x7b, 0xef, 0xfe, 0xbf, + 0x02, 0x00, 0x00, 0xff, 0xff, 0x2b, 0x34, 0xfa, 0x5d, 0xae, 0x10, 0x00, 0x00, } func (m *ConsumerAdditionProposal) Marshal() (dAtA []byte, err error) { @@ -2088,6 +2145,50 @@ func (m *VscSendTimestamp) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *ExportedVscSendTimestamp) 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 *ExportedVscSendTimestamp) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ExportedVscSendTimestamp) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.VscSendTimestamps) > 0 { + for iNdEx := len(m.VscSendTimestamps) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.VscSendTimestamps[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintProvider(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.ChainId) > 0 { + i -= len(m.ChainId) + copy(dAtA[i:], m.ChainId) + i = encodeVarintProvider(dAtA, i, uint64(len(m.ChainId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *KeyAssignmentReplacement) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -2602,6 +2703,25 @@ func (m *VscSendTimestamp) Size() (n int) { return n } +func (m *ExportedVscSendTimestamp) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ChainId) + if l > 0 { + n += 1 + l + sovProvider(uint64(l)) + } + if len(m.VscSendTimestamps) > 0 { + for _, e := range m.VscSendTimestamps { + l = e.Size() + n += 1 + l + sovProvider(uint64(l)) + } + } + return n +} + func (m *KeyAssignmentReplacement) Size() (n int) { if m == nil { return 0 @@ -5009,6 +5129,122 @@ func (m *VscSendTimestamp) Unmarshal(dAtA []byte) error { } return nil } +func (m *ExportedVscSendTimestamp) 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: ExportedVscSendTimestamp: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ExportedVscSendTimestamp: 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 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.ChainId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field VscSendTimestamps", 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.VscSendTimestamps = append(m.VscSendTimestamps, VscSendTimestamp{}) + if err := m.VscSendTimestamps[len(m.VscSendTimestamps)-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 (m *KeyAssignmentReplacement) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 From 7484dbceb66ceafad05d34d46c6b4e4f145cb022 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Wed, 19 Jul 2023 09:04:35 -0700 Subject: [PATCH 066/134] tests: regression tests for types sent over wire as json (#1160) * tests * linting is the most important part of programming --------- Co-authored-by: Marius Poke --- x/ccv/consumer/keeper/relay_test.go | 12 ++- x/ccv/types/ccv.go | 12 +-- x/ccv/types/ccv_test.go | 131 ++++++++++++++++++++++++++++ 3 files changed, 143 insertions(+), 12 deletions(-) diff --git a/x/ccv/consumer/keeper/relay_test.go b/x/ccv/consumer/keeper/relay_test.go index 6dbebe273f..ed6771900e 100644 --- a/x/ccv/consumer/keeper/relay_test.go +++ b/x/ccv/consumer/keeper/relay_test.go @@ -234,13 +234,21 @@ func TestOnAcknowledgementPacket(t *testing.T) { // Set an established provider channel for later in test consumerKeeper.SetProviderChannel(ctx, channelIDToProvider) - packetData := types.NewSlashPacketData( + slashPacketData := types.NewSlashPacketData( abci.Validator{Address: bytes.HexBytes{}, Power: int64(1)}, uint64(1), stakingtypes.Infraction_INFRACTION_DOWNTIME, ) + // The type that'd be JSON marshaled and sent over the wire + consumerPacketData := types.NewConsumerPacketData( + types.SlashPacket, + &types.ConsumerPacketData_SlashPacketData{ + SlashPacketData: slashPacketData, + }, + ) + // AcknowledgePacket is in reference to a packet originally sent from this (consumer) module. packet := channeltypes.NewPacket( - packetData.GetBytes(), + consumerPacketData.GetBytes(), 1, types.ConsumerPortID, // Source port channelIDToDestChain, // Source channel diff --git a/x/ccv/types/ccv.go b/x/ccv/types/ccv.go index 91175eab5d..70921704f7 100644 --- a/x/ccv/types/ccv.go +++ b/x/ccv/types/ccv.go @@ -29,6 +29,8 @@ func (vsc ValidatorSetChangePacketData) ValidateBasic() error { return nil } +// GetBytes marshals the ValidatorSetChangePacketData into JSON string bytes +// to be sent over the wire with IBC. func (vsc ValidatorSetChangePacketData) GetBytes() []byte { valUpdateBytes := ModuleCdc.MustMarshalJSON(&vsc) return valUpdateBytes @@ -48,11 +50,6 @@ func (mat VSCMaturedPacketData) ValidateBasic() error { return nil } -func (mat VSCMaturedPacketData) GetBytes() []byte { - bytes := ModuleCdc.MustMarshalJSON(&mat) - return bytes -} - func NewSlashPacketData(validator abci.Validator, valUpdateId uint64, infractionType stakingtypes.Infraction) *SlashPacketData { return &SlashPacketData{ Validator: validator, @@ -90,11 +87,6 @@ func (vdt SlashPacketData) ValidateBasic() error { return nil } -func (vdt SlashPacketData) GetBytes() []byte { - valDowntimeBytes := ModuleCdc.MustMarshalJSON(&vdt) - return valDowntimeBytes -} - func (vdt SlashPacketData) ToV1() *SlashPacketDataV1 { return NewSlashPacketDataV1(vdt.Validator, vdt.ValsetUpdateId, vdt.Infraction) } diff --git a/x/ccv/types/ccv_test.go b/x/ccv/types/ccv_test.go index 596967b199..50164fcf73 100644 --- a/x/ccv/types/ccv_test.go +++ b/x/ccv/types/ccv_test.go @@ -1,15 +1,18 @@ package types_test import ( + "strings" "testing" "github.com/stretchr/testify/require" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" abci "github.com/cometbft/cometbft/abci/types" + "github.com/cosmos/interchain-security/v3/testutil/crypto" "github.com/cosmos/interchain-security/v3/x/ccv/types" ) @@ -93,3 +96,131 @@ func TestMarshalPacketData(t *testing.T) { require.Nil(t, err) require.Equal(t, vpd, recovered, "unmarshaled packet data does not equal original value") } + +// TestVSCPacketDataWireBytes is a regression test that the JSON schema +// for ValidatorSetChangePacketData (sent over the wire) does not change. +func TestVSCPacketDataWireBytes(t *testing.T) { + cId1 := crypto.NewCryptoIdentityFromIntSeed(4732894) + cId2 := crypto.NewCryptoIdentityFromIntSeed(4732895) + + pd := types.NewValidatorSetChangePacketData( + []abci.ValidatorUpdate{ + { + PubKey: cId1.TMProtoCryptoPublicKey(), + Power: 30, + }, + { + PubKey: cId2.TMProtoCryptoPublicKey(), + Power: 20, + }, + }, + 73, + []string{"slash", "acks", "example"}, + ) + + jsonBz := pd.GetBytes() + str := string(jsonBz) + + // Expected string formatted for human readability + expectedStr := `{ + "validator_updates": [ + { + "pub_key": { + "ed25519": "SMxP2pXAuxQC7FmBn4dh4Kt5eYdQFWC/wN7oWobZKds=" + }, + "power": "30" + }, + { + "pub_key": { + "ed25519": "J/nGy0vCXhgVbr8S71B4ZgHi4fsMqtDxDlERZ+gG238=" + }, + "power": "20" + } + ], + "valset_update_id": "73", + "slash_acks": ["slash", "acks", "example"] + }` + + // Remove newlines, tabs, and spaces for comparison + expectedStr = strings.ReplaceAll(expectedStr, "\n", "") + expectedStr = strings.ReplaceAll(expectedStr, "\t", "") + expectedStr = strings.ReplaceAll(expectedStr, " ", "") + + require.Equal(t, expectedStr, str) +} + +// TestSlashPacketDataWireBytes is a regression test that the JSON schema +// for SlashPacketData (sent over the wire) does not change. +func TestSlashPacketDataWireBytes(t *testing.T) { + // Construct consumer packet data wrapping slash packet data + cId := crypto.NewCryptoIdentityFromIntSeed(4732894342) + slashPacketData := types.NewSlashPacketData( + abci.Validator{ + Address: cId.SDKValConsAddress(), + Power: int64(4328), + }, + uint64(894732), + stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN, + ) + + // The type that'd be JSON marshaled and sent over the wire + cpd := types.NewConsumerPacketData( + types.SlashPacket, + &types.ConsumerPacketData_SlashPacketData{ + SlashPacketData: slashPacketData, + }, + ) + + jsonBz := cpd.GetBytes() + str := string(jsonBz) + + // Expected string formatted for human readability + expectedStr := `{ + "type": "CONSUMER_PACKET_TYPE_SLASH", + "slashPacketData": { + "validator": { + "address": "BP9q4oXCgubvoujOKyxIxd+3IwM=", + "power": "4328" + }, + "valset_update_id": "894732", + "infraction": "INFRACTION_TYPE_DOUBLE_SIGN" + } + }` + + // Remove newlines, tabs, and spaces for comparison + expectedStr = strings.ReplaceAll(expectedStr, "\n", "") + expectedStr = strings.ReplaceAll(expectedStr, "\t", "") + expectedStr = strings.ReplaceAll(expectedStr, " ", "") + + require.Equal(t, expectedStr, str) +} + +// TestVSCMaturedPacketDataWireBytes is a regression test that the JSON schema +// for VSCMaturedPacketData (sent over the wire) does not change. +func TestVSCMaturedPacketDataWireBytes(t *testing.T) { + // Construct consumer packet data wrapping vsc matured packet data + cpd := types.ConsumerPacketData{ + Type: types.VscMaturedPacket, + Data: &types.ConsumerPacketData_VscMaturedPacketData{ + VscMaturedPacketData: types.NewVSCMaturedPacketData(84923), + }, + } + + jsonBz := cpd.GetBytes() + str := string(jsonBz) + + // Expected string formatted for human readability + expectedStr := `{ + "type": "CONSUMER_PACKET_TYPE_VSCM", + "vscMaturedPacketData": { + "valset_update_id": "84923" + } + }` + + // Remove newlines, tabs, and spaces for comparison + expectedStr = strings.ReplaceAll(expectedStr, "\n", "") + expectedStr = strings.ReplaceAll(expectedStr, "\t", "") + expectedStr = strings.ReplaceAll(expectedStr, " ", "") + + require.Equal(t, expectedStr, str) +} From 5e5e2fa7508b69e7242ec007347cabe8ea676f79 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Date: Tue, 1 Aug 2023 13:29:57 +0200 Subject: [PATCH 067/134] test: Fix mismatching code/comment and use WaitTime instead of sleep (#1174) Fix mismatching comment and use WaitTime instead of sleep --- tests/e2e/actions.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index 3dd8fb704e..8faca43c0a 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -1655,8 +1655,8 @@ type unjailValidatorAction struct { // Sends an unjail transaction to the provider chain func (tr TestRun) unjailValidator(action unjailValidatorAction, verbose bool) { - // wait a block to be sure downtime_jail_duration has elapsed - time.Sleep(61 * time.Second) + // wait until downtime_jail_duration has elapsed, to make sure the validator can be unjailed + tr.WaitTime(61 * time.Second) //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. cmd := exec.Command("docker", "exec", From b72ad0d62832043675b8148727def24925b0eb9a Mon Sep 17 00:00:00 2001 From: karolos Date: Wed, 2 Aug 2023 15:02:42 +0200 Subject: [PATCH 068/134] docs: remove an obsolete comment before setting the order of EndBlockers (#1081) Remove the whole comment because the described order does not constitute an interchain security requirement. --- app/provider/app.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/app/provider/app.go b/app/provider/app.go index a25e3f4ab6..c054f4a00b 100644 --- a/app/provider/app.go +++ b/app/provider/app.go @@ -530,12 +530,7 @@ func New( vestingtypes.ModuleName, providertypes.ModuleName, ) - // Interchain Security requirements - // - provider.EndBlock gets validator updates from the staking module; - // thus, staking.EndBlock must be executed before provider.EndBlock; - // - creating a new consumer chain requires the following order, - // CreateChildClient(), staking.EndBlock, provider.EndBlock; - // thus, gov.EndBlock must be executed before staking.EndBlock + app.MM.SetOrderEndBlockers( crisistypes.ModuleName, govtypes.ModuleName, From c49651332ff824235e75fb3ae32df43858c34fb4 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Date: Wed, 2 Aug 2023 17:52:57 +0200 Subject: [PATCH 069/134] chore: Migrate containers to informalsystems repos (#1172) * Migrate containers to informalsystems repos and fix versions * Remove fixed shas from container images --- Dockerfile | 4 ++-- tests/e2e/testnet-scripts/start-chain.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index dee88dae7c..7c45187034 100644 --- a/Dockerfile +++ b/Dockerfile @@ -32,10 +32,10 @@ RUN make install FROM ghcr.io/informalsystems/hermes:1.4.1 AS hermes-builder # Get CometMock -FROM informalofftermatt/cometmock:latest as cometmock-builder +FROM ghcr.io/informalsystems/cometmock:v0.37.x as cometmock-builder # Get GoRelayer -FROM informalofftermatt/gorelayer:nogas AS gorelayer-builder +FROM ghcr.io/informalsystems/relayer-no-gas-sim:v2.3.0-rc4-no-gas-sim AS gorelayer-builder FROM --platform=linux/amd64 fedora:36 RUN dnf update -y diff --git a/tests/e2e/testnet-scripts/start-chain.sh b/tests/e2e/testnet-scripts/start-chain.sh index a3609acf73..88c8455e51 100644 --- a/tests/e2e/testnet-scripts/start-chain.sh +++ b/tests/e2e/testnet-scripts/start-chain.sh @@ -362,7 +362,7 @@ NODE_HOMES=${NODE_HOMES%?} # CometMock takes the role of the query node if [[ "$USE_COMETMOCK" == "true" ]]; then sleep 2 - ip netns exec $QUERY_NET_NAMESPACE_NAME cometmock $NODE_LISTEN_ADDR_STR /$CHAIN_ID/genesis.json tcp://$CHAIN_IP_PREFIX.$QUERY_IP_SUFFIX:26658 $NODE_HOMES &> cometmock_${CHAIN_ID}_out.log & + ip netns exec $QUERY_NET_NAMESPACE_NAME cometmock $NODE_LISTEN_ADDR_STR /$CHAIN_ID/genesis.json tcp://$CHAIN_IP_PREFIX.$QUERY_IP_SUFFIX:26658 $NODE_HOMES grpc &> cometmock_${CHAIN_ID}_out.log & sleep 3 fi From c0d8314490bf403363968c131a5e9e6f399390a1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Aug 2023 17:56:56 +0200 Subject: [PATCH 070/134] build(deps): bump github.com/tidwall/gjson from 1.14.4 to 1.15.0 (#1171) Bumps [github.com/tidwall/gjson](https://github.com/tidwall/gjson) from 1.14.4 to 1.15.0. - [Commits](https://github.com/tidwall/gjson/compare/v1.14.4...v1.15.0) --- updated-dependencies: - dependency-name: github.com/tidwall/gjson dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 7947a36e66..7ee8399acc 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/spf13/cast v1.5.1 github.com/spf13/cobra v1.6.1 github.com/stretchr/testify v1.8.4 - github.com/tidwall/gjson v1.14.4 + github.com/tidwall/gjson v1.15.0 golang.org/x/crypto v0.11.0 // indirect golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc golang.org/x/net v0.12.0 // indirect diff --git a/go.sum b/go.sum index 26ceadb4ea..5377f849fa 100644 --- a/go.sum +++ b/go.sum @@ -1115,8 +1115,8 @@ github.com/tidwall/btree v1.6.0 h1:LDZfKfQIBHGHWSwckhXI0RPSXzlo+KYdjK7FWSqOzzg= github.com/tidwall/btree v1.6.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.14.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= -github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.15.0 h1:5n/pM+v3r5ujuNl4YLZLsQ+UE5jlkLVm7jMzT5Mpolw= +github.com/tidwall/gjson v1.15.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= From 8c40f32869936bfe9b4a1dee9a44b3a6b8f8f484 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Aug 2023 08:45:34 -0700 Subject: [PATCH 071/134] build(deps): bump google.golang.org/grpc from 1.56.2 to 1.57.0 (#1170) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.56.2 to 1.57.0. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.56.2...v1.57.0) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 11 ++++++++--- go.sum | 14 ++++++++++---- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 7ee8399acc..ff38553879 100644 --- a/go.mod +++ b/go.mod @@ -26,8 +26,8 @@ require ( golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc golang.org/x/net v0.12.0 // indirect golang.org/x/sys v0.10.0 // indirect - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 - google.golang.org/grpc v1.56.2 + google.golang.org/genproto v0.0.0-20230629202037-9506855d4529 // indirect + google.golang.org/grpc v1.57.0 google.golang.org/protobuf v1.31.0 gopkg.in/yaml.v2 v2.4.0 ) @@ -165,13 +165,18 @@ require ( sigs.k8s.io/yaml v1.3.0 // indirect ) -require github.com/spf13/viper v1.15.0 +require ( + github.com/spf13/viper v1.15.0 + google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e +) require ( cosmossdk.io/log v1.1.0 // indirect github.com/go-playground/locales v0.14.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/rs/zerolog v1.29.1 // indirect + golang.org/x/sync v0.1.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130 // indirect ) // following versions might cause unexpected behavior diff --git a/go.sum b/go.sum index 5377f849fa..4a93323e50 100644 --- a/go.sum +++ b/go.sum @@ -1362,6 +1362,8 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1747,8 +1749,12 @@ google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqw google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= +google.golang.org/genproto v0.0.0-20230629202037-9506855d4529 h1:9JucMWR7sPvCxUFd6UsOUNmA5kCcWOfORaT3tpAsKQs= +google.golang.org/genproto v0.0.0-20230629202037-9506855d4529/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= +google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e h1:AZX1ra8YbFMSb7+1pI8S9v4rrgRR7jU1FmuFSSjTVcQ= +google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130 h1:2FZP5XuJY9zQyGM5N0rtovnoXjiMUEIUMvw0m9wlpLc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:8mL13HKkDa+IuJ8yruA3ci0q+0vsUz4m//+ottjwS5o= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= @@ -1790,8 +1796,8 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.56.2 h1:fVRFRnXvU+x6C4IlHZewvJOVHoOv1TUuQyoRsYnB4bI= -google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= +google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= From 006680a60bfe7fc48ee142bb0107a3e82e076470 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Aug 2023 18:05:04 +0200 Subject: [PATCH 072/134] build(deps): bump bufbuild/buf-setup-action from 1.25.0 to 1.25.1 (#1187) Bumps [bufbuild/buf-setup-action](https://github.com/bufbuild/buf-setup-action) from 1.25.0 to 1.25.1. - [Release notes](https://github.com/bufbuild/buf-setup-action/releases) - [Commits](https://github.com/bufbuild/buf-setup-action/compare/v1.25.0...v1.25.1) --- updated-dependencies: - dependency-name: bufbuild/buf-setup-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/proto-registry.yml | 2 +- .github/workflows/proto.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/proto-registry.yml b/.github/workflows/proto-registry.yml index 9764edd806..a3291cec36 100644 --- a/.github/workflows/proto-registry.yml +++ b/.github/workflows/proto-registry.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: bufbuild/buf-setup-action@v1.25.0 + - uses: bufbuild/buf-setup-action@v1.25.1 - uses: bufbuild/buf-push-action@v1 with: input: "proto" diff --git a/.github/workflows/proto.yml b/.github/workflows/proto.yml index 8f80957d92..deb110dad0 100644 --- a/.github/workflows/proto.yml +++ b/.github/workflows/proto.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: bufbuild/buf-setup-action@v1.25.0 + - uses: bufbuild/buf-setup-action@v1.25.1 - uses: bufbuild/buf-breaking-action@v1 with: input: "proto" From aaa545dc936cb3b56adebdef327dbedc45066315 Mon Sep 17 00:00:00 2001 From: yaruwangway <69694322+yaruwangway@users.noreply.github.com> Date: Wed, 9 Aug 2023 10:45:26 +0200 Subject: [PATCH 073/134] feat: add provider info query (#1164) * feat: add provider info query * feat: refactor query providerInfo * feat: query provider info * feat: query all provider info * feat: add provider info query cli * feat: add consumer info to provider info query * feat: add consumer chain-id to provider info query * fix: return err when client, channel not found * fix: lint * chore: fix lint * chore: lint fix * chore: add nonlint * chore: add nonlint to the right place * chore: add nolint nolintlint * chore: nolint all * chore: nolint:golint * chore: fix package import order * chore: update queryProviderChainInfo to queryProviderInfo * chore: update proto * update query.go * docs: update changelog --- CHANGELOG.md | 1 + .../ccv/consumer/v1/query.proto | 18 + testutil/keeper/mocks.go | 10 + x/ccv/consumer/client/cli/query.go | 32 +- x/ccv/consumer/keeper/grpc_query.go | 17 +- x/ccv/consumer/keeper/provider_info.go | 54 ++ x/ccv/consumer/types/query.pb.go | 780 +++++++++++++++++- x/ccv/consumer/types/query.pb.gw.go | 65 ++ x/ccv/types/expected_keepers.go | 1 + 9 files changed, 940 insertions(+), 38 deletions(-) create mode 100644 x/ccv/consumer/keeper/provider_info.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 818bdca374..5003260943 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ Add an entry to the unreleased section whenever merging a PR to main that is not * (fix!) revert consumer packet data changes from #1037 [#1150](https://github.com/cosmos/interchain-security/pull/1150) * (fix!) proper deletion of pending packets [#1146](https://github.com/cosmos/interchain-security/pull/1146) * (feat!) optimize pending packets storage on consumer, with migration! [#1037](https://github.com/cosmos/interchain-security/pull/1037) +* (feat) 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. ## v3.1.0 diff --git a/proto/interchain_security/ccv/consumer/v1/query.proto b/proto/interchain_security/ccv/consumer/v1/query.proto index df90b1d0aa..43a7b0bccc 100644 --- a/proto/interchain_security/ccv/consumer/v1/query.proto +++ b/proto/interchain_security/ccv/consumer/v1/query.proto @@ -19,6 +19,10 @@ service Query { rpc QueryParams(QueryParamsRequest) returns (QueryParamsResponse) { option (google.api.http).get = "/interchain_security/ccv/consumer/params"; } + + rpc QueryProviderInfo(QueryProviderInfoRequest) returns (QueryProviderInfoResponse) { + option (google.api.http).get = "/interchain_security/ccv/consumer/provider-info"; + } } // NextFeeDistributionEstimate holds information about next fee distribution @@ -52,3 +56,17 @@ message QueryParamsResponse { // params holds all the parameters of this module. Params params = 1 [ (gogoproto.nullable) = false ]; } + +message QueryProviderInfoRequest {} + +message QueryProviderInfoResponse { + ChainInfo consumer = 1 [ (gogoproto.nullable) = false ]; + ChainInfo provider = 2 [ (gogoproto.nullable) = false ]; +} + +message ChainInfo { + string chainID = 1; + string clientID = 2; + string connectionID = 3; + string channelID = 4; +} diff --git a/testutil/keeper/mocks.go b/testutil/keeper/mocks.go index fea83079d3..b075819cc4 100644 --- a/testutil/keeper/mocks.go +++ b/testutil/keeper/mocks.go @@ -564,6 +564,16 @@ func (m *MockChannelKeeper) GetChannel(ctx types0.Context, srcPort, srcChan stri return ret0, ret1 } +func (m *MockChannelKeeper) GetChannelConnection(ctx types0.Context, portID, channelID string) (string, exported.ConnectionI, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetChannelConnection", ctx, portID, channelID) + ret0, _ := ret[0].(string) + ret1, _ := ret[0].(exported.ConnectionI) + ret2, _ := ret[1].(error) + + return ret0, ret1, ret2 +} + // GetChannel indicates an expected call of GetChannel. func (mr *MockChannelKeeperMockRecorder) GetChannel(ctx, srcPort, srcChan interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() diff --git a/x/ccv/consumer/client/cli/query.go b/x/ccv/consumer/client/cli/query.go index a961b9642c..dc1ecfc2f4 100644 --- a/x/ccv/consumer/client/cli/query.go +++ b/x/ccv/consumer/client/cli/query.go @@ -19,7 +19,10 @@ func NewQueryCmd() *cobra.Command { RunE: client.ValidateCmd, } - cmd.AddCommand(CmdNextFeeDistribution()) + cmd.AddCommand( + CmdNextFeeDistribution(), + CmdProviderInfo(), + ) return cmd } @@ -50,3 +53,30 @@ func CmdNextFeeDistribution() *cobra.Command { return cmd } + +func CmdProviderInfo() *cobra.Command { + cmd := &cobra.Command{ + Use: "provider-info", + Short: "Query provider info", + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) (err error) { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + req := &types.QueryProviderInfoRequest{} + res, err := queryClient.QueryProviderInfo(cmd.Context(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/ccv/consumer/keeper/grpc_query.go b/x/ccv/consumer/keeper/grpc_query.go index 174f591497..80e6b695a9 100644 --- a/x/ccv/consumer/keeper/grpc_query.go +++ b/x/ccv/consumer/keeper/grpc_query.go @@ -11,9 +11,9 @@ import ( "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" ) -var _ types.QueryServer = Keeper{} +var _ types.QueryServer = Keeper{} //nolint:golint -func (k Keeper) QueryNextFeeDistribution(c context.Context, +func (k Keeper) QueryNextFeeDistribution(c context.Context, //nolint:golint req *types.QueryNextFeeDistributionEstimateRequest, ) (*types.QueryNextFeeDistributionEstimateResponse, error) { ctx := sdk.UnwrapSDKContext(c) @@ -27,7 +27,7 @@ func (k Keeper) QueryNextFeeDistribution(c context.Context, return &types.QueryNextFeeDistributionEstimateResponse{Data: &nextDist}, nil } -func (k Keeper) QueryParams(c context.Context, +func (k Keeper) QueryParams(c context.Context, //nolint:golint req *types.QueryParamsRequest, ) (*types.QueryParamsResponse, error) { ctx := sdk.UnwrapSDKContext(c) @@ -40,3 +40,14 @@ func (k Keeper) QueryParams(c context.Context, return &types.QueryParamsResponse{Params: p}, nil } + +func (k Keeper) QueryProviderInfo(c context.Context, //nolint:golint + req *types.QueryProviderInfoRequest, +) (*types.QueryProviderInfoResponse, error) { + ctx := sdk.UnwrapSDKContext(c) + if req == nil { + return nil, status.Errorf(codes.InvalidArgument, "empty request") + } + + return k.GetProviderInfo(ctx) +} diff --git a/x/ccv/consumer/keeper/provider_info.go b/x/ccv/consumer/keeper/provider_info.go new file mode 100644 index 0000000000..d8dfef100a --- /dev/null +++ b/x/ccv/consumer/keeper/provider_info.go @@ -0,0 +1,54 @@ +package keeper + +import ( + ibctm "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" //nolint:golint + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" +) + +func (k Keeper) GetProviderInfo(ctx sdk.Context) (*types.QueryProviderInfoResponse, error) { //nolint:golint + consumerChannelID, found := k.GetProviderChannel(ctx) + if !found { + return nil, ccvtypes.ErrChannelNotFound + } + consumerChannel, found := k.channelKeeper.GetChannel(ctx, ccvtypes.ConsumerPortID, consumerChannelID) + if !found { + return nil, ccvtypes.ErrChannelNotFound + } + + // from channel get connection + consumerConnectionID, consumerConnection, err := k.channelKeeper.GetChannelConnection(ctx, ccvtypes.ConsumerPortID, consumerChannelID) + if err != nil { + return nil, err + } + + providerChannelID := consumerChannel.GetCounterparty().GetChannelID() + providerConnection := consumerConnection.GetCounterparty() + + consumerClientState, found := k.clientKeeper.GetClientState(ctx, consumerConnection.GetClientID()) + if !found { + return nil, ccvtypes.ErrClientNotFound + } + providerChainID := consumerClientState.(*ibctm.ClientState).ChainId + + resp := types.QueryProviderInfoResponse{ + Consumer: types.ChainInfo{ + ChainID: ctx.ChainID(), + ClientID: consumerConnection.GetClientID(), + ConnectionID: consumerConnectionID, + ChannelID: consumerChannelID, + }, + + Provider: types.ChainInfo{ + ChainID: providerChainID, + ClientID: providerConnection.GetClientID(), + ConnectionID: providerConnection.GetConnectionID(), + ChannelID: providerChannelID, + }, + } + + return &resp, nil +} diff --git a/x/ccv/consumer/types/query.pb.go b/x/ccv/consumer/types/query.pb.go index 5b9c52d962..effe4757ef 100644 --- a/x/ccv/consumer/types/query.pb.go +++ b/x/ccv/consumer/types/query.pb.go @@ -295,12 +295,171 @@ func (m *QueryParamsResponse) GetParams() Params { return Params{} } +type QueryProviderInfoRequest struct { +} + +func (m *QueryProviderInfoRequest) Reset() { *m = QueryProviderInfoRequest{} } +func (m *QueryProviderInfoRequest) String() string { return proto.CompactTextString(m) } +func (*QueryProviderInfoRequest) ProtoMessage() {} +func (*QueryProviderInfoRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_f627751d3cc10225, []int{5} +} +func (m *QueryProviderInfoRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryProviderInfoRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryProviderInfoRequest.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 *QueryProviderInfoRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryProviderInfoRequest.Merge(m, src) +} +func (m *QueryProviderInfoRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryProviderInfoRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryProviderInfoRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryProviderInfoRequest proto.InternalMessageInfo + +type QueryProviderInfoResponse struct { + Consumer ChainInfo `protobuf:"bytes,1,opt,name=consumer,proto3" json:"consumer"` + Provider ChainInfo `protobuf:"bytes,2,opt,name=provider,proto3" json:"provider"` +} + +func (m *QueryProviderInfoResponse) Reset() { *m = QueryProviderInfoResponse{} } +func (m *QueryProviderInfoResponse) String() string { return proto.CompactTextString(m) } +func (*QueryProviderInfoResponse) ProtoMessage() {} +func (*QueryProviderInfoResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_f627751d3cc10225, []int{6} +} +func (m *QueryProviderInfoResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryProviderInfoResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryProviderInfoResponse.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 *QueryProviderInfoResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryProviderInfoResponse.Merge(m, src) +} +func (m *QueryProviderInfoResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryProviderInfoResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryProviderInfoResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryProviderInfoResponse proto.InternalMessageInfo + +func (m *QueryProviderInfoResponse) GetConsumer() ChainInfo { + if m != nil { + return m.Consumer + } + return ChainInfo{} +} + +func (m *QueryProviderInfoResponse) GetProvider() ChainInfo { + if m != nil { + return m.Provider + } + return ChainInfo{} +} + +type ChainInfo struct { + ChainID string `protobuf:"bytes,1,opt,name=chainID,proto3" json:"chainID,omitempty"` + ClientID string `protobuf:"bytes,2,opt,name=clientID,proto3" json:"clientID,omitempty"` + ConnectionID string `protobuf:"bytes,3,opt,name=connectionID,proto3" json:"connectionID,omitempty"` + ChannelID string `protobuf:"bytes,4,opt,name=channelID,proto3" json:"channelID,omitempty"` +} + +func (m *ChainInfo) Reset() { *m = ChainInfo{} } +func (m *ChainInfo) String() string { return proto.CompactTextString(m) } +func (*ChainInfo) ProtoMessage() {} +func (*ChainInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_f627751d3cc10225, []int{7} +} +func (m *ChainInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ChainInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ChainInfo.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 *ChainInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_ChainInfo.Merge(m, src) +} +func (m *ChainInfo) XXX_Size() int { + return m.Size() +} +func (m *ChainInfo) XXX_DiscardUnknown() { + xxx_messageInfo_ChainInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_ChainInfo proto.InternalMessageInfo + +func (m *ChainInfo) GetChainID() string { + if m != nil { + return m.ChainID + } + return "" +} + +func (m *ChainInfo) GetClientID() string { + if m != nil { + return m.ClientID + } + return "" +} + +func (m *ChainInfo) GetConnectionID() string { + if m != nil { + return m.ConnectionID + } + return "" +} + +func (m *ChainInfo) GetChannelID() string { + if m != nil { + return m.ChannelID + } + return "" +} + func init() { proto.RegisterType((*NextFeeDistributionEstimate)(nil), "interchain_security.ccv.consumer.v1.NextFeeDistributionEstimate") proto.RegisterType((*QueryNextFeeDistributionEstimateRequest)(nil), "interchain_security.ccv.consumer.v1.QueryNextFeeDistributionEstimateRequest") proto.RegisterType((*QueryNextFeeDistributionEstimateResponse)(nil), "interchain_security.ccv.consumer.v1.QueryNextFeeDistributionEstimateResponse") proto.RegisterType((*QueryParamsRequest)(nil), "interchain_security.ccv.consumer.v1.QueryParamsRequest") proto.RegisterType((*QueryParamsResponse)(nil), "interchain_security.ccv.consumer.v1.QueryParamsResponse") + proto.RegisterType((*QueryProviderInfoRequest)(nil), "interchain_security.ccv.consumer.v1.QueryProviderInfoRequest") + proto.RegisterType((*QueryProviderInfoResponse)(nil), "interchain_security.ccv.consumer.v1.QueryProviderInfoResponse") + proto.RegisterType((*ChainInfo)(nil), "interchain_security.ccv.consumer.v1.ChainInfo") } func init() { @@ -308,40 +467,49 @@ func init() { } var fileDescriptor_f627751d3cc10225 = []byte{ - // 521 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0xcf, 0x8b, 0xd3, 0x40, - 0x14, 0x6e, 0xfa, 0x4b, 0x9c, 0xc5, 0xcb, 0x58, 0x21, 0x54, 0x89, 0x4b, 0x15, 0xac, 0x4a, 0x33, - 0x6e, 0x7b, 0x58, 0x3d, 0x88, 0xb2, 0xea, 0xa2, 0xa0, 0xb2, 0x16, 0x41, 0xf0, 0xb2, 0x4e, 0xa7, - 0x6f, 0xd3, 0x81, 0x26, 0x93, 0x9d, 0x99, 0x84, 0xf6, 0x26, 0xfe, 0x01, 0x22, 0xf8, 0x9f, 0x78, - 0xf1, 0x5f, 0xd8, 0xe3, 0x82, 0x17, 0x4f, 0x22, 0xad, 0x7f, 0x84, 0x47, 0xc9, 0x24, 0x59, 0x53, - 0xd0, 0x6d, 0x04, 0x6f, 0xd3, 0xef, 0x7b, 0xef, 0x7b, 0xdf, 0x7c, 0xf3, 0x1a, 0x44, 0x78, 0xa0, - 0x41, 0xb2, 0x09, 0xe5, 0xc1, 0xbe, 0x02, 0x16, 0x49, 0xae, 0xe7, 0x84, 0xb1, 0x98, 0x30, 0x11, - 0xa8, 0xc8, 0x07, 0x49, 0xe2, 0x2d, 0x72, 0x18, 0x81, 0x9c, 0xbb, 0xa1, 0x14, 0x5a, 0xe0, 0x2b, - 0x7f, 0x68, 0x70, 0x19, 0x8b, 0xdd, 0xbc, 0xc1, 0x8d, 0xb7, 0xda, 0x2d, 0x4f, 0x78, 0xc2, 0xd4, - 0x93, 0xe4, 0x94, 0xb6, 0xb6, 0x2f, 0x79, 0x42, 0x78, 0x53, 0x20, 0x34, 0xe4, 0x84, 0x06, 0x81, - 0xd0, 0x54, 0x73, 0x11, 0xa8, 0x8c, 0xed, 0x97, 0x71, 0x72, 0x32, 0xc4, 0xf4, 0x74, 0xde, 0x57, - 0xd1, 0xc5, 0xe7, 0x30, 0xd3, 0xbb, 0x00, 0x0f, 0xb9, 0xd2, 0x92, 0x8f, 0xa2, 0x44, 0xf2, 0x91, - 0xd2, 0xdc, 0xa7, 0x1a, 0xf0, 0x55, 0x74, 0x8e, 0x45, 0x52, 0x42, 0xa0, 0x1f, 0x03, 0xf7, 0x26, - 0xda, 0xb6, 0x36, 0xad, 0x6e, 0x6d, 0xb8, 0x0a, 0x62, 0x07, 0xa1, 0x29, 0x55, 0x79, 0x49, 0xd5, - 0x94, 0x14, 0x90, 0x84, 0x0f, 0x60, 0x96, 0xf3, 0xb5, 0x94, 0xff, 0x8d, 0xe0, 0x01, 0xba, 0x30, - 0x2e, 0x4c, 0xdf, 0x3f, 0x90, 0x94, 0x25, 0x07, 0xbb, 0xbe, 0x69, 0x75, 0xcf, 0x0e, 0x5b, 0x45, - 0x72, 0x37, 0xe3, 0x70, 0x0b, 0x35, 0xb4, 0xd0, 0x74, 0x6a, 0x37, 0x4c, 0x51, 0xfa, 0x23, 0x19, - 0xa5, 0xc5, 0x9e, 0x14, 0x31, 0x1f, 0x83, 0xb4, 0x9b, 0x86, 0x2a, 0x20, 0x29, 0xff, 0x20, 0x0b, - 0xc1, 0x3e, 0x93, 0xf3, 0x39, 0xd2, 0xb9, 0x8e, 0xae, 0xbd, 0x48, 0x1e, 0xeb, 0x94, 0x50, 0x86, - 0x70, 0x18, 0x81, 0xd2, 0x9d, 0xb7, 0x16, 0xea, 0xae, 0xaf, 0x55, 0xa1, 0x08, 0x14, 0xe0, 0x97, - 0xa8, 0x3e, 0xa6, 0x9a, 0x9a, 0xfc, 0x36, 0xfa, 0xf7, 0xdd, 0x12, 0x4b, 0xe0, 0x9e, 0xa6, 0x6b, - 0xd4, 0x3a, 0x2d, 0x84, 0x8d, 0x83, 0x3d, 0x2a, 0xa9, 0xaf, 0x72, 0x63, 0x6f, 0xd0, 0xf9, 0x15, - 0x34, 0xb3, 0xf0, 0x04, 0x35, 0x43, 0x83, 0x64, 0x26, 0x6e, 0x96, 0x32, 0x91, 0x8a, 0xec, 0xd4, - 0x8f, 0xbe, 0x5d, 0xae, 0x0c, 0x33, 0x81, 0xfe, 0xe7, 0x1a, 0x6a, 0x98, 0x11, 0xf8, 0xa7, 0x85, - 0xec, 0xbf, 0x85, 0x80, 0x9f, 0x96, 0x9a, 0x50, 0x32, 0xef, 0xf6, 0xb3, 0xff, 0xa4, 0x96, 0xc6, - 0xd1, 0xb9, 0xf7, 0xee, 0xcb, 0x8f, 0x8f, 0xd5, 0x3b, 0x78, 0x7b, 0xfd, 0x3f, 0x38, 0x59, 0xd5, - 0xde, 0x01, 0x40, 0xaf, 0xb8, 0x88, 0xf8, 0x93, 0x85, 0x36, 0x0a, 0x39, 0xe3, 0xed, 0xf2, 0xfe, - 0x56, 0xde, 0xab, 0x7d, 0xfb, 0xdf, 0x1b, 0xb3, 0x3b, 0xdc, 0x32, 0x77, 0xb8, 0x81, 0xbb, 0xeb, - 0xef, 0x90, 0xbe, 0xdc, 0xce, 0xab, 0xa3, 0x85, 0x63, 0x1d, 0x2f, 0x1c, 0xeb, 0xfb, 0xc2, 0xb1, - 0x3e, 0x2c, 0x9d, 0xca, 0xf1, 0xd2, 0xa9, 0x7c, 0x5d, 0x3a, 0x95, 0xd7, 0x77, 0x3d, 0xae, 0x27, - 0xd1, 0xc8, 0x65, 0xc2, 0x27, 0x4c, 0x28, 0x5f, 0xa8, 0x82, 0x68, 0xef, 0x44, 0x34, 0x1e, 0x90, - 0xd9, 0xaa, 0xb2, 0x9e, 0x87, 0xa0, 0x46, 0x4d, 0xf3, 0x41, 0x19, 0xfc, 0x0a, 0x00, 0x00, 0xff, - 0xff, 0xcc, 0x57, 0x2e, 0xd6, 0x10, 0x05, 0x00, 0x00, + // 672 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x55, 0x41, 0x6b, 0x13, 0x4f, + 0x14, 0xcf, 0xa6, 0x4d, 0xdb, 0xbc, 0xfe, 0xff, 0x07, 0xc7, 0x08, 0xeb, 0x5a, 0xd6, 0xb2, 0x0a, + 0x46, 0x25, 0xbb, 0xb6, 0x3d, 0x54, 0x0f, 0x55, 0xb1, 0xb1, 0x18, 0x50, 0xa9, 0x8b, 0x20, 0x78, + 0xa9, 0xd3, 0xe9, 0x34, 0x19, 0x48, 0x66, 0xd2, 0x9d, 0xd9, 0xd0, 0xde, 0x44, 0xf1, 0x2a, 0x82, + 0xdf, 0xc4, 0x2f, 0xe0, 0xb5, 0xe0, 0xa5, 0xe0, 0xc5, 0x93, 0x48, 0xeb, 0x87, 0xf0, 0x28, 0x3b, + 0x3b, 0x9b, 0x6e, 0x68, 0x69, 0xb7, 0xea, 0x6d, 0xe7, 0xfd, 0xde, 0xfb, 0xbd, 0xdf, 0x7b, 0xf3, + 0xde, 0x2c, 0x04, 0x8c, 0x2b, 0x1a, 0x91, 0x0e, 0x66, 0x7c, 0x4d, 0x52, 0x12, 0x47, 0x4c, 0xed, + 0x04, 0x84, 0x0c, 0x02, 0x22, 0xb8, 0x8c, 0x7b, 0x34, 0x0a, 0x06, 0x73, 0xc1, 0x56, 0x4c, 0xa3, + 0x1d, 0xbf, 0x1f, 0x09, 0x25, 0xd0, 0x95, 0x63, 0x02, 0x7c, 0x42, 0x06, 0x7e, 0x16, 0xe0, 0x0f, + 0xe6, 0x9c, 0x5a, 0x5b, 0xb4, 0x85, 0xf6, 0x0f, 0x92, 0xaf, 0x34, 0xd4, 0x99, 0x69, 0x0b, 0xd1, + 0xee, 0xd2, 0x00, 0xf7, 0x59, 0x80, 0x39, 0x17, 0x0a, 0x2b, 0x26, 0xb8, 0x34, 0xe8, 0x7c, 0x11, + 0x25, 0xc3, 0x24, 0x3a, 0xc6, 0x7b, 0x5f, 0x86, 0x4b, 0x4f, 0xe9, 0xb6, 0x5a, 0xa1, 0xb4, 0xc9, + 0xa4, 0x8a, 0xd8, 0x7a, 0x9c, 0x50, 0x3e, 0x94, 0x8a, 0xf5, 0xb0, 0xa2, 0xe8, 0x2a, 0xfc, 0x4f, + 0xe2, 0x28, 0xa2, 0x5c, 0x3d, 0xa2, 0xac, 0xdd, 0x51, 0xb6, 0x35, 0x6b, 0xd5, 0xc7, 0xc2, 0x51, + 0x23, 0x72, 0x01, 0xba, 0x58, 0x66, 0x2e, 0x65, 0xed, 0x92, 0xb3, 0x24, 0x38, 0xa7, 0xdb, 0x19, + 0x3e, 0x96, 0xe2, 0x87, 0x16, 0xb4, 0x00, 0x17, 0x36, 0x72, 0xd9, 0xd7, 0x36, 0x23, 0x4c, 0x92, + 0x0f, 0x7b, 0x7c, 0xd6, 0xaa, 0x57, 0xc3, 0x5a, 0x1e, 0x5c, 0x31, 0x18, 0xaa, 0x41, 0x45, 0x09, + 0x85, 0xbb, 0x76, 0x45, 0x3b, 0xa5, 0x87, 0x24, 0x95, 0x12, 0xab, 0x91, 0x18, 0xb0, 0x0d, 0x1a, + 0xd9, 0x13, 0x1a, 0xca, 0x59, 0x52, 0x7c, 0xd9, 0x34, 0xc1, 0x9e, 0xcc, 0xf0, 0xcc, 0xe2, 0x5d, + 0x87, 0x6b, 0xcf, 0x92, 0xcb, 0x3a, 0xa1, 0x29, 0x21, 0xdd, 0x8a, 0xa9, 0x54, 0xde, 0x6b, 0x0b, + 0xea, 0xa7, 0xfb, 0xca, 0xbe, 0xe0, 0x92, 0xa2, 0xe7, 0x30, 0xbe, 0x81, 0x15, 0xd6, 0xfd, 0x9b, + 0x9e, 0xbf, 0xef, 0x17, 0x18, 0x02, 0xff, 0x24, 0x5e, 0xcd, 0xe6, 0xd5, 0x00, 0x69, 0x05, 0xab, + 0x38, 0xc2, 0x3d, 0x99, 0x09, 0x7b, 0x05, 0xe7, 0x47, 0xac, 0x46, 0x42, 0x0b, 0x26, 0xfa, 0xda, + 0x62, 0x44, 0xdc, 0x2c, 0x24, 0x22, 0x25, 0x79, 0x30, 0xbe, 0xfb, 0xfd, 0x72, 0x29, 0x34, 0x04, + 0x9e, 0x03, 0x76, 0x9a, 0xc1, 0xb4, 0xb5, 0xc5, 0x37, 0x45, 0x96, 0xfd, 0xb3, 0x05, 0x17, 0x8f, + 0x01, 0x8d, 0x88, 0x55, 0x98, 0xca, 0xd8, 0x8d, 0x0c, 0xbf, 0x90, 0x8c, 0xe5, 0x04, 0x4e, 0x98, + 0x8c, 0x92, 0x21, 0x4b, 0xc2, 0xd8, 0xcf, 0xee, 0xbb, 0xfc, 0x37, 0x8c, 0x19, 0x8b, 0xf7, 0xd6, + 0x82, 0xea, 0x10, 0x45, 0x36, 0x4c, 0x6a, 0xa6, 0x56, 0x53, 0x0b, 0xae, 0x86, 0xd9, 0x11, 0x39, + 0x30, 0x45, 0xba, 0x8c, 0x72, 0xd5, 0x6a, 0xea, 0xcc, 0xd5, 0x70, 0x78, 0x46, 0x1e, 0xfc, 0x47, + 0x04, 0xe7, 0x54, 0xcf, 0x6a, 0xab, 0xa9, 0x87, 0xbe, 0x1a, 0x8e, 0xd8, 0xd0, 0x0c, 0x54, 0x49, + 0x07, 0x73, 0x4e, 0xbb, 0xad, 0xa6, 0x19, 0xf5, 0x43, 0xc3, 0xfc, 0xbb, 0x0a, 0x54, 0x74, 0x1f, + 0xd1, 0x2f, 0xcb, 0xb4, 0xfb, 0x98, 0x81, 0x40, 0x8f, 0x0b, 0x15, 0x5b, 0x70, 0xa6, 0x9d, 0x27, + 0xff, 0x88, 0x2d, 0xbd, 0x6d, 0xef, 0xde, 0x9b, 0xaf, 0x3f, 0x3f, 0x96, 0xef, 0xa0, 0xc5, 0xd3, + 0x5f, 0xc9, 0xe4, 0x39, 0x68, 0x6c, 0x52, 0xda, 0xc8, 0x2f, 0x3b, 0xfa, 0x64, 0xc1, 0x74, 0x6e, + 0x96, 0xd1, 0x62, 0x71, 0x7d, 0x23, 0x3b, 0xe1, 0xdc, 0x3e, 0x7b, 0xa0, 0xa9, 0xe1, 0x96, 0xae, + 0xe1, 0x06, 0xaa, 0x9f, 0x5e, 0x43, 0xba, 0x1d, 0xe8, 0x8b, 0x05, 0xe7, 0x8e, 0x6c, 0x00, 0x5a, + 0x3a, 0x83, 0x82, 0xa3, 0x6b, 0xe5, 0xdc, 0xfd, 0xd3, 0x70, 0x53, 0xc6, 0xa2, 0x2e, 0x63, 0x0e, + 0x05, 0x05, 0xca, 0x30, 0xf1, 0x0d, 0x96, 0x6c, 0xc7, 0x8b, 0xdd, 0x7d, 0xd7, 0xda, 0xdb, 0x77, + 0xad, 0x1f, 0xfb, 0xae, 0xf5, 0xe1, 0xc0, 0x2d, 0xed, 0x1d, 0xb8, 0xa5, 0x6f, 0x07, 0x6e, 0xe9, + 0xe5, 0x52, 0x9b, 0xa9, 0x4e, 0xbc, 0xee, 0x13, 0xd1, 0x0b, 0x88, 0x90, 0x3d, 0x21, 0x73, 0xdc, + 0x8d, 0x21, 0xf7, 0x60, 0x21, 0xd8, 0x1e, 0x4d, 0xa0, 0x76, 0xfa, 0x54, 0xae, 0x4f, 0xe8, 0x5f, + 0xd0, 0xc2, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0x78, 0x73, 0x9f, 0x0e, 0x42, 0x07, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -361,6 +529,7 @@ type QueryClient interface { QueryNextFeeDistribution(ctx context.Context, in *QueryNextFeeDistributionEstimateRequest, opts ...grpc.CallOption) (*QueryNextFeeDistributionEstimateResponse, error) // QueryParams queries the ccv/consumer module parameters. QueryParams(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) + QueryProviderInfo(ctx context.Context, in *QueryProviderInfoRequest, opts ...grpc.CallOption) (*QueryProviderInfoResponse, error) } type queryClient struct { @@ -389,6 +558,15 @@ func (c *queryClient) QueryParams(ctx context.Context, in *QueryParamsRequest, o return out, nil } +func (c *queryClient) QueryProviderInfo(ctx context.Context, in *QueryProviderInfoRequest, opts ...grpc.CallOption) (*QueryProviderInfoResponse, error) { + out := new(QueryProviderInfoResponse) + err := c.cc.Invoke(ctx, "/interchain_security.ccv.consumer.v1.Query/QueryProviderInfo", 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 @@ -396,6 +574,7 @@ type QueryServer interface { QueryNextFeeDistribution(context.Context, *QueryNextFeeDistributionEstimateRequest) (*QueryNextFeeDistributionEstimateResponse, error) // QueryParams queries the ccv/consumer module parameters. QueryParams(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) + QueryProviderInfo(context.Context, *QueryProviderInfoRequest) (*QueryProviderInfoResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -408,6 +587,9 @@ func (*UnimplementedQueryServer) QueryNextFeeDistribution(ctx context.Context, r func (*UnimplementedQueryServer) QueryParams(ctx context.Context, req *QueryParamsRequest) (*QueryParamsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method QueryParams not implemented") } +func (*UnimplementedQueryServer) QueryProviderInfo(ctx context.Context, req *QueryProviderInfoRequest) (*QueryProviderInfoResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method QueryProviderInfo not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -449,6 +631,24 @@ func _Query_QueryParams_Handler(srv interface{}, ctx context.Context, dec func(i return interceptor(ctx, in, info, handler) } +func _Query_QueryProviderInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryProviderInfoRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).QueryProviderInfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/interchain_security.ccv.consumer.v1.Query/QueryProviderInfo", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).QueryProviderInfo(ctx, req.(*QueryProviderInfoRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "interchain_security.ccv.consumer.v1.Query", HandlerType: (*QueryServer)(nil), @@ -461,6 +661,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "QueryParams", Handler: _Query_QueryParams_Handler, }, + { + MethodName: "QueryProviderInfo", + Handler: _Query_QueryProviderInfo_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "interchain_security/ccv/consumer/v1/query.proto", @@ -646,6 +850,123 @@ func (m *QueryParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *QueryProviderInfoRequest) 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 *QueryProviderInfoRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryProviderInfoRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryProviderInfoResponse) 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 *QueryProviderInfoResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryProviderInfoResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Provider.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + { + size, err := m.Consumer.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *ChainInfo) 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 *ChainInfo) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ChainInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ChannelID) > 0 { + i -= len(m.ChannelID) + copy(dAtA[i:], m.ChannelID) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ChannelID))) + i-- + dAtA[i] = 0x22 + } + if len(m.ConnectionID) > 0 { + i -= len(m.ConnectionID) + copy(dAtA[i:], m.ConnectionID) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ConnectionID))) + i-- + dAtA[i] = 0x1a + } + if len(m.ClientID) > 0 { + i -= len(m.ClientID) + copy(dAtA[i:], m.ClientID) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ClientID))) + 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 encodeVarintQuery(dAtA []byte, offset int, v uint64) int { offset -= sovQuery(v) base := offset @@ -733,6 +1054,53 @@ func (m *QueryParamsResponse) Size() (n int) { return n } +func (m *QueryProviderInfoRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryProviderInfoResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Consumer.Size() + n += 1 + l + sovQuery(uint64(l)) + l = m.Provider.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *ChainInfo) 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.ClientID) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.ConnectionID) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.ChannelID) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + func sovQuery(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1243,6 +1611,350 @@ func (m *QueryParamsResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryProviderInfoRequest) 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: QueryProviderInfoRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryProviderInfoRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + 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 *QueryProviderInfoResponse) 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: QueryProviderInfoResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryProviderInfoResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Consumer", 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.Consumer.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Provider", 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.Provider.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 *ChainInfo) 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: ChainInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ChainInfo: 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 ClientID", 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.ClientID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConnectionID", 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.ConnectionID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChannelID", 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.ChannelID = 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 skipQuery(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/ccv/consumer/types/query.pb.gw.go b/x/ccv/consumer/types/query.pb.gw.go index 2aaa7d4b49..1151ab0b60 100644 --- a/x/ccv/consumer/types/query.pb.gw.go +++ b/x/ccv/consumer/types/query.pb.gw.go @@ -69,6 +69,24 @@ func local_request_Query_QueryParams_0(ctx context.Context, marshaler runtime.Ma } +func request_Query_QueryProviderInfo_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryProviderInfoRequest + var metadata runtime.ServerMetadata + + msg, err := client.QueryProviderInfo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_QueryProviderInfo_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryProviderInfoRequest + var metadata runtime.ServerMetadata + + msg, err := server.QueryProviderInfo(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. @@ -121,6 +139,29 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_QueryProviderInfo_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_QueryProviderInfo_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_QueryProviderInfo_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -202,6 +243,26 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_QueryProviderInfo_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_QueryProviderInfo_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_QueryProviderInfo_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -209,10 +270,14 @@ var ( pattern_Query_QueryNextFeeDistribution_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"interchain_security", "ccv", "consumer", "next-fee-distribution"}, "", 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", "consumer", "params"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_QueryProviderInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"interchain_security", "ccv", "consumer", "provider-info"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( forward_Query_QueryNextFeeDistribution_0 = runtime.ForwardResponseMessage forward_Query_QueryParams_0 = runtime.ForwardResponseMessage + + forward_Query_QueryProviderInfo_0 = runtime.ForwardResponseMessage ) diff --git a/x/ccv/types/expected_keepers.go b/x/ccv/types/expected_keepers.go index 2a82561cf0..2f203a47ea 100644 --- a/x/ccv/types/expected_keepers.go +++ b/x/ccv/types/expected_keepers.go @@ -82,6 +82,7 @@ type ChannelKeeper interface { ) (sequence uint64, err error) WriteAcknowledgement(ctx sdk.Context, chanCap *capabilitytypes.Capability, packet ibcexported.PacketI, acknowledgement ibcexported.Acknowledgement) error ChanCloseInit(ctx sdk.Context, portID, channelID string, chanCap *capabilitytypes.Capability) error + GetChannelConnection(ctx sdk.Context, portID, channelID string) (string, ibcexported.ConnectionI, error) } // PortKeeper defines the expected IBC port keeper From 3f4c54cd79c4e708f1c8d4b14ab4a84ff87432e1 Mon Sep 17 00:00:00 2001 From: bernd-m <43466467+bermuell@users.noreply.github.com> Date: Wed, 9 Aug 2023 11:43:12 +0200 Subject: [PATCH 074/134] test: Fix failing e2e test (#1186) * Tests: Fix failing e2e tests * Update tests/e2e/actions.go Co-authored-by: MSalopek * chore: appease lint rules * added check error message --------- Co-authored-by: MSalopek --- tests/e2e/actions.go | 12 +++++++++--- tests/e2e/steps_start_chains.go | 2 ++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index 8faca43c0a..faad8cb6f8 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -1813,14 +1813,16 @@ type assignConsumerPubKeyAction struct { // reconfigureNode will change keys the node uses and restart reconfigureNode bool // executing the action should raise an error - expectError bool + expectError bool + expectedError string } func (tr TestRun) assignConsumerPubKey(action assignConsumerPubKeyAction, verbose bool) { valCfg := tr.validatorConfigs[action.validator] + // Note: to get error response reported back from this command '--gas auto' needs to be set. assignKey := fmt.Sprintf( - `%s tx provider assign-consensus-key %s '%s' --from validator%s --chain-id %s --home %s --node %s --gas 90000 --keyring-backend test -y -o json`, + `%s tx provider assign-consensus-key %s '%s' --from validator%s --chain-id %s --home %s --node %s --gas auto --keyring-backend test -y -o json`, tr.chainConfigs[chainID("provi")].binaryName, string(tr.chainConfigs[action.chain].chainId), action.consumerPubkey, @@ -1847,8 +1849,12 @@ func (tr TestRun) assignConsumerPubKey(action assignConsumerPubKeyAction, verbos } if action.expectError { + if err == nil || !strings.Contains(string(bz), action.expectedError) { + log.Fatalf("expected error not raised: expected: '%s', got '%s'", action.expectedError, (bz)) + } + if verbose { - fmt.Printf("got expected error during key assignment | err: %s \n", err.Error()) + fmt.Printf("got expected error during key assignment | err: %s | output: %s \n", err, string(bz)) } } diff --git a/tests/e2e/steps_start_chains.go b/tests/e2e/steps_start_chains.go index 15d0045760..6017a22641 100644 --- a/tests/e2e/steps_start_chains.go +++ b/tests/e2e/steps_start_chains.go @@ -88,6 +88,7 @@ func stepsStartConsumerChain(consumerName string, proposalIndex, chainIndex uint 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", }, state: State{}, }, @@ -100,6 +101,7 @@ func stepsStartConsumerChain(consumerName string, proposalIndex, chainIndex uint 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", }, state: State{ chainID(consumerName): ChainState{ From 4045b6a8fc9664c06156bdb4b98fb04aa8aa513f Mon Sep 17 00:00:00 2001 From: MSalopek Date: Wed, 9 Aug 2023 12:56:28 +0200 Subject: [PATCH 075/134] test: use cometmock in CI; run parallel jobs (#1181) * test: reduce number of happyPath steps * test: reduce number of happyPath steps * test: update steps after opt-out * test: update steps and fix lint * tests: add cometmock tests * chore: Fix and enable CometMock in e2e tests (#1184) * Add make time.sleep WaitTime and wait block after waiting time * Uncomment verbose error check * Fix spacing * Make format * Add make target for CometMock e2e tests * Add CometMock job to automated tests * tests: revert reducing happyPath steps count * tests: revert reducing happyPath steps count * Fix --gas auto with CometMock --------- Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Co-authored-by: Philip Offtermatt --- .github/workflows/automated-tests.yml | 26 ++++++++++++++++++++++++++ Makefile | 5 +++++ tests/e2e/actions.go | 15 ++++++++++++--- 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/.github/workflows/automated-tests.yml b/.github/workflows/automated-tests.yml index d48b8ef817..a9b594f53d 100644 --- a/.github/workflows/automated-tests.yml +++ b/.github/workflows/automated-tests.yml @@ -28,5 +28,31 @@ jobs: run: make proto-check - name: Unit, integration and difference tests run: go test ./... + E2E_Tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + lfs: true + - name: Checkout LFS objects + run: git lfs checkout + - name: Setup Go + uses: actions/setup-go@v4 + with: + go-version: "1.20" - name: E2E tests run: make test-e2e-short + Cometmock_Tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + lfs: true + - name: Checkout LFS objects + run: git lfs checkout + - name: Setup Go + uses: actions/setup-go@v4 + with: + go-version: "1.20" + - name: E2E tests + run: make test-e2e-short-cometmock diff --git a/Makefile b/Makefile index 28c02f7c85..7ab6a4fa24 100644 --- a/Makefile +++ b/Makefile @@ -33,6 +33,11 @@ test-diff: test-e2e-short: go run ./tests/e2e/... --happy-path-only +# run only happy path E2E tests with cometmock +# this set of traces does not test equivocation but it does check downtime +test-e2e-short-cometmock: + go run ./tests/e2e/... --short-happy-path --use-cometmock --use-gorelayer + # run full E2E tests in sequence (including multiconsumer) test-e2e-multi-consumer: go run ./tests/e2e/... --include-multi-consumer diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index faad8cb6f8..2cae615f70 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -538,7 +538,7 @@ func (tr *TestRun) voteGovProposal( wg.Wait() // wait for inclusion in a block -> '--broadcast-mode block' is deprecated tr.waitBlocks(action.chain, 1, 10*time.Second) - time.Sleep(time.Duration(tr.chainConfigs[action.chain].votingWaitTime) * time.Second) + tr.WaitTime(time.Duration(tr.chainConfigs[action.chain].votingWaitTime) * time.Second) } type startConsumerChainAction struct { @@ -1821,8 +1821,13 @@ func (tr TestRun) assignConsumerPubKey(action assignConsumerPubKeyAction, verbos valCfg := tr.validatorConfigs[action.validator] // 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" + } assignKey := fmt.Sprintf( - `%s tx provider assign-consensus-key %s '%s' --from validator%s --chain-id %s --home %s --node %s --gas auto --keyring-backend test -y -o json`, + `%s tx provider assign-consensus-key %s '%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.consumerPubkey, @@ -1830,6 +1835,7 @@ func (tr TestRun) assignConsumerPubKey(action assignConsumerPubKeyAction, verbos tr.chainConfigs[chainID("provi")].chainId, tr.getValidatorHome(chainID("provi"), action.validator), tr.getValidatorNode(chainID("provi"), action.validator), + gas, ) //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. @@ -1848,7 +1854,7 @@ func (tr TestRun) assignConsumerPubKey(action assignConsumerPubKeyAction, verbos log.Fatalf("unexpected error during key assignment - output: %s, err: %s", string(bz), err) } - if action.expectError { + if action.expectError && !tr.useCometmock { // error report ony works with --gas auto, which does not work with CometMock, so ignore if err == nil || !strings.Contains(string(bz), action.expectedError) { log.Fatalf("expected error not raised: expected: '%s', got '%s'", action.expectedError, (bz)) } @@ -1972,6 +1978,8 @@ func (tr TestRun) GetPathNameForGorelayer(chainA, chainB chainID) string { } // 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. // The CometMock version of this takes a pointer to the TestRun as it needs to manipulate // information in the testrun that stores how much each chain has waited, to keep times in sync. // Be careful that all functions calling WaitTime should therefore also take a pointer to the TestRun. @@ -1985,6 +1993,7 @@ func (tr *TestRun) WaitTime(duration time.Duration) { continue } tr.AdvanceTimeForChain(chain, duration) + tr.waitBlocks(chain, 1, 2*time.Second) } } } From 5cb2ffaec2771b2a52f7916c05c6014a42accdcd Mon Sep 17 00:00:00 2001 From: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Date: Thu, 10 Aug 2023 12:23:11 +0200 Subject: [PATCH 076/134] chore: Add integration for equivocation with CometMock (#1192) Add support for equivocation --- Makefile | 2 +- tests/e2e/actions.go | 58 +++++++++++++++++++++++++++++--------------- tests/e2e/main.go | 11 ++++----- tests/e2e/steps.go | 4 ++- 4 files changed, 47 insertions(+), 28 deletions(-) diff --git a/Makefile b/Makefile index 7ab6a4fa24..edbacbc0e0 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,7 @@ test-e2e-short: # run only happy path E2E tests with cometmock # this set of traces does not test equivocation but it does check downtime test-e2e-short-cometmock: - go run ./tests/e2e/... --short-happy-path --use-cometmock --use-gorelayer + go run ./tests/e2e/... --cometmock-happy-path --use-cometmock --use-gorelayer # run full E2E tests in sequence (including multiconsumer) test-e2e-multi-consumer: diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index 2cae615f70..e5ac465aa0 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -1604,18 +1604,7 @@ func (tr TestRun) setValidatorDowntime(chain chainID, validator validatorID, dow if tr.useCometmock { // send set_signing_status either to down or up for validator - var validatorAddress string - if chain == chainID("provi") { - validatorAddress = tr.getValidatorKeyAddressFromString(tr.validatorConfigs[validator].privValidatorKey) - } else { - var valAddressString string - if tr.validatorConfigs[validator].useConsumerKey { - valAddressString = tr.validatorConfigs[validator].consumerPrivValidatorKey - } else { - valAddressString = tr.validatorConfigs[validator].privValidatorKey - } - validatorAddress = tr.getValidatorKeyAddressFromString(valAddressString) - } + validatorAddress := tr.GetValidatorAddress(chain, validator) method := "set_signing_status" params := fmt.Sprintf(`{"private_key_address":"%s","status":"%s"}`, validatorAddress, lastArg) @@ -1648,6 +1637,22 @@ func (tr TestRun) setValidatorDowntime(chain chainID, validator validatorID, dow } } +func (tr TestRun) GetValidatorAddress(chain chainID, validator validatorID) string { + var validatorAddress string + if chain == chainID("provi") { + validatorAddress = tr.getValidatorKeyAddressFromString(tr.validatorConfigs[validator].privValidatorKey) + } else { + var valAddressString string + if tr.validatorConfigs[validator].useConsumerKey { + valAddressString = tr.validatorConfigs[validator].consumerPrivValidatorKey + } else { + valAddressString = tr.validatorConfigs[validator].privValidatorKey + } + validatorAddress = tr.getValidatorKeyAddressFromString(valAddressString) + } + return validatorAddress +} + type unjailValidatorAction struct { provider chainID validator validatorID @@ -1795,15 +1800,28 @@ func (tr TestRun) invokeDoublesignSlash( action doublesignSlashAction, verbose bool, ) { - chainConfig := tr.chainConfigs[action.chain] - //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - bz, err := exec.Command("docker", "exec", tr.containerConfig.instanceName, "/bin/bash", - "/testnet-scripts/cause-doublesign.sh", chainConfig.binaryName, string(action.validator), - string(chainConfig.chainId), chainConfig.ipPrefix).CombinedOutput() - if err != nil { - log.Fatal(err, "\n", string(bz)) + if !tr.useCometmock { + chainConfig := tr.chainConfigs[action.chain] + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + bz, err := exec.Command("docker", "exec", tr.containerConfig.instanceName, "/bin/bash", + "/testnet-scripts/cause-doublesign.sh", chainConfig.binaryName, string(action.validator), + string(chainConfig.chainId), chainConfig.ipPrefix).CombinedOutput() + if err != nil { + log.Fatal(err, "\n", string(bz)) + } + tr.waitBlocks("provi", 10, 2*time.Minute) + } else { // tr.useCometMock + validatorAddress := tr.GetValidatorAddress(action.chain, action.validator) + + method := "cause_double_sign" + params := fmt.Sprintf(`{"private_key_address":"%s"}`, validatorAddress) + + address := tr.getQueryNodeRPCAddress(action.chain) + + tr.curlJsonRPCRequest(method, params, address) + tr.waitBlocks(action.chain, 1, 10*time.Second) + return } - tr.waitBlocks("provi", 10, 2*time.Minute) } type assignConsumerPubKeyAction struct { diff --git a/tests/e2e/main.go b/tests/e2e/main.go index 9943d6f9bd..58bb065c26 100644 --- a/tests/e2e/main.go +++ b/tests/e2e/main.go @@ -16,12 +16,11 @@ import ( ) var ( - verbose = flag.Bool("verbose", false, "turn verbose logging on/off") - happyPathOnly = flag.Bool("happy-path-only", false, "run happy path tests only") - shortHappyPathOnly = flag.Bool("short-happy-path", false, `run abridged happy path tests only. + verbose = flag.Bool("verbose", false, "turn verbose logging on/off") + happyPathOnly = flag.Bool("happy-path-only", false, "run happy path tests only") + cometmockCompatibleHappyPath = flag.Bool("cometmock-happy-path", false, `run cometmock compatible happy path tests only. This is like the happy path, but skips steps that involve starting or stopping nodes for the same chain outside of the chain setup or teardown. -In particular, this skips steps related to downtime and double signing. This is suited for CometMock+Gorelayer testing`) includeMultiConsumer = flag.Bool("include-multi-consumer", false, "include multiconsumer tests in run") parallel = flag.Bool("parallel", false, "run all tests in parallel") @@ -42,10 +41,10 @@ var ( func main() { flag.Parse() - if shortHappyPathOnly != nil && *shortHappyPathOnly { + if cometmockCompatibleHappyPath != nil && *cometmockCompatibleHappyPath { fmt.Println("=============== running short happy path only ===============") tr := DefaultTestRun() - tr.Run(shortHappyPathSteps, *localSdkPath, *useGaia, *gaiaTag) + tr.Run(cometmockCompatibleHappyPathSteps, *localSdkPath, *useGaia, *gaiaTag) return } diff --git a/tests/e2e/steps.go b/tests/e2e/steps.go index aa08426103..770ac45dda 100644 --- a/tests/e2e/steps.go +++ b/tests/e2e/steps.go @@ -31,12 +31,14 @@ var happyPathSteps = concatSteps( stepsStopChain("consu", 4), // stop chain ) -var shortHappyPathSteps = concatSteps( +var cometmockCompatibleHappyPathSteps = concatSteps( stepsStartChains([]string{"consu"}, false), stepsDelegate("consu"), stepsUnbond("consu"), stepsRedelegateShort("consu"), stepsDowntime("consu"), + stepsRejectEquivocationProposal("consu", 2), // prop to tombstone bob is rejected + stepsDoubleSignOnProviderAndConsumer("consu"), // carol double signs on provider, bob double signs on consumer stepsStartRelayer(), stepsConsumerRemovalPropNotPassing("consu", 2), // submit removal prop but vote no on it - chain should stay stepsStopChain("consu", 3), // stop chain From fbbac82181dc43d76193aab694dd595079117cbb Mon Sep 17 00:00:00 2001 From: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Thu, 10 Aug 2023 09:08:17 -0700 Subject: [PATCH 077/134] feat!: throttle with retries, consumer changes (#1024) * wip * wip * bouncing slash constructor and nits * UT * define cross chain ack enum * wip * tests * tests * update genesis tests * comments * migration and changelog * migration test * lints * merge fixes * clean * Update ccv.pb.go * add to ADR * address some PR comments * rebuild protos * v3s * lint * regen pbs * refactor for simplicity * comment * changes with slash record type * wip * Update ccv.pb.go * Update ccv.pb.go * update SendPackets and test * test packet sending permitted * test for OnAckPacket * note on FSM design * CRUD UT * packet sending permitted UT * nits * Update throttle_retry.go * v1 result and change tests * Update relay.go * expectation func * reg test * Update CHANGELOG.md * lints * doc on upgrade order * small updates * vsc matured handled res * handle vsc matured acks * adjust TestSendPacketsDeletion * Update relay_test.go * fix integration test * fix send slash packet deletion test * fix TestConsumerPacketSendExpiredClient * lint * fix more tests * final test fixes * disable diff tests * smalls * Update steps_downtime.go * Update slashing.go * Update CHANGELOG.md * Update x/ccv/consumer/keeper/throttle_retry.go Co-authored-by: Marius Poke * Update throttle_retry.go * Update x/ccv/consumer/keeper/throttle_retry.go Co-authored-by: Marius Poke * docstrings * comment * DeleteHeadOfPendingPackets unit tests * fix dup deletion * better comment * const * rm todo and unneeded call * linting is very important * break instead of return * return instead of just print * fix test * fix slashing test * comment * camel case * FSM event explanation --------- Co-authored-by: Marius Poke --- CHANGELOG.md | 1 + docs/docs/adrs/adr-008-throttle-retries.md | 9 +- .../ccv/consumer/v1/consumer.proto | 8 + tests/difference/core/driver/core_test.go | 10 +- tests/e2e/steps_downtime.go | 43 ++- tests/integration/expired_client.go | 24 +- tests/integration/slashing.go | 72 +++- tests/integration/throttle_retry.go | 150 +++++++++ testutil/integration/debug_test.go | 8 + x/ccv/consumer/keeper/keeper.go | 11 + x/ccv/consumer/keeper/keeper_test.go | 27 ++ x/ccv/consumer/keeper/relay.go | 49 ++- x/ccv/consumer/keeper/relay_test.go | 225 +++++++++++-- x/ccv/consumer/keeper/throttle_retry.go | 112 ++++++ x/ccv/consumer/keeper/throttle_retry_test.go | 91 +++++ x/ccv/consumer/types/consumer.pb.go | 318 +++++++++++++++--- x/ccv/consumer/types/keys.go | 8 + x/ccv/consumer/types/keys_test.go | 2 + x/ccv/consumer/types/throttle_retry.go | 11 + x/ccv/provider/keeper/relay.go | 6 +- x/ccv/types/ccv.go | 14 + 21 files changed, 1077 insertions(+), 122 deletions(-) create mode 100644 tests/integration/throttle_retry.go create mode 100644 x/ccv/consumer/keeper/throttle_retry.go create mode 100644 x/ccv/consumer/keeper/throttle_retry_test.go create mode 100644 x/ccv/consumer/types/throttle_retry.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 5003260943..f5c4d215d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ Add an entry to the unreleased section whenever merging a PR to main that is not targeted at a specific release. These entries will eventually be included in a release. * `[x/ccv/provider]` (fix) [#1076](https://github.com/cosmos/interchain-security/pull/1076) Add `InitTimeoutTimestamps` and `ExportedVscSendTimestamps` to exported genesis. +* (feat!) [#1024](https://github.com/cosmos/interchain-security/pull/1024) throttle with retries, consumer changes * (fix!) revert consumer packet data changes from #1037 [#1150](https://github.com/cosmos/interchain-security/pull/1150) * (fix!) proper deletion of pending packets [#1146](https://github.com/cosmos/interchain-security/pull/1146) * (feat!) optimize pending packets storage on consumer, with migration! [#1037](https://github.com/cosmos/interchain-security/pull/1037) diff --git a/docs/docs/adrs/adr-008-throttle-retries.md b/docs/docs/adrs/adr-008-throttle-retries.md index 134214fffb..1faf7bd7ee 100644 --- a/docs/docs/adrs/adr-008-throttle-retries.md +++ b/docs/docs/adrs/adr-008-throttle-retries.md @@ -9,6 +9,7 @@ title: Throttle with retries * 6/9/23: Initial draft * 6/22/23: added note on consumer pending packets storage optimization +* 7/14/23: Added note on upgrade order ## Status @@ -47,6 +48,8 @@ With the behavior described, we maintain very similar behavior to the current th In the normal case, when no or a few slash packets are being sent, the VSCMaturedPackets will not be delayed, and hence unbonding will not be delayed. +For implementation of this design, see [throttle_retry.go](../../../x/ccv/consumer/keeper/throttle_retry.go). + ### Consumer pending packets storage optimization In addition to the mentioned consumer changes above. An optimization will need to be made to the consumer's pending packets storage to properly implement the feature from this ADR. @@ -86,9 +89,11 @@ If a consumer sends VSCMatured packets too leniently: The consumer is malicious If a consumer blocks the sending of VSCMatured packets: The consumer is malicious and blocking vsc matured packets that should have been sent. This will block unbonding only up until the VSC timeout period has elapsed. At that time, the consumer is removed. Again the malicious behavior only creates a negative outcome for the chain that is being malicious. -### Splitting of PRs +### Splitting of PRs and Upgrade Order + +This feature will implement consumer changes in [#1024](https://github.com/cosmos/interchain-security/pull/1024). Note these changes should be deployed to prod for all consumers before the provider changes are deployed to prod. That is the consumer changes in #1024 are compatible with the current ("v1") provider implementation of throttling that's running on the Cosmos Hub as of July 2023. -We could split this feature into two PRs, one affecting the consumer and one affecting the provider, along with a third PR which could setup a clever way to upgrade the provider in multiple steps, ensuring that queued slash packets at upgrade time are handled properly. +Once all consumers have deployed the changes in #1024, the provider changes from (TBD) can be deployed to prod, fully enabling v2 throttling. ## Consequences diff --git a/proto/interchain_security/ccv/consumer/v1/consumer.proto b/proto/interchain_security/ccv/consumer/v1/consumer.proto index 97ba14f6da..2b4b6f88c3 100644 --- a/proto/interchain_security/ccv/consumer/v1/consumer.proto +++ b/proto/interchain_security/ccv/consumer/v1/consumer.proto @@ -89,3 +89,11 @@ message MaturingVSCPacket { google.protobuf.Timestamp maturity_time = 2 [ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ]; } + +// A record storing the state of a slash packet sent to the provider chain +// which may bounce back and forth until handled by the provider. +message SlashRecord { + bool waiting_on_reply = 1; + google.protobuf.Timestamp send_time = 2 + [ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ]; +} \ No newline at end of file diff --git a/tests/difference/core/driver/core_test.go b/tests/difference/core/driver/core_test.go index 12192eb8e4..ec97fbf9c1 100644 --- a/tests/difference/core/driver/core_test.go +++ b/tests/difference/core/driver/core_test.go @@ -2,7 +2,6 @@ package core import ( "fmt" - "testing" "time" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" @@ -331,9 +330,12 @@ func (s *CoreSuite) TestTraces() { fmt.Println("Shortest [traceIx, actionIx]:", shortest, shortestLen) } -func TestCoreSuite(t *testing.T) { - suite.Run(t, new(CoreSuite)) -} +// TODO: diff tests will eventually be replaced by quint tests, and all this code could then be deleted. +// Until that decision is finalized, we'll just comment out the top-level test. + +// func TestCoreSuite(t *testing.T) { +// suite.Run(t, new(CoreSuite)) +// } // SetupTest sets up the test suite in a 'zero' state which matches // the initial state in the model. diff --git a/tests/e2e/steps_downtime.go b/tests/e2e/steps_downtime.go index 74cb349000..e6d320bec1 100644 --- a/tests/e2e/steps_downtime.go +++ b/tests/e2e/steps_downtime.go @@ -278,7 +278,7 @@ func stepsThrottledDowntime(consumerName string) []Step { validator: validatorID("bob"), }, state: State{ - // powers not affected on either chain yet + // slash packet queued on consumer, but powers not affected on either chain yet chainID("provi"): ChainState{ ValPowers: &map[validatorID]uint{ validatorID("alice"): 511, @@ -295,6 +295,39 @@ func stepsThrottledDowntime(consumerName string) []Step { }, }, }, + // Relay packets so bob is jailed on provider, + // and consumer receives ack that provider recv the downtime slash. + // The latter is necessary for the consumer to send the second downtime slash. + { + action: relayPacketsAction{ + chainA: chainID("provi"), + chainB: chainID(consumerName), + port: "provider", + channel: 0, + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 511, + validatorID("bob"): 0, // bob is jailed + validatorID("carol"): 500, + }, + // no provider throttling engaged yet + GlobalSlashQueueSize: uintPointer(0), + ConsumerChainQueueSizes: &map[chainID]uint{ + chainID(consumerName): uint(0), + }, + }, + chainID(consumerName): ChainState{ + // VSC packet applying jailing is not yet relayed to consumer + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 511, + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + }, + }, { action: downtimeSlashAction{ chain: chainID(consumerName), @@ -305,11 +338,12 @@ func stepsThrottledDowntime(consumerName string) []Step { chainID("provi"): ChainState{ ValPowers: &map[validatorID]uint{ validatorID("alice"): 511, - validatorID("bob"): 500, + validatorID("bob"): 0, validatorID("carol"): 500, }, }, chainID(consumerName): ChainState{ + // VSC packet applying jailing is not yet relayed to consumer ValPowers: &map[validatorID]uint{ validatorID("alice"): 511, validatorID("bob"): 500, @@ -338,10 +372,9 @@ func stepsThrottledDowntime(consumerName string) []Step { }, }, chainID(consumerName): ChainState{ - // no updates received on consumer ValPowers: &map[validatorID]uint{ validatorID("alice"): 511, - validatorID("bob"): 500, + validatorID("bob"): 0, validatorID("carol"): 500, }, }, @@ -373,7 +406,7 @@ func stepsThrottledDowntime(consumerName string) []Step { // no updates received on consumer ValPowers: &map[validatorID]uint{ validatorID("alice"): 511, - validatorID("bob"): 500, + validatorID("bob"): 0, validatorID("carol"): 500, }, }, diff --git a/tests/integration/expired_client.go b/tests/integration/expired_client.go index 53863d2881..2a8babacfa 100644 --- a/tests/integration/expired_client.go +++ b/tests/integration/expired_client.go @@ -139,20 +139,34 @@ func (s *CCVTestSuite) TestConsumerPacketSendExpiredClient() { // check that the packets were added to the list of pending data packets consumerPackets = consumerKeeper.GetPendingPackets(s.consumerCtx()) s.Require().NotEmpty(consumerPackets) + // At this point we expect 4 packets, two vsc matured packets and two trailing slash packets s.Require().Len(consumerPackets, 4, "unexpected number of pending data packets") // upgrade expired client to the consumer upgradeExpiredClient(s, Provider) - // go to next block to trigger SendPendingDataPackets + // go to next block to trigger SendPendingPackets s.consumerChain.NextBlock() - // check that the list of pending data packets is emptied + // Check that the leading vsc matured packets were sent and no longer pending consumerPackets = consumerKeeper.GetPendingPackets(s.consumerCtx()) - s.Require().Empty(consumerPackets) + s.Require().Len(consumerPackets, 2, "unexpected number of pending data packets") + + // relay committed packets from consumer to provider, first slash packet should be committed + relayAllCommittedPackets(s, s.consumerChain, s.path, ccv.ConsumerPortID, s.path.EndpointA.ChannelID, 3) // two vsc matured + one slash + + // First slash has been acked, now only the second slash packet should remain as pending + consumerPackets = consumerKeeper.GetPendingPackets(s.consumerCtx()) + s.Require().Len(consumerPackets, 1, "unexpected number of pending data packets") - // relay all packet from consumer to provider - relayAllCommittedPackets(s, s.consumerChain, s.path, ccv.ConsumerPortID, s.path.EndpointA.ChannelID, 4) + // go to next block to trigger SendPendingPackets + s.consumerChain.NextBlock() + + // relay committed packets from consumer to provider, only second slash packet should be committed + relayAllCommittedPackets(s, s.consumerChain, s.path, ccv.ConsumerPortID, s.path.EndpointA.ChannelID, 1) // one slash + + consumerPackets = consumerKeeper.GetPendingPackets(s.consumerCtx()) + s.Require().Empty(consumerPackets, "pending data packets found") // check that everything works // - bond more tokens on provider to change validator powers diff --git a/tests/integration/slashing.go b/tests/integration/slashing.go index 2bc960fd03..1ce7d11db8 100644 --- a/tests/integration/slashing.go +++ b/tests/integration/slashing.go @@ -247,14 +247,34 @@ func (s *CCVTestSuite) TestSlashPacketAcknowledgement() { s.SetupCCVChannel(s.path) s.SetupTransferChannel() - packet := channeltypes.NewPacket([]byte{}, 1, ccv.ConsumerPortID, s.path.EndpointA.ChannelID, + // Mock a proper slash packet from consumer + spd := keepertestutil.GetNewSlashPacketData() + + // We don't want truly randomized fields, infraction needs to be specified + if spd.Infraction == stakingtypes.Infraction_INFRACTION_UNSPECIFIED { + spd.Infraction = stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN + } + cpd := ccv.NewConsumerPacketData(ccv.SlashPacket, + &ccv.ConsumerPacketData_SlashPacketData{ + SlashPacketData: &spd, + }, + ) + packet := channeltypes.NewPacket(cpd.GetBytes(), // Consumer always sends v1 packet data + 1, ccv.ConsumerPortID, s.path.EndpointA.ChannelID, ccv.ProviderPortID, s.path.EndpointB.ChannelID, clienttypes.Height{}, 0) - ack := providerKeeper.OnRecvSlashPacket(s.providerCtx(), packet, - keepertestutil.GetNewSlashPacketData()) - s.Require().NotNil(ack) + // Map infraction height on provider so validation passes and provider returns valid ack result + providerKeeper.SetValsetUpdateBlockHeight(s.providerCtx(), spd.ValsetUpdateId, 47923) + + exportedAck := providerKeeper.OnRecvSlashPacket(s.providerCtx(), packet, spd) + s.Require().NotNil(exportedAck) - err := consumerKeeper.OnAcknowledgementPacket(s.consumerCtx(), packet, channeltypes.NewResultAcknowledgement(ack.Acknowledgement())) + // Unmarshal ack to struct that's compatible with consumer. IBC does this automatically + ack := channeltypes.Acknowledgement{} + err := channeltypes.SubModuleCdc.UnmarshalJSON(exportedAck.Acknowledgement(), &ack) + s.Require().NoError(err) + + err = consumerKeeper.OnAcknowledgementPacket(s.consumerCtx(), packet, ack) s.Require().NoError(err) err = consumerKeeper.OnAcknowledgementPacket(s.consumerCtx(), packet, ccv.NewErrorAcknowledgementWithLog(s.consumerCtx(), fmt.Errorf("another error"))) @@ -492,9 +512,15 @@ func (suite *CCVTestSuite) TestValidatorDowntime() { // clear queue, commit packets suite.consumerApp.GetConsumerKeeper().SendPackets(ctx) - // check queue was cleared + // Check slash record is created + slashRecord, found := suite.consumerApp.GetConsumerKeeper().GetSlashRecord(suite.consumerCtx()) + suite.Require().True(found, "slash record not found") + suite.Require().True(slashRecord.WaitingOnReply) + suite.Require().Equal(slashRecord.SendTime, suite.consumerCtx().BlockTime()) + + // check queue is not cleared, since no ack has been received from provider pendingPackets = suite.consumerApp.GetConsumerKeeper().GetPendingPackets(ctx) - suite.Require().Empty(pendingPackets, "pending packets NOT empty") + suite.Require().Len(pendingPackets, 1, "pending packets len should be 1 is %d", len(pendingPackets)) // verify that the slash packet was sent gotCommit := consumerIBCKeeper.ChannelKeeper.GetPacketCommitment(ctx, ccv.ConsumerPortID, channelID, seq) @@ -579,9 +605,15 @@ func (suite *CCVTestSuite) TestValidatorDoubleSigning() { // clear queue, commit packets suite.consumerApp.GetConsumerKeeper().SendPackets(ctx) - // check queue was cleared + // Check slash record is created + slashRecord, found := suite.consumerApp.GetConsumerKeeper().GetSlashRecord(suite.consumerCtx()) + suite.Require().True(found, "slash record not found") + suite.Require().True(slashRecord.WaitingOnReply) + suite.Require().Equal(slashRecord.SendTime, suite.consumerCtx().BlockTime()) + + // check queue is not cleared, since no ack has been received from provider pendingPackets = suite.consumerApp.GetConsumerKeeper().GetPendingPackets(ctx) - suite.Require().Empty(pendingPackets, "pending packets NOT empty") + suite.Require().Len(pendingPackets, 1, "pending packets len should be 1 is %d", len(pendingPackets)) // check slash packet is sent gotCommit := suite.consumerApp.GetIBCKeeper().ChannelKeeper.GetPacketCommitment(ctx, ccv.ConsumerPortID, channelID, seq) @@ -644,10 +676,12 @@ func (suite *CCVTestSuite) TestQueueAndSendSlashPacket() { // establish ccv channel by sending an empty VSC packet to consumer endpoint suite.SendEmptyVSCPacket() - // check that each pending data packet is sent once + // check that each pending data packet is sent once, as long as the prev slash packet was relayed/acked. + // Note that consumer throttling blocks packet sending until a slash packet is successfully acked by the provider. for i := 0; i < 12; i++ { commit := consumerIBCKeeper.ChannelKeeper.GetPacketCommitment(ctx, ccv.ConsumerPortID, channelID, seq+uint64(i)) suite.Require().NotNil(commit) + relayAllCommittedPackets(suite, suite.consumerChain, suite.path, ccv.ConsumerPortID, channelID, 1) } // check that outstanding downtime flags @@ -657,8 +691,8 @@ func (suite *CCVTestSuite) TestQueueAndSendSlashPacket() { suite.Require().True(consumerKeeper.OutstandingDowntime(ctx, consAddr)) } - // send all pending packets - only slash packets should be queued in this test - consumerKeeper.SendPackets(ctx) + // SendPackets method should have already been called during + // endblockers in relayAllCommittedPackets above // check that pending data packets got cleared dataPackets = consumerKeeper.GetPendingPackets(ctx) @@ -676,6 +710,10 @@ func (suite *CCVTestSuite) TestCISBeforeCCVEstablished() { pendingPackets := consumerKeeper.GetPendingPackets(suite.consumerCtx()) suite.Require().Len(pendingPackets, 0) + // No slash record found (no slash sent) + _, found := consumerKeeper.GetSlashRecord(suite.consumerCtx()) + suite.Require().False(found) + consumerKeeper.SlashWithInfractionReason(suite.consumerCtx(), []byte{0x01, 0x02, 0x3}, 66, 4324, sdk.MustNewDecFromStr("0.05"), stakingtypes.Infraction_INFRACTION_DOWNTIME) @@ -683,6 +721,10 @@ func (suite *CCVTestSuite) TestCISBeforeCCVEstablished() { pendingPackets = consumerKeeper.GetPendingPackets(suite.consumerCtx()) suite.Require().Len(pendingPackets, 1) + // but slash packet is not yet sent + _, found = consumerKeeper.GetSlashRecord(suite.consumerCtx()) + suite.Require().False(found) + // Pass 5 blocks, confirming the consumer doesn't panic for i := 0; i < 5; i++ { suite.consumerChain.NextBlock() @@ -698,6 +740,8 @@ func (suite *CCVTestSuite) TestCISBeforeCCVEstablished() { // Pass one more block, and confirm the packet is sent now that ccv channel is established suite.consumerChain.NextBlock() - pendingPackets = consumerKeeper.GetPendingPackets(suite.consumerCtx()) - suite.Require().Len(pendingPackets, 0) + + // Slash record should now be found (slash sent) + _, found = consumerKeeper.GetSlashRecord(suite.consumerCtx()) + suite.Require().True(found) } diff --git a/tests/integration/throttle_retry.go b/tests/integration/throttle_retry.go new file mode 100644 index 0000000000..ae15aac977 --- /dev/null +++ b/tests/integration/throttle_retry.go @@ -0,0 +1,150 @@ +package integration + +import ( + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + provider "github.com/cosmos/interchain-security/v3/x/ccv/provider" + providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" +) + +// TestSlashRetries tests the throttling v2 retry logic. Without provider changes, +// the consumer will queue up a slash packet, the provider will return a v1 result, +// and the consumer will never need to retry. +// +// Once provider changes are made (slash packet queuing is removed), the consumer may retry packets +// via new result acks from the provider. +// +// TODO: This test will need updating once provider changes are made. +func (s *CCVTestSuite) TestSlashRetries() { + s.SetupAllCCVChannels() + s.setupValidatorPowers() + + // + // Provider setup + // + providerKeeper := s.providerApp.GetProviderKeeper() + providerModule := provider.NewAppModule(&providerKeeper, s.providerApp.GetSubspace(providertypes.ModuleName)) + // Initialize slash meter + providerKeeper.InitializeSlashMeter(s.providerCtx()) + // Assert that we start out with no jailings + providerStakingKeeper := s.providerApp.GetTestStakingKeeper() + vals := providerStakingKeeper.GetAllValidators(s.providerCtx()) + for _, val := range vals { + s.Require().False(val.IsJailed()) + } + // Setup signing info for jailings + s.setDefaultValSigningInfo(*s.providerChain.Vals.Validators[1]) + + // + // Consumer setup + // + consumerKeeper := s.consumerApp.GetConsumerKeeper() + // Assert no slash record exists + _, found := consumerKeeper.GetSlashRecord(s.consumerCtx()) + s.Require().False(found) + + // + // Test section: See FSM explanation in throttle_retry.go + // + + // Construct a mock slash packet from consumer + tmval1 := s.providerChain.Vals.Validators[1] + packet1 := s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval1, stakingtypes.Infraction_INFRACTION_DOWNTIME, 1) + + // Mock the sending of the packet on consumer + consumerKeeper.AppendPendingPacket(s.consumerCtx(), ccvtypes.SlashPacket, + &ccvtypes.ConsumerPacketData_SlashPacketData{ + SlashPacketData: &ccvtypes.SlashPacketData{}, + }, + ) + consumerKeeper.UpdateSlashRecordOnSend(s.consumerCtx()) + slashRecord, found := consumerKeeper.GetSlashRecord(s.consumerCtx()) + s.Require().True(found) + s.Require().True(slashRecord.WaitingOnReply) + s.Require().Len(consumerKeeper.GetPendingPackets(s.consumerCtx()), 1) + + // Recv packet on provider and assert ack. Provider should return v1 result. + ack := providerModule.OnRecvPacket(s.providerCtx(), packet1, nil) + expectedv1Ack := channeltypes.NewResultAcknowledgement([]byte(ccvtypes.V1Result)) + s.Require().Equal(expectedv1Ack.Acknowledgement(), ack.Acknowledgement()) + + // Couple blocks pass on provider for provider staking keeper to process jailing + s.providerChain.NextBlock() + s.providerChain.NextBlock() + + // Default slash meter replenish fraction is 0.05, so packet should be handled on provider. + vals = s.providerApp.GetTestStakingKeeper().GetAllValidators(s.providerCtx()) + s.Require().True(vals[1].IsJailed()) + s.Require().Equal(int64(0), + s.providerApp.GetTestStakingKeeper().GetLastValidatorPower(s.providerCtx(), vals[1].GetOperator())) + s.Require().Equal(uint64(0), providerKeeper.GetThrottledPacketDataSize(s.providerCtx(), + s.getFirstBundle().Chain.ChainID)) + + // Now slash meter should be negative on provider + s.Require().True(s.providerApp.GetProviderKeeper().GetSlashMeter(s.providerCtx()).IsNegative()) + + // Apply ack back on consumer + ackForConsumer := expectedv1Ack + err := consumerKeeper.OnAcknowledgementPacket(s.consumerCtx(), packet1, ackForConsumer) + s.Require().NoError(err) + + // Slash record should have been deleted, head of pending packets should have been popped + // Since provider has handled the packet + _, found = consumerKeeper.GetSlashRecord(s.consumerCtx()) + s.Require().False(found) + s.Require().Empty(consumerKeeper.GetPendingPackets(s.consumerCtx())) + + // pass two blocks on provider and consumer for good measure + s.providerChain.NextBlock() + s.providerChain.NextBlock() + s.consumerChain.NextBlock() + s.consumerChain.NextBlock() + + // Construct and mock the sending of a second packet on consumer + tmval2 := s.providerChain.Vals.Validators[2] + packet2 := s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval2, stakingtypes.Infraction_INFRACTION_DOWNTIME, 1) + + consumerKeeper.AppendPendingPacket(s.consumerCtx(), ccvtypes.SlashPacket, + &ccvtypes.ConsumerPacketData_SlashPacketData{ + SlashPacketData: &ccvtypes.SlashPacketData{}, + }, + ) + consumerKeeper.UpdateSlashRecordOnSend(s.consumerCtx()) + slashRecord, found = consumerKeeper.GetSlashRecord(s.consumerCtx()) + s.Require().True(found) + s.Require().True(slashRecord.WaitingOnReply) + s.Require().Len(consumerKeeper.GetPendingPackets(s.consumerCtx()), 1) + + // Recv 2nd slash packet on provider for different validator. + // Provider should return the same v1 result ack even tho the packet was queued. + ack = providerModule.OnRecvPacket(s.providerCtx(), packet2, nil) + expectedv1Ack = channeltypes.NewResultAcknowledgement([]byte(ccvtypes.V1Result)) + s.Require().Equal(expectedv1Ack.Acknowledgement(), ack.Acknowledgement()) + + // Couple blocks pass on provider for staking keeper to process jailings + s.providerChain.NextBlock() + s.providerChain.NextBlock() + + // Val shouldn't be jailed on provider. Slash packet was queued + s.Require().False(vals[2].IsJailed()) + s.Require().Equal(int64(1000), + providerStakingKeeper.GetLastValidatorPower(s.providerCtx(), vals[2].GetOperator())) + s.Require().Equal(uint64(1), providerKeeper.GetThrottledPacketDataSize(s.providerCtx(), + s.getFirstBundle().Chain.ChainID)) + + // Apply ack on consumer + ackForConsumer = expectedv1Ack + err = consumerKeeper.OnAcknowledgementPacket(s.consumerCtx(), packet2, ackForConsumer) + s.Require().NoError(err) + + // TODO: when provider changes are made, slashRecord.WaitingOnReply should have been updated to false on consumer. Slash Packet will still be in consumer's pending packets queue. + + // Slash record should have been deleted, head of pending packets should have been popped + // Since provider has handled the packet + _, found = consumerKeeper.GetSlashRecord(s.consumerCtx()) + s.Require().False(found) + s.Require().Empty(consumerKeeper.GetPendingPackets(s.consumerCtx())) +} diff --git a/testutil/integration/debug_test.go b/testutil/integration/debug_test.go index 077f33cde3..828c9b6810 100644 --- a/testutil/integration/debug_test.go +++ b/testutil/integration/debug_test.go @@ -252,3 +252,11 @@ func TestQueueAndSendVSCMaturedPackets(t *testing.T) { func TestRecycleTransferChannel(t *testing.T) { runCCVTestByName(t, "TestRecycleTransferChannel") } + +// +// Throttle retry tests +// + +func TestSlashRetries(t *testing.T) { + runCCVTestByName(t, "TestSlashRetries") +} diff --git a/x/ccv/consumer/keeper/keeper.go b/x/ccv/consumer/keeper/keeper.go index e8b1cb793e..94d5c790fd 100644 --- a/x/ccv/consumer/keeper/keeper.go +++ b/x/ccv/consumer/keeper/keeper.go @@ -606,6 +606,17 @@ func (k Keeper) getAndIncrementPendingPacketsIdx(ctx sdk.Context) (toReturn uint return toReturn } +// DeleteHeadOfPendingPackets deletes the head of the pending packets queue. +func (k Keeper) DeleteHeadOfPendingPackets(ctx sdk.Context) { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, []byte{types.PendingDataPacketsBytePrefix}) + defer iterator.Close() + if !iterator.Valid() { + return + } + store.Delete(iterator.Key()) +} + // GetPendingPackets returns ALL the pending CCV packets from the store without indexes. func (k Keeper) GetPendingPackets(ctx sdk.Context) []ccv.ConsumerPacketData { ppWithIndexes := k.GetAllPendingPacketsWithIdx(ctx) diff --git a/x/ccv/consumer/keeper/keeper_test.go b/x/ccv/consumer/keeper/keeper_test.go index 269c60d9c5..06fdeae082 100644 --- a/x/ccv/consumer/keeper/keeper_test.go +++ b/x/ccv/consumer/keeper/keeper_test.go @@ -579,3 +579,30 @@ func TestPrevStandaloneChainFlag(t *testing.T) { ck.MarkAsPrevStandaloneChain(ctx) require.True(t, ck.IsPrevStandaloneChain(ctx)) } + +func TestDeleteHeadOfPendingPackets(t *testing.T) { + consumerKeeper, ctx, ctrl, _ := testkeeper.GetConsumerKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + // append some pending packets + consumerKeeper.AppendPendingPacket(ctx, ccv.VscMaturedPacket, &ccv.ConsumerPacketData_VscMaturedPacketData{}) + consumerKeeper.AppendPendingPacket(ctx, ccv.SlashPacket, &ccv.ConsumerPacketData_SlashPacketData{}) + consumerKeeper.AppendPendingPacket(ctx, ccv.VscMaturedPacket, &ccv.ConsumerPacketData_VscMaturedPacketData{}) + + // Check there's 3 pending packets, vsc matured at head + pp := consumerKeeper.GetPendingPackets(ctx) + require.Len(t, pp, 3) + require.Equal(t, pp[0].Type, ccv.VscMaturedPacket) + + // Delete the head, confirm slash packet is now at head + consumerKeeper.DeleteHeadOfPendingPackets(ctx) + pp = consumerKeeper.GetPendingPackets(ctx) + require.Len(t, pp, 2) + require.Equal(t, pp[0].Type, ccv.SlashPacket) + + // Delete the head, confirm vsc matured packet is now at head + consumerKeeper.DeleteHeadOfPendingPackets(ctx) + pp = consumerKeeper.GetPendingPackets(ctx) + require.Len(t, pp, 1) + require.Equal(t, pp[0].Type, ccv.VscMaturedPacket) +} diff --git a/x/ccv/consumer/keeper/relay.go b/x/ccv/consumer/keeper/relay.go index 376110f26d..060aadff20 100644 --- a/x/ccv/consumer/keeper/relay.go +++ b/x/ccv/consumer/keeper/relay.go @@ -188,8 +188,11 @@ func (k Keeper) SendPackets(ctx sdk.Context) { pending := k.GetAllPendingPacketsWithIdx(ctx) idxsForDeletion := []uint64{} for _, p := range pending { + if !k.PacketSendingPermitted(ctx) { + break + } - // send packet over IBC + // Send packet over IBC err := ccv.SendIBCPacket( ctx, k.scopedKeeper, @@ -213,6 +216,16 @@ func (k Keeper) SendPackets(ctx sdk.Context) { k.Logger(ctx).Error("cannot send IBC packet; leaving packet data stored:", "type", p.Type.String(), "err", err.Error()) break } + // If the packet that was just sent was a Slash packet, set the waiting on slash reply flag. + // This flag will be toggled false again when consumer hears back from provider. See OnAcknowledgementPacket below. + if p.Type == ccv.SlashPacket { + k.UpdateSlashRecordOnSend(ctx) + // Break so slash stays at head of queue. + // This blocks the sending of any other packet until the leading slash packet is handled. + // Also see OnAcknowledgementPacket below which will eventually delete the leading slash packet. + break + } + // Otherwise the vsc matured will be deleted idxsForDeletion = append(idxsForDeletion, p.Idx) } // Delete pending packets that were successfully sent and did not return an error from SendIBCPacket @@ -223,6 +236,40 @@ func (k Keeper) SendPackets(ctx sdk.Context) { // in conjunction with the ibc module's execution of "acknowledgePacket", // according to https://github.com/cosmos/ibc/tree/main/spec/core/ics-004-channel-and-packet-semantics#processing-acknowledgements func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Packet, ack channeltypes.Acknowledgement) error { + if res := ack.GetResult(); res != nil { + if len(res) != 1 { + return fmt.Errorf("acknowledgement result length must be 1, got %d", len(res)) + } + + // Unmarshal into V1 consumer packet data type. We trust data is formed correctly + // as it was originally marshalled by this module, and consumers must trust the provider + // did not tamper with the data. Note ConsumerPacketData.GetBytes() always JSON marshals to the + // ConsumerPacketDataV1 type which is sent over the wire. + var consumerPacket ccv.ConsumerPacketDataV1 + ccv.ModuleCdc.MustUnmarshalJSON(packet.GetData(), &consumerPacket) + // If this ack is regarding a provider handling a vsc matured packet, there's nothing to do. + // As vsc matured packets are popped from the consumer pending packets queue on send. + if consumerPacket.Type == ccv.VscMaturedPacket { + return nil + } + + // Otherwise we handle the result of the slash packet acknowledgement. + switch res[0] { + // We treat a v1 result as the provider successfully queuing the slash packet w/o need for retry. + case ccv.V1Result[0]: + k.ClearSlashRecord(ctx) // Clears slash record state, unblocks sending of pending packets. + k.DeleteHeadOfPendingPackets(ctx) // Remove slash from head of queue. It's been handled. + case ccv.SlashPacketHandledResult[0]: + k.ClearSlashRecord(ctx) // Clears slash record state, unblocks sending of pending packets. + k.DeleteHeadOfPendingPackets(ctx) // Remove slash from head of queue. It's been handled. + case ccv.SlashPacketBouncedResult[0]: + k.UpdateSlashRecordOnBounce(ctx) + // Note slash is still at head of queue and will now be retried after appropriate delay period. + default: + return fmt.Errorf("unrecognized acknowledgement result: %c", res[0]) + } + } + if err := ack.GetError(); err != "" { // Reasons for ErrorAcknowledgment // - packet data could not be successfully decoded diff --git a/x/ccv/consumer/keeper/relay_test.go b/x/ccv/consumer/keeper/relay_test.go index ed6771900e..09cf987fc0 100644 --- a/x/ccv/consumer/keeper/relay_test.go +++ b/x/ccv/consumer/keeper/relay_test.go @@ -14,6 +14,7 @@ import ( cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" @@ -22,6 +23,7 @@ import ( "github.com/cosmos/interchain-security/v3/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" + consumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" "github.com/cosmos/interchain-security/v3/x/ccv/types" ) @@ -210,10 +212,105 @@ func TestOnRecvVSCPacketDuplicateUpdates(t *testing.T) { require.Equal(t, valUpdates[1], gotPendingChanges.ValidatorUpdates[0]) // Only latest update should be kept } -// TestOnAcknowledgementPacket tests application logic for acknowledgments of sent VSCMatured and Slash packets +// TestSendPackets tests the SendPackets method failing +func TestSendPacketsFailure(t *testing.T) { + // Keeper setup + consumerKeeper, ctx, ctrl, mocks := testkeeper.GetConsumerKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + consumerKeeper.SetProviderChannel(ctx, "consumerCCVChannelID") + consumerKeeper.SetParams(ctx, consumertypes.DefaultParams()) + + // Set some pending packets + consumerKeeper.AppendPendingPacket(ctx, types.VscMaturedPacket, &types.ConsumerPacketData_VscMaturedPacketData{}) + consumerKeeper.AppendPendingPacket(ctx, types.SlashPacket, &types.ConsumerPacketData_SlashPacketData{}) + consumerKeeper.AppendPendingPacket(ctx, types.VscMaturedPacket, &types.ConsumerPacketData_VscMaturedPacketData{}) + + // Mock the channel keeper to return an error + gomock.InOrder( + mocks.MockChannelKeeper.EXPECT().GetChannel(ctx, types.ConsumerPortID, + "consumerCCVChannelID").Return(channeltypes.Channel{}, false).Times(1), + ) + + // No panic should occur, pending packets should not be cleared + consumerKeeper.SendPackets(ctx) + require.Equal(t, 3, len(consumerKeeper.GetPendingPackets(ctx))) +} + +func TestSendPackets(t *testing.T) { + // Keeper setup + consumerKeeper, ctx, ctrl, mocks := testkeeper.GetConsumerKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + consumerKeeper.SetProviderChannel(ctx, "consumerCCVChannelID") + consumerKeeper.SetParams(ctx, consumertypes.DefaultParams()) + + // No slash record should exist + _, found := consumerKeeper.GetSlashRecord(ctx) + require.False(t, found) + require.True(t, consumerKeeper.PacketSendingPermitted(ctx)) + + // Queue up two vsc matured, followed by slash, followed by vsc matured + consumerKeeper.AppendPendingPacket(ctx, types.VscMaturedPacket, &types.ConsumerPacketData_VscMaturedPacketData{ + VscMaturedPacketData: &types.VSCMaturedPacketData{ + ValsetUpdateId: 77, + }, + }) + consumerKeeper.AppendPendingPacket(ctx, types.VscMaturedPacket, &types.ConsumerPacketData_VscMaturedPacketData{ + VscMaturedPacketData: &types.VSCMaturedPacketData{ + ValsetUpdateId: 90, + }, + }) + consumerKeeper.AppendPendingPacket(ctx, types.SlashPacket, &types.ConsumerPacketData_SlashPacketData{ + SlashPacketData: &types.SlashPacketData{ + Validator: abci.Validator{}, + ValsetUpdateId: 88, + Infraction: stakingtypes.Infraction_INFRACTION_DOWNTIME, + }, + }) + consumerKeeper.AppendPendingPacket(ctx, types.VscMaturedPacket, &types.ConsumerPacketData_VscMaturedPacketData{ + VscMaturedPacketData: &types.VSCMaturedPacketData{ + ValsetUpdateId: 99, + }, + }) + + // First two vsc matured and slash should be sent, 3 total + gomock.InAnyOrder( + testkeeper.GetMocksForSendIBCPacket(ctx, mocks, "consumerCCVChannelID", 3), + ) + consumerKeeper.SendPackets(ctx) + ctrl.Finish() + + // First two packets should be deleted, slash should be at head of queue + pendingPackets := consumerKeeper.GetPendingPackets(ctx) + require.Equal(t, 2, len(pendingPackets)) + require.Equal(t, types.SlashPacket, pendingPackets[0].Type) + require.Equal(t, types.VscMaturedPacket, pendingPackets[1].Type) + + // Packet sending not permitted + require.False(t, consumerKeeper.PacketSendingPermitted(ctx)) + + // Now delete slash record as would be done by a recv SlashPacketHandledResult + // then confirm last vsc matured is sent + consumerKeeper.ClearSlashRecord(ctx) + consumerKeeper.DeleteHeadOfPendingPackets(ctx) + + // Packet sending permitted + require.True(t, consumerKeeper.PacketSendingPermitted(ctx)) + + gomock.InAnyOrder( + testkeeper.GetMocksForSendIBCPacket(ctx, mocks, "consumerCCVChannelID", 1), + ) + + consumerKeeper.SendPackets(ctx) + ctrl.Finish() + + // No packets should be left + pendingPackets = consumerKeeper.GetPendingPackets(ctx) + require.Equal(t, 0, len(pendingPackets)) +} + +// TestOnAcknowledgementPacketError tests application logic for ERROR acknowledgments of sent VSCMatured and Slash packets // in conjunction with the ibc module's execution of "acknowledgePacket", // according to https://github.com/cosmos/ibc/tree/main/spec/core/ics-004-channel-and-packet-semantics#processing-acknowledgements -func TestOnAcknowledgementPacket(t *testing.T) { +func TestOnAcknowledgementPacketError(t *testing.T) { // Channel ID to some dest chain that's not the established provider channelIDToDestChain := "channelIDToDestChain" @@ -258,12 +355,6 @@ func TestOnAcknowledgementPacket(t *testing.T) { uint64(time.Now().Add(60*time.Second).UnixNano()), ) - ack := channeltypes.NewResultAcknowledgement([]byte{1}) - - // expect no error returned from OnAcknowledgementPacket, no input error with ack - err := consumerKeeper.OnAcknowledgementPacket(ctx, packet, ack) - require.Nil(t, err) - // Still expect no error returned from OnAcknowledgementPacket, // but the input error ack will be handled with appropriate ChanCloseInit calls dummyCap := &capabilitytypes.Capability{} @@ -287,33 +378,91 @@ func TestOnAcknowledgementPacket(t *testing.T) { ).Return(nil).Times(1), ) - ack = types.NewErrorAcknowledgementWithLog(ctx, fmt.Errorf("error")) - err = consumerKeeper.OnAcknowledgementPacket(ctx, packet, ack) + ack := types.NewErrorAcknowledgementWithLog(ctx, fmt.Errorf("error")) + err := consumerKeeper.OnAcknowledgementPacket(ctx, packet, ack) require.Nil(t, err) } -// TestSendPackets tests the SendPackets method failing -func TestSendPacketsFailure(t *testing.T) { - // Keeper setup - consumerKeeper, ctx, ctrl, mocks := testkeeper.GetConsumerKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) +// TestOnAcknowledgementPacketResult tests application logic for RESULT acknowledgments of sent VSCMatured and Slash packets +// in conjunction with the ibc module's execution of "acknowledgePacket", +func TestOnAcknowledgementPacketResult(t *testing.T) { + // Setup + consumerKeeper, ctx, ctrl, _ := testkeeper.GetConsumerKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - consumerKeeper.SetProviderChannel(ctx, "consumerCCVChannelID") - consumerKeeper.SetParams(ctx, consumertypes.DefaultParams()) - // Set some pending packets - consumerKeeper.AppendPendingPacket(ctx, types.VscMaturedPacket, &types.ConsumerPacketData_VscMaturedPacketData{}) - consumerKeeper.AppendPendingPacket(ctx, types.SlashPacket, &types.ConsumerPacketData_SlashPacketData{}) - consumerKeeper.AppendPendingPacket(ctx, types.VscMaturedPacket, &types.ConsumerPacketData_VscMaturedPacketData{}) + setupSlashBeforeVscMatured(ctx, &consumerKeeper) - // Mock the channel keeper to return an error - gomock.InOrder( - mocks.MockChannelKeeper.EXPECT().GetChannel(ctx, types.ConsumerPortID, - "consumerCCVChannelID").Return(channeltypes.Channel{}, false).Times(1), - ) + // Slash record found, 2 pending packets, slash is at head of queue + _, found := consumerKeeper.GetSlashRecord(ctx) + require.True(t, found) + pendingPackets := consumerKeeper.GetPendingPackets(ctx) + require.Len(t, pendingPackets, 2) + require.Equal(t, types.SlashPacket, pendingPackets[0].Type) - // No panic should occur, pending packets should not be cleared - consumerKeeper.SendPackets(ctx) - require.Equal(t, 3, len(consumerKeeper.GetPendingPackets(ctx))) + // v1 result should delete slash record and head of pending packets. Vsc matured remains + ack := channeltypes.NewResultAcknowledgement(types.V1Result) + packet := channeltypes.Packet{Data: pendingPackets[0].GetBytes()} + err := consumerKeeper.OnAcknowledgementPacket(ctx, packet, ack) + require.Nil(t, err) + _, found = consumerKeeper.GetSlashRecord(ctx) + require.False(t, found) + require.Len(t, consumerKeeper.GetPendingPackets(ctx), 1) + require.Equal(t, types.VscMaturedPacket, consumerKeeper.GetPendingPackets(ctx)[0].Type) + + // refresh state + setupSlashBeforeVscMatured(ctx, &consumerKeeper) + pendingPackets = consumerKeeper.GetPendingPackets(ctx) + packet = channeltypes.Packet{Data: pendingPackets[0].GetBytes()} + + // Slash packet handled result should delete slash record and head of pending packets + ack = channeltypes.NewResultAcknowledgement(types.SlashPacketHandledResult) + err = consumerKeeper.OnAcknowledgementPacket(ctx, packet, ack) + require.Nil(t, err) + _, found = consumerKeeper.GetSlashRecord(ctx) + require.False(t, found) + require.Len(t, consumerKeeper.GetPendingPackets(ctx), 1) + require.Equal(t, types.VscMaturedPacket, consumerKeeper.GetPendingPackets(ctx)[0].Type) + + // refresh state + setupSlashBeforeVscMatured(ctx, &consumerKeeper) + pendingPackets = consumerKeeper.GetPendingPackets(ctx) + packet = channeltypes.Packet{Data: pendingPackets[0].GetBytes()} + + slashRecordBefore, found := consumerKeeper.GetSlashRecord(ctx) + require.True(t, found) + require.True(t, slashRecordBefore.WaitingOnReply) + + // Slash packet bounced result should update slash record + ack = channeltypes.NewResultAcknowledgement(types.SlashPacketBouncedResult) + err = consumerKeeper.OnAcknowledgementPacket(ctx, packet, ack) + require.Nil(t, err) + slashRecordAfter, found := consumerKeeper.GetSlashRecord(ctx) + require.True(t, found) + require.False(t, slashRecordAfter.WaitingOnReply) // waiting on reply toggled false + require.Equal(t, slashRecordAfter.SendTime.UnixNano(), + slashRecordBefore.SendTime.UnixNano()) // send time NOT updated. Bounce result shouldn't affect that +} + +func setupSlashBeforeVscMatured(ctx sdk.Context, k *consumerkeeper.Keeper) { + // clear old state + k.ClearSlashRecord(ctx) + k.DeleteAllPendingDataPackets(ctx) + + // Set some related state to test against + k.SetSlashRecord(ctx, consumertypes.SlashRecord{WaitingOnReply: true, SendTime: time.Now()}) + // Slash packet before VSCMatured packet + k.AppendPendingPacket(ctx, types.SlashPacket, &types.ConsumerPacketData_SlashPacketData{ // Slash appears first + SlashPacketData: &types.SlashPacketData{ + Validator: abci.Validator{}, + ValsetUpdateId: 88, + Infraction: stakingtypes.Infraction_INFRACTION_DOWNTIME, + }, + }) + k.AppendPendingPacket(ctx, types.VscMaturedPacket, &types.ConsumerPacketData_VscMaturedPacketData{ + VscMaturedPacketData: &types.VSCMaturedPacketData{ + ValsetUpdateId: 90, + }, + }) } // Regression test for https://github.com/cosmos/interchain-security/issues/1145 @@ -324,7 +473,12 @@ func TestSendPacketsDeletion(t *testing.T) { consumerKeeper.SetProviderChannel(ctx, "consumerCCVChannelID") consumerKeeper.SetParams(ctx, consumertypes.DefaultParams()) - // Queue two pending packets + // Queue two pending packets, vsc matured first + consumerKeeper.AppendPendingPacket(ctx, types.VscMaturedPacket, &types.ConsumerPacketData_VscMaturedPacketData{ + VscMaturedPacketData: &types.VSCMaturedPacketData{ + ValsetUpdateId: 90, + }, + }) consumerKeeper.AppendPendingPacket(ctx, types.SlashPacket, &types.ConsumerPacketData_SlashPacketData{ // Slash appears first SlashPacketData: &types.SlashPacketData{ Validator: abci.Validator{}, @@ -332,15 +486,10 @@ func TestSendPacketsDeletion(t *testing.T) { Infraction: stakingtypes.Infraction_INFRACTION_DOWNTIME, }, }) - consumerKeeper.AppendPendingPacket(ctx, types.VscMaturedPacket, &types.ConsumerPacketData_VscMaturedPacketData{ - VscMaturedPacketData: &types.VSCMaturedPacketData{ - ValsetUpdateId: 90, - }, - }) - // Get mocks for a successful SendPacket call that does NOT return an error + // Get mocks for the (first) successful SendPacket call that does NOT return an error expectations := testkeeper.GetMocksForSendIBCPacket(ctx, mocks, "consumerCCVChannelID", 1) - // Append mocks for a failed SendPacket call, which returns an error + // Append mocks for the (second) failed SendPacket call, which returns an error expectations = append(expectations, mocks.MockChannelKeeper.EXPECT().GetChannel(ctx, types.ConsumerPortID, "consumerCCVChannelID").Return(channeltypes.Channel{}, false).Times(1)) gomock.InOrder(expectations...) @@ -349,5 +498,7 @@ func TestSendPacketsDeletion(t *testing.T) { // Expect the first successfully sent packet to be popped from queue require.Equal(t, 1, len(consumerKeeper.GetPendingPackets(ctx))) - require.Equal(t, types.VscMaturedPacket, consumerKeeper.GetPendingPackets(ctx)[0].Type) + + // Expect the slash packet to remain + require.Equal(t, types.SlashPacket, consumerKeeper.GetPendingPackets(ctx)[0].Type) } diff --git a/x/ccv/consumer/keeper/throttle_retry.go b/x/ccv/consumer/keeper/throttle_retry.go new file mode 100644 index 0000000000..4c4585cb1d --- /dev/null +++ b/x/ccv/consumer/keeper/throttle_retry.go @@ -0,0 +1,112 @@ +package keeper + +import ( + "fmt" + "time" + + sdktypes "github.com/cosmos/cosmos-sdk/types" + + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" +) + +// +// Throttling with retries follows a finite-state machine design: +// +// 2 states: "No Slash" and "Standby". +// Initial State: "No Slash" +// Transition Event: ("No Slash", Slash packet sent) => ("Standby") +// Transition Event: ("Standby", V1Result ack received) => ("No Slash") +// Transition Event: ("Standby", Slash packet successfully handled) => ("No Slash") +// Internal Transition Event: ("Standby", Slash packet bounced) => ("Standby", with SlashRecord.WaitingOnReply = false) +// Transition Event: ("Standby", Retry sent) => ("Standby", new cycle) +// +// Description in words: +// +// 1. "No slash": If no slash record exists, the consumer is permitted to send packets from the pending packets queue. +// The consumer starts in this state from genesis. +// +// 2. On the event that a slash packet is obtained from the head of the pending packets queue and sent, +// a consumer transitions from "No Slash" to "Standby". A slash record is created upon entry to this state, +// and the consumer is now restricted from sending anymore packets. +// +// The slash packet remains at the head of the pending packets queue within the "Standby" state. +// +// - If the consumer receives a V1Result ack from the provider, +// OR if the consumer receives an ack from the provider that the slash packet was successfully handled, +// the consumer transitions from "Standby" to "No Slash". +// The slash record is cleared upon this transition, and the slash packet is popped from the pending packets queue. +// +// - Else if the consumer receives an ack from the provider that the slash packet was bounced (not handled), +// then SlashRecord.WaitingOnReply is set false, and the consumer retries sending the slash packet after a delay period. +// +// Once a retry is sent, the consumer enters a new cycle of the "Standby" state and the process repeats. +// +// This design is implemented below, and in relay.go under SendPackets() and OnAcknowledgementPacket(). +// + +// Retry delay period could be implemented as a param, but 1 hour is reasonable +const RetryDelayPeriod = time.Hour + +// PacketSendingPermitted returns whether the consumer is allowed to send packets +// from the pending packets queue. +func (k Keeper) PacketSendingPermitted(ctx sdktypes.Context) bool { + record, found := k.GetSlashRecord(ctx) + if !found { + // no slash record exists, send is permitted + return true + } + if record.WaitingOnReply { + // We are waiting on a reply from provider, block sending + return false + } + // If retry delay period has elapsed, we can send again + return ctx.BlockTime().After(record.SendTime.Add(RetryDelayPeriod)) +} + +func (k Keeper) UpdateSlashRecordOnSend(ctx sdktypes.Context) { + record := consumertypes.NewSlashRecord( + ctx.BlockTime(), // sendTime + true, // waitingOnReply + ) + // We don't mind overwriting here, since this is either a retry or the first time we send a slash + k.SetSlashRecord(ctx, record) +} + +func (k Keeper) UpdateSlashRecordOnBounce(ctx sdktypes.Context) { + record, found := k.GetSlashRecord(ctx) + if !found { + // This should never happen + panic("could not find slash record, but reply was received from provider") + } + record.WaitingOnReply = false + k.SetSlashRecord(ctx, record) +} + +func (k Keeper) GetSlashRecord(ctx sdktypes.Context) (record consumertypes.SlashRecord, found bool) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(consumertypes.SlashRecordKey()) + if bz == nil { + return record, false + } + err := record.Unmarshal(bz) + if err != nil { + // This should never happen + panic(fmt.Sprintf("could not unmarshal slash record: %v", err)) + } + return record, true +} + +func (k Keeper) SetSlashRecord(ctx sdktypes.Context, record consumertypes.SlashRecord) { + store := ctx.KVStore(k.storeKey) + bz, err := record.Marshal() + if err != nil { + // This should never happen + panic(fmt.Sprintf("could not marshal slash record: %v", err)) + } + store.Set(consumertypes.SlashRecordKey(), bz) +} + +func (k Keeper) ClearSlashRecord(ctx sdktypes.Context) { + store := ctx.KVStore(k.storeKey) + store.Delete(consumertypes.SlashRecordKey()) +} diff --git a/x/ccv/consumer/keeper/throttle_retry_test.go b/x/ccv/consumer/keeper/throttle_retry_test.go new file mode 100644 index 0000000000..cc14ce3cdd --- /dev/null +++ b/x/ccv/consumer/keeper/throttle_retry_test.go @@ -0,0 +1,91 @@ +package keeper_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + + testutil "github.com/cosmos/interchain-security/v3/testutil/keeper" + consumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" +) + +func TestPacketSendingPermitted(t *testing.T) { + consumerKeeper, ctx, ctrl, _ := testutil.GetConsumerKeeperAndCtx(t, testutil.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + ctx = ctx.WithBlockTime(time.Now()) + + // No slash record exists, send is permitted + slashRecord, found := consumerKeeper.GetSlashRecord(ctx) + require.False(t, found) + require.Zero(t, slashRecord) + require.True(t, consumerKeeper.PacketSendingPermitted(ctx)) + + // Update slash record on sending of slash packet + consumerKeeper.UpdateSlashRecordOnSend(ctx) + slashRecord, found = consumerKeeper.GetSlashRecord(ctx) + require.True(t, found) + require.True(t, slashRecord.WaitingOnReply) + + // Packet sending not permitted since we're waiting on a reply from provider + require.False(t, consumerKeeper.PacketSendingPermitted(ctx)) + + // Call update that happens when provider bounces slash packet + consumerKeeper.UpdateSlashRecordOnBounce(ctx) + slashRecord, found = consumerKeeper.GetSlashRecord(ctx) + require.True(t, found) + require.False(t, slashRecord.WaitingOnReply) + + // Packet sending still not permitted since retry delay period has not elapsed + require.False(t, consumerKeeper.PacketSendingPermitted(ctx)) + + // Elapse retry delay period + ctx = ctx.WithBlockTime(ctx.BlockTime().Add(2 * consumerkeeper.RetryDelayPeriod)) + + // Now packet sending is permitted again + require.True(t, consumerKeeper.PacketSendingPermitted(ctx)) +} + +func TestThrottleRetryCRUD(t *testing.T) { + consumerKeeper, ctx, ctrl, _ := testutil.GetConsumerKeeperAndCtx(t, testutil.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + slashRecord, found := consumerKeeper.GetSlashRecord(ctx) + require.False(t, found) + require.Zero(t, slashRecord) + + consumerKeeper.SetSlashRecord(ctx, consumertypes.SlashRecord{ + WaitingOnReply: true, + SendTime: ctx.BlockTime(), + }) + + slashRecord, found = consumerKeeper.GetSlashRecord(ctx) + require.True(t, found) + require.True(t, slashRecord.WaitingOnReply) + require.Equal(t, ctx.BlockTime(), slashRecord.SendTime) + + // UpdateSlashRecordOnBounce should set WaitingOnReply to false, and leave SendTime unchanged + oldBlocktime := ctx.BlockTime() + ctx = ctx.WithBlockTime(ctx.BlockTime().Add(time.Hour)) + consumerKeeper.UpdateSlashRecordOnBounce(ctx) + slashRecord, found = consumerKeeper.GetSlashRecord(ctx) + require.True(t, found) + require.False(t, slashRecord.WaitingOnReply) + require.Equal(t, oldBlocktime, slashRecord.SendTime) // Old SendTime expected + + // UpdateSlashRecordOnSend should replace slash record with WaitingOnReply set to true, and new SendTime + ctx = ctx.WithBlockTime(ctx.BlockTime().Add(time.Hour)) + consumerKeeper.UpdateSlashRecordOnSend(ctx) + slashRecord, found = consumerKeeper.GetSlashRecord(ctx) + require.True(t, found) + require.True(t, slashRecord.WaitingOnReply) + require.Equal(t, ctx.BlockTime(), slashRecord.SendTime) // New SendTime expected + require.Equal(t, oldBlocktime.Add(2*time.Hour), slashRecord.SendTime) // Sanity check + + consumerKeeper.ClearSlashRecord(ctx) + slashRecord, found = consumerKeeper.GetSlashRecord(ctx) + require.False(t, found) + require.Zero(t, slashRecord) +} diff --git a/x/ccv/consumer/types/consumer.pb.go b/x/ccv/consumer/types/consumer.pb.go index 90d5d6e12b..b16b561b7b 100644 --- a/x/ccv/consumer/types/consumer.pb.go +++ b/x/ccv/consumer/types/consumer.pb.go @@ -354,11 +354,66 @@ func (m *MaturingVSCPacket) GetMaturityTime() time.Time { return time.Time{} } +// A record storing the state of a slash packet sent to the provider chain +// which may bounce back and forth until handled by the provider. +type SlashRecord struct { + WaitingOnReply bool `protobuf:"varint,1,opt,name=waiting_on_reply,json=waitingOnReply,proto3" json:"waiting_on_reply,omitempty"` + SendTime time.Time `protobuf:"bytes,2,opt,name=send_time,json=sendTime,proto3,stdtime" json:"send_time"` +} + +func (m *SlashRecord) Reset() { *m = SlashRecord{} } +func (m *SlashRecord) String() string { return proto.CompactTextString(m) } +func (*SlashRecord) ProtoMessage() {} +func (*SlashRecord) Descriptor() ([]byte, []int) { + return fileDescriptor_5b27a82b276e7f93, []int{4} +} +func (m *SlashRecord) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SlashRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_SlashRecord.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 *SlashRecord) XXX_Merge(src proto.Message) { + xxx_messageInfo_SlashRecord.Merge(m, src) +} +func (m *SlashRecord) XXX_Size() int { + return m.Size() +} +func (m *SlashRecord) XXX_DiscardUnknown() { + xxx_messageInfo_SlashRecord.DiscardUnknown(m) +} + +var xxx_messageInfo_SlashRecord proto.InternalMessageInfo + +func (m *SlashRecord) GetWaitingOnReply() bool { + if m != nil { + return m.WaitingOnReply + } + return false +} + +func (m *SlashRecord) GetSendTime() time.Time { + if m != nil { + return m.SendTime + } + return time.Time{} +} + func init() { proto.RegisterType((*Params)(nil), "interchain_security.ccv.consumer.v1.Params") proto.RegisterType((*LastTransmissionBlockHeight)(nil), "interchain_security.ccv.consumer.v1.LastTransmissionBlockHeight") proto.RegisterType((*CrossChainValidator)(nil), "interchain_security.ccv.consumer.v1.CrossChainValidator") proto.RegisterType((*MaturingVSCPacket)(nil), "interchain_security.ccv.consumer.v1.MaturingVSCPacket") + proto.RegisterType((*SlashRecord)(nil), "interchain_security.ccv.consumer.v1.SlashRecord") } func init() { @@ -366,57 +421,60 @@ func init() { } var fileDescriptor_5b27a82b276e7f93 = []byte{ - // 786 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0xcf, 0x6e, 0xdb, 0x36, - 0x18, 0x8f, 0x96, 0xd6, 0x4d, 0x98, 0x14, 0x6b, 0x59, 0x2f, 0x55, 0x33, 0x40, 0x76, 0xdd, 0x1e, - 0x7c, 0x89, 0x84, 0x26, 0xdb, 0xa5, 0xc0, 0x0e, 0xb5, 0xb3, 0xa2, 0xdd, 0xbf, 0x78, 0xaa, 0xd1, - 0x01, 0xdb, 0x81, 0xa0, 0x28, 0x5a, 0x22, 0x22, 0x91, 0x02, 0x49, 0xa9, 0xd3, 0x7d, 0x0f, 0xd0, - 0xe3, 0x1e, 0x61, 0x0f, 0xb0, 0x87, 0x28, 0x76, 0xea, 0x71, 0xa7, 0x6e, 0x48, 0xde, 0x60, 0x4f, - 0x30, 0x90, 0x92, 0x5c, 0x3b, 0x6d, 0x80, 0xdc, 0xf8, 0xe9, 0xf7, 0xfb, 0x7e, 0xfa, 0xfe, 0x83, - 0x43, 0xc6, 0x35, 0x95, 0x24, 0xc5, 0x8c, 0x23, 0x45, 0x49, 0x29, 0x99, 0xae, 0x03, 0x42, 0xaa, - 0x80, 0x08, 0xae, 0xca, 0x9c, 0xca, 0xa0, 0x7a, 0xb4, 0x7c, 0xfb, 0x85, 0x14, 0x5a, 0xc0, 0x07, - 0x1f, 0xf1, 0xf1, 0x09, 0xa9, 0xfc, 0x25, 0xaf, 0x7a, 0xb4, 0xff, 0xf0, 0x32, 0x61, 0xa3, 0x47, - 0xaa, 0x46, 0x6a, 0xff, 0x5e, 0x22, 0x44, 0x92, 0xd1, 0xc0, 0x5a, 0x51, 0xb9, 0x08, 0x30, 0xaf, - 0x5b, 0xa8, 0x9f, 0x88, 0x44, 0xd8, 0x67, 0x60, 0x5e, 0x9d, 0x03, 0x11, 0x2a, 0x17, 0x0a, 0x35, - 0x40, 0x63, 0xb4, 0x90, 0x77, 0x51, 0x2b, 0x2e, 0x25, 0xd6, 0x4c, 0xf0, 0x16, 0x1f, 0x5c, 0xc4, - 0x35, 0xcb, 0xa9, 0xd2, 0x38, 0x2f, 0x1a, 0xc2, 0xe8, 0xb7, 0x1e, 0xe8, 0xcd, 0xb0, 0xc4, 0xb9, - 0x82, 0x2e, 0xb8, 0x41, 0x39, 0x8e, 0x32, 0x1a, 0xbb, 0xce, 0xd0, 0x19, 0x6f, 0x85, 0x9d, 0x09, - 0x4f, 0xc0, 0xc3, 0x28, 0x13, 0xe4, 0x54, 0xa1, 0x82, 0x4a, 0x14, 0x33, 0xa5, 0x25, 0x8b, 0x4a, - 0xf3, 0x1b, 0xa4, 0x25, 0xe6, 0x2a, 0x67, 0x4a, 0x31, 0xc1, 0xdd, 0x4f, 0x86, 0xce, 0x78, 0x33, - 0xbc, 0xdf, 0x70, 0x67, 0x54, 0x1e, 0xaf, 0x30, 0xe7, 0x2b, 0x44, 0xf8, 0x0d, 0xb8, 0x7f, 0xa9, - 0x0a, 0x22, 0x29, 0xe6, 0x9c, 0x66, 0xee, 0xe6, 0xd0, 0x19, 0x6f, 0x87, 0x83, 0xf8, 0x12, 0x91, - 0x69, 0x43, 0x83, 0x8f, 0xc1, 0x7e, 0x21, 0x45, 0xc5, 0x62, 0x2a, 0xd1, 0x82, 0x52, 0x54, 0x08, - 0x91, 0x21, 0x1c, 0xc7, 0x12, 0x29, 0x2d, 0xdd, 0x6b, 0x56, 0x64, 0xaf, 0x63, 0x3c, 0xa5, 0x74, - 0x26, 0x44, 0xf6, 0x24, 0x8e, 0xe5, 0x0b, 0x2d, 0xe1, 0x8f, 0x00, 0x12, 0x52, 0x21, 0x53, 0x14, - 0x51, 0x6a, 0x93, 0x1d, 0x13, 0xb1, 0x7b, 0x7d, 0xe8, 0x8c, 0x77, 0x0e, 0xef, 0xf9, 0x4d, 0xed, - 0xfc, 0xae, 0x76, 0xfe, 0x71, 0x5b, 0xdb, 0xc9, 0xd6, 0x9b, 0x77, 0x83, 0x8d, 0xdf, 0xff, 0x19, - 0x38, 0xe1, 0x2d, 0x42, 0xaa, 0x79, 0xe3, 0x3d, 0xb3, 0xce, 0xf0, 0x17, 0x70, 0xd7, 0x66, 0xb3, - 0xa0, 0xf2, 0xa2, 0x6e, 0xef, 0xea, 0xba, 0x9f, 0x75, 0x1a, 0xeb, 0xe2, 0xcf, 0xc0, 0xb0, 0x9b, - 0x37, 0x24, 0xe9, 0x5a, 0x09, 0x17, 0x12, 0x13, 0xf3, 0x70, 0x6f, 0xd8, 0x8c, 0xbd, 0x8e, 0x17, - 0xae, 0xd1, 0x9e, 0xb6, 0x2c, 0x78, 0x00, 0x60, 0xca, 0x94, 0x16, 0x92, 0x11, 0x9c, 0x21, 0xca, - 0xb5, 0x64, 0x54, 0xb9, 0x5b, 0xb6, 0x81, 0xb7, 0xdf, 0x23, 0x5f, 0x37, 0x00, 0xfc, 0x01, 0xdc, - 0x2a, 0x79, 0x24, 0x78, 0xcc, 0x78, 0xd2, 0xa5, 0xb3, 0x7d, 0xf5, 0x74, 0x3e, 0x5d, 0x3a, 0xb7, - 0x89, 0x1c, 0x81, 0x3d, 0x25, 0x16, 0x1a, 0x89, 0x42, 0x23, 0x53, 0x21, 0x9d, 0x4a, 0xaa, 0x52, - 0x91, 0xc5, 0x2e, 0xb0, 0xe1, 0xdf, 0x31, 0xe8, 0x49, 0xa1, 0x4f, 0x4a, 0x3d, 0xef, 0x20, 0xf8, - 0x00, 0xdc, 0x94, 0xf4, 0x15, 0x96, 0x31, 0x8a, 0x29, 0x17, 0xb9, 0x72, 0x77, 0x86, 0x9b, 0xe3, - 0xed, 0x70, 0xb7, 0xf9, 0x78, 0x6c, 0xbf, 0xc1, 0x2f, 0xc0, 0xb2, 0xd9, 0x68, 0x9d, 0xbd, 0x6b, - 0xd9, 0xfd, 0x0e, 0x0d, 0x57, 0xbc, 0x46, 0x5f, 0x82, 0xcf, 0xbf, 0xc3, 0x4a, 0xaf, 0xce, 0xd7, - 0xc4, 0x4c, 0xf1, 0x33, 0xca, 0x92, 0x54, 0xc3, 0x3d, 0xd0, 0x4b, 0xed, 0xcb, 0x6e, 0xc6, 0x66, - 0xd8, 0x5a, 0xa3, 0x3f, 0x1c, 0x70, 0x67, 0x2a, 0x85, 0x52, 0x53, 0xb3, 0xf3, 0x2f, 0x71, 0xc6, - 0x62, 0xac, 0x85, 0x34, 0xab, 0x64, 0x26, 0x90, 0x2a, 0x65, 0x1d, 0x76, 0xc3, 0xce, 0x84, 0x7d, - 0x70, 0xbd, 0x10, 0xaf, 0xa8, 0x6c, 0x77, 0xa5, 0x31, 0x20, 0x06, 0xbd, 0xa2, 0x8c, 0x4e, 0x69, - 0x6d, 0x87, 0x7e, 0xe7, 0xb0, 0xff, 0x41, 0x51, 0x9f, 0xf0, 0x7a, 0x72, 0xf4, 0xdf, 0xbb, 0xc1, - 0xdd, 0x1a, 0xe7, 0xd9, 0xe3, 0x91, 0xe9, 0x2e, 0xe5, 0xaa, 0x54, 0xa8, 0xf1, 0x1b, 0xfd, 0xf5, - 0xe7, 0x41, 0xbf, 0xbd, 0x0c, 0x44, 0xd6, 0x85, 0x16, 0xfe, 0xac, 0x8c, 0xbe, 0xa5, 0x75, 0xd8, - 0x0a, 0x8f, 0x34, 0xb8, 0xfd, 0x3d, 0xd6, 0xa5, 0x64, 0x3c, 0x79, 0xf9, 0x62, 0x3a, 0xc3, 0xe4, - 0x94, 0x6a, 0x13, 0x4d, 0xa5, 0xc8, 0xf3, 0x66, 0xe1, 0xaf, 0x85, 0x8d, 0x01, 0x9f, 0x83, 0x9b, - 0xb9, 0xa5, 0xea, 0xda, 0x8e, 0xb0, 0x8d, 0x75, 0xe7, 0x70, 0xff, 0x83, 0xa0, 0xe6, 0xdd, 0x31, - 0x69, 0x5a, 0xfd, 0xda, 0xb4, 0x7a, 0xb7, 0x73, 0x35, 0xe0, 0xe4, 0xa7, 0x37, 0x67, 0x9e, 0xf3, - 0xf6, 0xcc, 0x73, 0xfe, 0x3d, 0xf3, 0x9c, 0xd7, 0xe7, 0xde, 0xc6, 0xdb, 0x73, 0x6f, 0xe3, 0xef, - 0x73, 0x6f, 0xe3, 0xe7, 0xaf, 0x12, 0xa6, 0xd3, 0x32, 0xf2, 0x89, 0xc8, 0xdb, 0x93, 0x16, 0xbc, - 0xbf, 0x9e, 0x07, 0xcb, 0xeb, 0x59, 0x1d, 0x05, 0xbf, 0xae, 0xdf, 0x66, 0x5d, 0x17, 0x54, 0x45, - 0x3d, 0x1b, 0xc4, 0xd1, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0x26, 0xe0, 0xb8, 0xdf, 0xcc, 0x05, - 0x00, 0x00, + // 836 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0xcf, 0x6e, 0xdb, 0x36, + 0x18, 0x8f, 0x96, 0xd6, 0x4d, 0xe8, 0x74, 0x4b, 0x59, 0x2f, 0x55, 0x33, 0xc0, 0x76, 0xdd, 0x1e, + 0x7c, 0x89, 0x8d, 0x26, 0xdb, 0xa5, 0xc0, 0x0e, 0xf9, 0xb3, 0xa2, 0xdd, 0xbf, 0x78, 0x4a, 0xd0, + 0x01, 0xdb, 0x81, 0xa0, 0xa8, 0xcf, 0x16, 0x11, 0x89, 0x14, 0x48, 0x4a, 0x99, 0x76, 0xde, 0x03, + 0xf4, 0xb8, 0x47, 0xd8, 0x03, 0xec, 0x21, 0x8a, 0x9d, 0x7a, 0xdc, 0xa9, 0x1b, 0x92, 0x37, 0xd8, + 0x13, 0x0c, 0xa4, 0x24, 0xd7, 0x4e, 0x17, 0xa0, 0xbb, 0xf1, 0xe3, 0xef, 0x8f, 0xf8, 0x7d, 0xfc, + 0xf8, 0x09, 0xed, 0x72, 0x61, 0x40, 0xb1, 0x98, 0x72, 0x41, 0x34, 0xb0, 0x5c, 0x71, 0x53, 0x8e, + 0x19, 0x2b, 0xc6, 0x4c, 0x0a, 0x9d, 0xa7, 0xa0, 0xc6, 0xc5, 0xe3, 0xf9, 0x7a, 0x94, 0x29, 0x69, + 0x24, 0x7e, 0xf8, 0x1f, 0x9a, 0x11, 0x63, 0xc5, 0x68, 0xce, 0x2b, 0x1e, 0x6f, 0x3f, 0xba, 0xce, + 0xd8, 0xfa, 0xb1, 0xa2, 0xb2, 0xda, 0xbe, 0x3f, 0x93, 0x72, 0x96, 0xc0, 0xd8, 0x45, 0x61, 0x3e, + 0x1d, 0x53, 0x51, 0xd6, 0x50, 0x67, 0x26, 0x67, 0xd2, 0x2d, 0xc7, 0x76, 0xd5, 0x08, 0x98, 0xd4, + 0xa9, 0xd4, 0xa4, 0x02, 0xaa, 0xa0, 0x86, 0xba, 0x57, 0xbd, 0xa2, 0x5c, 0x51, 0xc3, 0xa5, 0xa8, + 0xf1, 0xde, 0x55, 0xdc, 0xf0, 0x14, 0xb4, 0xa1, 0x69, 0x56, 0x11, 0x06, 0xbf, 0xb4, 0x50, 0x6b, + 0x42, 0x15, 0x4d, 0x35, 0xf6, 0xd1, 0x2d, 0x10, 0x34, 0x4c, 0x20, 0xf2, 0xbd, 0xbe, 0x37, 0x5c, + 0x0b, 0x9a, 0x10, 0x1f, 0xa3, 0x47, 0x61, 0x22, 0xd9, 0x99, 0x26, 0x19, 0x28, 0x12, 0x71, 0x6d, + 0x14, 0x0f, 0x73, 0xfb, 0x19, 0x62, 0x14, 0x15, 0x3a, 0xe5, 0x5a, 0x73, 0x29, 0xfc, 0x0f, 0xfa, + 0xde, 0x70, 0x35, 0x78, 0x50, 0x71, 0x27, 0xa0, 0x8e, 0x16, 0x98, 0xa7, 0x0b, 0x44, 0xfc, 0x25, + 0x7a, 0x70, 0xad, 0x0b, 0x61, 0x31, 0x15, 0x02, 0x12, 0x7f, 0xb5, 0xef, 0x0d, 0xd7, 0x83, 0x5e, + 0x74, 0x8d, 0xc9, 0x61, 0x45, 0xc3, 0x4f, 0xd0, 0x76, 0xa6, 0x64, 0xc1, 0x23, 0x50, 0x64, 0x0a, + 0x40, 0x32, 0x29, 0x13, 0x42, 0xa3, 0x48, 0x11, 0x6d, 0x94, 0x7f, 0xc3, 0x99, 0x6c, 0x35, 0x8c, + 0xa7, 0x00, 0x13, 0x29, 0x93, 0xfd, 0x28, 0x52, 0x27, 0x46, 0xe1, 0xef, 0x10, 0x66, 0xac, 0x20, + 0xb6, 0x28, 0x32, 0x37, 0x36, 0x3b, 0x2e, 0x23, 0xff, 0x66, 0xdf, 0x1b, 0xb6, 0x77, 0xef, 0x8f, + 0xaa, 0xda, 0x8d, 0x9a, 0xda, 0x8d, 0x8e, 0xea, 0xda, 0x1e, 0xac, 0xbd, 0x7a, 0xd3, 0x5b, 0xf9, + 0xf5, 0xaf, 0x9e, 0x17, 0x6c, 0x32, 0x56, 0x9c, 0x56, 0xea, 0x89, 0x13, 0xe3, 0x1f, 0xd1, 0x3d, + 0x97, 0xcd, 0x14, 0xd4, 0x55, 0xdf, 0xd6, 0xfb, 0xfb, 0x7e, 0xdc, 0x78, 0x2c, 0x9b, 0x3f, 0x43, + 0xfd, 0xa6, 0xdf, 0x88, 0x82, 0xa5, 0x12, 0x4e, 0x15, 0x65, 0x76, 0xe1, 0xdf, 0x72, 0x19, 0x77, + 0x1b, 0x5e, 0xb0, 0x44, 0x7b, 0x5a, 0xb3, 0xf0, 0x0e, 0xc2, 0x31, 0xd7, 0x46, 0x2a, 0xce, 0x68, + 0x42, 0x40, 0x18, 0xc5, 0x41, 0xfb, 0x6b, 0xee, 0x02, 0xef, 0xbc, 0x45, 0xbe, 0xa8, 0x00, 0xfc, + 0x2d, 0xda, 0xcc, 0x45, 0x28, 0x45, 0xc4, 0xc5, 0xac, 0x49, 0x67, 0xfd, 0xfd, 0xd3, 0xf9, 0x68, + 0x2e, 0xae, 0x13, 0xd9, 0x43, 0x5b, 0x5a, 0x4e, 0x0d, 0x91, 0x99, 0x21, 0xb6, 0x42, 0x26, 0x56, + 0xa0, 0x63, 0x99, 0x44, 0x3e, 0x72, 0xc7, 0xbf, 0x6b, 0xd1, 0xe3, 0xcc, 0x1c, 0xe7, 0xe6, 0xb4, + 0x81, 0xf0, 0x43, 0x74, 0x5b, 0xc1, 0x39, 0x55, 0x11, 0x89, 0x40, 0xc8, 0x54, 0xfb, 0xed, 0xfe, + 0xea, 0x70, 0x3d, 0xd8, 0xa8, 0x36, 0x8f, 0xdc, 0x1e, 0xfe, 0x14, 0xcd, 0x2f, 0x9b, 0x2c, 0xb3, + 0x37, 0x1c, 0xbb, 0xd3, 0xa0, 0xc1, 0x82, 0x6a, 0xf0, 0x19, 0xfa, 0xe4, 0x6b, 0xaa, 0xcd, 0x62, + 0x7f, 0x1d, 0xd8, 0x2e, 0x7e, 0x06, 0x7c, 0x16, 0x1b, 0xbc, 0x85, 0x5a, 0xb1, 0x5b, 0xb9, 0x97, + 0xb1, 0x1a, 0xd4, 0xd1, 0xe0, 0x37, 0x0f, 0xdd, 0x3d, 0x54, 0x52, 0xeb, 0x43, 0xfb, 0xe6, 0x5f, + 0xd0, 0x84, 0x47, 0xd4, 0x48, 0x65, 0x9f, 0x92, 0xed, 0x40, 0xd0, 0xda, 0x09, 0x36, 0x82, 0x26, + 0xc4, 0x1d, 0x74, 0x33, 0x93, 0xe7, 0xa0, 0xea, 0xb7, 0x52, 0x05, 0x98, 0xa2, 0x56, 0x96, 0x87, + 0x67, 0x50, 0xba, 0xa6, 0x6f, 0xef, 0x76, 0xde, 0x29, 0xea, 0xbe, 0x28, 0x0f, 0xf6, 0xfe, 0x79, + 0xd3, 0xbb, 0x57, 0xd2, 0x34, 0x79, 0x32, 0xb0, 0xb7, 0x0b, 0x42, 0xe7, 0x9a, 0x54, 0xba, 0xc1, + 0x1f, 0xbf, 0xef, 0x74, 0xea, 0xc9, 0xc0, 0x54, 0x99, 0x19, 0x39, 0x9a, 0xe4, 0xe1, 0x57, 0x50, + 0x06, 0xb5, 0xf1, 0xc0, 0xa0, 0x3b, 0xdf, 0x50, 0x93, 0x2b, 0x2e, 0x66, 0x2f, 0x4e, 0x0e, 0x27, + 0x94, 0x9d, 0x81, 0xb1, 0xa7, 0x29, 0x34, 0x7b, 0x5e, 0x3d, 0xf8, 0x1b, 0x41, 0x15, 0xe0, 0xe7, + 0xe8, 0x76, 0xea, 0xa8, 0xa6, 0x74, 0x2d, 0xec, 0xce, 0xda, 0xde, 0xdd, 0x7e, 0xe7, 0x50, 0xa7, + 0xcd, 0x30, 0xa9, 0xae, 0xfa, 0xa5, 0xbd, 0xea, 0x8d, 0x46, 0x6a, 0xc1, 0xc1, 0xcf, 0xa8, 0x7d, + 0x92, 0x50, 0x1d, 0x07, 0xc0, 0xa4, 0x8a, 0xf0, 0x10, 0x6d, 0x9e, 0x53, 0x6e, 0x6c, 0x13, 0x49, + 0x41, 0x14, 0x64, 0x49, 0x59, 0xcf, 0x9a, 0x0f, 0xeb, 0xfd, 0x63, 0x11, 0xd8, 0x5d, 0xbc, 0x8f, + 0xd6, 0x35, 0x88, 0xe8, 0xff, 0x7f, 0x7f, 0xcd, 0xca, 0x2c, 0x70, 0xf0, 0xfd, 0xab, 0x8b, 0xae, + 0xf7, 0xfa, 0xa2, 0xeb, 0xfd, 0x7d, 0xd1, 0xf5, 0x5e, 0x5e, 0x76, 0x57, 0x5e, 0x5f, 0x76, 0x57, + 0xfe, 0xbc, 0xec, 0xae, 0xfc, 0xf0, 0xf9, 0x8c, 0x9b, 0x38, 0x0f, 0x47, 0x4c, 0xa6, 0xf5, 0x38, + 0x1d, 0xbf, 0x9d, 0xdc, 0x3b, 0xf3, 0xc9, 0x5d, 0xec, 0x8d, 0x7f, 0x5a, 0xfe, 0x2f, 0x98, 0x32, + 0x03, 0x1d, 0xb6, 0xdc, 0x01, 0xf6, 0xfe, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x61, 0xb7, 0xcd, 0x97, + 0x48, 0x06, 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -643,6 +701,47 @@ func (m *MaturingVSCPacket) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *SlashRecord) 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 *SlashRecord) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SlashRecord) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + n6, err6 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.SendTime, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.SendTime):]) + if err6 != nil { + return 0, err6 + } + i -= n6 + i = encodeVarintConsumer(dAtA, i, uint64(n6)) + i-- + dAtA[i] = 0x12 + if m.WaitingOnReply { + i-- + if m.WaitingOnReply { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func encodeVarintConsumer(dAtA []byte, offset int, v uint64) int { offset -= sovConsumer(v) base := offset @@ -752,6 +851,20 @@ func (m *MaturingVSCPacket) Size() (n int) { return n } +func (m *SlashRecord) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.WaitingOnReply { + n += 2 + } + l = github_com_cosmos_gogoproto_types.SizeOfStdTime(m.SendTime) + n += 1 + l + sovConsumer(uint64(l)) + return n +} + func sovConsumer(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1467,6 +1580,109 @@ func (m *MaturingVSCPacket) Unmarshal(dAtA []byte) error { } return nil } +func (m *SlashRecord) 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 ErrIntOverflowConsumer + } + 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: SlashRecord: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SlashRecord: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field WaitingOnReply", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowConsumer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.WaitingOnReply = bool(v != 0) + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SendTime", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowConsumer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthConsumer + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthConsumer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(&m.SendTime, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipConsumer(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthConsumer + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipConsumer(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/ccv/consumer/types/keys.go b/x/ccv/consumer/types/keys.go index 8b792419ef..b755cf9f5a 100644 --- a/x/ccv/consumer/types/keys.go +++ b/x/ccv/consumer/types/keys.go @@ -102,6 +102,9 @@ const ( // This index is used for implementing a FIFO queue of pending packets in the KV store. PendingPacketsIndexByteKey + // SlashRecordByteKey is the single byte key storing the consumer's slash record. + SlashRecordByteKey + // NOTE: DO NOT ADD NEW BYTE PREFIXES HERE WITHOUT ADDING THEM TO getAllKeyPrefixes() IN keys_test.go ) @@ -218,6 +221,11 @@ func PendingPacketsIndexKey() []byte { return []byte{PendingPacketsIndexByteKey} } +// SlashRecordKey returns the key storing the consumer's slash record. +func SlashRecordKey() []byte { + return []byte{SlashRecordByteKey} +} + // NOTE: DO NOT ADD FULLY DEFINED KEY FUNCTIONS WITHOUT ADDING THEM TO getAllFullyDefinedKeys() IN keys_test.go // diff --git a/x/ccv/consumer/types/keys_test.go b/x/ccv/consumer/types/keys_test.go index 5290dd3599..a8cebee284 100644 --- a/x/ccv/consumer/types/keys_test.go +++ b/x/ccv/consumer/types/keys_test.go @@ -42,6 +42,7 @@ func getAllKeyPrefixes() []byte { StandaloneTransferChannelIDByteKey, PrevStandaloneChainByteKey, PendingPacketsIndexByteKey, + SlashRecordByteKey, } } @@ -79,5 +80,6 @@ func getAllFullyDefinedKeys() [][]byte { StandaloneTransferChannelIDKey(), PrevStandaloneChainKey(), PendingPacketsIndexKey(), + SlashRecordKey(), } } diff --git a/x/ccv/consumer/types/throttle_retry.go b/x/ccv/consumer/types/throttle_retry.go new file mode 100644 index 0000000000..9ea179ffe4 --- /dev/null +++ b/x/ccv/consumer/types/throttle_retry.go @@ -0,0 +1,11 @@ +package types + +import time "time" + +// NewSlashRecord creates a new slash record +func NewSlashRecord(sendTime time.Time, waitingOnReply bool) (record SlashRecord) { + return SlashRecord{ + SendTime: sendTime, + WaitingOnReply: true, + } +} diff --git a/x/ccv/provider/keeper/relay.go b/x/ccv/provider/keeper/relay.go index df4fdb98ce..d63594dad1 100644 --- a/x/ccv/provider/keeper/relay.go +++ b/x/ccv/provider/keeper/relay.go @@ -44,7 +44,7 @@ func (k Keeper) OnRecvVSCMaturedPacket( "vscID", data.ValsetUpdateId, ) - ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) + ack := channeltypes.NewResultAcknowledgement(ccv.V1Result) return ack } @@ -355,7 +355,7 @@ func (k Keeper) OnRecvSlashPacket(ctx sdk.Context, packet channeltypes.Packet, d // return successful ack, as an error would result // in the consumer closing the CCV channel - return channeltypes.NewResultAcknowledgement([]byte{byte(1)}) + return channeltypes.NewResultAcknowledgement(ccv.V1Result) } // Queue a slash entry to the global queue, which will be seen by the throttling logic @@ -379,7 +379,7 @@ func (k Keeper) OnRecvSlashPacket(ctx sdk.Context, packet channeltypes.Packet, d "infractionType", data.Infraction, ) - return channeltypes.NewResultAcknowledgement([]byte{byte(1)}) + return channeltypes.NewResultAcknowledgement(ccv.V1Result) } // ValidateSlashPacket validates a recv slash packet before it is diff --git a/x/ccv/types/ccv.go b/x/ccv/types/ccv.go index 70921704f7..5b4e57994f 100644 --- a/x/ccv/types/ccv.go +++ b/x/ccv/types/ccv.go @@ -157,6 +157,20 @@ func (vdt1 SlashPacketDataV1) FromV1() *SlashPacketData { } } +type PacketAckResult []byte + +var ( // slice types can't be const + + // The result ack that has historically been sent from the provider. + // A provider with v1 throttling sends these acks for all successfully recv packets. + V1Result = PacketAckResult([]byte{byte(1)}) + // Slash packet handled result ack, sent by a throttling v2 provider to indicate that a slash packet was handled. + SlashPacketHandledResult = PacketAckResult([]byte{byte(2)}) + // Slash packet bounced result ack, sent by a throttling v2 provider to indicate that a slash packet was NOT handled + // and should eventually be retried. + SlashPacketBouncedResult = PacketAckResult([]byte{byte(3)}) +) + // An exported wrapper around the auto generated isConsumerPacketData_Data interface, only for // AppendPendingPacket to accept the interface as an argument. type ExportedIsConsumerPacketData_Data interface { From 64d860d10d6055950dd0672f7c3b8b2790d0f0a5 Mon Sep 17 00:00:00 2001 From: bernd-m <43466467+bermuell@users.noreply.github.com> Date: Fri, 11 Aug 2023 11:38:51 +0200 Subject: [PATCH 078/134] Tests: 1175 ci refactor e2e (#1191) * Refactor E2E Tests * Update docstring for short-happy-path The old docstring was outdated and since modified on main --------- Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> --- .github/workflows/manual-e2e.yml | 91 ++++++++++++++-- .github/workflows/nightly-e2e.yml | 104 ++++++++++++++++-- Makefile | 12 +-- tests/e2e/main.go | 172 +++++++++++++++++++++--------- tests/e2e/steps.go | 2 +- 5 files changed, 311 insertions(+), 70 deletions(-) diff --git a/.github/workflows/manual-e2e.yml b/.github/workflows/manual-e2e.yml index 899e4ba230..388a19f0f5 100644 --- a/.github/workflows/manual-e2e.yml +++ b/.github/workflows/manual-e2e.yml @@ -5,22 +5,99 @@ on: workflow_dispatch: jobs: - manual-integration-main: + happy-path-test: runs-on: ubuntu-latest - timeout-minutes: 60 + timeout-minutes: 20 steps: - uses: actions/setup-go@v4 with: go-version: "1.20" - uses: actions/checkout@v3 - - name: Checkout LFS objects run: git lfs checkout - - name: Setup Go uses: actions/setup-go@v4 with: go-version: "1.20" # The Go version to download (if necessary) and use. - - - name: E2E tests - run: make test-e2e + - name: E2E happy-path test + run: go run ./tests/e2e/... --tc happy-path + changeover-test: + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - uses: actions/setup-go@v4 + with: + go-version: "1.20" + - uses: actions/checkout@v3 + - name: Checkout LFS objects + run: git lfs checkout + - name: Setup Go + uses: actions/setup-go@v4 + with: + go-version: "1.20" # The Go version to download (if necessary) and use. + - name: E2E changeover test + run: go run ./tests/e2e/... --tc changeover + democracy-reward-test: + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - uses: actions/setup-go@v4 + with: + go-version: "1.20" + - uses: actions/checkout@v3 + - name: Checkout LFS objects + run: git lfs checkout + - name: Setup Go + uses: actions/setup-go@v4 + with: + go-version: "1.20" # The Go version to download (if necessary) and use. + - name: E2E democracy-reward tests + run: go run ./tests/e2e/... --tc democracy-reward + democracy-test: + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - uses: actions/setup-go@v4 + with: + go-version: "1.20" + - uses: actions/checkout@v3 + - name: Checkout LFS objects + run: git lfs checkout + - name: Setup Go + uses: actions/setup-go@v4 + with: + go-version: "1.20" # The Go version to download (if necessary) and use. + - name: E2E democracy tests + run: go run ./tests/e2e/... --tc democracy + slash-throttle-test: + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - uses: actions/setup-go@v4 + with: + go-version: "1.20" + - uses: actions/checkout@v3 + - name: Checkout LFS objects + run: git lfs checkout + - name: Setup Go + uses: actions/setup-go@v4 + with: + go-version: "1.20" # The Go version to download (if necessary) and use. + - name: E2E slash-throttle tests + run: go run ./tests/e2e/... --tc slash-throttle + multiconsumer-test: + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - uses: actions/setup-go@v4 + with: + go-version: "1.20" + - uses: actions/checkout@v3 + - name: Checkout LFS objects + run: git lfs checkout + - name: Setup Go + uses: actions/setup-go@v4 + with: + go-version: "1.20" # The Go version to download (if necessary) and use. + - name: E2E multi-consumer tests + run: go run ./tests/e2e/... --tc multiconsumer diff --git a/.github/workflows/nightly-e2e.yml b/.github/workflows/nightly-e2e.yml index f69125e6b8..cd7f155e12 100644 --- a/.github/workflows/nightly-e2e.yml +++ b/.github/workflows/nightly-e2e.yml @@ -18,21 +18,111 @@ on: - cron: "0 3 * * *" jobs: - nightly-test: + happy-path-test: runs-on: ubuntu-latest - timeout-minutes: 60 + timeout-minutes: 20 steps: - uses: actions/setup-go@v4 with: go-version: "1.20" - - uses: actions/checkout@v3 - - - name: E2E tests - run: make test-e2e + - name: Checkout LFS objects + run: git lfs checkout + - name: Setup Go + uses: actions/setup-go@v4 + with: + go-version: "1.20" # The Go version to download (if necessary) and use. + - name: E2E happy-path test + run: go run ./tests/e2e/... --tc happy-path + changeover-test: + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - uses: actions/setup-go@v4 + with: + go-version: "1.20" + - uses: actions/checkout@v3 + - name: Checkout LFS objects + run: git lfs checkout + - name: Setup Go + uses: actions/setup-go@v4 + with: + go-version: "1.20" # The Go version to download (if necessary) and use. + - name: E2E changeover test + run: go run ./tests/e2e/... --tc changeover + democracy-reward-test: + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - uses: actions/setup-go@v4 + with: + go-version: "1.20" + - uses: actions/checkout@v3 + - name: Checkout LFS objects + run: git lfs checkout + - name: Setup Go + uses: actions/setup-go@v4 + with: + go-version: "1.20" # The Go version to download (if necessary) and use. + - name: E2E democracy-reward tests + run: go run ./tests/e2e/... --tc democracy-reward + democracy-test: + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - uses: actions/setup-go@v4 + with: + go-version: "1.20" + - uses: actions/checkout@v3 + - name: Checkout LFS objects + run: git lfs checkout + - name: Setup Go + uses: actions/setup-go@v4 + with: + go-version: "1.20" # The Go version to download (if necessary) and use. + - name: E2E democracy tests + run: go run ./tests/e2e/... --tc democracy + slash-throttle-test: + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - uses: actions/setup-go@v4 + with: + go-version: "1.20" + - uses: actions/checkout@v3 + - name: Checkout LFS objects + run: git lfs checkout + - name: Setup Go + uses: actions/setup-go@v4 + with: + go-version: "1.20" # The Go version to download (if necessary) and use. + - name: E2E slash-throttle tests + run: go run ./tests/e2e/... --tc slash-throttle + multiconsumer-test: + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - uses: actions/setup-go@v4 + with: + go-version: "1.20" + - uses: actions/checkout@v3 + - name: Checkout LFS objects + run: git lfs checkout + - name: Setup Go + uses: actions/setup-go@v4 + with: + go-version: "1.20" # The Go version to download (if necessary) and use. + - name: E2E multi-consumer tests + run: go run ./tests/e2e/... --tc multiconsumer nightly-test-fail: - needs: nightly-test + needs: + - happy-path-test + - changeover-test + - democracy-reward-test + - democracy-test + - slash-throttle-test + - multiconsumer-test if: ${{ failure() }} runs-on: ubuntu-latest steps: diff --git a/Makefile b/Makefile index edbacbc0e0..ac7c38f068 100644 --- a/Makefile +++ b/Makefile @@ -10,8 +10,8 @@ install: go.sum go install $(BUILD_FLAGS) ./cmd/interchain-security-sd # run all tests: unit, integration, diff, and E2E -test: - go test ./... && go run ./tests/e2e/... +test: + go test ./... && go run ./tests/e2e/... # run all unit tests test-unit: @@ -31,12 +31,12 @@ test-diff: # run only happy path E2E tests test-e2e-short: - go run ./tests/e2e/... --happy-path-only + go run ./tests/e2e/... --tc happy-path # run only happy path E2E tests with cometmock # this set of traces does not test equivocation but it does check downtime test-e2e-short-cometmock: - go run ./tests/e2e/... --cometmock-happy-path --use-cometmock --use-gorelayer + go run ./tests/e2e/... --tc happy-path-short --use-cometmock --use-gorelayer # run full E2E tests in sequence (including multiconsumer) test-e2e-multi-consumer: @@ -52,7 +52,7 @@ test-gaia-e2e: # run only happy path E2E tests using latest tagged gaia test-gaia-e2e-short: - go run ./tests/e2e/... --happy-path-only --use-gaia + go run ./tests/e2e/... --tc happy-path --use-gaia # run full E2E tests in parallel (including multiconsumer) using latest tagged gaia test-gaia-e2e-parallel: @@ -66,7 +66,7 @@ test-gaia-e2e-tagged: # run only happy path E2E tests using latest tagged gaia # usage: GAIA_TAG=v9.0.0 make test-gaia-e2e-short-tagged test-gaia-e2e-short-tagged: - go run ./tests/e2e/... --happy-path-only --use-gaia --gaia-tag $(GAIA_TAG) + go run ./tests/e2e/... --tc happy-path --use-gaia --gaia-tag $(GAIA_TAG) # run full E2E tests in parallel (including multiconsumer) using specific tagged version of gaia # usage: GAIA_TAG=v9.0.0 make test-gaia-e2e-parallel-tagged diff --git a/tests/e2e/main.go b/tests/e2e/main.go index 58bb065c26..e9336422ae 100644 --- a/tests/e2e/main.go +++ b/tests/e2e/main.go @@ -15,13 +15,26 @@ import ( "github.com/kylelemons/godebug/pretty" ) +// The list of test cases to be executed +type TestSet []string + +func (t *TestSet) Set(value string) (err error) { + // Check and skip duplicates + for _, v := range *t { + if v == value { + return + } + } + *t = append(*t, value) + return +} + +func (t *TestSet) String() string { + return fmt.Sprint(*t) +} + var ( - verbose = flag.Bool("verbose", false, "turn verbose logging on/off") - happyPathOnly = flag.Bool("happy-path-only", false, "run happy path tests only") - cometmockCompatibleHappyPath = flag.Bool("cometmock-happy-path", false, `run cometmock compatible happy path tests only. -This is like the happy path, but skips steps -that involve starting or stopping nodes for the same chain outside of the chain setup or teardown. -This is suited for CometMock+Gorelayer testing`) + verbose = flag.Bool("verbose", false, "turn verbose logging on/off") includeMultiConsumer = flag.Bool("include-multi-consumer", false, "include multiconsumer tests in run") parallel = flag.Bool("parallel", false, "run all tests in parallel") localSdkPath = flag.String("local-sdk-path", "", @@ -35,59 +48,119 @@ var ( gaiaTag = flag.String("gaia-tag", "", "gaia tag to use - default is latest") ) -// runs E2E tests -// all docker containers are built sequentially to avoid race conditions when using local cosmos-sdk -// after building docker containers, all tests are run in parallel using their respective docker containers -func main() { - flag.Parse() - - if cometmockCompatibleHappyPath != nil && *cometmockCompatibleHappyPath { - fmt.Println("=============== running short happy path only ===============") - tr := DefaultTestRun() - tr.Run(cometmockCompatibleHappyPathSteps, *localSdkPath, *useGaia, *gaiaTag) - return - } - - if happyPathOnly != nil && *happyPathOnly { - fmt.Println("=============== running happy path only ===============") - tr := DefaultTestRun() - tr.Run(happyPathSteps, *localSdkPath, *useGaia, *gaiaTag) - return - } - - testRuns := []testRunWithSteps{ - {ChangeoverTestRun(), changeoverSteps}, - {DefaultTestRun(), happyPathSteps}, - {DemocracyTestRun(true), democracySteps}, - {DemocracyTestRun(false), rewardDenomConsumerSteps}, - {SlashThrottleTestRun(), slashThrottleSteps}, - } - if includeMultiConsumer != nil && *includeMultiConsumer { - testRuns = append(testRuns, testRunWithSteps{MultiConsumerTestRun(), multipleConsumers}) +var ( + testSelection TestSet + testMap map[string]*testRunWithSteps = map[string]*testRunWithSteps{ + "happy-path-short": { + testRun: DefaultTestRun(), steps: shortHappyPathSteps, + description: `This is like the happy path, but skips steps +that involve starting or stopping nodes for the same chain outside of the chain setup or teardown. +This is suited for CometMock+Gorelayer testing`, + }, + "happy-path": {testRun: DefaultTestRun(), steps: happyPathSteps, description: "happy path tests"}, + "changeover": {testRun: ChangeoverTestRun(), steps: changeoverSteps, description: "changeover tests"}, + "democracy-reward": {testRun: DemocracyTestRun(true), steps: democracySteps, description: "democracy tests allowing rewards"}, + "democracy": {testRun: DemocracyTestRun(false), steps: rewardDenomConsumerSteps, description: "democracy tests"}, + "slash-throttle": {testRun: SlashThrottleTestRun(), steps: slashThrottleSteps, description: "slash throttle tests"}, + "multiconsumer": {testRun: MultiConsumerTestRun(), steps: multipleConsumers, description: "multi consumer tests"}, } +) - start := time.Now() +func executeTests(tests []testRunWithSteps) (err error) { if parallel != nil && *parallel { fmt.Println("=============== running all tests in parallel ===============") - var wg sync.WaitGroup - for _, run := range testRuns { + } + + var wg sync.WaitGroup + for _, testCase := range tests { + if parallel != nil && *parallel { wg.Add(1) go func(run testRunWithSteps) { defer wg.Done() - tr := run.testRun - tr.Run(run.steps, *localSdkPath, *useGaia, *gaiaTag) - }(run) + run.testRun.Run(run.steps, *localSdkPath, *useGaia, *gaiaTag) + }(testCase) + } else { + log.Printf("=============== running %s ===============\n", testCase.testRun.name) + testCase.testRun.Run(testCase.steps, *localSdkPath, *useGaia, *gaiaTag) } + } + + if parallel != nil && *parallel { wg.Wait() - fmt.Printf("TOTAL TIME ELAPSED: %v\n", time.Since(start)) - return + } + return +} + +func parseArguments() (err error) { + flag.Var(&testSelection, "tc", + fmt.Sprintf("Selection of test cases to be executed:\n%s,\n%s", + func() string { + var keys []string + for k, v := range testMap { + keys = append(keys, fmt.Sprintf("- %s : %s", k, v.description)) + } + return strings.Join(keys, "\n") + }(), + "Example: -tc multiconsumer -tc happy-path ")) + flag.Parse() + + // Enforce go-relayer in case of cometmock as hermes is not yet supported + if useCometmock != nil && *useCometmock && (useGorelayer == nil || !*useGorelayer) { + fmt.Println("Enforcing go-relayer as cometmock is requested") + if err = flag.Set("use-gorelayer", "true"); err != nil { + return + } + } + // check if specified test case exists + for _, tc := range testSelection { + if _, hasKey := testMap[tc]; !hasKey { + err := fmt.Errorf("unknown test case '%s'", tc) + return err + } + } + return +} + +func getTestCases(selection TestSet) (tests []testRunWithSteps) { + // Run default tests if no test cases were selected + if len(selection) == 0 { + selection = TestSet{ + "changeover", "happy-path", + "democracy-reward", "democracy", "slash-throttle", + } + if includeMultiConsumer != nil && *includeMultiConsumer { + selection = append(selection, "multiconsumer") + } + } + + // Get tests from selection + tests = []testRunWithSteps{} + for _, tc := range selection { + if _, exists := testMap[tc]; !exists { + log.Fatalf("Test case '%s' not found", tc) + } + tests = append(tests, *testMap[tc]) + } + return +} + +// runs E2E tests +// all docker containers are built sequentially to avoid race conditions when using local cosmos-sdk +// after building docker containers, all tests are run in parallel using their respective docker containers +func main() { + if err := parseArguments(); err != nil { + flag.Usage() + log.Fatalf("Error parsing command arguments %s\n", err) } - for _, run := range testRuns { - tr := run.testRun - tr.Run(run.steps, *localSdkPath, *useGaia, *gaiaTag) + testCases := getTestCases(testSelection) + + start := time.Now() + err := executeTests(testCases) + if err != nil { + log.Fatalf("Test execution failed '%s'", err) } - fmt.Printf("TOTAL TIME ELAPSED: %v\n", time.Since(start)) + log.Printf("TOTAL TIME ELAPSED: %v\n", time.Since(start)) } // Run sets up docker container and executes the steps in the test run. @@ -104,8 +177,9 @@ func (tr *TestRun) Run(steps []Step, localSdkPath string, useGaia bool, gaiaTag } type testRunWithSteps struct { - testRun TestRun - steps []Step + testRun TestRun + steps []Step + description string } func (tr *TestRun) runStep(step Step, verbose bool) { diff --git a/tests/e2e/steps.go b/tests/e2e/steps.go index 770ac45dda..b33d19783a 100644 --- a/tests/e2e/steps.go +++ b/tests/e2e/steps.go @@ -31,7 +31,7 @@ var happyPathSteps = concatSteps( stepsStopChain("consu", 4), // stop chain ) -var cometmockCompatibleHappyPathSteps = concatSteps( +var shortHappyPathSteps = concatSteps( stepsStartChains([]string{"consu"}, false), stepsDelegate("consu"), stepsUnbond("consu"), From ec0c46aa3b2705707f0f6793329ea618c24957ea Mon Sep 17 00:00:00 2001 From: Marius Poke Date: Mon, 14 Aug 2023 18:01:13 +0200 Subject: [PATCH 079/134] deps!: bump IBC to v7.2.0 (#1196) * bump IBC to v7.2.0 * add changelog entry --- CHANGELOG.md | 3 ++- go.mod | 15 ++++++++------- go.sum | 37 +++++++++++++++++++++---------------- 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5c4d215d8..9c019b885c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,9 @@ ## [Unreleased] Add an entry to the unreleased section whenever merging a PR to main that is not targeted at a specific release. These entries will eventually be included in a release. -* `[x/ccv/provider]` (fix) [#1076](https://github.com/cosmos/interchain-security/pull/1076) Add `InitTimeoutTimestamps` and `ExportedVscSendTimestamps` to exported genesis. +* (deps!) [#1196](https://github.com/cosmos/interchain-security/pull/1196) Bump [ibc-go](https://github.com/cosmos/ibc-go) to [v7.2.0](https://github.com/cosmos/ibc-go/releases/tag/v7.2.0). +* `[x/ccv/provider]` (fix) [#1076](https://github.com/cosmos/interchain-security/pull/1076) Add `InitTimeoutTimestamps` and `ExportedVscSendTimestamps` to exported genesis. * (feat!) [#1024](https://github.com/cosmos/interchain-security/pull/1024) throttle with retries, consumer changes * (fix!) revert consumer packet data changes from #1037 [#1150](https://github.com/cosmos/interchain-security/pull/1150) * (fix!) proper deletion of pending packets [#1146](https://github.com/cosmos/interchain-security/pull/1146) diff --git a/go.mod b/go.mod index ff38553879..4e769eee32 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/cometbft/cometbft-db v0.8.0 github.com/cosmos/cosmos-sdk v0.47.3 github.com/cosmos/gogoproto v1.4.10 - github.com/cosmos/ibc-go/v7 v7.1.0 + github.com/cosmos/ibc-go/v7 v7.2.0 github.com/cosmos/ics23/go v0.10.0 github.com/golang/mock v1.6.0 github.com/golang/protobuf v1.5.3 @@ -19,7 +19,7 @@ require ( github.com/oxyno-zeta/gomock-extra-matcher v1.1.0 github.com/rakyll/statik v0.1.7 // indirect github.com/spf13/cast v1.5.1 - github.com/spf13/cobra v1.6.1 + github.com/spf13/cobra v1.7.0 github.com/stretchr/testify v1.8.4 github.com/tidwall/gjson v1.15.0 golang.org/x/crypto v0.11.0 // indirect @@ -92,7 +92,7 @@ require ( github.com/google/orderedcode v0.0.1 // indirect github.com/google/uuid v1.3.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect - github.com/googleapis/gax-go/v2 v2.7.1 // indirect + github.com/googleapis/gax-go/v2 v2.8.0 // indirect github.com/gorilla/handlers v1.5.1 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect @@ -127,7 +127,7 @@ require ( github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mtibben/percent v0.2.1 // indirect - github.com/pelletier/go-toml/v2 v2.0.7 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -138,7 +138,7 @@ require ( github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rs/cors v1.8.3 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect - github.com/spf13/afero v1.9.3 // indirect + github.com/spf13/afero v1.9.5 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.4.2 // indirect @@ -156,7 +156,7 @@ require ( golang.org/x/term v0.10.0 // indirect golang.org/x/text v0.11.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect - google.golang.org/api v0.114.0 // indirect + google.golang.org/api v0.122.0 // indirect google.golang.org/appengine v1.6.7 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect @@ -166,13 +166,14 @@ require ( ) require ( - github.com/spf13/viper v1.15.0 + github.com/spf13/viper v1.16.0 google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e ) require ( cosmossdk.io/log v1.1.0 // indirect github.com/go-playground/locales v0.14.0 // indirect + github.com/google/s2a-go v0.1.3 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/rs/zerolog v1.29.1 // indirect golang.org/x/sync v0.1.0 // indirect diff --git a/go.sum b/go.sum index 4a93323e50..98f6b92736 100644 --- a/go.sum +++ b/go.sum @@ -393,8 +393,8 @@ github.com/cosmos/gogoproto v1.4.10 h1:QH/yT8X+c0F4ZDacDv3z+xE3WU1P1Z3wQoLMBRJoK github.com/cosmos/gogoproto v1.4.10/go.mod h1:3aAZzeRWpAwr+SS/LLkICX2/kDFyaYVzckBDzygIxek= github.com/cosmos/iavl v0.20.0 h1:fTVznVlepH0KK8NyKq8w+U7c2L6jofa27aFX6YGlm38= github.com/cosmos/iavl v0.20.0/go.mod h1:WO7FyvaZJoH65+HFOsDir7xU9FWk2w9cHXNW1XHcl7A= -github.com/cosmos/ibc-go/v7 v7.1.0 h1:SCLgs7tqVnzdIDO5MRLgovAnc696vTTKl+8qsTu8IMM= -github.com/cosmos/ibc-go/v7 v7.1.0/go.mod h1:7MptlWeIyqmDiuJeRAFqBvXKY8Hybd+rF8vMSmGd2zg= +github.com/cosmos/ibc-go/v7 v7.2.0 h1:dx0DLUl7rxdyZ8NiT6UsrbzKOJx/w7s+BOaewFRH6cg= +github.com/cosmos/ibc-go/v7 v7.2.0/go.mod h1:OOcjKIRku/j1Xs1RgKK0yvKRrJ5iFuZYMetR1n3yMlc= github.com/cosmos/ics23/go v0.10.0 h1:iXqLLgp2Lp+EdpIuwXTYIQU+AiHj9mOC2X9ab++bZDM= github.com/cosmos/ics23/go v0.10.0/go.mod h1:ZfJSmng/TBNTBkFemHHHj5YY7VAU/MBU980F4VU1NG0= github.com/cosmos/ledger-cosmos-go v0.12.2 h1:/XYaBlE2BJxtvpkHiBm97gFGSGmYGKunKyF3nNqAXZA= @@ -645,6 +645,8 @@ github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/s2a-go v0.1.3 h1:FAgZmpLl/SXurPEZyCMPBIiiYeTbqfjlbdnCNTAkbGE= +github.com/google/s2a-go v0.1.3/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -665,8 +667,8 @@ github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99 github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= -github.com/googleapis/gax-go/v2 v2.7.1 h1:gF4c0zjUP2H/s/hEGyLA3I0fA2ZWjzYiONAD6cvPr8A= -github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= +github.com/googleapis/gax-go/v2 v2.8.0 h1:UBtEZqx1bjXtOQ5BVTkuYghXrr3N4V123VKJK67vJZc= +github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -754,7 +756,6 @@ github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1: github.com/improbable-eng/grpc-web v0.15.0 h1:BN+7z6uNXZ1tQGcNAuaU1YjsLTApzkjt2tzCixLaUPQ= github.com/improbable-eng/grpc-web v0.15.0/go.mod h1:1sy9HKV4Jt9aEs9JSnkWlRJPuPtwNr0l57L4f878wP8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY= @@ -964,8 +965,8 @@ github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144T github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us= -github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= @@ -1065,15 +1066,15 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= -github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= +github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= -github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= @@ -1082,8 +1083,8 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= -github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA= +github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= +github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= @@ -1103,6 +1104,7 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= @@ -1207,7 +1209,8 @@ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1307,6 +1310,7 @@ golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= @@ -1489,6 +1493,7 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= @@ -1628,8 +1633,8 @@ google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= -google.golang.org/api v0.114.0 h1:1xQPji6cO2E2vLiI+C/XiFAnsn1WV3mjaEwGLhi3grE= -google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= +google.golang.org/api v0.122.0 h1:zDobeejm3E7pEG1mNHvdxvjs5XJoCMzyNH+CmwL94Es= +google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= From f636cfc4793e3518104bab001d1586441724b699 Mon Sep 17 00:00:00 2001 From: Jehan Date: Mon, 14 Aug 2023 14:22:44 -0700 Subject: [PATCH 080/134] docs: Create adr-005-cryptographic-equivocation-verification.md (#909) * Create adr-005-cryptographic-equivocation-verification.md * docs: update ADR-005 on cryptographic equivocation verifcation (#1022) * save first gist * add first draft * Update docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md Co-authored-by: Marius Poke --------- Co-authored-by: Marius Poke * docs: update cryptographic equivocation verification ADR (#1168) * add first draft * udpate refs * update * Update docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md Co-authored-by: Marius Poke * Update docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md Co-authored-by: Marius Poke * Update docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md Co-authored-by: Marius Poke * Update docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md Co-authored-by: Marius Poke * Update docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md Co-authored-by: Marius Poke * Update docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md Co-authored-by: Marius Poke * Update docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md Co-authored-by: Marius Poke * Update docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md Co-authored-by: Marius Poke * Update docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md Co-authored-by: Marius Poke * Update docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md Co-authored-by: Marius Poke * Update docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md Co-authored-by: Marius Poke * Update docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md Co-authored-by: Marius Poke * add little changes * address comments * fix todos * Update docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md Co-authored-by: Anca Zamfir * Update docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md Co-authored-by: Anca Zamfir * Update docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md * apply review suggestions * Update docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md --------- Co-authored-by: Marius Poke Co-authored-by: Anca Zamfir * update intro.md --------- Co-authored-by: Simon Noetzlin Co-authored-by: Marius Poke Co-authored-by: Anca Zamfir --- ...cryptographic-equivocation-verification.md | 105 ++++++++++++++++++ docs/docs/adrs/intro.md | 2 + 2 files changed, 107 insertions(+) create mode 100644 docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md diff --git a/docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md b/docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md new file mode 100644 index 0000000000..f0b487d2b1 --- /dev/null +++ b/docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md @@ -0,0 +1,105 @@ +--- +sidebar_position: 4 +title: Cryptographic verification of equivocation evidence +--- +# ADR 005: Cryptographic verification of equivocation evidence + +## Changelog +* 5/1/2023: First draft +* 7/23/23: Add light client attacks handling + +## Status + +Accepted + +## Context + +Currently, we use a governance proposal to slash validators for equivocation (double signing and light client attacks). +Every proposal needs to go through a (two weeks) voting period before it can be approved. +Given a three-week unbonding period, this means that an equivocation proposal needs to be submitted within one week since the infraction occurred. + +This ADR proposes a system to slash validators automatically for equivocation, immediately upon the provider chain's receipt of the evidence. Another thing to note is that we intend to introduce this system in stages, since even the partial ability to slash and/or tombstone is a strict improvement in security. +For the first stage of this work, we will only handle light client attacks. + +### Light Client Attack + +In a nutshell, the light client is a process that solely verifies a specific state machine's +consensus without executing the transactions. The light clients get new headers by querying +multiple nodes, called primary and witness nodes. + +Light clients download new headers committed on chain from a primary. Headers can be verified in two ways: sequentially, +where the block height of headers is serial, or using skipping. This second verification method allows light clients to download headers +with nonconsecutive block height, where some intermediate headers are skipped (see [Tendermint Light Client, Figure 1 and Figure 3](https://arxiv.org/pdf/2010.07031.pdf)). +Additionally, light clients are cross-checking new headers obtained from a primary with witnesses to ensure all nodes share the same state. + +A light client attack occurs when a Byzantine validator sends invalid headers to a light client. +As the light client doesn't execute transactions, it can be deceived into trusting corrupted application state transitions. +For instance, if a light client receives header `A` from the primary and header `B` from a witness for the same block height `H`, +and both headers are successfully verified, it indicates a light client attack. +Note that in this case, either the primary or the witness or both are malicious. + +The types of light client attacks are defined by analyzing the differences between the conflicting headers. +There are three types of light client attacks: lunatic attack, equivocation attack, and amnesia attack. +For details, see the [CometBFT specification](https://github.com/cometbft/cometbft/blob/main/spec/light-client/attacks/notes-on-evidence-handling.md#evidence-handling). + +When a light client agent detects two conflicting headers, it will initially verify their traces (see [cometBFT detector](https://github.com/cometbft/cometbft/blob/2af25aea6cfe6ac4ddac40ceddfb8c8eee17d0e6/light/detector.go#L28)) using its primary and witness nodes. +If these headers pass successful verification, the Byzantine validators will be identified based on the header's commit signatures +and the type of light client attack. The agent will then transmit this information to its nodes using a [`LightClientAttackEvidence`](https://github.com/cometbft/cometbft/blob/feed0ddf564e113a840c4678505601256b93a8bc/docs/architecture/adr-047-handling-evidence-from-light-client.md) to be eventually voted on and added to a block. +Note that from a light client agent perspective, it is not possible to establish whether a primary or a witness node, or both, are malicious. +Therefore, it will create and send two `LightClientAttackEvidence`: one against the primary (sent to the witness), and one against the witness (sent to the primary). +Both nodes will then verify it before broadcasting it and adding it to the [evidence pool](https://github.com/cometbft/cometbft/blob/2af25aea6cfe6ac4ddac40ceddfb8c8eee17d0e6/evidence/pool.go#L28). +If a `LightClientAttackEvidence` is finally committed to a block, the chain's evidence module will execute it, resulting in the jailing and the slashing of the validators responsible for the light client attack. + + +Light clients are a core component of IBC. In the event of a light client attack, IBC relayers notify the affected chains by submitting an [IBC misbehavior message]((https://github.com/cosmos/ibc-go/blob/2b7c969066fbcb18f90c7f5bd256439ca12535c7/proto/ibc/lightclients/tendermint/v1/tendermint.proto#L79)). +A misbehavior message includes the conflicting headers that constitute a `LightClientAttackEvidence`. Upon receiving such a message, +a chain will first verify whether these headers would have convinced its light client. This verification is achieved by checking +the header states against the light client consensus states (see [IBC misbehaviour handler](https://github.com/cosmos/ibc-go/blob/2b7c969066fbcb18f90c7f5bd256439ca12535c7/modules/light-clients/07-tendermint/types/misbehaviour_handle.go#L101)). If the misbehaviour is successfully verified, the chain will then "freeze" the +light client, halting any further trust in or updating of its states. + + +## Decision + +In the first iteration of the feature, we will introduce a new endpoint: `HandleConsumerMisbehaviour(ctx sdk.Context, misbehaviour ibctmtypes.Misbehaviour)`. +The main idea is to leverage the current IBC misbehaviour handling and update it to solely jail and slash the validators that +performed a light client attack. This update will be made under the assumption that the chain connected via this light client +share the same validator set, as it is the case with Replicated Security. + +This endpoint will reuse the IBC client libraries to verify that the misbehaviour headers would have fooled the light client. +Additionally, it’s crucial that the endpoint logic result in the slashing and jailing of validators under the same conditions +as a light client agent detector. Therefore, the endpoint will ensure that the two conditions are met: +the headers in the misbehaviour message have the same block height, and +the light client isn’t expired. + +After having successfully verified a misbehaviour, the endpoint will execute the jailing and slashing of the malicious validators similarly as in the evidence module. + +### Current limitations: + +- This only handles light client attacks, not double signing. In the future, we will add the code to also verify double signing. + +- We cannot derive an infraction height from the evidence, so it is only possible to tombstone validators, not actually slash them. +To explain the technical reasons behind this limitation, let's recap the initial consumer initiated slashing logic. +In a nutshell, consumer heights are mapped to provider heights through VSCPackets, namely through the so called vscIDs. +When an infraction occurs on the consumer, a SlashPacket containing the vscID obtained from mapping the consumer infraction height +is sent to the provider. Upon receiving the packet, the provider maps the consumer infraction height to a local infraction height, +which is used to slash the misbehaving validator. In the context of untrusted consumer chains, all their states, including vscIDs, +could be corrupted and therefore cannot be used for slashing purposes. + +- Currently, the endpoint can only handle "equivocation" light client attacks. This is because the "lunatic" attacks require the endpoint to possess the ability to dissociate which header is conflicted or trusted upon receiving a misbehavior message. Without this information, it's not possible to define the Byzantine validators from the conflicting headers (see [comment](https://github.com/cosmos/interchain-security/pull/826#discussion_r1268668684)). + + +## Consequences + +### Positive + +- After this ADR is applied, it will be possible for the provider chain to tombstone validators who committed a light client attack. + +### Negative + +- N/A + + +## References + +* [ICS misbehaviour handling PR](https://github.com/cosmos/interchain-security/pull/826) +* [Architectural diagrams](https://docs.google.com/document/d/1fe1uSJl1ZIYWXoME3Yf4Aodvz7V597Ric875JH-rigM/edit#heading=h.rv4t8i6d6jfn) diff --git a/docs/docs/adrs/intro.md b/docs/docs/adrs/intro.md index d0c097fb06..0c1c722366 100644 --- a/docs/docs/adrs/intro.md +++ b/docs/docs/adrs/intro.md @@ -36,6 +36,8 @@ To suggest an ADR, please make use of the [ADR template](./adr-template.md) prov | [002](./adr-002-throttle.md) | Jail Throttling | Accepted, Implemented | | [003](./adr-003-equivocation-gov-proposal.md) | Equivocation governance proposal | Accepted, Implemented | | [004](./adr-004-denom-dos-fixes) | Denom DOS fixes | Accepted, Implemented | +| [005](./adr-005-cryptographic-equivocation-verification.md) | Cryptographic verification of equivocation evidence | Accepted, In-progress | | [007](./adr-007-pause-unbonding-on-eqv-prop.md) | Pause validator unbonding during equivocation proposal | Proposed | | [008](./adr-008-throttle-retries.md) | Throttle with retries | Accepted, In-progress | | [009](./adr-009-soft-opt-out.md) | Soft Opt-out | Accepted, Implemented | +| [009](./adr-010-standalone-changeover.md) | Standalone to Consumer Changeover | Accepted, Implemented | From 89eca8c1abe98074b95b856ccd1992b970c1e07e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Aug 2023 14:19:46 +0200 Subject: [PATCH 081/134] build(deps): bump bufbuild/buf-setup-action from 1.25.1 to 1.26.0 (#1200) Bumps [bufbuild/buf-setup-action](https://github.com/bufbuild/buf-setup-action) from 1.25.1 to 1.26.0. - [Release notes](https://github.com/bufbuild/buf-setup-action/releases) - [Commits](https://github.com/bufbuild/buf-setup-action/compare/v1.25.1...v1.26.0) --- updated-dependencies: - dependency-name: bufbuild/buf-setup-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/proto-registry.yml | 2 +- .github/workflows/proto.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/proto-registry.yml b/.github/workflows/proto-registry.yml index a3291cec36..326cc566a1 100644 --- a/.github/workflows/proto-registry.yml +++ b/.github/workflows/proto-registry.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: bufbuild/buf-setup-action@v1.25.1 + - uses: bufbuild/buf-setup-action@v1.26.0 - uses: bufbuild/buf-push-action@v1 with: input: "proto" diff --git a/.github/workflows/proto.yml b/.github/workflows/proto.yml index deb110dad0..f6c0984da3 100644 --- a/.github/workflows/proto.yml +++ b/.github/workflows/proto.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: bufbuild/buf-setup-action@v1.25.1 + - uses: bufbuild/buf-setup-action@v1.26.0 - uses: bufbuild/buf-breaking-action@v1 with: input: "proto" From 361277cbd414241b1929ae1ae86571d9f132350b Mon Sep 17 00:00:00 2001 From: Jacob Gadikian Date: Wed, 16 Aug 2023 02:23:51 +0800 Subject: [PATCH 082/134] lint legacy ibc testing (#1078) * remove depguard * lint legacy-ibc-testing * revert the use of using a newer call * run linter --------- Co-authored-by: Jehan Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> --- .github/workflows/golangci-lint.yml | 4 +-- .golangci.yml | 21 ++++++--------- legacy_ibc_testing/core/events.go | 8 +++--- legacy_ibc_testing/simapp/test_helpers.go | 14 ++++++---- legacy_ibc_testing/testing/app.go | 13 ++++----- legacy_ibc_testing/testing/chain.go | 32 ++++++++++++----------- legacy_ibc_testing/testing/coordinator.go | 3 ++- legacy_ibc_testing/testing/endpoint.go | 6 ++--- legacy_ibc_testing/testing/events.go | 18 ++++++------- legacy_ibc_testing/testing/utils.go | 3 ++- 10 files changed, 63 insertions(+), 59 deletions(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 11e422b923..45e3b3c1d7 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -19,13 +19,13 @@ jobs: steps: - uses: actions/setup-go@v4 with: - go-version: "1.20" + go-version: '1.20' - uses: actions/checkout@v3 - name: golangci-lint uses: golangci/golangci-lint-action@v3 with: # Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version - version: v1.52.2 + version: v1.53.3 # Optional: working directory, useful for monorepos # working-directory: somedir diff --git a/.golangci.yml b/.golangci.yml index 5a3b555a6d..5bf3cfb98f 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -3,9 +3,8 @@ run: timeout: 10m sort-results: true allow-parallel-runners: true - skip-dirs: - - "legacy_ibc_testing" - - "testutil" + skip-dirs: + - 'testutil' linters: disable-all: true @@ -31,28 +30,24 @@ linters: - unconvert - unused - - - - issues: exclude-rules: - - text: "Use of weak random number generator" + - text: 'Use of weak random number generator' linters: - gosec - - text: "ST1003:" + - text: 'ST1003:' linters: - stylecheck # FIXME: Disabled until golangci-lint updates stylecheck with this fix: # https://github.com/dominikh/go-tools/issues/389 - - text: "ST1016:" + - text: 'ST1016:' linters: - stylecheck - - path: "migrations" - text: "SA1019:" + - path: 'migrations' + text: 'SA1019:' linters: - staticcheck - - text: "leading space" + - text: 'leading space' linters: - nolintlint diff --git a/legacy_ibc_testing/core/events.go b/legacy_ibc_testing/core/events.go index daabc92d54..a01c14c685 100644 --- a/legacy_ibc_testing/core/events.go +++ b/legacy_ibc_testing/core/events.go @@ -3,10 +3,10 @@ package core import ( "strconv" - abci "github.com/cometbft/cometbft/abci/types" - clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + + abci "github.com/cometbft/cometbft/abci/types" ) /* @@ -20,7 +20,7 @@ These files will be deprecated once ICS is able to upgrade to ibc-go v5. func ReconstructPacketFromEvent(event abci.Event) (packet types.Packet, err error) { attrMap := make(map[string][]byte) for _, attr := range event.Attributes { - attrMap[string(attr.Key)] = []byte(attr.Value) + attrMap[attr.Key] = []byte(attr.Value) } sequence, err := strconv.Atoi(string(attrMap[string(types.AttributeKeySequence)])) @@ -36,7 +36,7 @@ func ReconstructPacketFromEvent(event abci.Event) (packet types.Packet, err erro return packet, err } return types.NewPacket( - attrMap[string(types.AttributeKeyData)], // data + attrMap[string(types.AttributeKeyData)], //nolint:staticcheck // data uint64(sequence), string(attrMap[string(types.AttributeKeySrcPort)]), // sourcePort, string(attrMap[string(types.AttributeKeySrcChannel)]), // sourceChannel, diff --git a/legacy_ibc_testing/simapp/test_helpers.go b/legacy_ibc_testing/simapp/test_helpers.go index 249fffb903..efdc359499 100644 --- a/legacy_ibc_testing/simapp/test_helpers.go +++ b/legacy_ibc_testing/simapp/test_helpers.go @@ -8,15 +8,19 @@ import ( "testing" "time" - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - tmtypes "github.com/cometbft/cometbft/types" + "github.com/stretchr/testify/require" + + errorsmod "cosmossdk.io/errors" + bam "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/stretchr/testify/require" + + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + tmtypes "github.com/cometbft/cometbft/types" "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/simapp/helpers" ) @@ -60,7 +64,7 @@ func ConvertAddrsToValAddrs(addrs []sdk.AccAddress) []sdk.ValAddress { return valAddrs } -func TestAddr(addr string, bech string) (sdk.AccAddress, error) { +func TestAddr(addr, bech string) (sdk.AccAddress, error) { res, err := sdk.AccAddressFromHexUnsafe(addr) if err != nil { return nil, err @@ -140,7 +144,7 @@ func NewPubKeyFromHex(pk string) (res cryptotypes.PubKey) { panic(err) } if len(pkBytes) != ed25519.PubKeySize { - panic(errors.Wrap(errors.ErrInvalidPubKey, "invalid pubkey size")) + panic(errorsmod.Wrap(errors.ErrInvalidPubKey, "invalid pubkey size")) } return &ed25519.PubKey{Key: pkBytes} } diff --git a/legacy_ibc_testing/testing/app.go b/legacy_ibc_testing/testing/app.go index 8a1fef452c..da861481a7 100644 --- a/legacy_ibc_testing/testing/app.go +++ b/legacy_ibc_testing/testing/app.go @@ -5,12 +5,11 @@ import ( "testing" "time" + "github.com/cosmos/ibc-go/v7/modules/core/keeper" + "github.com/stretchr/testify/require" + "cosmossdk.io/math" - "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/core" - abci "github.com/cometbft/cometbft/abci/types" - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - tmtypes "github.com/cometbft/cometbft/types" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" @@ -22,10 +21,12 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/stretchr/testify/require" - "github.com/cosmos/ibc-go/v7/modules/core/keeper" + abci "github.com/cometbft/cometbft/abci/types" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + tmtypes "github.com/cometbft/cometbft/types" + "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/core" "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/simapp" consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" ) diff --git a/legacy_ibc_testing/testing/chain.go b/legacy_ibc_testing/testing/chain.go index 945c5b94d0..14177679b7 100644 --- a/legacy_ibc_testing/testing/chain.go +++ b/legacy_ibc_testing/testing/chain.go @@ -6,13 +6,18 @@ import ( "testing" "time" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v7/modules/core/24-host" + "github.com/cosmos/ibc-go/v7/modules/core/exported" + "github.com/cosmos/ibc-go/v7/modules/core/types" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + "github.com/cosmos/ibc-go/v7/testing/mock" + "github.com/stretchr/testify/require" + errorsmod "cosmossdk.io/errors" - abci "github.com/cometbft/cometbft/abci/types" - "github.com/cometbft/cometbft/crypto/tmhash" - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - tmprotoversion "github.com/cometbft/cometbft/proto/tendermint/version" - tmtypes "github.com/cometbft/cometbft/types" - tmversion "github.com/cometbft/cometbft/version" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" @@ -24,16 +29,13 @@ import ( capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" teststaking "github.com/cosmos/cosmos-sdk/x/staking/testutil" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/stretchr/testify/require" - clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" - commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v7/modules/core/24-host" - "github.com/cosmos/ibc-go/v7/modules/core/exported" - "github.com/cosmos/ibc-go/v7/modules/core/types" - ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - "github.com/cosmos/ibc-go/v7/testing/mock" + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/crypto/tmhash" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + tmprotoversion "github.com/cometbft/cometbft/proto/tendermint/version" + tmtypes "github.com/cometbft/cometbft/types" + tmversion "github.com/cometbft/cometbft/version" ibctestingcore "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/core" "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/simapp" diff --git a/legacy_ibc_testing/testing/coordinator.go b/legacy_ibc_testing/testing/coordinator.go index 4aee8f8923..13f5ac1bec 100644 --- a/legacy_ibc_testing/testing/coordinator.go +++ b/legacy_ibc_testing/testing/coordinator.go @@ -6,8 +6,9 @@ import ( "testing" "time" - abci "github.com/cometbft/cometbft/abci/types" "github.com/stretchr/testify/require" + + abci "github.com/cometbft/cometbft/abci/types" ) /* diff --git a/legacy_ibc_testing/testing/endpoint.go b/legacy_ibc_testing/testing/endpoint.go index c3f2ac9abb..ef9213d222 100644 --- a/legacy_ibc_testing/testing/endpoint.go +++ b/legacy_ibc_testing/testing/endpoint.go @@ -3,9 +3,6 @@ package testing import ( "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/stretchr/testify/require" - clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" connectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" @@ -13,6 +10,9 @@ import ( host "github.com/cosmos/ibc-go/v7/modules/core/24-host" "github.com/cosmos/ibc-go/v7/modules/core/exported" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" ) /* diff --git a/legacy_ibc_testing/testing/events.go b/legacy_ibc_testing/testing/events.go index 763199a695..4bab444cbb 100644 --- a/legacy_ibc_testing/testing/events.go +++ b/legacy_ibc_testing/testing/events.go @@ -3,11 +3,11 @@ package testing import ( "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" - clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" connectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + + sdk "github.com/cosmos/cosmos-sdk/types" ) /* @@ -23,8 +23,8 @@ func ParseClientIDFromEvents(events sdk.Events) (string, error) { for _, ev := range events { if ev.Type == clienttypes.EventTypeCreateClient { for _, attr := range ev.Attributes { - if string(attr.Key) == clienttypes.AttributeKeyClientID { - return string(attr.Value), nil + if attr.Key == clienttypes.AttributeKeyClientID { + return attr.Value, nil } } } @@ -39,8 +39,8 @@ func ParseConnectionIDFromEvents(events sdk.Events) (string, error) { if ev.Type == connectiontypes.EventTypeConnectionOpenInit || ev.Type == connectiontypes.EventTypeConnectionOpenTry { for _, attr := range ev.Attributes { - if string(attr.Key) == connectiontypes.AttributeKeyConnectionID { - return string(attr.Value), nil + if attr.Key == connectiontypes.AttributeKeyConnectionID { + return attr.Value, nil } } } @@ -54,8 +54,8 @@ func ParseChannelIDFromEvents(events sdk.Events) (string, error) { for _, ev := range events { if ev.Type == channeltypes.EventTypeChannelOpenInit || ev.Type == channeltypes.EventTypeChannelOpenTry { for _, attr := range ev.Attributes { - if string(attr.Key) == channeltypes.AttributeKeyChannelID { - return string(attr.Value), nil + if attr.Key == channeltypes.AttributeKeyChannelID { + return attr.Value, nil } } } @@ -69,7 +69,7 @@ func ParseAckFromEvents(events sdk.Events) ([]byte, error) { for _, ev := range events { if ev.Type == channeltypes.EventTypeWriteAck { for _, attr := range ev.Attributes { - if string(attr.Key) == channeltypes.AttributeKeyAck { + if attr.Key == channeltypes.AttributeKeyAck { //nolint:staticcheck // data return []byte(attr.Value), nil } } diff --git a/legacy_ibc_testing/testing/utils.go b/legacy_ibc_testing/testing/utils.go index 885958f25e..047793f455 100644 --- a/legacy_ibc_testing/testing/utils.go +++ b/legacy_ibc_testing/testing/utils.go @@ -3,9 +3,10 @@ package testing import ( "testing" + "github.com/stretchr/testify/require" + abci "github.com/cometbft/cometbft/abci/types" tmtypes "github.com/cometbft/cometbft/types" - "github.com/stretchr/testify/require" ) /* From 97f695aab3d13e27f85072253e55fff098fbdd20 Mon Sep 17 00:00:00 2001 From: Jacob Gadikian Date: Wed, 16 Aug 2023 02:48:05 +0800 Subject: [PATCH 083/134] refactor: this PR adds the testutil folder to the linter configuration (#1080) * this PR adds the testutil folder to the linter configuration * run golangci-lint --------- Co-authored-by: Marius Poke Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> --- .golangci.yml | 2 -- testutil/crypto/crypto.go | 8 ++++---- testutil/ibc_testing/generic_setup.go | 13 +++++++------ testutil/ibc_testing/specific_setup.go | 2 +- testutil/integration/interfaces.go | 4 +++- testutil/keeper/expectations.go | 27 ++++++++++++-------------- testutil/keeper/unit_test_helpers.go | 26 ++++++++++++------------- testutil/simibc/chain_util.go | 6 ++++-- testutil/simibc/relay_util.go | 20 +++++++++++-------- testutil/simibc/relayed_path.go | 1 + 10 files changed, 57 insertions(+), 52 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 5bf3cfb98f..d86d8ae7af 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -3,8 +3,6 @@ run: timeout: 10m sort-results: true allow-parallel-runners: true - skip-dirs: - - 'testutil' linters: disable-all: true diff --git a/testutil/crypto/crypto.go b/testutil/crypto/crypto.go index dd733f0ab3..53babef942 100644 --- a/testutil/crypto/crypto.go +++ b/testutil/crypto/crypto.go @@ -1,9 +1,8 @@ package crypto import ( - "encoding/binary" - cryptoEd25519 "crypto/ed25519" + "encoding/binary" sdkcryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" sdkcryptoEd25519 "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" @@ -11,11 +10,12 @@ import ( sdkcryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdktypes "github.com/cosmos/cosmos-sdk/types" sdkstakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" tmcrypto "github.com/cometbft/cometbft/crypto" tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" tmtypes "github.com/cometbft/cometbft/types" + + providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ) // CryptoIdentity is a test helper for generating keys and addresses of @@ -48,7 +48,7 @@ func NewCryptoIdentityFromIntSeed(i int) *CryptoIdentity { } // GenMultipleCryptoIds generates and returns multiple CryptoIdentities from a starting int seed. -func GenMultipleCryptoIds(num int, fromIntSeed int) []*CryptoIdentity { +func GenMultipleCryptoIds(num, fromIntSeed int) []*CryptoIdentity { ids := make([]*CryptoIdentity, num) for i := 0; i < num; i++ { ids[i] = NewCryptoIdentityFromIntSeed(fromIntSeed + i) diff --git a/testutil/ibc_testing/generic_setup.go b/testutil/ibc_testing/generic_setup.go index e784ee23b7..25c483fca5 100644 --- a/testutil/ibc_testing/generic_setup.go +++ b/testutil/ibc_testing/generic_setup.go @@ -4,17 +4,18 @@ import ( "fmt" "testing" - sdk "github.com/cosmos/cosmos-sdk/types" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" - ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" - testutil "github.com/cosmos/interchain-security/v3/testutil/integration" - testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" - consumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" - "github.com/stretchr/testify/suite" + sdk "github.com/cosmos/cosmos-sdk/types" + tmencoding "github.com/cometbft/cometbft/crypto/encoding" tmtypes "github.com/cometbft/cometbft/types" + + ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" + testutil "github.com/cosmos/interchain-security/v3/testutil/integration" + testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" + consumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" ) // Contains generic setup code for running integration tests against a provider, consumer, diff --git a/testutil/ibc_testing/specific_setup.go b/testutil/ibc_testing/specific_setup.go index 01c8315de8..948007d212 100644 --- a/testutil/ibc_testing/specific_setup.go +++ b/testutil/ibc_testing/specific_setup.go @@ -8,7 +8,6 @@ import ( "encoding/json" simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" - ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" tmdb "github.com/cometbft/cometbft-db" "github.com/cometbft/cometbft/libs/log" @@ -16,6 +15,7 @@ import ( appConsumer "github.com/cosmos/interchain-security/v3/app/consumer" appConsumerDemocracy "github.com/cosmos/interchain-security/v3/app/consumer-democracy" appProvider "github.com/cosmos/interchain-security/v3/app/provider" + ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" ) // ProviderAppIniter implements ibctesting.AppIniter for a provider app diff --git a/testutil/integration/interfaces.go b/testutil/integration/interfaces.go index 41e6fd70c3..b677d46789 100644 --- a/testutil/integration/interfaces.go +++ b/testutil/integration/interfaces.go @@ -4,7 +4,7 @@ import ( "time" "cosmossdk.io/math" - abci "github.com/cometbft/cometbft/abci/types" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -16,6 +16,8 @@ import ( slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" "github.com/cosmos/cosmos-sdk/x/staking/types" + abci "github.com/cometbft/cometbft/abci/types" + ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" consumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" providerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" diff --git a/testutil/keeper/expectations.go b/testutil/keeper/expectations.go index 8a231f4760..07d4d320ba 100644 --- a/testutil/keeper/expectations.go +++ b/testutil/keeper/expectations.go @@ -3,23 +3,20 @@ package keeper import ( time "time" - sdk "github.com/cosmos/cosmos-sdk/types" - capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - - "github.com/golang/mock/gomock" - 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" + host "github.com/cosmos/ibc-go/v7/modules/core/24-host" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" - "github.com/cosmos/interchain-security/v3/x/ccv/types" + "github.com/golang/mock/gomock" + extra "github.com/oxyno-zeta/gomock-extra-matcher" - host "github.com/cosmos/ibc-go/v7/modules/core/24-host" - ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" + sdk "github.com/cosmos/cosmos-sdk/types" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - extra "github.com/oxyno-zeta/gomock-extra-matcher" + providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + "github.com/cosmos/interchain-security/v3/x/ccv/types" ) // @@ -68,7 +65,7 @@ func GetMocksForSetConsumerChain(ctx sdk.Context, mocks *MockedKeepers, chainIDToInject string, ) []*gomock.Call { return []*gomock.Call{ - mocks.MockChannelKeeper.EXPECT().GetChannel(ctx, ccv.ProviderPortID, gomock.Any()).Return( + mocks.MockChannelKeeper.EXPECT().GetChannel(ctx, types.ProviderPortID, gomock.Any()).Return( channeltypes.Channel{ State: channeltypes.OPEN, ConnectionHops: []string{"connectionID"}, @@ -88,11 +85,11 @@ func GetMocksForSetConsumerChain(ctx sdk.Context, mocks *MockedKeepers, func GetMocksForStopConsumerChain(ctx sdk.Context, mocks *MockedKeepers) []*gomock.Call { dummyCap := &capabilitytypes.Capability{} return []*gomock.Call{ - mocks.MockChannelKeeper.EXPECT().GetChannel(gomock.Any(), ccv.ProviderPortID, "channelID").Return( + mocks.MockChannelKeeper.EXPECT().GetChannel(gomock.Any(), types.ProviderPortID, "channelID").Return( channeltypes.Channel{State: channeltypes.OPEN}, true, ).Times(1), mocks.MockScopedKeeper.EXPECT().GetCapability(gomock.Any(), gomock.Any()).Return(dummyCap, true).Times(1), - mocks.MockChannelKeeper.EXPECT().ChanCloseInit(gomock.Any(), ccv.ProviderPortID, "channelID", dummyCap).Times(1), + mocks.MockChannelKeeper.EXPECT().ChanCloseInit(gomock.Any(), types.ProviderPortID, "channelID", dummyCap).Times(1), } } @@ -137,7 +134,7 @@ func ExpectCreateClientMock(ctx sdk.Context, mocks MockedKeepers, clientID strin func ExpectGetCapabilityMock(ctx sdk.Context, mocks MockedKeepers, times int) *gomock.Call { return mocks.MockScopedKeeper.EXPECT().GetCapability( - ctx, host.PortPath(ccv.ConsumerPortID), + ctx, host.PortPath(types.ConsumerPortID), ).Return(nil, true).Times(times) } diff --git a/testutil/keeper/unit_test_helpers.go b/testutil/keeper/unit_test_helpers.go index b8e69a4045..c5540f4601 100644 --- a/testutil/keeper/unit_test_helpers.go +++ b/testutil/keeper/unit_test_helpers.go @@ -6,32 +6,32 @@ import ( "testing" "time" - abci "github.com/cometbft/cometbft/abci/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" - tmdb "github.com/cometbft/cometbft-db" - "github.com/cometbft/cometbft/libs/log" - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/store" storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + tmdb "github.com/cometbft/cometbft-db" + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/libs/log" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + consumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" providerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" "github.com/cosmos/interchain-security/v3/x/ccv/types" - "github.com/golang/mock/gomock" - "github.com/stretchr/testify/require" - - cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" - "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - - clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" ) // Parameters needed to instantiate an in-memory keeper diff --git a/testutil/simibc/chain_util.go b/testutil/simibc/chain_util.go index 0e6d14cd38..98622695d3 100644 --- a/testutil/simibc/chain_util.go +++ b/testutil/simibc/chain_util.go @@ -3,10 +3,12 @@ package simibc import ( "time" - abci "github.com/cometbft/cometbft/abci/types" - tmproto "github.com/cometbft/cometbft/proto/tendermint/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" + + abci "github.com/cometbft/cometbft/abci/types" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + ibctestingcore "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/core" ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" ) diff --git a/testutil/simibc/relay_util.go b/testutil/simibc/relay_util.go index 7015dc72c1..97bcabf57c 100644 --- a/testutil/simibc/relay_util.go +++ b/testutil/simibc/relay_util.go @@ -1,16 +1,20 @@ package simibc import ( - errorsmod "cosmossdk.io/errors" - 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" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v7/modules/core/24-host" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + "github.com/stretchr/testify/require" + + errorsmod "cosmossdk.io/errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + + tmtypes "github.com/cometbft/cometbft/types" + simapp "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/simapp" ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" - "github.com/stretchr/testify/require" ) // UpdateReceiverClient DELIVERs a header to the receiving endpoint @@ -20,7 +24,7 @@ import ( // must have a client of the sender chain that it can update. // // NOTE: this function MAY be used independently of the rest of simibc. -func UpdateReceiverClient(sender *ibctesting.Endpoint, receiver *ibctesting.Endpoint, header *ibctmtypes.Header) (err error) { +func UpdateReceiverClient(sender, receiver *ibctesting.Endpoint, header *ibctmtypes.Header) (err error) { err = augmentHeader(sender.Chain, receiver.Chain, receiver.ClientID, header) if err != nil { @@ -65,7 +69,7 @@ func UpdateReceiverClient(sender *ibctesting.Endpoint, receiver *ibctesting.Endp // The packet must be sent from the sender chain to the receiver chain, and the // receiver chain must have a client for the sender chain which has been updated // to a recent height of the sender chain so that it can verify the packet. -func TryRecvPacket(sender *ibctesting.Endpoint, receiver *ibctesting.Endpoint, packet channeltypes.Packet) (ack []byte, err error) { +func TryRecvPacket(sender, receiver *ibctesting.Endpoint, packet channeltypes.Packet) (ack []byte, err error) { packetKey := host.PacketCommitmentKey(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) proof, proofHeight := sender.Chain.QueryProof(packetKey) @@ -107,7 +111,7 @@ func TryRecvPacket(sender *ibctesting.Endpoint, receiver *ibctesting.Endpoint, p // to packet which was previously delivered from the receiver to the sender. // The receiver chain must have a client for the sender chain which has been // updated to a recent height of the sender chain so that it can verify the packet. -func TryRecvAck(sender *ibctesting.Endpoint, receiver *ibctesting.Endpoint, packet channeltypes.Packet, ack []byte) (err error) { +func TryRecvAck(sender, receiver *ibctesting.Endpoint, packet channeltypes.Packet, ack []byte) (err error) { p := packet packetKey := host.PacketAcknowledgementKey(p.GetDestPort(), p.GetDestChannel(), p.GetSequence()) proof, proofHeight := sender.Chain.QueryProof(packetKey) @@ -141,7 +145,7 @@ func TryRecvAck(sender *ibctesting.Endpoint, receiver *ibctesting.Endpoint, pack // augmentHeader is a helper that augments the header with the height and validators that are most recently trusted // by the receiver chain. If there is an error, the header will not be modified. -func augmentHeader(sender *ibctesting.TestChain, receiver *ibctesting.TestChain, clientID string, header *ibctmtypes.Header) error { +func augmentHeader(sender, receiver *ibctesting.TestChain, clientID string, header *ibctmtypes.Header) error { trustedHeight := receiver.GetClientState(clientID).GetLatestHeight().(clienttypes.Height) var ( diff --git a/testutil/simibc/relayed_path.go b/testutil/simibc/relayed_path.go index dfc5febe9c..7ef97c4bee 100644 --- a/testutil/simibc/relayed_path.go +++ b/testutil/simibc/relayed_path.go @@ -5,6 +5,7 @@ import ( "time" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" ) From cd1818abc26c431df3cf1058872dd372d4eecf7c Mon Sep 17 00:00:00 2001 From: Marius Poke Date: Wed, 16 Aug 2023 09:49:33 +0200 Subject: [PATCH 084/134] ci: add PR labeler (#1204) add PR labeler --- .github/pr_labeler.yml | 29 +++++++++++++++++++++++++++++ .github/workflows/pr_labeler.yml | 18 ++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 .github/pr_labeler.yml create mode 100644 .github/workflows/pr_labeler.yml diff --git a/.github/pr_labeler.yml b/.github/pr_labeler.yml new file mode 100644 index 0000000000..56249140c4 --- /dev/null +++ b/.github/pr_labeler.yml @@ -0,0 +1,29 @@ +"C:x/consumer": + - x/ccv/consumer/**/* +"C:x/democracy": + - x/ccv/democracy/**/* +"C:x/provider": + - x/ccv/provider/**/* +"C:x/types": + - x/ccv/types/**/* +"C:Docs": + - docs/docs/**/* +"C:ADR": + - docs/docs/adrs/**/* +"C:CI": + - .github/**/*.yml + - buf.work.yaml + - .mergify.yml + - .golangci.yml + - mlc_config.json + - sonar-project.properties +"C:Build": + - Makefile + - Dockerfile + - scripts/* +"C:Testing": + - app/**/* + - cmd/**/* + - legacy_ibc_testing/**/* + - tests/**/* + - testutil/**/* \ No newline at end of file diff --git a/.github/workflows/pr_labeler.yml b/.github/workflows/pr_labeler.yml new file mode 100644 index 0000000000..3adc6112d0 --- /dev/null +++ b/.github/workflows/pr_labeler.yml @@ -0,0 +1,18 @@ +name: "Pull Request Labeler" +on: + - pull_request_target + +permissions: + contents: read + +jobs: + labeler: + permissions: + contents: read # for actions/labeler to determine modified files + pull-requests: write # for actions/labeler to add labels to PRs + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@main + with: + configuration-path: .github/pr_labeler.yml + repo-token: "${{ secrets.GITHUB_TOKEN }}" \ No newline at end of file From 877b0fe8c70e1a6a2caec8688f905e3d56e422b8 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Wed, 16 Aug 2023 00:55:32 -0700 Subject: [PATCH 085/134] chore: fix link in recent ADR (#1207) Update adr-005-cryptographic-equivocation-verification.md --- .../adrs/adr-005-cryptographic-equivocation-verification.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md b/docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md index f0b487d2b1..dac41b912e 100644 --- a/docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md +++ b/docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md @@ -51,7 +51,7 @@ Both nodes will then verify it before broadcasting it and adding it to the [evid If a `LightClientAttackEvidence` is finally committed to a block, the chain's evidence module will execute it, resulting in the jailing and the slashing of the validators responsible for the light client attack. -Light clients are a core component of IBC. In the event of a light client attack, IBC relayers notify the affected chains by submitting an [IBC misbehavior message]((https://github.com/cosmos/ibc-go/blob/2b7c969066fbcb18f90c7f5bd256439ca12535c7/proto/ibc/lightclients/tendermint/v1/tendermint.proto#L79)). +Light clients are a core component of IBC. In the event of a light client attack, IBC relayers notify the affected chains by submitting an [IBC misbehavior message](https://github.com/cosmos/ibc-go/blob/2b7c969066fbcb18f90c7f5bd256439ca12535c7/proto/ibc/lightclients/tendermint/v1/tendermint.proto#L79). A misbehavior message includes the conflicting headers that constitute a `LightClientAttackEvidence`. Upon receiving such a message, a chain will first verify whether these headers would have convinced its light client. This verification is achieved by checking the header states against the light client consensus states (see [IBC misbehaviour handler](https://github.com/cosmos/ibc-go/blob/2b7c969066fbcb18f90c7f5bd256439ca12535c7/modules/light-clients/07-tendermint/types/misbehaviour_handle.go#L101)). If the misbehaviour is successfully verified, the chain will then "freeze" the From e2ada9e330a78f70c2f8dfa47a197b8935cb7f4b Mon Sep 17 00:00:00 2001 From: Justin Tieri <37750742+jtieri@users.noreply.github.com> Date: Wed, 16 Aug 2023 03:27:50 -0500 Subject: [PATCH 086/134] docs: update supported relayers section in faq (#1208) --- docs/docs/frequently-asked-questions.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/docs/frequently-asked-questions.md b/docs/docs/frequently-asked-questions.md index e431ef3f01..dc0745807e 100644 --- a/docs/docs/frequently-asked-questions.md +++ b/docs/docs/frequently-asked-questions.md @@ -102,6 +102,7 @@ To become a consumer chain use this [checklist](./consumer-development/onboardin Currently supported versions: - Hermes 1.4.1 +- Support for the CCV module was added to the Go [relayer](https://github.com/cosmos/relayer) in v2.2.0 but v2.4.0 has significant performance fixes which makes it the earliest suggested version to use. ## How does key delegation work in ICS? From a8ebd4a4403e01e634483320f5d521b1888eef35 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Aug 2023 12:05:20 +0200 Subject: [PATCH 087/134] build(deps): bump github.com/tidwall/gjson from 1.15.0 to 1.16.0 (#1199) Bumps [github.com/tidwall/gjson](https://github.com/tidwall/gjson) from 1.15.0 to 1.16.0. - [Commits](https://github.com/tidwall/gjson/compare/v1.15.0...v1.16.0) --- updated-dependencies: - dependency-name: github.com/tidwall/gjson dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 4e769eee32..03b50c43cd 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/spf13/cast v1.5.1 github.com/spf13/cobra v1.7.0 github.com/stretchr/testify v1.8.4 - github.com/tidwall/gjson v1.15.0 + github.com/tidwall/gjson v1.16.0 golang.org/x/crypto v0.11.0 // indirect golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc golang.org/x/net v0.12.0 // indirect diff --git a/go.sum b/go.sum index 98f6b92736..f1056f8135 100644 --- a/go.sum +++ b/go.sum @@ -1117,8 +1117,8 @@ github.com/tidwall/btree v1.6.0 h1:LDZfKfQIBHGHWSwckhXI0RPSXzlo+KYdjK7FWSqOzzg= github.com/tidwall/btree v1.6.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.14.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.15.0 h1:5n/pM+v3r5ujuNl4YLZLsQ+UE5jlkLVm7jMzT5Mpolw= -github.com/tidwall/gjson v1.15.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.16.0 h1:SyXa+dsSPpUlcwEDuKuEBJEz5vzTvOea+9rjyYodQFg= +github.com/tidwall/gjson v1.16.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= From cca008d856e3ffc60ec1a486871d0faa702abe26 Mon Sep 17 00:00:00 2001 From: Marius Poke Date: Wed, 16 Aug 2023 12:09:23 +0200 Subject: [PATCH 088/134] docs: update semantic versioning (#1203) * update semantic versioning * Update CONTRIBUTING.md Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> * add clarification on API breaking * Update CONTRIBUTING.md Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> --------- Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> --- CONTRIBUTING.md | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e9a3c092ae..8975d37269 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -245,17 +245,11 @@ ICS adheres to the [trunk based development branching model](https://trunkbasedd ### Semantic Versioning -ICS uses a variation of [semantic versioning](https://semver.org/). +ICS follows [semantic versioning](https://semver.org), but with the following deviations (similar to [IBC-Go](https://github.com/cosmos/ibc-go/blob/main/RELEASES.md)): -Note that state breaking changes are a subset of consensus breaking changes. Therefore we'll only refer to the latter when talking about versioning. - -ICS is a distributed, IBC based protocol in which multiple blockchains could be affected by a version bump. Therefore incrementing a MAJOR version number indicates that the PR updates, or is a breaking change to the way that the provider and consumer(s) communicate with one another over IBC. If a PR is consensus breaking to both the provider and consumer(s), then it requires a MAJOR version bump. - -Incrementing a MINOR version number indicates that a PR is only consensus breaking to the provider, or only to the consumers, where IBC communication remains unchanged. - -Incrementing a PATCH version number indicates that a PR is not consensus breaking to the provider or consumers. This could include node API changes, or other miscellaneous and often rare changes. - -Pure documentation, testing, and refactoring PRs do not require a version bump. +- A library API breaking change will result in an increase of the MAJOR version number (X.y.z | x > 0). +- A state breaking change (change requiring coordinated upgrade and/or state migration for the consumer, the provider, or both) will result in an increase of the MINOR version number (x.Y.z | x > 0). +- Any other changes (including node API breaking changes) will result in an increase of the PATCH version number (x.y.Z | x > 0). ### Backwards Compatibility From 653d29d4424441ad82d24b6aae3570eab45e2c9a Mon Sep 17 00:00:00 2001 From: Jacob Gadikian Date: Tue, 22 Aug 2023 01:07:41 +0800 Subject: [PATCH 089/134] other: remove depguard and bump golangci-lint (#1077) * remove depguard * bump golangci-lint --- .github/workflows/golangci-lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 45e3b3c1d7..56166af86a 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -25,7 +25,7 @@ jobs: uses: golangci/golangci-lint-action@v3 with: # Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version - version: v1.53.3 + version: v1.54.1 # Optional: working directory, useful for monorepos # working-directory: somedir From ad370e2fde2b597d02f8fb13040be8a88c560407 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Aug 2023 10:54:53 -0700 Subject: [PATCH 090/134] build(deps): bump cosmossdk.io/math from 1.0.1 to 1.1.2 (#1220) Bumps [cosmossdk.io/math](https://github.com/cosmos/cosmos-sdk) from 1.0.1 to 1.1.2. - [Release notes](https://github.com/cosmos/cosmos-sdk/releases) - [Changelog](https://github.com/cosmos/cosmos-sdk/blob/main/CHANGELOG.md) - [Commits](https://github.com/cosmos/cosmos-sdk/compare/math/v1.0.1...math/v1.1.2) --- updated-dependencies: - dependency-name: cosmossdk.io/math dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 03b50c43cd..b7d1eb9afe 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.20 require ( cosmossdk.io/errors v1.0.0 - cosmossdk.io/math v1.0.1 + cosmossdk.io/math v1.1.2 github.com/cometbft/cometbft v0.37.2 github.com/cometbft/cometbft-db v0.8.0 github.com/cosmos/cosmos-sdk v0.47.3 diff --git a/go.sum b/go.sum index f1056f8135..a008e343c5 100644 --- a/go.sum +++ b/go.sum @@ -202,8 +202,8 @@ cosmossdk.io/errors v1.0.0 h1:nxF07lmlBbB8NKQhtJ+sJm6ef5uV1XkvPXG2bUntb04= cosmossdk.io/errors v1.0.0/go.mod h1:+hJZLuhdDE0pYN8HkOrVNwrIOYvUGnn6+4fjnJs/oV0= cosmossdk.io/log v1.1.0 h1:v0ogPHYeTzPcBTcPR1A3j1hkei4pZama8kz8LKlCMv0= cosmossdk.io/log v1.1.0/go.mod h1:6zjroETlcDs+mm62gd8Ig7mZ+N+fVOZS91V17H+M4N4= -cosmossdk.io/math v1.0.1 h1:Qx3ifyOPaMLNH/89WeZFH268yCvU4xEcnPLu3sJqPPg= -cosmossdk.io/math v1.0.1/go.mod h1:Ygz4wBHrgc7g0N+8+MrnTfS9LLn9aaTGa9hKopuym5k= +cosmossdk.io/math v1.1.2 h1:ORZetZCTyWkI5GlZ6CZS28fMHi83ZYf+A2vVnHNzZBM= +cosmossdk.io/math v1.1.2/go.mod h1:l2Gnda87F0su8a/7FEKJfFdJrM0JZRXQaohlgJeyQh0= cosmossdk.io/tools/rosetta v0.2.1 h1:ddOMatOH+pbxWbrGJKRAawdBkPYLfKXutK9IETnjYxw= cosmossdk.io/tools/rosetta v0.2.1/go.mod h1:Pqdc1FdvkNV3LcNIkYWt2RQY6IP1ge6YWZk8MhhO9Hw= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= From e9c178eb1a444308dc1866ea12e90cb7fe8d23d2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Aug 2023 20:56:56 +0200 Subject: [PATCH 091/134] build(deps): bump bufbuild/buf-setup-action from 1.26.0 to 1.26.1 (#1221) Bumps [bufbuild/buf-setup-action](https://github.com/bufbuild/buf-setup-action) from 1.26.0 to 1.26.1. - [Release notes](https://github.com/bufbuild/buf-setup-action/releases) - [Commits](https://github.com/bufbuild/buf-setup-action/compare/v1.26.0...v1.26.1) --- updated-dependencies: - dependency-name: bufbuild/buf-setup-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/proto-registry.yml | 2 +- .github/workflows/proto.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/proto-registry.yml b/.github/workflows/proto-registry.yml index 326cc566a1..5e4c7cb9ad 100644 --- a/.github/workflows/proto-registry.yml +++ b/.github/workflows/proto-registry.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: bufbuild/buf-setup-action@v1.26.0 + - uses: bufbuild/buf-setup-action@v1.26.1 - uses: bufbuild/buf-push-action@v1 with: input: "proto" diff --git a/.github/workflows/proto.yml b/.github/workflows/proto.yml index f6c0984da3..1b0846a842 100644 --- a/.github/workflows/proto.yml +++ b/.github/workflows/proto.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: bufbuild/buf-setup-action@v1.26.0 + - uses: bufbuild/buf-setup-action@v1.26.1 - uses: bufbuild/buf-breaking-action@v1 with: input: "proto" From aa0063de28d65e0e2bab89b649a021900f813867 Mon Sep 17 00:00:00 2001 From: insumity Date: Tue, 22 Aug 2023 11:20:24 +0200 Subject: [PATCH 092/134] test: introduce tests for OnTimeoutPacket and OnAcknowledgementPacket (#1169) * Add test that verify provider's chain state is clean after a call to `StopConsumerChain`. * Remove helper function in favor of using `GetMocksForStopConsumerChainWithCloseChannel` directly. --------- Co-authored-by: Karolos Antoniadis --- testutil/keeper/expectations.go | 5 +- testutil/keeper/unit_test_helpers.go | 43 ++++++++++++++- x/ccv/provider/keeper/proposal_test.go | 51 +++++------------- x/ccv/provider/keeper/relay_test.go | 72 ++++++++++++++++++++++++- x/ccv/provider/proposal_handler_test.go | 3 ++ 5 files changed, 130 insertions(+), 44 deletions(-) diff --git a/testutil/keeper/expectations.go b/testutil/keeper/expectations.go index 07d4d320ba..7814fe0fcf 100644 --- a/testutil/keeper/expectations.go +++ b/testutil/keeper/expectations.go @@ -81,8 +81,9 @@ func GetMocksForSetConsumerChain(ctx sdk.Context, mocks *MockedKeepers, } } -// GetMocksForStopConsumerChain returns mock expectations needed to call StopConsumerChain(). -func GetMocksForStopConsumerChain(ctx sdk.Context, mocks *MockedKeepers) []*gomock.Call { +// GetMocksForStopConsumerChainWithCloseChannel returns mock expectations needed to call StopConsumerChain() when +// `closeChan` is true. +func GetMocksForStopConsumerChainWithCloseChannel(ctx sdk.Context, mocks *MockedKeepers) []*gomock.Call { dummyCap := &capabilitytypes.Capability{} return []*gomock.Call{ mocks.MockChannelKeeper.EXPECT().GetChannel(gomock.Any(), types.ProviderPortID, "channelID").Return( diff --git a/testutil/keeper/unit_test_helpers.go b/testutil/keeper/unit_test_helpers.go index c5540f4601..4ccb8a1861 100644 --- a/testutil/keeper/unit_test_helpers.go +++ b/testutil/keeper/unit_test_helpers.go @@ -207,7 +207,10 @@ func GetNewVSCMaturedPacketData() types.VSCMaturedPacketData { } // SetupForStoppingConsumerChain registers expected mock calls and corresponding state setup -// which asserts that a consumer chain was properly stopped from StopConsumerChain(). +// which assert that a consumer chain was properly setup to be later stopped from `StopConsumerChain`. +// Note: This function only setups and tests that we correctly setup a consumer chain that we could later stop when +// calling `StopConsumerChain` -- this does NOT necessarily mean that the consumer chain is stopped. +// Also see `TestProviderStateIsCleanedAfterConsumerChainIsStopped`. func SetupForStoppingConsumerChain(t *testing.T, ctx sdk.Context, providerKeeper *providerkeeper.Keeper, mocks MockedKeepers, ) { @@ -215,7 +218,6 @@ func SetupForStoppingConsumerChain(t *testing.T, ctx sdk.Context, expectations := GetMocksForCreateConsumerClient(ctx, &mocks, "chainID", clienttypes.NewHeight(4, 5)) expectations = append(expectations, GetMocksForSetConsumerChain(ctx, &mocks, "chainID")...) - expectations = append(expectations, GetMocksForStopConsumerChain(ctx, &mocks)...) gomock.InOrder(expectations...) @@ -226,6 +228,43 @@ func SetupForStoppingConsumerChain(t *testing.T, ctx sdk.Context, require.NoError(t, err) } +// TestProviderStateIsCleanedAfterConsumerChainIsStopped executes test assertions for the provider's state being cleaned +// after a stopped consumer chain. +func TestProviderStateIsCleanedAfterConsumerChainIsStopped(t *testing.T, ctx sdk.Context, providerKeeper providerkeeper.Keeper, + expectedChainID, expectedChannelID string, +) { + t.Helper() + _, found := providerKeeper.GetConsumerClientId(ctx, expectedChainID) + require.False(t, found) + _, found = providerKeeper.GetChainToChannel(ctx, expectedChainID) + require.False(t, found) + _, found = providerKeeper.GetChannelToChain(ctx, expectedChannelID) + require.False(t, found) + _, found = providerKeeper.GetInitChainHeight(ctx, expectedChainID) + require.False(t, found) + acks := providerKeeper.GetSlashAcks(ctx, expectedChainID) + require.Empty(t, acks) + _, found = providerKeeper.GetInitTimeoutTimestamp(ctx, expectedChainID) + require.False(t, found) + + require.Empty(t, providerKeeper.GetAllVscSendTimestamps(ctx, expectedChainID)) + + // test key assignment state is cleaned + require.Empty(t, providerKeeper.GetAllValidatorConsumerPubKeys(ctx, &expectedChainID)) + require.Empty(t, providerKeeper.GetAllValidatorsByConsumerAddr(ctx, &expectedChainID)) + require.Empty(t, providerKeeper.GetAllKeyAssignmentReplacements(ctx, expectedChainID)) + require.Empty(t, providerKeeper.GetAllConsumerAddrsToPrune(ctx, expectedChainID)) + + allGlobalEntries := providerKeeper.GetAllGlobalSlashEntries(ctx) + for _, entry := range allGlobalEntries { + require.NotEqual(t, expectedChainID, entry.ConsumerChainID) + } + + slashPacketData, vscMaturedPacketData, _, _ := providerKeeper.GetAllThrottledPacketData(ctx, expectedChainID) + require.Empty(t, slashPacketData) + require.Empty(t, vscMaturedPacketData) +} + func GetTestConsumerAdditionProp() *providertypes.ConsumerAdditionProposal { prop := providertypes.NewConsumerAdditionProposal( "chainID", diff --git a/x/ccv/provider/keeper/proposal_test.go b/x/ccv/provider/keeper/proposal_test.go index c84369e815..0d7085068a 100644 --- a/x/ccv/provider/keeper/proposal_test.go +++ b/x/ccv/provider/keeper/proposal_test.go @@ -473,6 +473,9 @@ func TestHandleConsumerRemovalProposal(t *testing.T) { // meaning no external keeper methods are allowed to be called. if tc.expAppendProp { testkeeper.SetupForStoppingConsumerChain(t, ctx, &providerKeeper, mocks) + + // assert mocks for expected calls to `StopConsumerChain` when closing the underlying channel + gomock.InOrder(testkeeper.GetMocksForStopConsumerChainWithCloseChannel(ctx, &mocks)...) } tc.setupMocks(ctx, providerKeeper, tc.prop.ChainId) @@ -528,6 +531,9 @@ func TestStopConsumerChain(t *testing.T) { setup: func(ctx sdk.Context, providerKeeper *providerkeeper.Keeper, mocks testkeeper.MockedKeepers) { testkeeper.SetupForStoppingConsumerChain(t, ctx, providerKeeper, mocks) + // assert mocks for expected calls to `StopConsumerChain` when closing the underlying channel + gomock.InOrder(testkeeper.GetMocksForStopConsumerChainWithCloseChannel(ctx, &mocks)...) + providerKeeper.QueueGlobalSlashEntry(ctx, providertypes.NewGlobalSlashEntry( ctx.BlockTime(), "chainID", 1, cryptoutil.NewCryptoIdentityFromIntSeed(90).ProviderConsAddress())) @@ -546,6 +552,9 @@ func TestStopConsumerChain(t *testing.T) { description: "valid stop of consumer chain, all mock calls hit", setup: func(ctx sdk.Context, providerKeeper *providerkeeper.Keeper, mocks testkeeper.MockedKeepers) { testkeeper.SetupForStoppingConsumerChain(t, ctx, providerKeeper, mocks) + + // assert mocks for expected calls to `StopConsumerChain` when closing the underlying channel + gomock.InOrder(testkeeper.GetMocksForStopConsumerChainWithCloseChannel(ctx, &mocks)...) }, expErr: false, }, @@ -569,48 +578,12 @@ func TestStopConsumerChain(t *testing.T) { require.NoError(t, err) } - testProviderStateIsCleaned(t, ctx, providerKeeper, "chainID", "channelID") + testkeeper.TestProviderStateIsCleanedAfterConsumerChainIsStopped(t, ctx, providerKeeper, "chainID", "channelID") ctrl.Finish() } } -// testProviderStateIsCleaned executes test assertions for the proposer's state being cleaned after a stopped consumer chain. -func testProviderStateIsCleaned(t *testing.T, ctx sdk.Context, providerKeeper providerkeeper.Keeper, - expectedChainID, expectedChannelID string, -) { - t.Helper() - _, found := providerKeeper.GetConsumerClientId(ctx, expectedChainID) - require.False(t, found) - _, found = providerKeeper.GetChainToChannel(ctx, expectedChainID) - require.False(t, found) - _, found = providerKeeper.GetChannelToChain(ctx, expectedChannelID) - require.False(t, found) - _, found = providerKeeper.GetInitChainHeight(ctx, expectedChainID) - require.False(t, found) - acks := providerKeeper.GetSlashAcks(ctx, expectedChainID) - require.Empty(t, acks) - _, found = providerKeeper.GetInitTimeoutTimestamp(ctx, expectedChainID) - require.False(t, found) - - require.Empty(t, providerKeeper.GetAllVscSendTimestamps(ctx, expectedChainID)) - - // test key assignment state is cleaned - require.Empty(t, providerKeeper.GetAllValidatorConsumerPubKeys(ctx, &expectedChainID)) - require.Empty(t, providerKeeper.GetAllValidatorsByConsumerAddr(ctx, &expectedChainID)) - require.Empty(t, providerKeeper.GetAllKeyAssignmentReplacements(ctx, expectedChainID)) - require.Empty(t, providerKeeper.GetAllConsumerAddrsToPrune(ctx, expectedChainID)) - - allGlobalEntries := providerKeeper.GetAllGlobalSlashEntries(ctx) - for _, entry := range allGlobalEntries { - require.NotEqual(t, expectedChainID, entry.ConsumerChainID) - } - - slashPacketData, vscMaturedPacketData, _, _ := providerKeeper.GetAllThrottledPacketData(ctx, expectedChainID) - require.Empty(t, slashPacketData) - require.Empty(t, vscMaturedPacketData) -} - // TestPendingConsumerRemovalPropDeletion tests the getting/setting // and deletion methods for pending consumer removal props func TestPendingConsumerRemovalPropDeletion(t *testing.T) { @@ -1075,8 +1048,8 @@ func TestBeginBlockCCR(t *testing.T) { expectations = append(expectations, testkeeper.GetMocksForSetConsumerChain(ctx, &mocks, prop.ChainId)...) } // Only first two consumer chains should be stopped - expectations = append(expectations, testkeeper.GetMocksForStopConsumerChain(ctx, &mocks)...) - expectations = append(expectations, testkeeper.GetMocksForStopConsumerChain(ctx, &mocks)...) + expectations = append(expectations, testkeeper.GetMocksForStopConsumerChainWithCloseChannel(ctx, &mocks)...) + expectations = append(expectations, testkeeper.GetMocksForStopConsumerChainWithCloseChannel(ctx, &mocks)...) gomock.InOrder(expectations...) diff --git a/x/ccv/provider/keeper/relay_test.go b/x/ccv/provider/keeper/relay_test.go index b266211a42..590286261c 100644 --- a/x/ccv/provider/keeper/relay_test.go +++ b/x/ccv/provider/keeper/relay_test.go @@ -1,6 +1,7 @@ package keeper_test import ( + "strings" "testing" "time" @@ -699,7 +700,7 @@ func TestSendVSCPacketsToChainFailure(t *testing.T) { ) // Append mocks for expected call to StopConsumerChain - mockCalls = append(mockCalls, testkeeper.GetMocksForStopConsumerChain(ctx, &mocks)...) + mockCalls = append(mockCalls, testkeeper.GetMocksForStopConsumerChainWithCloseChannel(ctx, &mocks)...) // Assert mock calls hit gomock.InOrder(mockCalls...) @@ -715,3 +716,72 @@ func TestSendVSCPacketsToChainFailure(t *testing.T) { // Pending VSC packets should be deleted in StopConsumerChain require.Empty(t, providerKeeper.GetPendingVSCPackets(ctx, "consumerChainID")) } + +// TestOnTimeoutPacketWithNoChainFound tests the `OnTimeoutPacket` method fails when no chain is found +func TestOnTimeoutPacketWithNoChainFound(t *testing.T) { + // Keeper setup + providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + // We do not `SetChannelToChain` for "channelID" and therefore `OnTimeoutPacket` fails + packet := channeltypes.Packet{ + SourceChannel: "channelID", + } + err := providerKeeper.OnTimeoutPacket(ctx, packet) + require.Error(t, err) + require.True(t, strings.Contains(err.Error(), channeltypes.ErrInvalidChannel.Error())) +} + +// TestOnTimeoutPacketStopsChain tests that the chain is stopped in case of a timeout +func TestOnTimeoutPacketStopsChain(t *testing.T) { + // Keeper setup + providerKeeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + providerKeeper.SetParams(ctx, providertypes.DefaultParams()) + + testkeeper.SetupForStoppingConsumerChain(t, ctx, &providerKeeper, mocks) + + packet := channeltypes.Packet{ + SourceChannel: "channelID", + } + err := providerKeeper.OnTimeoutPacket(ctx, packet) + + testkeeper.TestProviderStateIsCleanedAfterConsumerChainIsStopped(t, ctx, providerKeeper, "chainID", "channelID") + require.NoError(t, err) +} + +// TestOnAcknowledgementPacketWithNoAckError tests `OnAcknowledgementPacket` when the underlying ack contains no error +func TestOnAcknowledgementPacketWithNoAckError(t *testing.T) { + // Keeper setup + providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + ack := channeltypes.Acknowledgement{Response: &channeltypes.Acknowledgement_Result{Result: []byte{}}} + err := providerKeeper.OnAcknowledgementPacket(ctx, channeltypes.Packet{}, ack) + require.NoError(t, err) +} + +// TestOnAcknowledgementPacketWithAckError tests `OnAcknowledgementPacket` when the underlying ack contains an error +func TestOnAcknowledgementPacketWithAckError(t *testing.T) { + // Keeper setup + providerKeeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + providerKeeper.SetParams(ctx, providertypes.DefaultParams()) + + // test that `OnAcknowledgementPacket` returns an error if the ack contains an error and the channel is unknown + ackError := channeltypes.Acknowledgement{Response: &channeltypes.Acknowledgement_Error{Error: "some error"}} + err := providerKeeper.OnAcknowledgementPacket(ctx, channeltypes.Packet{}, ackError) + require.Error(t, err) + require.True(t, strings.Contains(err.Error(), providertypes.ErrUnknownConsumerChannelId.Error())) + + // test that we stop the consumer chain when `OnAcknowledgementPacket` returns an error and the chain is found + testkeeper.SetupForStoppingConsumerChain(t, ctx, &providerKeeper, mocks) + packet := channeltypes.Packet{ + SourceChannel: "channelID", + } + + err = providerKeeper.OnAcknowledgementPacket(ctx, packet, ackError) + + testkeeper.TestProviderStateIsCleanedAfterConsumerChainIsStopped(t, ctx, providerKeeper, "chainID", "channelID") + require.NoError(t, err) +} diff --git a/x/ccv/provider/proposal_handler_test.go b/x/ccv/provider/proposal_handler_test.go index d3707d8c28..e8963421d2 100644 --- a/x/ccv/provider/proposal_handler_test.go +++ b/x/ccv/provider/proposal_handler_test.go @@ -108,6 +108,9 @@ func TestProviderProposalHandler(t *testing.T) { case tc.expValidConsumerRemoval: testkeeper.SetupForStoppingConsumerChain(t, ctx, &providerKeeper, mocks) + // assert mocks for expected calls to `StopConsumerChain` when closing the underlying channel + gomock.InOrder(testkeeper.GetMocksForStopConsumerChainWithCloseChannel(ctx, &mocks)...) + case tc.expValidEquivocation: providerKeeper.SetSlashLog(ctx, providertypes.NewProviderConsAddress(equivocation.GetConsensusAddress())) mocks.MockEvidenceKeeper.EXPECT().HandleEquivocationEvidence(ctx, equivocation) From 4a7bd10409c151f4e4e470a217dcc6480f763aac Mon Sep 17 00:00:00 2001 From: insumity Date: Tue, 22 Aug 2023 14:47:04 +0200 Subject: [PATCH 093/134] supress gosec false positives (#1228) Add gosec supressions for false positives --- x/ccv/consumer/types/keys.go | 1 + x/ccv/types/events.go | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/x/ccv/consumer/types/keys.go b/x/ccv/consumer/types/keys.go index b755cf9f5a..c9a3d3f5b0 100644 --- a/x/ccv/consumer/types/keys.go +++ b/x/ccv/consumer/types/keys.go @@ -26,6 +26,7 @@ const ( ConsumerRedistributeName = "cons_redistribute" // ConsumerToSendToProviderName is a "buffer" address for outgoing fees to be transferred to the provider chain + //#nosec G101 -- (false positive) this is not a hardcoded credential ConsumerToSendToProviderName = "cons_to_send_to_provider" ) diff --git a/x/ccv/types/events.go b/x/ccv/types/events.go index ba71e063f3..8bd3549393 100644 --- a/x/ccv/types/events.go +++ b/x/ccv/types/events.go @@ -35,10 +35,11 @@ const ( AttributeConsumerConsensusPubKey = "consumer_consensus_pub_key" AttributeDistributionCurrentHeight = "current_distribution_height" - AttributeDistributionNextHeight = "next_distribution_height" - AttributeDistributionFraction = "distribution_fraction" - AttributeDistributionTotal = "total" - AttributeDistributionToProvider = "provider_amount" + //#nosec G101 -- (false positive) this is not a hardcoded credential + AttributeDistributionNextHeight = "next_distribution_height" + AttributeDistributionFraction = "distribution_fraction" + AttributeDistributionTotal = "total" + AttributeDistributionToProvider = "provider_amount" AttributeConsumerRewardDenom = "consumer_reward_denom" AttributeConsumerRewardDepositor = "consumer_reward_depositor" From 2a1e3a90b61ea23317b7715aa8c1a2d676079d56 Mon Sep 17 00:00:00 2001 From: MSalopek Date: Thu, 24 Aug 2023 14:30:33 +0200 Subject: [PATCH 094/134] docs: add testing improvements ADR (adr-011) (#1197) * docs: add testing improvements ADR * docs: fix links and typos * Update docs/docs/adrs/adr-011-improving-test-confidence.md Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> * Update docs/docs/adrs/adr-011-improving-test-confidence.md Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> * docs: update from comments --------- Co-authored-by: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> --- .../adrs/adr-011-improving-test-confidence.md | 202 ++++++++++++++++++ docs/figures/cometmock_matrix_test.png | Bin 0 -> 1427685 bytes docs/figures/matrix_e2e_tests.png | Bin 0 -> 807219 bytes 3 files changed, 202 insertions(+) create mode 100644 docs/docs/adrs/adr-011-improving-test-confidence.md create mode 100644 docs/figures/cometmock_matrix_test.png create mode 100644 docs/figures/matrix_e2e_tests.png diff --git a/docs/docs/adrs/adr-011-improving-test-confidence.md b/docs/docs/adrs/adr-011-improving-test-confidence.md new file mode 100644 index 0000000000..8ba0e6e5a1 --- /dev/null +++ b/docs/docs/adrs/adr-011-improving-test-confidence.md @@ -0,0 +1,202 @@ +--- +sidebar_position: 12 +title: ADR Template +--- +# ADR 11: Improving testing and increasing confidence + +## Changelog +* 2023-08-11: Proposed, first draft of ADR. + +## Status + +Proposed + +## Context + +Testing, QA, and maintenance of interchain-security libraries is an ever-evolving area of software engineering we have to keep incrementally improving. The purpose of the QA process is to catch bugs as early as possible. In an ideal development workflow a bug should never reach production. A bug found in the specification stage is a lot cheaper to resolve than a bug discovered in production (or even in testnet). Ideally, all bugs should be found during the CI execution, and we hope that no bugs will ever even reach the testnet (although nothing can replace actual system stress test under load interacting with users). + +During development and testnet operation the following types of bugs were the most commonly found: +- improper iterator usage +- unbounded array access/iteration +- improper input handling and validation +- improper cached context usage +- non-determinism check (improper use of maps in go, relying on random values) +- KV store management and/or how keys are defined +- deserialization issues arising from consumer/provider versioning mismatch + +Such bugs can be discovered earlier with better tooling. Some of these bugs can induce increases in block times, chain halts, state corruption, or introduce an attack surface which is difficult to remove if other systems have started depending on that behavior. + +#### Current state of testing +Our testing suites consist of multiple parts, each with their own trade-offs and benefits with regards to code coverage, complexity and confidence they provide. + +### Unit testing +Unit testing is employed mostly for testing single-module functionality. It is the first step in testing and often the most practical. While highly important, unit tests often **test a single piece of code** and don't test relationships between different moving parts, this makes them less valuable when dealing with multi-module interactions. + +Unit tests often employ mocks to abstract parts of the system that are not under test. Mocks are not equivalent to actual models and should not be treated as such. + +Out of all the approaches used, unit testing has the most tools available and the coverage can simply be displayed as % of code lines tested. Although this is a very nice and very easy to understand metric, it does not speak about the quality of the test coverage. + +Since distributed systems testing is a lot more involved, unit tests are oftentimes not sufficient to cover complex interactions. Unit tests are still necessary and helpful, but in cases where unit tests are not helpful e2e or integration tests should be favored. + +### Integration testing +With integration testing we **test the multi-module interactions** while isolating them from the remainder of the system. +Integration tests can uncover bugs that are often missed by unit tests. + +It is very difficult to gauge the actual test coverage imparted by integration tests and the available tooling is limited. +In interchain-security we employ the `ibc-go/testing` framework to test interactions in-memory. + +At present, integration testing does not involve the consensus layer - it is only concerned with application level state and logic. + +### End-to-end testing +In our context end-to-end testing comprises of tests that use the actual application binaries in an isolated environment (e.g. docker container). During test execution the inputs are meant to simulate actual user interaction, either by submitting transactions/queries using the command line or using gRPC/REST APIs and checking for state changes after an action has been performed. With this testing strategy we also include the consensus layer in all of our runs. This is the closest we can get to testing user interactions without starting a full testnet. + +End-to-end testing strategies vary between different teams and projects and we strive to unify our approach to the best of our ability (at least for ICS and gaia). + +The available tooling does not give us significant (or relevant) line of code coverage information since most of the tools are geared towards analyzing unit tests and simple code branch evaluation. + +We aim to adapt our best practices by learning from other similar systems and projects such as cosmos-sdk, ibc-go and CometBFT. + + +## Decision + +### 1. Connect specifications to code and tooling +Oftentimes, specifications are disconnected from the development and QA processes. This gives rise to problems where the specification does not reflect the actual state of the system and vice-versa. +Usually specifications are just text files that are rarely used and go unmaintained after a while, resulting in consistency issues and misleading instructions/expectations about system behavior. + +#### Decision context and hypothesis +Specifications written in a dedicated and executable specification language are easier to maintain than the ones written entirely in text. +Additionally, we can create models based on the specification OR make the model equivalent to a specification. + +Models do not care about the intricacies of implementation and neither do specifications. Since both models and specifications care about concisely and accurately describing a system (such as a finite state machine), we see a benefit of adding model based tools (such as [quint](https://github.com/informalsystems/quint)) to our testing and development workflows. + +#### Main benefit +MBT tooling can be used to generate test traces that can be executed by multiple different testing setups. + +### 2. Improve e2e tooling + +#### Matrix tests +Instead of only running tests against current `main` branch we should adopt an approach where we also: +- **run regression tests against different released software versions** (`ICS v1 vs v2 vs v3`) +- **run non-determinism tests to uncover issues quickly** + +Matrix tests can be implemented using [CometMock](https://github.com/informalsystems/CometMock) and refactoring our current e2e CI setup. + +#### Introducing e2e regression testing + +This e2e test suite would execute using a cronjob in our CI (nightly, multiple times a day etc.) + +Briefly, the same set of traces is run against different **maintained** versions of the software and the `main` branch. +This would allow us to discover potential issues during development instead of in a testnet scenarios. + +The most valuable issues that can be discovered in this way are **state breaking changes**, **regressions** and **version incompatibilities**. + +The setup is illustrated by the image below. +![e2e matrix tests](../../figures/matrix_e2e_tests.png) + +This table explains which versions are tested against each other for the same set of test traces: +* ✅ marks a passing test +* ❌ marks a failing test + +| **USES: ICS v1 PROVIDER** | **start chain** | **add key** | **delegate** | **undelegate** | **redelegate** | **downtime** | **equivocation** | **stop chain** | +|---------------------------------|-----------------|-------------|--------------|----------------|----------------|--------------|------------------|----------------| +| **v1 consumer (sdk45,ibc4.3)** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| **v2 consumer (sdk45, ibc4.4)** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| **v3 consumer (sdk47, ibc7)** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| **main consumer** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | +| **neutron** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | +| **stride** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | + + +#### Introducing e2e CometMock tests + +CometMock is a mock implementation of the [CometBFT](https://github.com/cometbft/cometbft) consensus engine. It supports most operations performed by CometBFT while also being lightweight and relatively easy to use. + +CometMock tests allow more nuanced control of test scenarios because CometMock can "fool" the blockchain app into thinking that a certain number of blocks had passed. +**This allows us to test very nuanced scenarios, difficult edge cases and long-running operations (such as unbonding operations).** + +Examples of tests made easier with CometMock are listed below: +- regression tests +- non-determinism tests +- upgrade tests +- state-breaking changes + +With CometMock, the **matrix test** approach can also be used. The image below illustrates a CometMock setup that can be used to discover non-deterministic behavior and state-breaking changes. +![e2e matrix tests](../../figures/cometmock_matrix_test.png) + +This table explains which versions are tested against each other for the same set of test traces: +* ✅ marks a passing test +* ❌ marks a failing test + +| **SCENARIO** | **start chain** | **add key** | **delegate** | **undelegate** | **redelegate** | **downtime** | **equivocation** | **stop chain** | +|---------------------------------|-----------------|-------------|--------------|----------------|----------------|--------------|------------------|----------------| +| **v3 provi + v3 consu** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| **main provi + main consu** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| **commit provi + commit consu** | ✅ | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | + + +Briefly; multiple versions of the application are run against the same CometMock instance and any deviations in app behavior would result in `app hash` errors (the apps would be in different states after performing the same set of actions). + +### 3. Introduce innovative testing approaches + +When discussing e2e testing, some very important patterns emerge - especially if test traces are used instead of ad-hoc tests written by hand. + +We see a unique opportunity to clearly identify concerns and modularize the testing architecture. + +The e2e testing frameworks can be split into a **pipeline consisting of 3 parts: model, driver and harness**. + +#### Model + +Model is the part of the system that can emulate the behavior of the system under test. +Ideally, it is very close to the specification and is written in a specification language such as quint, TLA+ or similar. +One of the purposes of the model is that it can be used to generate test traces. + + +#### Driver + +The purpose of the driver is to accept test traces (generated by the model or written by hand), process them and provide inputs to the next part of the pipeline. + +Basically, the driver sits between the model and the actual infrastructure on which the test traces are being executed on. + +#### Harness + +Harness is the infrastructure layer of the pipeline that accepts inputs from the driver. + +There can be multiple harnesses as long as they can perform four things: +* bootstrap a test execution environment (local, docker, k8s…) +* accept inputs from drivers +* perform the action specified by the driver +* report results after performing actions + + +## Consequences + +The procedure outlined in this ADR is not an all-or-nothing approach. Concepts introduced here do not rely on each other, so this ADR may only be applied partially without negative impact on test coverage and code confidence. + +### Positive + +1. introduction of maintainable MBT solutions +* improvement over the current "difftest" setup that relies on an opinionated typescript model and go driver + +2. increased code coverage and confidence +* using CometMock allows us to run more tests in less time +* adding matrix e2e tests allows us to quickly pinpoint differences between code versions + + +### Negative +It might be easier to forgo the MBT tooling and instead focus on pure property based testing + +- [PBT proof of concept](https://github.com/cosmos/interchain-security/pull/667) +- [property based testing in go](https://github.com/flyingmutant/rapid) + +The solutions are potentially expensive if we increase usage of the CI pipeline - this is fixed by running "expensive" tests using a cronjob, instead of running them on every commit. + +### Neutral +The process of changing development and testing process is not something that can be thought of and delivered quickly. Luckily, the changes can be rolled out incrementally without impacting existing workflows. + +## References + +> Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here! + +* https://github.com/cosmos/gaia/issues/2427 +* https://github.com/cosmos/gaia/issues/2420 +* [ibc-go e2e tests](https://github.com/cosmos/ibc-go/tree/main/e2e) diff --git a/docs/figures/cometmock_matrix_test.png b/docs/figures/cometmock_matrix_test.png new file mode 100644 index 0000000000000000000000000000000000000000..740005aed18c6068def2adf79d9d0bf46541e212 GIT binary patch literal 1427685 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%0A>@;>6wv|kNex@_p8qcEMD9+hxC-r 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%0Da} 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 QZxY0E1 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

    Sk zv(-tUWz(1_M-z_~gn_Yt-n2AxqPX;G2}rqpDGL=_xe%g@c9B=0aK*ScqJ=e&yR@3w zjkLq%raG0+b_#!)Oc2!d8CfmmsJ(>glgJatqoROiuKp!bawRQ2W7=7bSzCO2uZN~6 zKsML)WD(egwew2h9?G5xDWsdmg?4-5Mu-zAX;N3BwW}mznPrdGc&^0BUj z1=7EFo)Rb6lZu~={vrF+kKY&fUZ4r+D(Du8b5JKGp=|UjGyBtfF4jO>@2sPO{e=uu zcG>L^LifI;Y>ofL;g=2fYUOjIe(ef8iyft>AD@;0rjF2YwvgV&cXW62l_We)kUIqi+XK`dHO&63)d>}Newt4s}FU8Nk;3Wm%9RQmwvWL_4?6^fpJs;6%Ne`Aapu&S$;kB8zbvlRThu zSo`a}tB1t%h2bB#)qLQ9UD#{`*5toe$#VYw{8Jpv6!x)d59z6a9t*mcjK`<`sQWm# zUyJgUwgah;^VC~Tfk}%eMAjT>$Og|58-tZgkyGtCiFfT4(n}LdOXo5+ODOvm$4ghA z-&+Oqc?B?gMvO(L@>23z(0{q~wU>^2h-_?h8Vb^P32kY1nf`28KK|&n4MsHkuk!Is zKcD3%-8gGLiET4=Y>Twh3i!CUak9imr4SJ7d-v*A4%`1JoM`7F+!2H#nzyV=og=ZY z*wbD%Vs12R?{%LO)Az$hYI*M8UCKk<*<(Mm-O~niv4%f=xkaL=U%iUBnpDZVJBz3s zGTY*elp6czdq{2r!>tQum2{w>n2^7b^ZCEsT@QoOo&`O}mV#4@HE(H^_sS^w{pXc@ z;|Nwybe17jBz*JtNqX{*W(a2D3f8?=+^yfu@$8A|%}JNcM^;>l_vP^Ed1!yuO%l8{ zB+)Pv`ML3fw)#lW8BEA@KmTUaoFyMvYb3b>*Y&2RfV-f+c16KMZ39Yf`*f2h(={yL zV`^BdBj_<15AXG<5sGitPy{_irG8Jg)b0<%F6G_!+A1;Di~h}wOKE-UqMDw?m|S}l z^cdvLKX)76Zb1!LkQloYY-TnLjA?OpQ`<(Sxd?|%z*uytL)sBff`Sb;w)>G?!0j=E z!3qmCmG8kNu&kDUgqDHuGeNnnDvbNVlCtCz&VmVfKn4x@f?$V2D%~#sJ+*wUMqLs9 zm^1&&Wf+gd2~WD3_RfgkpYNp+x%-g&WeLwJSjXx9gm#DQe7ZJ9`$Ms`{Dd1!!IxS9 zPR~A4jE{3dsHCTVh%8e-%E`c>^H6b6tzc&7Tjvs6{DfC`Kuc3W`;MoR(^J#zRdNgV zKUhMBrG0`;7jP#5aBGf^-0N4i@N@sn1lB&jo{d}g&}ED6&9{SJlgR6aw3A;f85@KN6d-`U+ z3_?&|(#N%-MOBn=hZ|7DSZA(B`fSr4P6Y3Hety}H(0{H~qj|;Al-PIW; z4jM^)#+q*+W7~@w=Dzf3Z}|?=g8^UMGtrWyuZ=}pIX@Yotu*-$ifjkG&w)fbz`Ut# zTX(~`!ktk+_iuwv<5kYu63GO6Zagx;Swp^ABsYSkh4_wm}3l6%s?MZ!!`u)e9NY>OB!AbrM9g?-VGOv4TbE6Ulm*gIjjeJ^RgB zoYs`CGUY`zyZ#Wwk)oE+%Cnm%x=P{hV2fJAolyQ47qj6sBn{)O-a3o7OgwwJ7OkYY zMJ!jTP2kOE({kqKGuKINq(d(m3)D@Vlru=4GOK76q&}Z;KP`VZU(Bz8NFv<3IAbL! zJce0+kl`P=`0%oJhX1QF$7&iakMWZj=i0sNRwBC}2xI$%c%%%-XX3HlICl;|v0zn< zd)s(~z=iPXv{h+7!1S5l>3PblsY`*!5MSPhNj`qs?#0Ql1ozv6WI}DwmN@;Z#1qNb zv8>2(i{<7x$7hf*KqoZ^D|6Pb2o2ad|1P$4e~E{0+ITL#asP}IZdYfhiDVzX@?Q!! z!JYp+xKTAkw(LW>K@ViC?^(C>iM9#{T%;9nKKkw6P*66t{{Xb7FC;L6GiXD1IxZaG zHoO{Qwi|HbUpGCnuQaRV5&Q7Lf`6ABFpicqc1}{yQe;T-oB#L{IZorP*?E5u0I@Vj zTd?NnwAY&k-6MFSdhQCPj8~lyl*ilKJgX|qHHQ08T3=0$>;&EC;FrIlaDz~XYzS8Y zf^BgjOK-*qyjWdosXKt4%Gqt~Fs$kiILqn>6xXOjYyoot&1tVnraC)?*SuP|?C_ry45z>3)H54p;5_lcq#ZF}2zaKVdM z9Y{z<>BAFe{(^wJ69Id!uXVT4%Df8yB7~6Zrh*eyg;WB|U8HO;y*S#C2LQqDFguAyUimzcMa$Br7BQg( zkVP}NmqDXgQZ2j-;Wop#f~UF(e9dby$DGEuuX{HOWv$gE&%=ZUrkiE!wQqJt=pCzcpyY6Rek`(}>y7xL$`4 zA^v)dox&SoYtMVE%F8Yn<-kR#NQ)go7at0FtR1A;LZdszx|X&_JETnT>*KlnOoEet z13nH=P5$%50Ki8MERN?O#ABaZt9#u(K;v)Jozp-4_btSKKiepyZ_R??b_z=SGYs*| za^DMA<-}-(TPxkyF_;R3gBj0^n&fD6vHkuK_qpKG9g5RFMQ;E)H>vU|ck$ znj^@R0ap#8PB>ecMQ{q+ZkQlNiOWKq5n9r`nOonLPz~z&kFhis_@FbvRe7cyF&4Ft z+(O6_2dIKN{I-6iPVt&@Q)rFEtHq=fe!3ZYnRj%IS7g!mESA(8T$cl*@KU0`r$Bq23}8C? zxP60$ctSxXReE&#Y@Hs(zu3UbLgRkf?_c(xn=O@Oudrh9hVTkoc;WB>GL%r9e54N_ z=a|#*%?x&!W)nU42}K-ctTFMErlw)ko?JhL1&a{5-)CIC=+00}3XZKf~!m6S? z((!#-Gtg(SbejhM8!dgWZ6%)@fHV*akOn}>I(96e&oavg)G*rye}CmCt+yy>|K$U{ zr_dhQl(o)&)0G;1ga35Oj|-g+WAj9p?_oep(}6?y;dB|FpI#n7L62)j#cQID>{x-R!nsq6@lH4KmUX z`rrNV$Hk0_zAQk0BzyBZg95JzYa)h^v_=p%jLPvF^ue==W$DGXatK+wd|fJUgWcMH zTD1`HU#T<+mnPyf-)&9B`IhFd_%n4_-?l3Bt_HfF**I@Jno+623$1Wpt?ymf19W8n z9HRtZ+Ii5-L{Y1T5xf%RVV6qy7P{NmM|SRG4gZDcgxYdf$P2w)6>}Z-9}q7xF5uQU zDznF`O>@1CbI$=-T>huj1!P@0CW)2P$aELMseADgu+hyO;JO15@Rq3$V+?Ll|8egOhnzWrB+azc5qM3-!L!R{9m^mIJh6 zxa8Gy)c`a*VhVkA%vyL6~GwMKW#>y)Fa_? zo_%Iw!wY;z#xw`a?eMn9Duhh)Zg`e(IL4mSU=r3p{;#u+qa3cD|eDhb+L2YCh$d=W0M2*uJ` zBaX>v0)Um%1R=7A_hYFki72{FDA?XTH5Ho0qWo~4)~kvVAqjH+_L7kFD+h@WdM0gt zn(NnO+s)6tCJ`!TbI(>qXVD0U%-0H-4Pmpo`GfPXMXgU)rRo8@Dg{U zrgpbBA5m}3AQ@=*^HdNNy!~uJ{8f7&W%O5bX5$sx?5LQRR4IBJ)=l)ri@=TYfHr$I zqWUDYNU7}?P$j0iT77`#oT7?Q08sNy4zg{=)607GQ6D~3H2Gph9_O^iq&KBA7eqal z{yz7xcmK31c#TD()Be?gpyxlN82^pL|6S-gDsRX#2#{Q)+CBEYVM)RiI_6UY% zKHr2Me}Qegd-bjD-1c3`?#oc|6G?(y}>(j+;^0rGjYNH9hK|`R4L} zoCbRa(23+VYsOy=BaIIwod4-%r-pUse=g)0+IF$KQFj%tooB@ z14)mKqgQ5;!`hj4w=obvT;k%gK1N;P)dI%8N}PAJj^i|r0Qjx;9<|ZX`%pOXvkM?| zCAJ)`3_TxNm6I)046&)79H|e)|Ams{61b44XB0l0{Ua>VaBK3^3KkDP!Nv4rN|;Rv zDUilIC03aUx)elzvUNj?M@YVdi*)*}9Lq@#WXG_sq!D2j$0}#nJrU_#vJnD$>}s*I z&B+5S9ni_4Q9+IYp;=nkZ7vbexoOrM=JHqbp5LNZDNOhX?RkX~s}w<6Wr_i9gic;< z)h1)uv4Kg1>XaWNlc~zHG1Ubj1yQ629J2T-*(Cgh_N600)HXnEO77EY_&^6xjwhFr zzZSG{(cF4-q!>2WVBBW4p#P>8zcC+x(_02Ciy2>>^v!)VeN1e579}gqGvV(V9;&Y| z(o(^%i6Gp)e|0iOp5a$ojy4coyKb$qW6RR1%?KgiHdTAjpHA-M^yBxge|4Q^n;xJk zohP=dnmdb3Fq@`Zx@&G6zeK*L-mTne=NfDuf)hix@5{D-QEHC6yIdn<24mqZF zFFl&5Wt@Vc9u56DrteQY!nHH6QjNc52b}q>17xhu57QGeZ&yMA3ZaQ1P9&K4R&{SV zHN-13zh`ksd9!3rXQnpO$E2Qj>1y;U7iW0nS1cI4Et2kF*n?RcCgQD{)h3H@h!k=~ ze4eu23hZU@?)j3xZzt)vjST&H_3(79T+ACE0}=%Y>&;WH0Dss2&h~F)qt`-H)hEbs z5sKWTBvo*u$A)#}_o2W>$M{SCjoO5(0fesQRRWe)Kj`!~9X;S4@<Egk-hkZIopEr=v3pks0L#^)h2WeYqps{;PGt9g+?Cv?I%+#z~I9e@bg=Z!{E+T?is!8K-Q% zTm9m4EJmVUtjMBG^Ejt>+Mt zfYqLSelEFBcoMZ2jttCXnk|38e)NC}^vM*Pa~i?DtVS2ZY{C`a9+uJVJuz!_ntUyA z^{y^wwz7XtVYt$_gcmaJrH0{hDL3W7Iwb{Swk!o@rIFSVxOMG<6Fv zk{h6e`#M;R#t)alDZ-qF-+s@H52@(DizN1_dzW%%UO_4Wk(G^9J?7sR)whztEr`t# zzyoU8T9|_tonB>;YyBe?{MQNEH3GfImP)!)zx&97dBkNsaBRpad9ir9J7Oh0MSb9| z!YWxDk!HSvZ1%FS5D#;L-NoDuYGK2q5dhB-t&E=<)71%TwAa&`Yss6vWqgn~-nD48 z#QG}IMzc#IPWflbsQ>%xD|Cyk>#dSh@Y4OZbEc^}S@z8R(1J8*ssMjR9&7h%*VJxl zgQ{gASNYk6f|<5PQsjh*%Zk2C@I5n#5?z52eWrsw71!?2*ScnAp1hhzNt1SO{J z;%0)`FOBcpD*f3IE*6}qldpLz3~7vqXUr(`x{c80F$2{V7R*^af|76F0)h9QF`=6j z)6c9oW* zNXJu$@<-IJLHv%_U+IYL3*JA`{8baH8%uiD@-U7@*eOIabHm^>Jr;9(36wgf zfPg(OrD#b)8&sT4+ebBX=t3bx;r@9$LP^$g@DYGbgSR`lF*mhZE7DflVO5g-Mb2(5 zDM7RejOyKWQA9o69ZdW*3RHsLDQm!j;FZENl-Ez8b0*@xS;=3Y4*nD#0^prSHtw!7 zG)NKoAHu+Ylp-v}W?ObS!fL#@vn0XEE_?+RqcLZjdgD_r9_)vE`K}huLpYj`B0x?9 z#v5T0!`T62NUX^iX`}GFwifrYZNYP6quG;w zvD;JzZ%+_iP$qWv@pTE880thCYYzRKV6#5;hRrgW&T-{rOS#Ls1IRt$wutC`cqcA$ zm3t#QO;_2#`sx_i!>Aneojxn0{z=Yrfq^s@?2&`Pz_s4tjPreQcqhN-yQls>$g8ErtHSpHlv6 zOA3Dd~AQ`Gh9AfSAXujfB(2;CKbVS>@?#xm&Ww3R)t+^?rtb|l444T7wbcP9nj%J(?a$pGKx;4Ln>=bx$LGYDm z;n~-+a3?LY+`~tea!v(9{1t178w~KJA~GjyszyQO{`wkal|=69XDlwRSTd2y2YxVB zLtoLzH_607&26juQ>K%O#wZQIr`yl(RdHK)baNzd%-SvxS5i_;f>D8uVTk3uL|J?D zHf_4*M%@hSR#c-tEfFFLvg2zAZTfp_m<*vvg3u!n znCJ+L4k6!V)&WJ{DC(B}3}O++Fr)yKwkUsnQY9YyaLmd48a#_2g*j#u>X272(w!bodCNjoez-O2i^O7pT3TLNwK@oLax8|9kbgpv~hci zcod5}rXlg;w>8e!fEFbf5@U8)(Zu3hocNQOIW{%ou&*g~kYaEiD0YxCLqcE|=0poi{FH!=@f zl_eY>memna8`||t_!m=3_r9YSzoHgE+p!tG*>ZZG)`mYPHof9 z^}?IZTa377tYt?(WCi(2g#Q_-P>EPdG)wWt!9pseY}`nSy!dYpYbIX^vTLMDKi(g|p)7~yWCb@U0hrgA#RTy`N$Yzu*@Ke6xoPPw@ zB{2aqt_gwzz4u1MU(o7=mf^m-u~+$)0V&x(c zw`cUQ55quI)|A&`-<7l7w>|^?+Z6E=U1MJ`HMFgZYg`zeB{ILIy;DyaB(gL**RpTK z^%?aPmkZ+4rK)Nphh(?+8w`dP&6unZ!R@eKo7gNgJ2Koc@mX8F?;Ca+;J{mPTx)CB z(sws9AyRU(L8;6|R$L7>S%EkW<#HA8=x{YqC~Y4iL3$WCwJ$N%l$C+O-#)=v{2mVWTrk1m#v8N>pJ0~M)+txomXO3dO} z`7CA<&gF39SJchOT2n4&scORlTK zJZ4giuy%mbQ+PuxEvnrRZBx1hq3<$}Bd86@`Yrw6o8`Z6k!2>?tVhza7-}!~{{oFU zCz$F^-mWkH{=omL;!Fbtv4Bv3k5MBe#VAB1_#IuCyFvY>^E}`SRfKzRAulc>W=1QX z5jD9?s71cR_$w;7ydaXLI9U6^y(2vxJ6U_G}2(-xwN)E6r}4bk8iN|g(dSgs7s z6Wn=z$=@@`M0_QPG~+9236eZH*jC0O)F^caPHTwDzPEb+G~~($qE8V7<<>@g7>~F& z?IddcJd$DFVLvoPh0#yMgdchuaakx#?D;Ct<=l&lJD_q46Ex9MHQ2F@AaaS>rMbRs zq5VW;R|s2epENRx!Ah*La>M~F+R?WfjDfLz6x4R3Bu@9s)knXUO99UD7z=w&=2VHLoADTFlb$Pbu~$nYqIeHV^&p^zs9n=$uENyM)5XKF?vD=gSFMP+rjJa_4- zz5pV+ZS?!6>Q%Wr$8mN)&lN(8IX^oc#>R)rnmQ)mm*cOE?(DZpMV_#P_&- zSM>i9aC|DkS=tDNl0ZX1OaDN1BLQvDZgVd$^IdkFcM0b~HM`Z*rHi0B z{xd}9b+F5#DgTot!zSbG`kF^X}uVJoxt(nnPP z>`f!y%>H&~=4H7V1DSHlrctO5|AFHbgxn^-HTKDPQ@4T}&g#XxRf`gM5MAzJ3tb|1dZbZ#N+1Q2_paS6c`PGQ=Q~QsA8> z#%zY&aRb<@Z5h$)E~@7V*sdbL>hof^J#iT>{W4iT8WlqS6nVs#K!}BuC+h%9F*ll| z70+gR`^jRmSo+?%ssMM5rKqFvmh$N|qNkhI;O08h=aTZJ3fbw!4Si%v&6A~+yZxRN zFIL6~#Jue9vdbdPD4KrJzx(ta1-#Otm`?(uj8x4AGzl%(k`J3n=tg^ey^fQdRuaQA z>~i8m6DmKhT|8lLx=04zhI37;+4qqfdiuH+&MiDh%2=;jveVQ6AMtgK{9vY4(>hRi3{4rOaof6ZhL$7G`$tIWa=P zhn@mXi@WMi6%nipnrqU4EmiWi7W#;v79sd8-WUPq$!Pq>W4AKY`ik%U-Gm{Cpf>0W zGG{iR(Jk|`ZoU2Ds5*-IqpD(H}M`s}O3)(z9PmXA0LLJ_}W1BZcqIN}A=w*T> zEMSHbjsY#Gr^(plDUGkb&cL>4UzZ!dIoW{>6O6co#5H?-IL!B-6HBX@ylnAq5_fXK zdXavd$uVgo-&qjAd?qR4v>L!kYv~pHkGo@r4-2U80iHZN1@FqbU4b>zE_ug4>PP;c zwP1}7AnJ+Voc~d9d2si7HQWw=ym0wv+&uu1;t}6KpI5MPcBxEoH)Zo{k8f)`IwO4q}5Do>Azo}kpT%Xh?_M+-dc4gUqm{C$nEQhl7SL37<+w$vm`|d!IAlU5HkYD|LyC9 zk^I2G0+7l`Vp4eG_PwUP=p1@j$-ZkNyO3IhW5f$Ms+0R+KmI|; zJ%gG%l3~nyk(xT&766Do2Vh8{4vs(gVEOS-#Yq6dI6O7$_pMI~pq^Yz34EiiemI}T69eUOqRi2q>DDUmjz z#r{d!vhaq5daQj*2G&o?>rG@_25ePaJ*|AFtmsGKL5&U<+zZ~_7BOAA705fytXBc3 zFDDkUxCiNx5|go3#;UC!md|C*HWzf9_GkZ4sqtHv^vSY*rV&+17gU!X-Ld?xNov)C*d;TpGoy8lsz{y%>zXTCL}MJ)ef7iVlV_%pHUx?Mv* zE!6eFr)fC&X|kIfZ>%6)o6oxnIJMy#RswblFvo|0@!6ZA!IDlXOw~bz{@xc#JL2q&sc7nJ)WW+5pWaJ zmdAQi1s%o=Qd5ay&iv+3;OR%B*mWO8#gFH%figRKs+oHNPLb75<>)_rh!q9=y50|g zQ|YPq40VeeB{y`?$03D2a-N>YnxeI46Es`#WRwRrw?_+HP;Jx6Gqo%1RA@Vg22 zUVVk1Zfg!NRht$^MlkNx$8f}Vp~y|kr*qm(4L^+=qb0A7j2GX~jqdz0-{}+~4r;jW z9B@A)o$jGYTP>KJ99C9Yzl>Yb4*D>+y6!OHU*I`drktT11RHAv?82ua<&-KD9XCV0 z@&`F1dpS_xVus)_W4sP<+!t#9Qk__&s&aGx^rw4%>%&t#)`Z+NOY-r&<`&`S^gwAa zv8CVnQ(!{PFjhSrXAxiaxkMjle(0-P*a!OH_I8Q_wfk2#9j@zdemrVFV@9l!wpC&e zh+*Q@bAo_;jvAH$<}E~vR0U>FIvtwT`hcBU@Z0Cdq6k9>W#?@ByZv$R#o1QQBbTR% zvzScAVsqWgy&-AbgBZJAv*Q*^qskT^Np{b zwV>BN#7zhQi8C6;pjl3u{DpHEMYbf^E zpApoG>)uGE`;W!%^y6DUW^4YJ+o5H;487g?kHhjWhnXan(nF~X%hA?_2dQlq7oGhC zBUcfe22CPLTZ5dBDa5y2A`o0?;{$P}1*MG>Y5DKcoDZ z9mxpj7a}G(c6DVyk^b-LESVz@&N~F1LY8lXt^R%NrYBM|H{ zU{M*6LYD_%g4v!XU1eXT-{8nv0%cQfO3V9kf({dy*gll1^1DIRfLMif7Ij#P*gHe+ zOU@|46|yM+lKN43pEh|r(A%iB#>Yfi@QQ=%o@}ue4{u*gR9#>m5rA4}h9``PI&wem zml@y(cqjdgOF5<*rrw;G)4~LzrhJTTD>|5dcjiOezEq3toNntzN~#6?zE^_y5x|*U zdlU%#l7L0=H@e&m9CLfI zB;22JHYUlPO7p*~-JE{hn|S$Nqw^tCpBbecRyKcq*1TwYwYrwR|mk81$tN z`$|`|;w-tF5|I+wkYU17#&~e;=-HkBL0|-JWwUgFS>|`vf@qSZYO*zc3#G8~iKUq3 zzj|{Y5cxWeuny9D7SjZyx7j@@dv@9Y@W4z|?Pv3rTcw>bd+kz0BB%Xq1KJaZb2!lg zjl=77*jo(LALr%w{sf)dJHeI4drgk5Hj6YZE8h2#36rLUn!?tRlm=IedOjmkG*;IK zf^VF-sAX2J$uE6UJ@CtyG$mq@_@1SC=lU?d$h(W_@f*qbu3pddJpP@88rm@&bvuS! zcU4(SZ$H`q61@Q)_OCWOlRQEqib`p7t|+D2jrWbR*L?h%5OSbv zB?Fio#op^?@ukHytP4#u0$EElprrdekH<%Z7!8=fg#{_4Uc9RS|8Ui7oEjidc1^FO z8LyLw6Qf|tv2jAlxhD0H{=t%eSTOf`l$xJos!+YBTma+S>yNA) z0@4gwmFS)m3>$354--;z@sXvTb^JsGNg#EquaR=EGzwXuk;fzHE5~BT=~rz_jx4xB za7_I4i$8w*VrNZfVjJJiGB?t-16GV{`yJX>AtktH4gh-=L+Qa|!c8dN-hP54cUC!_ zP+qxar&|PgF8$naOO!Y;tv zYl>rvvtsD7%Lv)KpAj@)qc3<&Z&Z_T=%*#)v%DG9UVADu9o$4PjQ+ldsi%d}3qKS0 zDa>f147bw%`B0aI-f@c#A3VB~DJ+h&+!Xt~UZmUs0flk?Y9IetbT)pH+V?%owxub! z=3yJWKFMF%@GUAPK{^-KIq=}z!?xmQ!=ONywT_jIR{ZnYhGH(2sYE|UtC#T^ICiB> zYaNU!ZLgTXE3G(2az zuzdETQR~@{K;(7nY={1*BD%-rgHJt!);vTBB_`CJ@}@`;-+{K#eqIz}4YCgwB)@G5 zj|$H`k+>w2dcmIgN&Jw&mM?> zUQvL0$Dbdn2!W|3GEs%iJiJf(uSLIcPU5nglHcw7uQ&enTUG?{RI<|wk&2sdA<;AM z^Z?Y>5KonD&)|4qoU#yerV()_q74y7nQrkmVmFXCFA&2djwm-Tn7uLN3{8dq$=;E8=zTGS~8TvcyIW z0MsYJ(N6G1`QmfjfQkEw)F83L?a)P3!}&l|Y)Ldct5d7=vJXY?*!atsDU;1$prX>{RN^nKx|o$l|M5pXj7h zstNr=&|)jErzb3ZPU8_}n}gX$ncbwb8qAAnQe3(yxvCT6lz|G%wa(;$_RX~2i|i_b z;BAlv1QQ9iSs^M69p<})fITqtI&mG~eh9;p(>gB&R6T|UcOKD7O8!MRchEOJlLk(doV|U+RidT*gpB12_apx5<|o}n)k&4SrJ-kRLooTKu#Tiby7|`OOx&#|Geno zl897#S2kg$oVb2DS04~u$;v^Zu_(LL!Li9U;W)SfWO!nI`Xw4%ukR~=a zdK~a}-Q&?Cs*uMYl3$sM1^yyJGHsd8_~Qy+J&02IvkLof(36R;ouNGLT-w2+AF%ay ze-_(&=;Sf{vP|J+9D(79=6J5kDNAWIRGdr@ar1zwOo?8L@!cHkt{|d6F3o|dCmD!v zQ%Y6yj(2E#CLq_4;Ee$7xanm1hqqar_F{4ivAXln6W`wvJC+c4Gq4CM1@mU_qw40A z-KY8#@1m&i4p>5z~G1hG>tB&xCbwtuV3Ndz0B?@t3D=@Ad+r(!OQHmM{cx)d2<0MY|dw) z_6OJmYjmTUnjxdIRFO(>+W+4&{=E}$!%0}~D>^`x^?*MBX^-juyLIsYruBW`oLhyB z*GS;}LE`7Q{A@yV;@+|c`=EsyUU+XzFT$@|0(u3aGpWylbNkcHeSU1io>-|DMlt$e zkKm|~tPri8H9}8vcjp*sZ`|AdmX^sHLwFmcnLz|(8X&oc*tcG`-a8t%)QQK8{||D@ZH_)$K$1OP3eTb3SDptB~=AGC=aHisftIT%XFQpSSLAVlJC*VX5p5G z)hEKs^8F9f@wqgKh+zc=Ard9=Io&45vuk^%&=Lz=6U{)STT;5aNgKsR07`n45*&}q z?1%fj7U#~53lmKT#vSchn=vUgdr(bx*CRnWkCRJT`Hu1&uqW=Z2^2+Yvk-#YiZ_UG zBIU;qH6u|6QGt?G2E7fdY%BASd~ZzpkZrNlnC!q|Bvc9M8{cN)tEa}QV#nai_vi~) zMv>Gb+vVmZ_Wkwo;TyTK-*o|KH@#X?KXRTORHaD0Ra^Ca2!&PCDxZ6w2#5Jq$Y7w| zZ{3h+{fpRngJ2B}w$C3CH&nSMY79y?ZQI(-iWC~o((kNIot|4w$L89-omgxUI1@?V zPL^!6^tmlJbE82^^VB&faRRgnnkR8uYKAtHrfQ|=zD9Qk7)clWh!<0D8F3b2A>Jk| zt2eDEnUgKUJvD#EUj(_7tgIFbjqqBSH``Xc7_Rnv{PbyN4+jiaXLI!91^H9yS1!Q# zjkZsb^mi^#j4M0We6EXUnnVuIMYJh}xGoVaJ(qc8_qj~WB zKCN-@Y$*PY3Yn^!2eAsLAYJLr6eTa2l7wIQLs!m_>!nPBZbJbcVX-mt^G%H=Cn7S} zB`#fb)4#5wQ(Z#!PTp^}*U)Bq_h!DVZ+sysQzpx3!f)Km?`5<+sV#UI1X3hDm7*V$ z{0EHs4@?EuVIgEx7Fn69-TWuS`j6NC0lqo{ctm5#EQt+wetL`8KXOqMR7-@Aen(VN zz3HHuVz!PGhY)^1+o!00TyNn8m`d*+?ZP-u`F=;!9*sW?o&D^s$8&o*Q#ve)h_`CU zmO%GWGIp=kjIfj96}yRut4yL?$m2(zOlzg6uMMdOJo;Zw zVOzF5oCt&UrQ;cO&3rGenQO(aF#h3T4SH46-~F%O`QA@O?Xg0CYfL>Z2c`rjlLMHQ zETAf;MK3`@3e^-rO}v_zJY`?kabDZZioH0WQh*8!dK^5XiuGtm_H71`)g74o=}M&hdXEg z7^NrYAIKF4wZ#>U>JX%h@AwSQm~`xV%`j<^PH3K63zTbGm3)^P;@g(McgBDTw$O_U zbECs$X|3^SPQ=)B#pFYtVG435cRX(heE9fPnDF^+e3IX9YrdUW;;ouEKt2Ce$5*LF z+#uIr>h*D$mdHcSRN8Sc#d=@^_8p#LxG78v3a&ywHl1?L82j%h0(~%@`fH z2d-Xw^6B*tD42fZauX@LVW{=qzg;ev!Rf&$>5}$lYiNE<=bFf`u8MQ{S%=b8Q<}XT z7d`rWBlC+s0yv5BY{;1uhSp^M@Z2oj8gkO^GE}n8g#+jU>uvtUFaA~h3&!dT2cx5w z;UAg%P!FOlA;cA66j|V{p#~?Zzo^K+-uhQVJ*Hz82uBcniX$_3lKw^Hs#X*uDU2^< zgaNjlH~S!5u1REY*qT^99-5^&hU^GCmg77{c3_%5+z1OlP9j#{@kz!eCKPsY5}6lZ zL57Yl`P54(d)`-2(c+KoFWhap_Bjaon0`~@2b=dmE&kSaDfu$VX#jD9){7i0X=NUJ zVC%2gk{J{!muux*bIYC3y}Pbrc=99}({UEE^5XFpdw>3`f{)LV?2|uAlY6t5XDUEC z*G@K9edFSpE=n%4jLGl&Qj-J}+fWDh!lMudbw@&SA$jnZ#~f$mr6tg?W>$lP8+jnZ z`|NqsIO^qaZ~mj>qM>jg>G#<4){+nW`AuXXIr)^UErgS5#bl~ABq*=GBm-RQIGgnr3nx77JtTy*nKr{=R%0AJU=T-pqu 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�FmWTl#tJY6oMF3;Y@aRbGR~7_z5k{3hx4Ki zRvFk=ax{pDA3+*g_XG3IofB}+?#DO`Sw8_>a)Xu=4yG!CNz~3@sr8rGgB{FG((sI8 zJq1`HJ89oKx2qnnBy9>3HQV-+v^!t;`sw=Z=pHkN#S77i0neaVv zujo^2i^fXD^KYR`a|u6OQqNa2>s$nzM}i&CACZb!Spqrjn<@<&-(8=N(5=3$rhWUm zw$e{buk2Ew{I(94u%6cNHOHYSyu+^6GE>LsZ1R2}r`@$_5gWP&XCEnsfSs@K%6MGo ztbx>SrL8U;#FPh49cRXEilHmt81QH#+?^VSw&Zx*zh1sMAb^}!9(nZt#&v)^Jl~(;c_v?p>>dZQ>?A|_7)#nQoVs@&p2_YL)#}g{bj2i$vkG=H+`fg$SI+Hl$i_B} zwvAp59%~-R%E!(&jS-U?d+2Uc*QnykA)?W#>iLlRSFhldn;`m}2WOrYgy|FC-5)-QB6;6=bbWr>O*0HMtqASOlH%Te z;1qf0=>WUNSlKXU`fksDbL@V7gj!mdle_IY!95QFRhiz!#NWZDkOx@@5p!)dsF+Li ztHJDkWne73rRr%Nu&j?(DtMePE;DIrO26zjof{rV!cZqsIg=IlJ+DK!fJ*Ol<e`2oCXGH37 zPgGpMy-Sf#SXLdrTGOlYxJlJ}1SS#QMF>}6X2KrweDi*p_8So3+g=6M5&-hSQfrVG zP+1I0Br|8;WrL+64NYVLlf|~fX>DhFj=@AiPx_^i`8=aRqfrgq9->bxHeS~cd%K?j z&^FA~boYgkY%N`cv-72`Lx~m%x?roPjUN^3&w*9Ly#S0xZ2Q3H*1^>I{H(L5_utkl zlKoHWJ{URmgri-Rep#cwmjD@xdF~H8DdT{PSUnz5vkeWIqSBn#n#W#(EIX~Fg@zoldO?GsVEat4Wq*TdZ;XwwXbNjGu&KP*T92~(JCVhgW z=U8R2>Sp+xwKDyO2S0-E@uF$2*sF(!#$us9DoD>R#%o=$5k3rFb^y-T_nb!{AsX=SxFJos>(*nKbZNja4&Q5!6gHn4-+6@Gv zwU04%E=lHuZ#n*^0I&DFP0v;0dU$fQB>1A9pd5);Qw~h+!w;NTC0i!%hc?1>L>mjf ze0MhuJx2TK|BN6vd(xcu-hYfpRaYPWFJEpbFBcIx@LS9cKjy(4tD+j~WIBi<2Y=2T zlb1bROzb*fu?L4&)2DTI^HrZiVsjEOTJ_B)gQNczIAyDcsduvGQ@|fuQW8}d#ANS2 zz_jl_IQX}3$>_N%!tQZuZ(K~dmY5vws_n9M=b24iF5a7N>$b+*uP-lJ()gED7xY-r z63wDYj>*KrS;!ay5Z(5+0H*!l5Zww9Nf`t~aj5wJ%~p+}d3}V!f~u8{zawKbAmEj; z`juw~QSyBLb>Q91;hbOkwt~Glhl3kLCFUqqv$ZZg=Nzv;81*BZt3$dRmU=BXqCn8z zFkmB*OrI_uA8JSPGy^k{AOnUkB*&Ysi(JT$>QJz=Uk$Y+*hh)4=F-+3+`LxfLT3{L zuieBmL$y!F1+pVp@9Go9u$Zt!4VoWkF&;r-ihDd-nLPLOsXi0PHuGD{cbrWvB@QX# zFWe4OCs&)e-REm)-K)YeiaF6s)Cg8P%K6d+^C;c}^y#&uNRnn!dpS53 zQic89IYs329R=HR6K&Ox$6t2{=nlUxa!GU{ni7GL5`dV2E}WzB!TS+mX2LU+`hRjtzT0 zi!&>>5}wLqT3=Y1 z*iir+Q?L}nffso{A>Q}w46p2VHPr<;%<44VG&)@WvC#Umt;yzICj%MD@1&zq2uyIU zKZ9W?O$T%v!S+1Ezr18dkRKlQGRU$JM9#a%${vZW=@yBnx;zY$#{hH)YHwz(2B(TT z&FTELP?MQilw#*&h^Cxh`t92`C2T<{QI}hbRg@Qji^p94GGT_d;~hf6uPY#O1=u=B*370a$8R?=&a8Cho30l5$`Fol1p*r~bIz4|jHDwW0oISt zsp6oNkAs#@aC0;%ej67)b&q*AdFz;QU&{B#*>Y{(64Wa~u-ww{RBhGQL%IN3T=yyi zVf;T^Zu9Lw@wA8tsUB-^lV-wURV29lDWGco{|&a0{VPi8sm7ENs|-tN3CM!xo%NS> z)MT9*Sh#JWCUt%H#jR{svnu*qZ|dHk>;9kC%Nb7G3&uTk2Ue$Bmss1Rv=Z;%;?i+T~-geKtx(Q!6S`4zq7ufA@|xth`W1o zUC&t){?(;1uSn!ZoyqpVzFV)jEr>S6)j|5`EnOLKR$qHPjC1N!hnVed6`+M@iaA2! zx$*H=uqFzGQ+6AS()fpgG9*)BwOR9dYCX+bY(0&0W&8cLZ0NPaU2h&WMGFtQr>C^l z(3%{_$9#;75#~s^P}e8&nu!lL|%v z{YnN%dhEl3PUlp3Qa`~8_f7WtQb^8Q6jQVmN@e=MH12BB?<%h(n}^V*7X1P1_~K=# zQw(^e1IbLPEan7~p>$@8aFwgN7XfE*bLHlcjM^hU8mw(9JhtC67G8h-iGFSaUkl&L z)4N195@pCU>vUy<4|sCK9?+2|9=7?AK%v6bXugE0&#oZ$>fxC8iMqA6-Oqlw2V5g)=6pd4_0ukox!j-3#q&1qrbMxvWnzUwp+XN6Y26uEG`nD^ zlP4}Fw=He5al6M{GL^~crfS*BL&lV|gxeyw%UTn0S%<5DXXD)7TA4_tSvFD)a){~?@sw0W3AKe;ao8MyTYtmO}R zW+JA3XN$|vYr)KB)In7|)`l&WX(%-sicECAv%a-%qPS$=o31F;dfxO}4c6ZgB78h@ z3u;H+b;ZZ}&fo^DxOPspkckr(x&V~|D|$aw^|VD7&@e+6NkUCRIr{_;Gvg5}Nwib0 zGX>o%_5_*?7dN|d&``4wXo}FHb!(fQxwcYHgH-rp;E%NdJD9iY^J&mg&g$VM9q^~G znyi4RDYD?AUISV~(lLtQ;cPD7mDMVWtJ+a0APz((y?V!}tPS`GVJ#Hlm=}T`ZbQ36 zkPdBpQ(b0tqyc#e)}=fb9kV87>BeG1_T4GwN6SNyBdUm1=uzPi+PW3tLO(`@;KW?r zJ;{~)9W}VZg`!OC0lI<%S-x)nf~xLj&okZ35t!8jXKA~YNlS~ZR4d*$vxXaGV9bvF zZ6IFa0bcP*;1y5)U$3|lvQ~>VzVqvCuei|VCawRIxb#47u_%i z@JcNq;VK-AmI1GBOOBT2Lw4zR_rJXW!!%HZtjgBPkK6MJnXr|{ua;=on8czOal|&s zoqsmi>*_gSQLhJ19mqkfaKRUyWvOUCl(Ei2rEV4Q&$1#a&IdowY}xsDw5!b~V~bu$ zmX?+V)mXV%e|n5xAx9Y%dXeL{_{nXal8L#nT15YMv+ppi%fGI|;`?)Mocho3tq!yZ zI7v9wHBN%JKGGj5ei3~!&b}Pe-V`sYncOP)%x&9A`-ab+J@N#PLX5 z;wKkZ?!2Zvcpp>qta@?><#UgZsPf7ePP|WtvbpfsT#jo}f2eAF`vufKuw^w3@(^6^ zo+bA9!1N4fG?+{LOvqo(+eZ9H^$xxgiGosxnXW2y<|3+~hsF+bm9s@lJLVM|bJeAo zj=*Opox8@&TrqjOBv@tZ^qm%OQ)7{)zBFZ7Menh)+ig8ppt5^BT40^<$7m=yu~*4- zJ~wA&Tb16SHX0&k53To{jrT)iXK_}LP%Eq;QL)D2+I5wW7}1HLf82L&>+H1*UYaYZX4zV*J1 zS#Ug8`~(_=QZ0nP+VsvYFW-?RbNlUeHeBO3zhjML&XAaFDknq++$I$ClareZ+an?67`)IiPlkrAv9(b+`o#(qz}GICZ~ZdbQ9Cu-lY4m76g_ ziS*ZAw`Omtelbsqmt9zu0pT)$n(B99mf)w>hOCBd*7H@s=FzQNa+MvFeCm#?w{$0E zW`rTO7om9Je^PEb-4=sV#JV+f5<8CIqq?*kr7*(2RwH9LyR z{zcdy6>SVjobo%(RS>X9+;gD(9Hf-$&xwjQg8QKhZeD?hbTgfX8(8G7nj$VGJG}~H zY1(Hn>{=9@4)~x8u41sp1i$BZSGaG;2mIe z6_ncVsJl(?OzOD(&5yB~Ng=00&-VGk0|7J15?{HV2R+3=<NQdL0)(hCy}ps9Y#fB8cG>xw24_>*N%PwlL? zsG!3sGSU1e}{>{FSSYqQDdK%G5?Lp zeJ5+XzY1b!v5C%wF9{JZ6N;XYXH0GVQY1oK)drQj$;c!)G}XrOglaWrYOz^y85her z@6F{mJipltltg;QQrgg{)&`I!f2bKsl=H|5wAXrH5_1pS;;j24r|(a0ZnrCo@p2W( zg7@ro<2{uxluRo72toawh2P|^)k5cm{mzGp9p(i)SRAxs=MzY^Z+E(WH;?scag1Z1}TQ=Fx|;6L}4xK9A(+3$4Y8hjPmx!X~;-Qq}ZW>2$dR zg}E)cCQO+uN3m^C$f_9r)50_mfHv!fA*_H<$jKpt!2z~TYN7q{5v<>HoQ2qPzC2Xk z>%^Bch|yn1Wy7rsB#WZS|NQX0J(fa*N1E|O-BL5|*fAsyX1us9Ep#TR^)_lyTz%hg z8&YMo>z66Pa!F;{X}xzob-+_)dumlZ^ytQe+RlG-d$#Ll+L_&>9dx;@^4K-KNs4Hb zS6m0N!`MopR*_4gIxOz_IH@?m8lfDL`u)o5+l&pj=&t^pJzSf170b-Y(TCSSR|HcC zB;rgQ7AOpa$hl0UAAZ<59+=NGSNR*LHJfjtrjL?1)kS<0uocZS+|TZzQv|kLea5^6 zu!?s`fjveaz~01slCzC01op*tU>m0O>eY~2X8*j$oTye909;D5p<8bREH3MCpk{rp z@Z7hBM|38_rrzBRoY~bUc{>zojyLnHwR2vYaADJ=+YcS+4Z%2~gtA$V-A&BA$!oz5iNjJ^`;sJifa)Qmrj&1#6n*D-23keFrEw#SSKVPX#vPsuEIeh)mP5{p0fC#<;h=F0IZ1)j}vGK zi5&iwp&l8T`++5(KoMdClXh@9tNz``^sq!II&&HeI@Y!0X590_roJS6)o200plhv< z^cDO~mO(ZLa9^f=00of)niC}WY?P5ABarZy;=KGx+tcAD zLi(k{vj>z#zklt;d;3cQo|{u&Qc)r6QHeE71<=K<^HcF7%`gW%zmq0zcWtXQiG$;* z&_w^F_L_?+l#WW7*Af86*^(&oofCF)np(7aG}7XxD86q@w>Ws)Bj8l!fn2zMI1NBp z{$dT_oM(9f@yZTI%zi9 z6lWHNbxilCcGv*QTbhV2mR$U)@JkwVDW{L5>&M!R^u2Bqsqd>Ii_Zt<0L0b9)y_sv zhgRf9Z>WTNx507Wn={KSzm}W4n+wwP_Y1e%Bp&6MV6K!HpLLqtF%cODa#(2 zR6yK-xXZCafnnHA`_nAFX7Yl6{2q)-@=g=}wL=r{lko&y^ScJE{T}vZML~0LyGe(0 zmC7FQb&G@BQN*@)l$I*je1kY=^F}BwY&ay(=uWXZUJb3x3{C3mN!K4?{>Yc0_W6yz z2rS>HW2pbt3<=9p7y!5k=f<+i|F`?VKgC}i{$Rmyj;bON3Pv3wIGN)UEK`%K@ytOl zhNXy)79a2}#07QMrkq2-%fpjPAb#u*dv-lOku&aoy_E2>!L!1g2|gw`L2N6a2}Uye z+?x5m^_8k}I5hBZv(^OrudJl?DnBK<)Ee4rGny-LF+w`wvK>grcVSl)!LVUasQqjg znAv0akVZ*-EcaaGRl!Y1EN#ucJnwWnkk3{Z;^I~StVkBB?j$dlYOTXHf5R2NMzf8} z(NgA^&lnxQfc>2TS!Q`j#n+@9moDU=2MY}A?Z*opa4Q-)NJH4~-ytejX7N-0Y_ODC zq+&TaBAp`imK*NmqO}JIy?kOEgCqERZHi>lt_w*apJ1;o+M)5-g6GXHFsexCQl~fr z$uh=jEr!SxRs_w8O(eg)IO$WFQ|hmpi`{&{ic`v3NG&+s92_lNX5il)jHTzQl@BvlH!1Z)BP?plC1w%7$3?k3qgF#Fv(hho(b8wgbsGNgitUCtbIW2D`aY zT^%2X!}CU~HnWJwy7Qv^B5@u^3qr;Pn~mp8t_A&EkH-wJPg151i((!rua3Q~k7|E} zHg@}*4u?H2zcIA#Cay<{^bhLXPl<|oe4DJAWsQ@g4mhuJxYkc^(-qe-#f-EU%-YPh z5`Y$_4gscvNe)EM1?7MsQ>DN|^Y&Tx>bRhT`Wf*cLkuK?e<-^$hIAlv%n7x27Uxk} z%NzpqEsPn$HzkC*HLexgJ1;4nQ?}O5FnELnhp-TU6xayzR zBEVGP4@@oEZ0PRp1GsA_h3nE#>-O(S;-5RbfCgbe9AI2L!Nrp9GBkD*P!I=w<)V^1 z3o`*sc*0ZnMTy@^~ z`k+#_l$KB34P!ip@T1~8(x*+QA5Ls-?Kd_Wt@)C7oiPf;zYS-$@W*-TRaCf$>u%3V zU&E%ouA9|6!NV_>e15+B7;|k_R!6l7p;_?1`}OCF1(Q@0yDml;3?>FsAYbJNJ_N;t zj%7XVOHSM1HCq3l)F%ps)yoqZpAlJP!SJL;pf%15pPc*J0=#JL7;wa7VTRLb?Z>sr z=o!q1c)tLXvo+2f@!$%%1R&Qek_lKSsAZhPZR#V@9GwtP6wSM31*sV|s^}!Z&Wcs5 z7bL&Uv|u#=IStXwqRpLT@eHN|*vj93#ns_}ky$DIaa*5L+2#Nc+S0~rI>u)nO(oXW zab`tc0$SwBq^&)Qy_ui(kC}NNJ%JorPdFe( zD(gmQbw@LLo!#z77N4c8+^3huecPWSuVzXWVlo8YUK_Q!vp=C!r*Z5bC+QrF)b(}% zPj6?iZ%VJiv)gaos&}tIfH;NJj}Li|mvh|}`0kD;f>_nIyU)31!&#tKExLnSqROS8 zzK@szugx9Fm;^N|10HJNBc0YWyVAq(?yPwp5`X9h?h2lz`hv5sUPexA4siMCqQ^Ws z^i~^dLz*1n7ANj;g#*H4fPMS8p#^vr&8a|t&=r@nPrRJz1EFJqao>Hkf9+YnkrxHK zv38=LD@dQ_UY(TukTTv}D3Wz#3j@q;lM1J4X#SVj6(}|EP`6ZPnTK}tW3zzo}s}bOuhnm=TX(P3#h=eUrxKi-3TWJdUw2EE!xiForiQp|zwBsJFA(o9pG1mK1 ze536`Y}1*mSO@xfk}A4Wsu#w-iZ|@aLrz1zbPh37fW@t+pU?3q!W49X(R3cZ+B>T2 z@K6YtRnL@UX!+aj_gDJ{QT92|+g)$Ab7zTvL8TU6y`+$Yh!yrZj707WVKVVuZ&2H{ z4!cA^#OAQ3ORn8yp^;GBkfyn4L> z3^0+?w|yUS0yg2MOja!8zm&z}N&w~!xDHRdC;%3B(Hu+ut`�KG|cC3Vn++A`s;R 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

    dxV4 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

    %5DX3 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 z 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�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�MZm#OofQmlvHgxDZ*v*De1k1WjRv5i{ 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

    @HQj{nxOO7V$5J(bYs^) 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%0D=Qkq83BAVk!8C+Oc=Q? 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

    (>=@6gKG+sAMk&xzvWCsaskK7`Z+nx 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 literal 0 HcmV?d00001 diff --git a/docs/figures/matrix_e2e_tests.png b/docs/figures/matrix_e2e_tests.png new file mode 100644 index 0000000000000000000000000000000000000000..4c94db81a32143467b7da38d9400b710ae635a5d GIT binary patch literal 807219 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 r}X6;po7T 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¬dvmPg7VOz|oZxHX>gWjoDvRt~>8K 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

    Qg9R}NO`cB-Vj{{mvO+#+<+i4*L% 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

  1. 0M^NP}|>;}+`#~B6#SnIcVz^k8FoFS9J zuaX)J6JAVX)8T_%&5zbpSC>`(P@AGUzc>ggaQdA{f+Y+;fW&u|gJ@C<`bU7H9>A@D z&`#V|K8m{0Rz|(e6(BjEDIP9b@PYM*>nCXx8Ut-pJxgPO@d)zi0kL+iO4fG$qzLz{ z2S(-UR_!&9*k_zB7-C9XnpSM6CGrv?*?b0x`QIvpa_f?D^*sT4;175!DTD(n=&E-p5%LcFP*ZJru0;9 zWkNtSsT{v-S*R@SVo5|~QO$zo??9$0=jea4F7obU^#7TIeehJ8T07OVs%L~K008fX zi;YUWYP`QLbb+kTB%-l1DPC?bDX5Q#|9_O(K-aUa>=mi#}eJDWb4Ej(xWWz`Lu}cSV~Ml z8jL*gq~r@VkLOBBm{6D`i=+4@+1L{>HGaBkLmqhL93!MF#-+HvL zo!SqrOq#F>(t{ z?8QfwjUq|srmp-8iu9Ice`SQ&Z6%z3Ww1wV{h|aQH?b|5HfZVNwjgDC_sgWl3uHU< zcTqBPXT6AO#L(ihVnK(deO*}$-VMB-9Je*l7!Ao`CpGI zoMrd?N4B{DIi`iAIp5>{tA#tjl2zSs0KZS&qH^aRFO2B>dm ztE|~0en1t7gx~S6qA!aLcXXql8E8ndi}D^jjfpmo3KMco^)ou-;m3_xVE?4MnZ7(r z)8zXWqD$hj;1FgeMSZH~8oM;14S4fAL44kWb?H1kP78X+RLp#9ltq$Jx|oYJf5W7q*~xNd`Y$0jl1`Ow+uUcP{c zlPSUmQKs~xuw>71YuI)D)gjd752;j*d(v5RJvHl~ROZdzy&ZY5Uaprw+nP_vaSU(? zI~|=o@ zEt7v-U_!HgZVAd6Xsq(OuSj!cTnE0xK6N#&JI@i-_I8#q1dbL*Fz=tEvhR$C0fjh>g8bhFza zb>dH@cQrg6v9~l@L*h^;i6a+&EV~|OX^Y7dP_(;tyc=E7VJ4f0PU~3Wr~QmYtEbBU zuYh6~vKMy&oQpGobu$JSj|rR|D4Em9rG|VzfG>z`*Cw5;x{iE4K~N*%1Td2kslYbP zB!T-)A|Sqr*d$GMlSwvEES8cP2=V>a6#ssdm~`jmB>#*-dw?@G-JX+1LiLkbs8}>* zTkvd;=pr_{<{69GT^jUspMGsd@O=iLNh`*!O}V$W!@!@REij68DRc9S<419wKuetK zwfI%~R+42)vs_6FamP}KS#*jUN6BV=4Pg38rr%ZUP$Gu-t*Q97*@D;pYmOs zVRsLYQ`zQl2!(sqWQz(l(v^0myG~0=zMgU@?oCQ%tGL&8Wk1u};IzX!CRUu;j_H}NV8Vh~X-ful9R&=wn7Ls5ppFlNj-?i) z1O&lqq^6t&Qem8A$_!nUVo2DTRTi08kx?b?U%I)2;9Q zg)EQ3#<>Duz1dKV+jsZN3htnl?d>}MFR`7Ec>l~9JRttlZvQ*bLjBj6`FD4zg=(2mUa*|!K^A{&o zuL|Jtl7tNYBwX70?>U@oal{_~xgMh&MNLUIxx(%$&=|N-I8|H}Brd%b!t8iwm#CF? zs(dtA-v+Im5X>)PSgfrxHiI~>+rc_Wa#@?OwM9ibCJ8((vlg4FT4NQv$Q{-hr&24r3vg5zZkNbIH^q++u4g$kJ7X1g+xMrsO<)K z@WkjTg;o?zPw2NB8j}Eb_)XHc9h@W=ZD+(}HlJleQMVS-y8eN60a6oT8LR+C09gohhad&Nzl~m0; zuQ-bheixhVCFh)Z_hh^|klN|F0n$|LX4EB=lRN6U@4}?poS5xBwCDyAhC#2SF5*1e zSeZSMqv533c?M_o^Yo$W^`-V;_Rl`mT^TYtV^7s%^&9HDA1KPyg@&H7kFaw%whWhis_>FuS3gSh)2S#&4o)NDn7C;)krbF&znh$82RX`t%YqAOtm{Eg~ zrOwLLLc*w9$&tnzYwV>PoqpMNWLQI@P-HW1V2x6hvf*%&Xf)vgR;JNiu2W$^Qxwzd z$6mgMSEM-fAMe!z9~eE?UTdNi)~RqZ35LD{KWfr~#1?+3LcIcLXBY8J{-_}~_oc}q zd*Lg#Fprx{aSn;2ugt8|CAEpI=Jb`+7aF~--A}_D*B1Eej{z@wlL2M2EiybX;S737 z-xVKybE>Vu+nj3$I=-HfpHR)#mEiKp{_)&nJO2+b-gE>3PHr+&kGYhh90<=FbLv)Q;|opIZ1{qS~4@0VTrgp_%Ie!C@hQsn?m!2S0oN+w*GVx1N4} zf}1_f9C$Y_ay5Q@+vVfR10%A6^M+)X7cXgS4shnadshMM>H+$h65+mYg&6;)-uQ67 z;aqKETxuVBW9tfo70uu<>TZQRb-#wyNh*>CzVgS}F%|aG51PIub#lh0;;}){d72@~(xm<)wr~kg+noH7AJf66?El}LcG+#7Nv8BT45kYcI zVEGnUq2@S6ey)B>uQG-INU!g?=*H*?|5CHnHt_h)f2n7B58fUhJjA;7Wwgcw$De14 zgYV@dQ+vqVw*S92iUJ(L|9r!fhecPHnUpp2M*VWf8`&u-9CNbo|Ha>LygVwB0DQzo zQ{lOihp!`Gr_%@h<_)`No0GGx{YgEcN-+ca)!bp;K**s+5h~*>4U<3;)UBl?XadEV_u=l6CfmF(|_tz_hoCaJ=lK8 zpnPLAe&tUwLARarSa@6Dt!PGWVwMOReKAtS{naD}p!hcgC+x6C3A1{s=r|P12FqR4;5A zDZCUbwm507*hm-!sIk{FuaT~@KvXKqI;y)^WHQQjD$m5Z}pn;9v(!^>g~6{(UQq)(D96 zPCHlk>M#BnL$TkK{7)t)_>CK;=9vIL+5mUxli1P#;HU^rn(Bjkrm(5I=3_HDH{Q!_ zTfQ3%33c_I-5zzf^rgR!^QMrkXoP?#9}^$OaLAxQ|<*4sNhzlr^MKF ziX#me{@HM$8A4^AstAq(O^Tm0Os_Nm&c7cu+g`eZT|MD90m3o~pkUq__+hpqug(~x zEB^X*Fe!_}6WgS0dQRZ#R5LxI1aW93WoWa$o^caCowjQRZ= z8WVQD*y^s&{!Lt_&%bpGkXj4J*92%1ZtABFdt>-|$0}}uy(E!b5K*D69~s{l9<<$L zYN=Aa4QtMU8i{CG(_As3k6H=wVN=bVhg*3-E2jmA8+Y=VUT6iWisT88l02sDTgdAV zvYwxI6*@^&dLr&JPHns(lR)-D#sMssJI(O3l+=D!$6WE5MmAu3SYZwze(*m2kzl z4eK2C`nnT33xjli=Q_=#H~lwz#R@qmP65TVmB_F>ZM>};t!DLXz!V!aWN=v{k?|3F zPam(wZE^cOj%ThC*uZHuIhTyg5f_LB!xSQthQJYn^%q+%inXEWN@3Ka01n9h24fs+M@rmT4ora`*w}Cl+gJnyin#l_T zD|a7yYDA})u61cqe{i7{GJkVvu)XBKeR7$wQt=gDs$S(AB>Tt%T2{43cdigf9k%Y| z%NrXVa}R||S$TCldd+}*Ry9`6Ls%Q+b2k%wka@r4X`I8xS@YzO`_Ib8NZ-|SH&TtH z^h&$1m3W48pxsk#3FxNn&I2AKEsFWEgG?E@gxur*Ft{sZ>iTh~+{r1hRAVN>-@8$M zhz}q~JG6H@P1yO=sA*jeRCAd^Ka>Q@N+WH5pCi^jDCA{pZZz;CXye!Am#A;y^u)+}QA4JB zewv#et`5c^#^Garj@-kg{jV*rr_jWfW2Z0Y7T0Bnq=H>l_t%-ErHPg6oO#fsI=@4K znOVV=Y5yc~y|~(*Cx;gbm!0>`0^?HU zH~Q-~NCX-dXU|LoQ$>Eo`lKr|!kK{zth$FU7Y!GQxSb~chJSN_GQF#1!zfh8tNeml zV&$}6C%=D1%!U>kRNs;TV1oZg(|Pz)`N!|y<|vdyWUm|}A{^_ODHMn7%%ZZ#G0w5K zL>ZCDI#y;@_8wW0y|=7mAC5iG@BVy$-|t_*{W$mi9@p!-o)BXz zvV;?Dihm|xkT6c2xrSQJX6yu841dH7tNWU(9&Jiqwxa20pvT6J@sE~m6o4Ur5F?&T z9p@q)c|BA75~zT154|!E;Ks@}xXHiVCmUS8&P2LO$76~S3AkM5$@R20>^(MsU_FvN z^DKfnTn~TCvW(XA#ue{3Zd1`7OV*T=Lr1oRe)B04ymrI!b z)YQP8k~9K=@s?(qsX^h1TH~lb(#`87oL;boIF|RobQit%LUfrRk3_Z3Q_r)#|H~ni zef#(M=S7Ik=$huu=Ova-M19mX^*+KY+$!-6OSD;{md*mQc`K0GuwUgGg#%vVu*Xd@t@`Qw5!|A{d;cY;_d)JDhgaYHUWaY zWaffx``=5DY&S2=Z>N8(H|09c5vO@X0sagCTaFt5dfss1qYbdzIHlXQd9 zo=r5+^PNwwy|`ZMzj163m1ahc zi?B$oOcWHkv~}xwY&Z4|&M~+OUwQ%q&T`DeZ^(U|%l4n9ny~>}ctLP1v4zg~ZB}qV zxXXiN$11MB-JN54^ppsH%IVrjY5Wel@km?+E4XnG(0uSn82@__KeOdYTXShjItT2U zZN(w5)H}bqCV4z6QhiS6Vps<$=G5bG4V6+*bp3CL+Q|hX@ zwLTKLcN%J`Q*yF-;;@zV>b;~Xlwb)m!-EbWm=!tI>IKTdA-?>Bn z#5(94liV(QU5;;>ihuNf@}C*%!s!JfxyyrSfv44;m`7^1!F0>Dq@n8|$6g?axqk1w zsqfDE$vIuaF^v6P;)ObPc+*F9ae7a#R(fK?JdiClV|y`=>$TkPhQd*=6961dpI0VU zGxPqXMHqk0C!>_sDGHY7dc#cR+>eOJ?7KvBB&ALk2o^db?INJCd zT{Q!nDyB+@5}!)&K{J5@V@=K~jh2yZFw$(#A9y49b7u73(ZUaRkxVxr25wguNLof7>fgUF1fmE9^sUJbSM`IQ96 z8~poskXNXZ)JNjQ*MsS@aI{@;xzTQzm^)~G8NjQAF0$v5Roa-8a;tvfqI2r6n_{N` zlu#%J(Sc{T%&6V@6b@xsZ?x!T#sUiZ2jF|2bRQsll(?lNMU6V{VrX5)r-CSKySFz` zN%3#v-t}BSu7d2)?}Qtab{CK#Lkgf-R0+PMD+NBj{fSNBn}AJgnd;UoNLoGg=S^O= z2AqQmvXcgjQT!h2c<-X70k2Q63zT(80k~oBu87xwocXc~V1camro#G-;)f_MD*~H>U{iy@){UYgFWm&lFgv04lux99kYlOpVJgcP zk>WhKjWr>VdXrHQl*&c|?JlONyh*&BmFur+*p~7DNWf8JpQ>;oI*`_Ejl}%&%KW=x z7l33ZdB&TuA{>1+#DZz28ZkyL-J1ALe3ct1z1g(pn@qq-{tUS&DvYY#dh9eW82g1l zHq2O8Se7uyH08>-aP>q(0jdz(b-ZzJPv=F{B({FOOTa<-<5tH64XoOIZraROs!H1uhU6^5Z>5s^Thn&@s)Z43Hc+QMZ;OjH)B-=Oiv+8 zGJFK0d4WX4>VJ4aahn1KWu>xrwTePEgnf>R{iGQw4}Qw_*Qnl>B7_nO?+L8S2#V#~fHR=V1X4av@oc=Tp zTc5TJ+<&xQ-_(zqaK^;XZ?ix6&!?vHs-|n2z23(n0O^uc!FrWGQ5-pMmRg%lle@)Y zmWoU6tXHq=W<6LUS)vw6Az+1^)Y}6B-_(Fn_~?HzMsEd&H{vx&*2-*o!obyqS81AK zg9F|C&NdAovLH>C#x`t?qk<86zTMgq`G=qpA7{WSEcHT_wa#lINwW1dQ6-SXom&h1 zyn71wmdr(&N5<0yKoGeuxtGwhzLrMc|MRO_bOCR=Z*yNG~ zT+r+_Ea;v<#vuYsd3Q`o5}3tpP>ZNrRz+%$=gmCr{6Rf3WJfm-w>W#F+Z+HKY?5C8 zuAKeuH?wR0{!-s!O7kxs$@LZ7mZ}MiCZiYkC^%TfZn+C^X!$3%(zL?r57`Jtd62p1 zvLcFpW+!Ubd<07w+~(HDSQ4GKJy7g(E}pJ#ecr9)+07E|Rx%1iHHLATCFRSEi<@%v zR7Ys!GB~z1AwkBoeZJ(TVZJCjT<)6UND!(MDzUnieBbN>Y-(64}eK!3hmC< zOQCdq09ewOcWPeI@M9WKDWBHHP()0o%>2k>?_gN4Z`ug znH?UT`|otdn(9ccVWyAV^!+@@{-KITce+L_`Kdns{oTfnTlc2*2)cyLOi^6MRo|mO z^Bp9hE|A)aRm5+aFJuXcpsKHU7(*SiVxtb@!C~?Ev6C`%WWPYi!PU4wwYfGSYkQ7C zd~1XCjM4yNJ0pT8F6;WDAq2tVxmxI?vC;t>-E$__%h#I!A~u`-Dm6{^pt)%3xBaeh zPc|_vFjnf0m9qH*8Wlc$on|{{m*QbTyQe$wT#@WDz=X7GO{k+Za!WWJ>^a&wP`Ni8 z^C{l__CVz`5iQd1Lx#aHUe8V?1qX<~{IrS^lstq(L6$&ev6TOr*}&V3*u_qMb}2*8=4U}e??mW%Js8ADXulS8N1t;T!=he6{%(D_?|}y6OT%DB z8S4K{EVU`Z6p~m-+S~PlK|>#AN=s0&w`PS|`$C{&29)SpN@ie?%Q}?i8SPKM?2_e5 z}pv!OF6gr2D+I zkNeUmWmZVHRjn6qIdi!z;oaFwomAfZ*Md99X19#+5YjP-({7!8URL!2mgClxZf5XT zt2n&G$sOy)bkl|1K-xh1ak7~etCu(46VJHuX(8}y(>oOJ!dMM zsMxBT(0fbg47ozFfRdGGlif9a6;028@Kud`o4 zEdP9oPxQylSAz8m`0`iqa3Sk|xs9Bqo(cE{H)~!7z&@*i6TB~1_p6_$Pe(rg-E}A4 z=PC4d?VC2xS1Bvw@H{yZQwb-E!~BW2#6m ze`I@{nKNXwuKvSCRDTI%tldKy!L=)1O zO4)G@VEr$8eVixBsm+d_y7@DZ;<0!F)NY<7F`PS?7 z64#(l)^iH_{w_e!!y>ku#k3QFR(X{eV~YQix4Gc>fT91cnF2(0NvemN^_}S2h&b=6 zs$9DAB$xT$k{Rv9zH=0atrhlfn`9&BH2Q+(RP-nW7^lF2iu)B^;V?}}plo%fL9oXv zc!gKZ%3D4NVirBZ@~@ecMSEDEb(p2xOpD+7fz9)Oxzz730v2wHF7=0riAeAH(TV`3 zLFA~R4=`6dEsG@~Tv2K5qIQ)3^@Nn2le$G@?uT65PE~=&;UlsY829 zpqfiF$Ik2gvhUHc2xUjw7asEf=ix*S5K}S)2vFsP?W;i7a)%B9sqYS1S4#m!hSdfE zvl#{?Fh$wG-%>ZF={9ow*|b$LwBZ{^j8N?ep|MfQ#}+V!$XZ%u`kc(LL@@NeygCP* zc5HmWM7Hi6C|!(fA^D}rp*uOrdoq7^KWW$_@k(!ZV_2%>mnM0WSU7E%qr* zL9a2tEm;U|($DTP-t}q+BGfYILf*|1Q&lvOwXz5pVL7PSpOU;}vO-ml*s};;!7iCO zf-3k=JL#Qe4ou&$$z^dUv4K`+l-b}gl;TH|TYJ;VvRCcUsA5}1*Y;48ravB@cz8Si@IVt}_Md4rzZyZ^X?b!qzf<^J6B}n|Wm5hi z>d)H8!RJq7;QMb8{UCeRjn>`tkEd%|VMMh;r1FK1_xfbZi)YfGccX&UZr+S5y*Yp@!NODV}a z^7|qX>fow!+OIR%y`oh{A>S4dV6!98ifqWDr;wherw)3Gdf7mE7Z^SV6V+$4tUPR~ z9XY#og>e6T5RExQ^=r5Edp0exKC$r7D776Y|H?x6c1!0gCNaxE!7 zX~L&2fLv^|f#Kj&?M&njfNGg_{`W;Vo%N~=P!jKKC40J78?ygi;K%ZRUfcQVnpqV4 zZ(-Pjs;)cehi_v2WxPxR*8gTWnaX`|Jt z{^aRnM%4|ckPM1^bfOkumpdp=@3DY2vgn5GBa6GqPgnncyds#M>^!g(8ixAPv* z@`i%GwyS07VN2hSeL`ZY%~!xWDOx8H7rI52Gd$fPw^;l#-CD+py!>;EtQuiC0YPu) zJfNAxu)D4(DQuc8FOV8%wzC#}ozM*)@SL|wXRg(BD&*hk((Kw9YxQTb|<>Jy1u)6M-##***Dm@P+H(FYv1jL?GE-SiYIU z3I&lN>#8u&3i>ae;#*-#?K~EQ3)Gsn4x~txn?_#TR&n!Bztl%dXEIl>t!O`gn8Fdy zqv!ThiZjZJ$+5K?=!0UbxjZGInS1sXr7FE4wQX%^tMn9T%VI^kW>pq3Wi`L>TG0!f zWNEuuNm8>c?-MQg^+^_KnZo_XI{FV!Z{F1SrIsRbm4`RdM~={#Khe=Qr|yYhxeGIY zqW$MgO+TzV_MxE=M8AC4XIj`ZF0vjBL~U^_%~dP1&!OLKc0{V>IJ}-N!EO zegC234oJLn(w0qnGP)#KPlL-Xh`shjNygFOaG5tGR#TsW0nc7fI7zgF17LG~@>CG@ zmV}s^MQi{HtZC6Yfq0`<%b-6X6S&HYc4J!mc%vlX>kGpRe@Q^SX=r9-3Fb?=;FEQX z)^UkdJMRQ-=w2ZewIU%$o%B!Zx!=y+l^pK^011UWB0$Ej(S_rCi5#Sr7r5*-7q2e~ zh`U=pDs_WYy1@`0bdVzh6ZN0Sz}T5rD?h=j;2alM00@Hs!Xx|PArAquj~yY8vX5Al zmYJaX{6ji=a={EJm7>(_eM!AvAd#h-0Nf|pDsrK&2z21*_$iN@ZlACg8rs*DawE14 zPSOhXE5R(h}bxN7dRzqDx2|o7xuKJXRGTSYK@$?Gt>F>o1r#%5EK(Z<_ z&}*QkRLcljNGUWgE0f%9-3!%+?BGn(<_UVoDqztA=@+sLT4nT~vO%T@C;*ZF>j8|< zd7b9Rq~b+3LcMFU)2*15WjZDbA~k|xbG5G_{g8du!77tM5Wz;^S0{{5)G>6~>z7cz zyB~Z}=pXMiPCS%gsI_~U0yP_WJ}Gjd*QsjtXf3HX#`m^nq#Wtv5pS2+9`%JM8e0g3 zy=#A5e@317nk4yXS@H3FNgW0Vhuby0j=&$|J=b(H!Y|+dJMbO3nK$585B^S>V)CYp zcM)hXq^YI6pH{2C`$Wz4I;VMCI*cZ6XlqZCAe@N6#a{-l*lmHlS(gmBqyzFbC$c@+ zCDM1JQ0LojOc`mV^j%XdF~A+6ejpf@K~7JXHdNfu0of;8W(v72;Y;{pbrV4akyEZ0>yt=J=LFZZBO^Pu3`*H7@c;E(t;ZWfx6zy&}5@?M)8{$Z}qIXek%$d?bq#|0UlZNLC+J%t@Q-}bCDHqFs~+> zFp*CjF0%xWX_)?ba0d(sI&1)5g%LEj@Ugac;oj11lYFNXpgHwo3N=PZ0aDDQ$pR>g#KpRA&K(rD?$3w^0&^GRy(r`#u~mPKq-~4h$&QtToMy0%peY*eYVv= z#gfNtli-p*|nP_qz5M{r&2$cJT)_`+&J>?Amm^6@+sDvnkxt z1@SH&RNMj09+pep$uwe20d~;qsl0K?-;5?bPXyo8Qi3)NgQ7^hG@7;ikwiR~#5cbW znMPUq90aQbV`d520c#UjwrWSAOJ?^5zOpmHy>9B*;90o1BJ-N3($ETX=5o#BvZfb^ z`maw4+TF^t@u1U|b_g);51?2x^iGRjr>eY(ngzd<)rSl>-@$^<;;y967eQwqfgtHn zT|?C(2uIE68mJBMcT%Nif7E(p5M6~QwGR#q7HowO(?h*fCp{Um`LWWkb^k?;m3*2% ziiR&~|5Ct=?w(R( z3;Rv4l9G%BZoNRDg|iGT8(FEiZ2Es*fZq{mzK+~GKOzMlA|YQEBibqTc;3KQ?)LS7 zK78b!s_{pv_Ssn2+&Z0Hq~<|P-T{af7Ngt86-7Y8r3j&!@Rrd@UEgzxy6g+(JV0;- z-O;`4ZbFqwY)ALOrP_+!PU6F64|RtTtWky6zqQvz}2tx%V&zg9R-m|DIUbLke5b+8X_Fo zfzjaP^K%kP9(LxW;X!J5 zat1|IllX+=4$n(Ad7TtEmhk60j1{?%Bj?@9BFEaRu7e)!r&}$1N+mD2S`NjoerPN8 zt_U;OyaRNM(OQ`e{va`GaX=XQb0Q2J-Pkq~yX&LOrk=Nr>>du}+Ri)frgn{W))D_T z^`K45v#+?oC*lvH`p{R00d8JE<>quTIx+xgy_vP$C9$FJwp)jA@q98@SJYUJ1~<`a z=&U67mO|R{()BrSaYcjw4jI;y5C4bKvC33?I&SymAF*|wdp{_NF%j$=aNf75Pw|rR zNlf?a1NN0w)}bBiFcks@k)#z%9a8Nx8{8oYxQ)!)o%~Z7rNhP-Q2{Pos>~Tic$)Cxc266uy?nO}X&ZE!&R2Y%3m2hb( zG!82Qm1UYNuzw|KdcrPsjX(gwzZfWO1Lnr{b89MI)#G1lq}eB%9*(%}6w2w+Cz0T4 zDHW-M-4xY>VT@ll7D9k-Jl>OdY~EGx_5`6$fpU2D_C)^?>r%ApcLAfcpKDCqE#%V9 z1zLdUHFZbdaJ*`fACRaUroS&&B9#j@~2maiH{m@>Z?!p57%7Z{11xYDl?n0p0(A< zQ1p{M^;O_-m02;J_Nm;hp6nS-%cfad^V4mk`7bmkYQ)fgtn;j%aa}n?iNq|G-lPs_ z6#zvh^X9hW<`{Z<9U4$@6_h6ik)eR;o6#+g+z0aG6m*UarN4BISr6N^D@h z_D7HUNrllo``yz5N^Go^>$vHYo=?erdLT<ddPME)t2JkdCVU!9!WvZdyv4NzmWR%{;oH6s@l`6*;~GKz^42NB_yG@3U6a zqt5pM5R8^KQPt&R4jSh~4$|Tj5(W4hrbu#fjS)ff+y97JfYqR@X$S+Abs@4^(l7Te-XW86Jv$o}wTJl*DPOOsuqD7IeY2Js#E zr6@L@-0I~2alY-;MWlllESdq#ISuf+W=reTIAKrT-74ACIPj}C~LZ8rjKolu-5VMY4*NuYH?T)N@V)9|ZNzHU-0URQhj90Ap}eXhS6@;p0`GDi2C2Ln}&c zx!Zzy2?iUAm3zjGv`AlXnIP@`E>rgu*;WSWD*2IL`zYKqr1~0Pls|0ogljKCV#CuP zxN!UVRw+ocZ4hnhQ1#$d1l>Ze%-^V%RVL zKnBwSowAfD`DwWtb7b^chjP@!)q_-tB5&m%Hs5kObY@6yq^dtO$D&iK9j)f!mG-bh z$p|sPP;X@iX-Fwcq1VcFtY7AQs>Wn5%da^J*FL5`w=BAoS=ToqtP+*~{lSIgUA^jr zrQ{`T0KbYgQ2%|sY1LGpo&{PK*Q)X%ns!)j@s$ezyXPd0VJn?-Ef_Wr>jZm3GB{&4 zj}(HGY%#_C>+wHhW9ePy1`HDv9)GKDT$A1uXjz*x@o&22WvXN~x^Ncc%HJlQx71Je zDDn>r@K12K{ztywzGzA3PPMO_qC+Wqh;!@-@~2G44_5~1eCNi!Rf z#V$>-G)i{xgYH@_>AulXHU{6xE8eXvI{krI2W@$M z=tW-^tb3tuaz09+@8)OplJ2U=1yNAK(D5;g7%x(0rxynb{vo^<=qd^l^`z783E2+kJa0DNO1dJc{cENn_z*xctOwCCRTZCSHPew zL}=uLri0_8u&EMTEI0Zu0yTDMYCs4D5$|&f3DcH#OJAN}mlA z%tqML7s1O8icg~P;w|s}|CX;GbB#HDLZ8S5PEb#yC%DW|xUAT2Tj3$pr=Jwn$LMi{ zja-%AO6j`7qTym78`?`|JwSK(cl>X`E9p|Fmxj!%UxHcnYp39aqx?oK&sQjM`{h5R z#8(zelsOQEg!KGV==NJ;WVDwyrn@Bj&|F)E%;+l=_#Ye|79W_j6nZK6bX8YY;*I0B z!qc8|QqZCBfVn;^BGXs)i=3ZX!Wn~j{G{OOF@>@9eJc{p^NLlUDEpgcVxTch#tZ%W zb`TLN=<{cFBFi3sT=`&{ygg*`c;}AvVJ9BW3PD8uz!m9gUA$ zY&|M^pV}%#)f20gAE|XA?iN0yM?KqG{JzM*BXoj7iH)SGsu@@%9i!5xB1$-9if78t zR|2lEi(Y4AC^=Y>_W`h18=g@eW;@OZdSCUkU)^8?ME|O7RBqEZ{>yS{fCBs+7la@9 zG-c{ra8!DqJs8^dc4uitEmN1R4+t3@=xz#f&93_Z$R^BG_N)49X3}6@pcxCmj zp(R&I=jLgF-zc`K)q9@ckuB$iz2Ixjouf07**r(!afT$YYT~(o(?dWvxR;^mk20`tA(^C7F&Mk_UmK*8pGsSIW2zJ#=rXH zM)psgF=Y2ua1h@>P46wk<)$kyQq!vPk@O$XV|a;Np-iT!*osYTcjcsS93l>BSJ(Pa z?mQp_mj6qO$Opw4L!xRN{YT2y2QUmK+%!hU7x_6CA+xWu*ER%W^LP8H?$~>A1trVY zT?wydN;g3>$lIuapNjEc8(|=weM+E|(r^bWZ5yt#GIXn`=v_7D{cW#zAbr3gZ)SuZ zWRi+o<^bsyk|{%WOF3fR%NAB=sUX(u84AD@cDwH%+#!4nvUP|h2hEGE!wS;cf08`W zhYcsO8Vt`#=5t+gc?Mr8WjqH%Hw8$sligknxE`d=&au&fXgtNt>n!BckkTez+~5VS zP+Tlsm#}{Nhmruu*g;e)fqSF(yXMrfm!q;rSBbAHur9d0oh)9C#COjYq-k-+K-0g) zzz@HkqW2Y*nHF*_Ta=#g|B9c-c3GKlJIY}&;* zylj4s@e)ce7y<-h%%*WJqhsqdKhH>4nUW`Spx3XM>v5TLpkjj@zx40V;MHgAkjWEF z-K%#_MqU?3n;7})@PIR)fQ#>v{~;81$h<3c#|>kg&@DvE)jiQEDZ&JVQk4N58G?AV^Bt_sQF-KqpRKT4|^dIiKn4`3?ix6v@^w0S$-A zt+&VDx|P}dxnv#ZLfc?<>3OBI{LbeJ|3a#fJ&$aEL;a5>0t6Q-OLPMJp^`68^+FwP zAerbH9uA(}a^TOVw(v8$~U+{Tl!MO9gk*7nGcuE=;p`8b#0+5vPY5M2y0{^#nW1A3ojWJ(ySj zI;--K;h5F6N80wL@GbDmtEJASr$GJoE+iv7#nVZc-eO=0^S(12G*v5>wz6wlTs)vP z{-5WjtiPs~Xio2_V z8X7s71iy~;RrZM=Jbb$g^urj_RG#22yVQ4h)t=FZjtz`g2n`g(QLYJJIJs0ID=~lZ zh?~)teX+rk?H92cD|q;|PnceE;B-ehoolkqljW9S#c^pfu&Td#*Pr1Y0Lx z)8H$gmp<8Y?{4|464lwO2x{WGp0YMTI(t+nOB9r1y|`esYsTS z93-e`AGR}Ov`618`Tj=<(&N6FV2gM!Xg`L(Bi3 zZt*^$iZsEnWCCeo-tys6hoPKbX0!>1tCx-2A|D814c>5duV8_iZ*Td|eqM33G82TW zX*Rz<$U$?6{2aTgclJq{O>@eQh_OGfKdnQV))cIQKsT6; zkq#eKi$y6&#P+$7C|R?`8~5QF3_UZ7IQY7o1bVWMwU$xfW7bCC1@E<`vnGj_YD5wl zSNc}BDGD`LdvYx5YB-+rS)Bq0pDN$D1`~Y&{G8i|-+*8PpUiSdL}szzvtm^*{fAGK zaq$5y!%Pb&!DN^^g)$*~Ov7LX*muV8u5$nrM7eEEwtEGwrA)XIH{*=6kWDHkG$h@_<1ny&b2_t> zdxG0q4R5dRo@~L};R)6tNI%+``@Z#b*Ojc*4jlh=CAnvB*IYlkhh(yRuyby=KN^UJ(_~2Kzq2gwi=c&?Rv_0d4j*hK84uN+RlDAJW=3Mi+*{C5`D*9 z6#CUms~tnXnz-f^y@L|>lJN!D zKPX{3-PC?r!-L6=y-NFvabAOl!0Cx8GKC?1>d2?~d4NH>^e|X~X%)f5jq1>uJ}ylD z1HJjI+v`kpABQSt0s+wOjLvV_Ba| z89%*G=luAK?u-}R0{UZlb^F$H!lGRwlNoM4Lxk3-YQ6dok>r5~}3 zPAI2ZPS8C-FfTA?z-VdV2YqX3&krvhCOf&PiW4Tcy{nJ$xi!8 zmvFJ_Obyd(aks239>~h%fd}yTv zpq#z;^Ht31^W6)60|c!}!@X(%rAL<55_fcs)H$caO@%gUrrKxKuP0=AN9t-O#Y-hX z`gMJs0Ur|yHHc?5v+Ak7Ovz45+7@#7q2Et0twoTA4S)>!+#MD|=1w$QR1zz42IxIR zGUAVvgs3)Z-J(?6AJN9keJII5)7dkhsnA3DkPpNgsGv4Q(~-by=mq0-9y)%)?{5u& zyGYn12$M6ulQE~RvUbAT%``U#%4xqU9yb0eC~c^w@!Xq~;dKc+i6ax&)`<7ik_K`W z9Qz+$fBh@{U99w^F}~^ZdL7X4-awLkcKV}QfwnT?T(KOJ5XH2r9Sde%U~fHo3y%AZo?cvQc;L*G_vVo2IzP5!1-kszg|| zjl~q~7y_KIZ?150ttS46 z!j`^&7NfN{*-4MYiRV!b)!`6D-b&|khkwRr>x)9^u8%lc^LAtEawQr0lzPc>=7M0ZgOe~Z z)XP+d)_Y2Cr+KH{E*6(Vm#BztF^4AEr&=aYco8ZuT&690d15|U_!4`=U@+fB$>swC ze{1{@x%ZORg8$_UXF0!%3av%&ZQz`Hb7|oXoOrSFFxb`p97v4kkHuvWyXV<<%S91; z4W8^wt!q1@8xwH#$4&Y4b_VE-2Rd+Atl{%5VsaI?MbBWFyaYuLqG1oP?U6Bl{<%8a zjz4MJnN~B)(G*Zkf&o#9p&*r-Py{^GzdlmsWCs3R693jztt{R#dFtUC0j;{4_)DI9 zaCUx|I;xGr+X`umg`AbHSLRefiXhq!v1fjwn8W_li_{XMjO|ZMOW7XkcM=^o6?=KN zpp5+2i!+YnERRulZi@}(1kPuGBky{*$mLm^z!8c9r9KB$q6)WkxRuPWf!L#M3vll< zV74o3Bl9v{8~LUMZ~Fq}Ee;n_uupRonMBTO?nxWE&0icO<@y~_TE1Z9_j@D@=6JeY zVD>7`a7w$1S;@`)cxDqt*gFjZ8WE}l9*R#0b!&ShbQ=hAsXg8PeqvG|_qjEGv}wOQ zw)-*Cf2Lxz0zdShOg{^O;f_w} zuf8n%P=+wSUFLF+)aQo{p1tcsX4Ox}zy~oEnh(?b551!u=W8jp{N8>B$13GbO7^U5 z9W{nLrj@J_-w)eFptE zoCGL3;La6 zvoaYUdj{Wc*GN*SK>qSbU+lo2`xWsn`JETwsOYpwBV}W|k5;nWLqMwzv~P4ja=Wx; z-lAj)hM9_UxhO&Hxa=aUNZ5GzV)vsRu}tYpw5PYl)f}M{`SkP$Z^3 z*|3Y{-KpLdPF~W`Zk^IZ*K89c2g+bC8r2A#CZEjRUBbMozu@TXhu+9mYawctNROn8 zt2DnV92~Rua68VZ?8Xn8%;^d{Nv~7lT+p;OiY{iv;g6kbM5_dN9ob*hesukL0uJ7$ zfO7>}u4A_gjt_wo-Y4tDPfVYcyjlSHx4Rno#}I_~@;^=eF({VH51&cbf@Welg>sFB zGY})S#`y2DHAzkg%D`!##fymwJpNeoX$)|Q?YnZ0s1gcd!|yFB_?-=-J#j4g!yGiU z%r)^_Jm2~=c%EGh(yApdJxd_Z$C5FL-*xR;Qsx2mGdH^E!11D1&k6lPVDJ)owKqD4 zIq@U^2@4JD36T3VdCM(C-{D;icM3e?T1!O5T_8^pr@CF)gVz2F@Iy?+eJgKts9a+}w>1i)O6pMCg_?v4ye(gRo-+hLB-czU~|8*2Tu}S8o{d3qn%l|QU zjSbl3N!*95&CB!Gy57tFx`thjJG+kGE;QzBF(-^!4Or~D(ROhxWn~j_xT*VQchYg{O(UBHq8## zyOj}(y{sg4+6f_aj!@54l3$tD?=_0&W%X%suNdUltf#|zj|Qb^eL3G~L+46HGo*%m z%*)@%a~~L^F<9Dr>OuWaE8g4x(v|%eV42sCa(_NQndYlC&ZuMbpy#($c<6fL2Ohtn ziIAF<{XpM%(Wm3mt|gie`;&BbwhkTB`9De$qD*}D@MP?N8TlCOqRxy!&pA@6VIFaA zYvDil5mjBb^XaBQwg_h zHT3@fya0c89^lt40uGM}<&tfb-r=y3v9#PgIPhCVE+b+_IJ`AFTbHAb_ST`@S3uw` zQw2L$P%)&@(yFQbh=7Ypl5=f*l>#NrQ1ndhjfRRgmKvP5DI^A{!v>4)Uo9Fcw(~Y` z=Uo3SH~YF9#bfkJJ2mL~EKtkxc)1?j-rJ z5)GM`{G!mEEiqFv$l1f~rpg>Zc`4K){j+KsZq+Z%*PS!9SaJo_ckyX`G25(=O}IrD z;ACylP|3zx&y{37lR9-^FHQ#$(mJoejgrxxC;C{79u8cY(0f(;CcaKoc(I+ktEIP@ z-zn4?jisS--9OGn$k-^+TQ?@F0AhS>=%w&%PE%=H`sjeZem)h2?c$TiNU*n^kN+jC zTWi~=k5uTU=TvB5WMK4tNgml!b>!>C%O)D#&RwdFgYS7(CzAAXu!!b%^x@V$Y$SX$ zeo9UGx-vd1;#T~j4?~iA($`uZPMd{6K~v+!!<{SJ-CT8D3XQf+>YOi-!EuI&K&r|l zl-gAKAZu#R7X8*Im7bmL=NlfJeO8xG`V( z!>qsmH%*hP3y&9es1VrI{k6h|SXJ7%G8CN8k&(Gp{I|IG6~BP)PU^tu z_3909O?-db|Jv{(U6H58qC~gwuegAFv;obig}Y{ca)UXPt43mZWQ-8Y=2d^YV1 zXDy%*;l_S9y|h(e-?JL3o#8*;v<8=zKHpiqn@iflqgV!nBAm|(_V3G9@wYvEaVm&+ zI5A8C5uG(Sy}&`H-2pKqZ)^`(`~@>(@mL}mlCL=gFEWBIqzSe7(xLmC)EO$*;2dRy zvORjI#w;v$iL%WWayWdp{)z!#%0W|jC(b^z>dOis5o}?2(k1zV0$W1$jD@+D9!}Pk zzUpnNJgGL_Yq4)lDIMm;*_$%+WqI1{2hQv_MRCyJuIYVa0}WRFb!&Is2W){?rL{n=7%=`5eA7M^qm_5v^}~&3rrOEb|6Sz)Iz!`+00zOFU5ZS`M$^F2r@6 ze{b^#M!%0G{eB=ME z|>uY!?9N?dmMWlGc)6mbFAYWeD6Nr z$LI0*{`CC|?sKmDzOL)_dahT&rnWkrh*C)qn9Q}J<`ic>0vCw6%DqHA#K#PJ%XtZO z4A@nHIYiObOhS1h=cDvdejqBDKSFBkM>-|V{6Vu zKD^Bp-wm&PSUE)qp(H^gI+LXWy=tP?^XakH8PmoeqUiJDpJ&O{(;{Q^SQBgyZ3D=} zD@gtA&FM88LOh|QxZ2V9`Y_Khp=qL()&ec1t#KnX9bTf|9iY;9awaUGvT zY}aKzs;pjZnXT(K#@H-`+~pinKSYa#;4&HB=L9UW&DxSBrVBbef7q1`jB@9uo|U{i z1|Z~)m;T4w3nWF}^1#E9R`bAh85#MKekL(EO67DGeg2m@Xcw+Z1h`o3mQiRdJ+l5) zRaC0pY(~$U8^_xpVB{i6pK+fOZRlhTz+l~b3#JG0*e>TCq367-nzH86jI5(DMl})j zk>@iy8w0Aqc4Zq=860I~_BFnRDVKJuyx*S9mH=X#DmF4pK2~M_<*^-T4hu^v2PRtQ zk`(zP!a214vyZ@y?o#rTx78k+u-@>~gQBl1mr>%j5*-&Tt+^lw8hguKcF)2<2wg52!xHSVy@7{*^7F? zE~II^hF?4TN<2|@Al}$PhB*Co7hF5`AfGhqJLrZCbTxI73Y4B0fQ>PCcm%FF;D{dr z=lPhim4>-thYpd6IC2IG9xS_hiaP)5ldZSxbwT-T*f?nQx6A3`kt!q55)TNaHrD$h z-n`ll^b%E!m=k-wy-DZHx?pohq_O^e$~ZqEIt1x`7WXY9?&BpQxa+Iq`PW6c(^}-! z6+UViO^r~FF9JcVZ|u&>g6isMY3|t|ymJrz%RxQ*@=h(#Plw>YV^t#@kgXebN4LWJcka)W! z8@U{QtK?v|0V3U)EfE`N3v1Q-QuVk~r%8IHI6*5T_QWL_3jX$_Np3I0@`RC~|8jtr zQ2o%MwJ0F#={P<0&9lrvAw~4Ayz9nhaS{CvMpSxb{jJ|ZhDbKx2_{Un-nEtxI!F00 z4B-SbYVRwU!^MS6=Whwi1)KxTKJPh&cU|@Lk}C1Jdvyvzne^Dwm&fCQ0oxroUD=KdFlb_oin~+W4Iau zYXiEi3@Tql&BMLS9|hZ5K)Sx%8(adf?cCt*y};(veFS47J_*UXIJcvMrI=OvA+AD~ zeXbWw2jY6~J0UBgYVO^A$x2t=J&5d3&tM%;E-C51XXsWqjb9-G7mCpU-%OqC1Vx7B zeb;sBC(}iiz9kIF4vsS(!Y&1;42^kbrh^0AM^${WWW$IASV>lIXst7wEnm%L)Mt|JY4);*biC+9u52+wV=Meue^k;m zGv^^!;+jej1hZ%vsEF9b%XQ~R73=LE)!V8JKEC2>v-aCko>UR_oLEjtfK=C2_D^$mtJ~*?VG;nm*Kr2r7 zslS>|ThJe>fLop*+JzljTv%~yY!h0{KYblmM6geq^(a5wVhs-VPp=%=o;{q6@gp63 zQW`pC;U@4gVEX4#Y3;6a++*CQ;+!FiZ;0kxQevzvjPO6GGqzA5d_`oj3(A8$X#ov^ zx8Lf51pun{>njhh(CHAWQ0lkbOoY^hcuA3~ubi5xaTCDcGlOS%)4ub-0405A~yM|p9nE7zkg@ZScKuq)OY5ApBF0ZVqvSB zFF17NgKuAuc#x~&lwkYW+uky*a||YCqjQ9u@5o{z)Q2*e6~MZe3kW{}7wZpm#$`ZI zFv+h?H~3gU&rvn1ZH*(;nLG7wiBl0T2SK}3Xi;k`sytcewf?fBiqqtO!WO{eX^M@% z?Nt_jnJrFa;q$!sg|EqRxvhBcHxN}K+s0rxZ3q&d33N z-}h5VRG|-l8rvos#oBF^eS0W(`tIq9+$1)m8-@PO?rpq!EZ?1<6{8xWBn^|l9vR+F z*_K#w$b7oW;39>ym4xz zx4gNcvRd}}0@BQ!Y0ST_T?Ws|Q6cPlp{#)l=7Bg5tm&C*z~3#~>}vL4hbJxXzo2me zS&`mx8`;J^$|!mGUi_sjv@nEb#jjZXo^g}4EJHL=(XZ+7Y40P_v<{+}DIv!prS@HS zOZXCyM@l%zvT`BAaK#^k`XV5~{fEknY(76Hr2z5kOOIvjA)9D(8m_UIDJ1Oq9lP<1&$R7nd;z%@Z(Ybw_A78} zSy0RRuJclWI-nmz4+>hp>C#8Dj%x0S;unk zX7_TX>*w{{OqaeUJ=?)%waFHixatmT3*vY%JuR7{$8+;X?<}@elUEzp30qPb^v^*fp zJyhN-K1uCLe`r-U5Jb4!cJg=T7ETKk{hZl^l#w zW0!uGIl#yya_FqCZ~*`N@e(=ENh8`X{b!7PNxbb9qEB^l7rpr~-%A-ae?`0OV7L)D z_ub(cfDN2eVt*Muhz~NE`{lH<%nyzHHDaI-b$Cz_*>j|`?Zsu2J(Ck!63sGmk|&#n z1!#cQHiX%pxlNcIx0#(AyrGo(rEzP%!z-o#Sp8FxaeS&M$fBmzg9~QO%HW0dBhZxw ze79EXj>-I?w}|TSam7jRfe(#L=9)3q?;g58G7WCh#AIQc+{if#dHLo}H)<5Vc5xtt zuihvsJll!o=IZ;>C6AN2;ttP}F^z>Xs_Xu{K7s4Mvw)1a>7((lUnn}q#G<^ey6L_v zzW!%jC?&3eWMMeOb-hKXw03k|AP1%hHq$Y)gP3#aS5k{u+{lS?Doc1|^s}BA$YtPg z`&4bQXX@kpxwjgRF*E{589i?5-h7f5RrKPwy4>U66PnP_|7M+e$W?F3Bbol{wBv!D z`eP0PSNQa|T^c-3(!G_nln<@R=ZC<64+)pJNL6wbA9E=4&ij$*haFpn+&Zq- zeSS>(x88{d47t0_@YY4&<@%-Nw{dvG96uszrmvznJ+t0IuRB5k}hpRxWs)y(j0%IZ<;Hw=2}_CP823kdvC*;WV7K@ibM&_W(dcJ83}!UouJ-IeY7Wtn{b&`cd1A^@nOY zbogTNI39gs%-$60TMqGoUP%5*o8*ApFYH&Nl6 z6G5h<3X?+nMfi#np^Tve`i&qOGnvB@2PbztnVnt0+aUYab?Xd=Q1A-+#^hXc##Xr+ zkDU#vhj?Y$g_hI$QRFg=FSgc3*U!|<$u*b!9xBl5<)jR**Z50?;I<3?OiN85_Ju3e z9>nAZV>vPJ7F z!yg(PV`P-6(E=!H^tu(q6WahVXu&D&5o7M-PliI~w^G+KXv%+5jSeRN(a4FWy1)?+ zHW|8pARmRhg0#JZWUQ~*LdoyVs=`$hhO%gGk>=MEtp<2d4s#qo=}DZ> z8(Ik82-o_O@E$As`daKHy$X%2X(@hN^-*=wpp!z6#E7!%-8pLA zi6-n*bW{m$hk8pD*@fJiIqDYtn)>bR{lo4r)p{pwsKKv+aamX2>B9sT?n7RIA`m@X_vP${el63~5ZVeGwX`&a26MnEeiU60{ z(^1ngb@O#UTn6;N{eEak*0Mc%tKkDtd}Fr%p(cOqjdeo>SK*xYOEQqMESu;t;RGC@07*kp z7GiHGwqK$Xj?b#|PeJ73YUGlb8TfKiZ50%cyhG#nZy-W?uB!%kn;s1W(z&phO)m*` z`P$%FSk!kDRpqpWJo+Jpd0isHYN2Pxl~Hm6F+~iryQu8LLbqBer#G9sP#y^43Il=f z`mgm(be};gOika9UX6#?G+GQ1;cLnf88)`sKfmUB)k~$V@m8Ligorvirx*$6{YUHy zSPD`BGT88!>B2B|G9YbZV)zuNde2+t?vXO}&9b}TZ}NKjA-CeT zO1^<24?1NdZkcI#^WVAf)3IVewVl0=t3$IKZOnwM-?fJD8ixtknh~epZv)VZiSGQ> zaXYglA8kh`^}4kr$;*iKT>n&}eQkd8>XuT4XY=$|NaJs`= z^6VKvhh?*&%N|4qwSE+vRH2ptfV05I+JzyCcrxrmTgnIJT}*TGZf&!kmD6I+%hfP> zs@z@3!M?0{Df*<;LA`NhXosi={#dw_+@<2N@iy?k=)=cGg)bj zd&PIDSSa2hQp0X@9VQqnH~985Yo&3kN02knx0~zViABvx2yE6)d8yWz6*t(NGsyue z>z((#rWt99ws(7GD?`BIF3&y*k#(9Eirs8uZ!Jm@K_S*mmifpUECXTcR}cUX?c!AY zWzXreR9aZ3qCtk(s=vy7fq-W?D;axoe?>dx_=|Y zdY5wQ!=rLw&WwG0v9+9C`D~3j@Z4k4tGgJ)6~|Cuv%w}|?k2g!nq@yIP1Fm|OW5=Q zY|g@2d2K;=(@--TTcn#ISHMmH8Rs-|J)Hs2I0%&M1tDo>BYx8(@3SrDjelSWyLT=0 zPE`Ph$iXMFV1#njg1?sAgrgq2vB~OxrHwhQGR(VS8s?>6_g(?4I8z16FErb5C*;m~I;-o2SK zgy}Uj$^1l>Xv&&QoRdQdVSpkA%Ealn296ZvJWc?%?Tu)Zw{pKX)B72V!#+y7_h6t& zrsLkscdi4kn$OnbahR91F$_C-_D|52ipzz~>kcOc>hv8Fh#MKLV69v4#jTnH>X}*a7X2VJi9Hf-0naAs(Y&Rgk8{#JH_=; zXdr9l*h|I^k%?+&BG(O>g=-yU~chus06X*W4r`jq%XiOz94j3=N0VIG~S!ruFy zAA5z4kxI4e+S{IsS_&bHUx2l-vU@Ezy8VZB-<&F)&FrAzd z0YY^dqfY4Uv`Z$leu4YFQY%;{vs+Zb69(mTLYVdXw@S#l$hA}lN7mkq*wG*+X`rZ5 z$_7rA_^nvWHd1Su!qLGsNCVGJz|7a39>_IR8FCH7v1Vewz{I%{&+?`k)B){YLcxQNVikAz zpUSpJu@wur_c-GlKapB4`9*786g4?ND}Ut1XeQ#^6r}VC7EVAOU0E51S#R}TY0SRu zG{RTN<~BNsakfSS&p5bFhl~lD?Hb)-7fz`B44H$M=wwE>FvSf&A1yCSr)$@sGx=g3 z3oMXLNAitJYCJN=;6=Fm#uRFivtyrvS7`)ye8t6e?T82uS=#uag4sf>(%@iW+bt!c zPI>&Shj14JnW-Cw^4GD5zIbgWOtz$>GvKy`xc*SYG4H7GGHm~{#nSU@Vl;+6P- zxdxuFVsFf2Zi1fCYn?xlzf6F!KXZ$hO!~%x9PT=)Tgp?zh%Y|etx`4*bE`^WBVVDH zIfhm~G?rn>DQHGAvK%+>82;5!b(m|`o)@I{Z*u=h{go-)Az7EZXwP4OSFT&bZAsxH zog3E1f=MI5>D9tp_{B1Re-Rb_$Q1QJD; zXVCtO?9&}imw0$5ghs%%#(+QQX-Wmv9DimNdWXy1){tqX%Hs865BKhdgsTb z{}6h)tj%cdKRQQ_C>22#z1`-No%}^|g z@jIR2>{m0%0Q6~XjUx7?8jtx=vIT9xa1IX0GSRi6erxXm1j zcPvm^)UMosN!2ccQCOQO+`Gi?ZbF5kTUqD(nu{F`DKW%NJ{WME0FMKA< z;o|pVt&Cox=CQD$-4@Mt3c&I78uO@-Bkm5>wNCC-19FPG=|Vc+I4T@$e7&0Pfy~t? z6|6nI9t%&kY)HhfVx)@ZwoxH}ht@~_3lMOyPPmihR*cAnbng61$)3`mdv}{yyf5@v zkFyoetL^;_I&TXS5k`M|^sW1!E?1A0V2dWo@A)_e2&Ty8Zo)=3Nl*=8v`OLk}Q10!QGER4R002~yf8 zK1&<8gNNdTgG@kgXe))gp2l3Yh8iahosIdYqYUO1%#VyKAMKU;$Sr<5*li^Bd;YH$ zz%AFi7D#^M0c61~!J<(t1rHaTV8vikbEg(6sl=4BB^%X<$KY>vTb;NL+bW7@3JwtW z&ypo;)#y1dwo{!ovGuO|%z*wd@$iRec^65a@5D|3JkN&p0XtrgJGVT3Ftt^l1u|`TyV@4mKcZKL~Kg}dP=!sS(DF-h#*N|?- zT|CJ5N+iX#x-{1Uik<(II=_^G-^-OZOaIi=0F`-~%yfJ`oZXKP6`|(zmEaF$BIN90 zZB%$UPAHcqDY}y3ZSWt@6${I2bzZrXAu+#0&&<1Tci}{#1x!6>oJWYX0FGk7QGNpXisxu&fS_`O@q!JL;Cc1$A!S!?3 zPO@H&^Rqh#&&TeKPEdLrAbeTrVKMI34JXhsq5J zbZO8NeofQ(NJ;PN!KyQFawO{P+InZI^ws-jKez`1?UZODTD{pUvAn(62cwk(dbO0Rx zifYW@19`Wvpf7=i^ikR(DZWTg4&`#HL^f^hRPNirum*w4a!)I>2xtPn%s(j1nqVJq z1P;WV4)31F@~d0Ty-ERy+4r+c{9PDOhhFNFtIq;^6Zbf=LbHQS3dX+kRw3n%_rEUP z`tZ`+^c%Ixz>&S_VOG#T$VeW0k_wKS=8F|tlsk@~pmN&hfEER;soeU83#==z4JfUf zmqIOXy}n-YOmbK7`kIbnmnM{E6~Y_qp1I!73SGxEJ~nMa=Shd$<~(QbUs5@E-bN!x z;LI8==AuK|X03TWOslIazJb&;DAydQMpWA>NauzMo!MmHKQLdLD4p^c0bF7jId|12 znw_LRk2z;a-L)&d!!t+MISpo(-BptEN6*ANg?TXnRx=-}qnSIRx`+^_eSk2}%p@#? zcd#XJHmil|DYiGxJ-yp5q#3jj`HXKm{0@f`&n2Yp0+`Nj`ya8uEb}E;0~r-6vQ)#! z&WU!c0fiYSU#sGLNCQ@h-8Mdz*DgYs-%xzOGC~zxIy*%7yvpG4^g0v*N7dP1cK%GC z9Y+;#0a?(Za~($AcmP*FsD%kjtn8LjX)Kk*W}Rd&jN%|qJ+lk_3!Xc%3zds<=r;NA z@qWCWTb&5BEZjX)<4PN%ALw?v1G(t5jc*QQJ}ZT=e4J2eHyp^mg47Md*mSox46=!V z+ONLXINWd1YPAo>((jmcc$)fgy&Ci1Tn6SH_$z09hvLaJ=J}%pSf_^RI$rT%)6%xJ za*a~FLN4{=m38`g{p=pfl)H`t5k={%P@x=t4%+(d@RFP!v`TtTq0Ekpt1Nk+1ZL~F z#n27;JD;6Ch4OGwTp5x5&kZtX_?V-*ja?r)ELWnFGwKWX(98fdvxasw@X+BOSl0Uf z@mF<>2#qY^W`}k5ziK^}$e3em>BCy6EMZparI^StNx`%;gYLd#4{k0FhIwIA%SEMG z_Lp1}XW$NIXMFL%yB2oQeVGIihJASeSDA#3%6ErRr2$~OU{(rmohUP8kr5EnasIq! z<7^X4rkI@}nrrOU&;d_X-0F)FA9`A}&w03t?wYhV;XF(PQ<%7cPo447=;XB^6XUy= z2=}7`ssIzu+BAJ#R_P<WTRnJzYZDHZ5 zLZ$W(B>oeM`AyRtUQqg$@9*udd*}0X6u>O_VMsu?Ru29o&jqlfTfi%0G<=!aIVY1= zd@9`)uihm;K2FkKv3y2!3sv-4oBtI=lC5ad=6hdGpXvi5{Cz%#CA55apKcSKj!Z{c zj?EnO-Ynw`U(?y@uK=+q4J{$(gRXXmt)=UCAd=}K8yE<-$!1^Fqi3vWt-H%14cdV? z=m*yBpHAgoPz8G;k)2ON0p{Qs_}Nkk5yPJmXI^LK`;5u51gC~j{j#ZD-bVjv=mGj{ z#vU|1rMUL@}%K;IhPMdAitcNH3ZPomK*0+o?pk&CefU zO_f}RZXo{Dhbs98pz#bW_Tz2k!IxvRSb2MRF^7~>IQWm6dZ%}>uj9LCzeB?%!3ic_ zabizhJ1ap#5}PjSM9i|~W5r}8>@Yhm5&21WW~`09qKX&fakd?`sGY3Dxx$~(5S;nL zmQ|>(mzEA$f2zag0sRp%JCN<%M$g(4==_<9s{RsEU+`*$aNc$JRjG&pCf7!=P{07= zTRW*W)OzESqc~rUm)9a4S3?HQAj!INxfD^D z67!o+4w42XSC)`LGrWHSXexytIVC^uj5S`2CHrJM#YMU+OyBK7jq_PQszZ0#(tZZh z=e6z{qI*tj)Z&Q9A4(=-$Qsy56cvie*M9dU;*lLPvNZ$KtRsbFe8Hmad2qU9@8T?_ zwZOFh!c;N#t3;mM`SDR3=`U9sWvhbukDDko5jq@Rph#2P8g7P2Od<*`y6Z0h0`HN_0vwYCADcyIApZMm(mr5CL_sO(l z@i>j4CZKQgY%}P|&HAER(DvCcdg4dyfgF|7M2_zgD)v~?(G~>U4x4sEG+-akI3DJT$vgOAGnhNM6D|6x%{6J#Bz@8YUPtSP17ghMbapss|l6w-E=gAXw*$BhHe-?p%4gskJxok2qmwA6i6-mb5Z8_NAz^Vjnm7&P{no_{{1@{bYNWFB7YwE?j6gYz1_3Z(MaCYCWOB2akI$;TBXyPJ_IB z6{s02zDTRSjH1Mf!~=?FJsB^Sj)+dmG+r07%dS|pEEfp=1sr(U3!=l;y4Dn3KO)+k zX}K~kv>7 zRVqeajfaO9&_y`92?fbhy;8w$y}*f(OT$OP)xc^xhAp>^0FotmP_C#_)5wi~FChE& zYsCxiI%2R#fQQFbtm49BmeSSCm|-RuptTI;x_4w$Srnoxl4S5n;UI{X0ccipx7?)x zOH3pEI^9SPNw^KwTwxPnkyfoN&#DBKJPY9&BfsA1M2>E@tVmn^SjdRp= z{y~|^2w(5pwpm`>!4qH#z-cSrOUS>yX%w+KHb`e|cNsHSK~+JYF>+j2^Jv*+2=U1- z?9KT=+u7R11(L;*aZhZ)S7yY%tvb$I`Iq-xZ-1!9rBH$NxKUU#`cEZrYldrod!i4; z>aaA?A`AYk=MuQN6q<7~~O26OFG(DqphA-CNIU9?V%_#u=kwGV#;ZB?p+AtLtfT^ut z9l18jMYTwN7|NV((^=)77RK)6VvpdeV$==38R!e_t*fLdLa zJKsH>kNjV}m=t?ySD?aqcsKpNyC9Xks};_RIvGZ`i0bkQiO&4ltcqS}ac|F((+O`T zw$6O-NNsi&()2wtX8ldr3>GS0JGlAcX+*hP>Y0w?{41W#HuKljpe;BHM+nvQsn3$kQ8_a;>ht9@UTbCdbBk}zB=buc$!kBv z+eqtP&6s!j8)|vqDVY=#?oCRB)-p--6-$vEGun>wTWu(G$Q7^KN%`82XWmdA@u>yKNDV}fhkeqrtIB!BERACn|UJrXrK+g_BGHQ?-)m=X2~@M zRoOF(GrlaM`s_^s>tgZrCrcmGqlPx;+FSqHBWSZCv~wf1n|FU2k!d|oo{eoL{{6b^ z`_AaW-=4&_(v`yp6rG{la9&j{jH}egU%i!F?bp!Ii^}p&a&A`PnOD~Z{_AlO*j}Sl z{Bl=)I*-$<1hQJaM>0p~{irUp^oEtAL3+ts(onqzDYW@>~6@u_@no>kl^p zMZsSeDyr#yMnW8ua7sWX$dE-QSu&yxC7Bp@-}e(AbMzzd5YTPPY911g0?KC)Y>?2x z?esnE!@utUsqEXtluONXfTjPFqe8LTRl^&?)HIvxjJ7($xqvh~89EXOz|0DHAUyTyuB1z1T-oFF#F@=j9rud;aFrxDsFzqO)i)HP^7p zIGZ_oU%Oi)W?Wv5u}2bj8Z*3`?X}2(YJWRLbn`3UN)*V=_~g?sI+MK4Vm;bhc=e&rhZ2E@1v`pOI!f?{1i!F2Z(#3P1E@8_<6`N-Cu{$(>@)ozu} zB>mmv$>;ByK$rfI=q37_1kTpiB`}R~D{hH_0=bI(T;TKom1xvJk)CTN_NKQsS3LvX zE#2cl3d49+;!yS}GK_b`MS{g;Ql}eUJSM6CC`^Ep0jRy+vcf$xju*;V-@S;7T$>k_ zVp&nsS5p+(CANw6j!wZ&fUsiucJ8q*e=Wdj{TwT3I7Dd(0UH+bi$w{)txCV3=4uzF zC^g|eO|M}FIxv=VgX*~@Bzwu6m$Il=KJj}S7GwJnS=!CRl-DNOyqhk>mJCy{tp~zDM+lB6|($j8I>%!zia342ca1S@CEY8%RVSM zC|ZrN%w4NVx(MOSx2Jkxgsosst4dyt%lFf(Y|>5h+$6UhC)<``T;YL6YbJKT^dV?J zuq1Q@H&?7Mq(f>R1itJmdZc@;a;#JFWt_t5agWv-Vst_s#^4_e8av<6ewKE5I-h@C zp)95NJbC&@A=IroPmfl%HjqKaBg4_kMG}4z^(u2CY9=Q(s0}bcd6 zEOAn8`BMGsK+|LU!;F@}1PEQE0$TtVQW{n#?UbJJPXI^P$h^oayZQOL#VaI%3&%o- z3Bh`&qZ=+j=D@cU1WhwD*z5G(<|Btv^O-mr$C9DN+7?cOPUn&pwedTDI1?+CNfTtC zEC^1ei)5g(M{mIC4vczkYd+;Isc>u53ip4kUWO}>gAvvyn4=m&kKYXz&Uztwme}qa zv=(IQxM?XAmpxsjuSm%a=$pr_U44y21_3cUDg3jM=gGJv#c;={%o6G2hUT<+-MW>y= z)YGxwBZOY{mW$kKs+Yyu-VymX5EJAf46719n(hl$;(nH$o0J4858qgWH&)%M;L24I=BS^W?Mmt^52kM<2vE1tsn5c8 z{J_8LV(YoAvQ15$_Zw`K-folT<0h?+YotxA04PsCwR2eXaHSa(-h1reARzV{Q*3BD z-*?|G*=fXk#lQqIgX4d{55)SaR^3!f5=WV@hL-F~L0a>@CKj6y9m&pW$jQ!q?mv4G zcm2_UvH@S0eG7BCV)hqWPY)P+&w!OB!~i2@udN->TonH1-(--P2;SSe1L% zTGKUjhHxMvHxGn2M7|DV2D4ibNK+89JyQIrx@gnF-eJe7t6omA`8D0q_fEDnPA3 zzm6dDtFnI6mIICnfHF;O2xK#^^H*%WZKKJ|`x8*!gqJDdm7Ef%W?+WsSEH~C^4cpv zyQ7yhIJ#anjnMHy1*zZC`}KHu9hOYj=>9OzpD`bh#nP~APh}v1@3G31v2Y+8fJyH= zU|}DA>YS$={MhHI>%k6rrKZyolLI* zac*L{O7I;UmGq!GMpn-Na1?If975GT1(|fuNOTuKWDhmYx-&=hju~gbSqonRNgd4_ z4SD9~tB8l3*T2ZIvJJ0u9ajO~Mde|{BQ{8MB&(}PZZ+^ui#-dGfJ&ZACfOmgn0;79 zi@fYVA!@BZpR;@U24pOjoJ63;bJ0X4@y^W8T5cB%)bgM!+Q@ULpdB$QGEdUkJ10@! z6^=C^Z9$`3N!(x1q~M!!z)OU9s*QHAGrI)vkMuj}r~k_drI#;wE(cg~(!Z_BrPXSG z-**#qTwEg2BXyfRL!Y1O@q!dHzf)hi>S*b5Vi9PR9K4NM5}46`R}?h|tTQ7Afcyop z_U9^?zjwuU908*d$7xqsX$o*r-arW)3~O=@pWumV!8j{R>r%_7_$d_rfUo|V_+e|vFGbXYQY^=HS-tZ z*4YXn+$PSRyf&Fv?>x$(D^ombau538hvVYZ&m%ps9_72idroiA%&-!#LXb_^8|@sT zECeT%P=+RGJ8Y{x`XFpUGG|Q=N+sQxROjI7af@e!nT!%s3&Oa#)w+DnqqE7M#B>rh9w7(0_*aF7#$waD0>YV@BRfFfM=2+i0P&vVzwXh{L z(s2bzV}6#r)xQJQ&>-of-n`)|9vnUVjqzgL=VH(#y;@7f%A?)}wQBii4RaPs)hPSW z(r@7EVo;;IQqfsR)M0&Ts(Lcg)}<&~)d?^2Zkg`61F>LN>xxpq2sBoRGwZ#C&#$+k z@;Dnv=*Pp<(uCo)d)U!x0o@|osb5Al3PCQD85k+2AD#~PRMDc;FAjca7LZ=hd|ula z7f27j<5$y*o$3@YL$Lq;KAyx(E@ve`WeH7#0 z>#&2;vqZ832I?1eDo1lfOxEeH6y|I$>#*p!W%3!A0*G3@Fx>5~qAY5}BuA9J;mmYi z>ElgKF*Q&XZ-)YCmBz*2LSVjR&YMZ+hlZh)kft3Ldy>V+8p+n|axsUYDAh*(?|&2d z<(H?o0Wn9bcLiS>pcY?qMK2AohyU67^j#4gvD`qdU^wtY z)9_;nqCHpi0u$k{Y%*U=SEm08;tCLGI9rlsq#UBrPv`$-YKIb<)~_w_j>&%vQt30(_LEyJ6W?9W&WgK0s{UxO_eYW$$miXy z3-~-?$HnoF&B^-i#KwF!Cm=Qm9gjT?d&9tjr2Nv@m@iA*u^)E6s3bJP{pGSt0TpXg+!E5v=n z*E&EulsrVkhrhbp`>1&A6|3=7DNox4eukv(8a~&bk@#=*`9@>-+Ne;pe4OEj$nG)Ch^N=-U+H(?a{O&aH^Z#e@@F`e8zhSGT<9$~+McSQNTs(tD1o76 ziIv}ZA3g|K)hQ|OpyG!V+djwTa#vuvl~S=dJ78|D%7uKp+nS&0UliO2!t(@HR&?+} zhjGFSYdE@nph|E8H$%}i@bb@bZSLg~V+Q`(+CpkbhkJ003)Xjb)q^L026RrxX~Leg zT>?7LvxPssk6)_v0La!+vDf#yYSavXn7WcRsPUbZ>J0r%Qbf6C&+`J=ig!7(u)JEr zQ;WKXR!&℘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 n;hyK49Kp!Ktc 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˶p1M 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 Date: Thu, 24 Aug 2023 08:58:06 -0700 Subject: [PATCH 095/134] refactor: clean protos for clarity (#1071) * consumer proto folder * provider comments, move one msg * ccv comments * moved shiz * proto changes to build * make proto gen again * no circ dep * Update wire.proto * comments * dun builds * progress save * FIN * refactors * rm improper proto ref * rm todos, issue now * lint till I die * update comments, rebuild protos * change ccv.go to wire.go, and test file * consistent comment * Update wire.proto * example alias diff --- app/consumer-democracy/app.go | 3 +- legacy_ibc_testing/testing/app.go | 3 +- .../ccv/consumer/v1/consumer.proto | 86 +- .../ccv/consumer/v1/genesis.proto | 58 - .../ccv/consumer/v1/query.proto | 3 +- .../ccv/provider/v1/genesis.proto | 13 +- .../ccv/provider/v1/provider.proto | 28 +- .../ccv/provider/v1/query.proto | 6 +- .../ccv/v1/shared_consumer.proto | 156 + .../ccv/v1/{ccv.proto => wire.proto} | 33 +- tests/difference/core/driver/setup.go | 14 +- tests/e2e/actions.go | 4 +- tests/integration/distribution.go | 6 +- tests/integration/normal_operations.go | 3 +- tests/integration/setup.go | 3 +- testutil/keeper/unit_test_helpers.go | 10 +- x/ccv/consumer/ibc_module.go | 3 +- x/ccv/consumer/ibc_module_test.go | 5 +- x/ccv/consumer/keeper/distribution.go | 8 +- x/ccv/consumer/keeper/distribution_test.go | 5 +- x/ccv/consumer/keeper/genesis.go | 15 +- x/ccv/consumer/keeper/genesis_test.go | 52 +- x/ccv/consumer/keeper/keeper.go | 24 +- x/ccv/consumer/keeper/keeper_test.go | 12 +- x/ccv/consumer/keeper/params.go | 37 +- x/ccv/consumer/keeper/params_test.go | 17 +- x/ccv/consumer/keeper/relay_test.go | 10 +- x/ccv/consumer/keeper/soft_opt_out_test.go | 4 +- x/ccv/consumer/module.go | 7 +- x/ccv/consumer/types/consumer.pb.go | 1240 +------- x/ccv/consumer/types/genesis.pb.go | 1394 --------- x/ccv/consumer/types/genesis_test.go | 245 +- x/ccv/consumer/types/params_test.go | 36 +- x/ccv/consumer/types/query.pb.go | 94 +- x/ccv/provider/ibc_module.go | 2 +- x/ccv/provider/ibc_module_test.go | 2 +- x/ccv/provider/keeper/genesis.go | 2 +- x/ccv/provider/keeper/genesis_test.go | 9 +- x/ccv/provider/keeper/keeper.go | 16 +- x/ccv/provider/keeper/proposal.go | 7 +- x/ccv/provider/keeper/proposal_test.go | 3 +- x/ccv/provider/types/consumer.go | 3 +- x/ccv/provider/types/genesis.go | 2 +- x/ccv/provider/types/genesis.pb.go | 137 +- x/ccv/provider/types/genesis_test.go | 9 +- x/ccv/provider/types/params.go | 5 +- x/ccv/provider/types/provider.pb.go | 898 +++--- x/ccv/provider/types/query.pb.go | 191 +- x/ccv/{consumer => }/types/genesis.go | 44 +- x/ccv/{consumer => }/types/params.go | 40 +- x/ccv/types/shared_consumer.pb.go | 2712 +++++++++++++++++ x/ccv/types/{ccv.go => wire.go} | 0 x/ccv/types/{ccv.pb.go => wire.pb.go} | 905 ++---- x/ccv/types/{ccv_test.go => wire_test.go} | 0 54 files changed, 4352 insertions(+), 4272 deletions(-) delete mode 100644 proto/interchain_security/ccv/consumer/v1/genesis.proto create mode 100644 proto/interchain_security/ccv/v1/shared_consumer.proto rename proto/interchain_security/ccv/v1/{ccv.proto => wire.proto} (83%) delete mode 100644 x/ccv/consumer/types/genesis.pb.go rename x/ccv/{consumer => }/types/genesis.go (67%) rename x/ccv/{consumer => }/types/params.go (83%) create mode 100644 x/ccv/types/shared_consumer.pb.go rename x/ccv/types/{ccv.go => wire.go} (100%) rename x/ccv/types/{ccv.pb.go => wire.pb.go} (66%) rename x/ccv/types/{ccv_test.go => wire_test.go} (100%) diff --git a/app/consumer-democracy/app.go b/app/consumer-democracy/app.go index 063c5bf427..fee730d752 100644 --- a/app/consumer-democracy/app.go +++ b/app/consumer-democracy/app.go @@ -112,6 +112,7 @@ import ( ccvdistr "github.com/cosmos/interchain-security/v3/x/ccv/democracy/distribution" ccvgov "github.com/cosmos/interchain-security/v3/x/ccv/democracy/governance" ccvstaking "github.com/cosmos/interchain-security/v3/x/ccv/democracy/staking" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) const ( @@ -712,7 +713,7 @@ func New( return fromVM, fmt.Errorf("failed to unmarshal genesis state: %w", err) } - consumerGenesis := consumertypes.GenesisState{} + consumerGenesis := ccvtypes.GenesisState{} appCodec.MustUnmarshalJSON(appState[consumertypes.ModuleName], &consumerGenesis) consumerGenesis.PreCCV = true diff --git a/legacy_ibc_testing/testing/app.go b/legacy_ibc_testing/testing/app.go index da861481a7..ff3c146a4a 100644 --- a/legacy_ibc_testing/testing/app.go +++ b/legacy_ibc_testing/testing/app.go @@ -29,6 +29,7 @@ import ( "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/core" "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/simapp" consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) /* @@ -111,7 +112,7 @@ func SetupWithGenesisValSet(t *testing.T, appIniter AppIniter, valSet *tmtypes.V // set validators and delegations var ( stakingGenesis stakingtypes.GenesisState - consumerGenesis consumertypes.GenesisState + consumerGenesis ccvtypes.GenesisState bondDenom string ) if genesisState[stakingtypes.ModuleName] != nil { diff --git a/proto/interchain_security/ccv/consumer/v1/consumer.proto b/proto/interchain_security/ccv/consumer/v1/consumer.proto index 2b4b6f88c3..39d6eb29de 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; -import "interchain_security/ccv/v1/ccv.proto"; +import "interchain_security/ccv/v1/wire.proto"; option go_package = "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types"; @@ -11,68 +11,17 @@ import "cosmos_proto/cosmos.proto"; import "google/protobuf/duration.proto"; import "google/protobuf/timestamp.proto"; -// Params defines the parameters for CCV consumer module -message Params { - // TODO: Remove enabled flag and find a better way to setup integration tests - // See: https://github.com/cosmos/interchain-security/issues/339 - bool enabled = 1; - - /////////////////////// - // Distribution Params - // Number of blocks between ibc-token-transfers from the consumer chain to - // the provider chain. Note that at this transmission event a fraction of - // the accumulated tokens are divided and sent consumer redistribution - // address. - int64 blocks_per_distribution_transmission = 2; - - // Channel, and provider-chain receiving address to send distribution token - // transfers over. These parameters is auto-set during the consumer <-> - // provider handshake procedure. - string distribution_transmission_channel = 3; - string provider_fee_pool_addr_str = 4; - // Sent CCV related IBC packets will timeout after this duration - google.protobuf.Duration ccv_timeout_period = 5 - [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; - - // Sent transfer related IBC packets will timeout after this duration - google.protobuf.Duration transfer_timeout_period = 6 - [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; - - // The fraction of tokens allocated to the consumer redistribution address - // during distribution events. The fraction is a string representing a - // decimal number. For example "0.75" would represent 75%. - string consumer_redistribution_fraction = 7; - - // The number of historical info entries to persist in store. - // This param is a part of the cosmos sdk staking module. In the case of - // a ccv enabled consumer chain, the ccv module acts as the staking module. - int64 historical_entries = 8; - - // Unbonding period for the consumer, - // which should be smaller than that of the provider in general. - google.protobuf.Duration unbonding_period = 9 - [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; - - // The threshold for the percentage of validators at the bottom of the set who - // can opt out of running the consumer chain without being punished. For - // example, a value of 0.05 means that the validators in the bottom 5% of the - // set can opt out - string soft_opt_out_threshold = 10; - - // Reward denoms. These are the denominations which are allowed to be sent to - // the provider as rewards. - repeated string reward_denoms = 11; - - // Provider-originated reward denoms. These are denoms coming from the - // provider which are allowed to be used as rewards. e.g. "uatom" - repeated string provider_reward_denoms = 12; -} - -// LastTransmissionBlockHeight is the last time validator holding -// pools were transmitted to the provider chain -message LastTransmissionBlockHeight { int64 height = 1; } - -// CrossChainValidator defines the validators for CCV consumer module +// +// Note any type defined in this file is ONLY used internally to the consumer CCV module. +// These schemas can change with proper consideration of compatibility or migration. +// + +// CrossChainValidator defines the type used to store validator information internal +// to the consumer CCV module. Note one cross chain validator entry is persisted for +// each consumer validator, where incoming VSC packets update this data, which is eventually +// forwarded to comet for consumer chain consensus. +// +// Note this type is only used internally to the consumer CCV module. message CrossChainValidator { bytes address = 1; int64 power = 2; @@ -83,17 +32,12 @@ message CrossChainValidator { ]; } -// MaturingVSCPacket contains the maturing time of a received VSCPacket -message MaturingVSCPacket { - uint64 vscId = 1; - google.protobuf.Timestamp maturity_time = 2 - [ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ]; -} - // A record storing the state of a slash packet sent to the provider chain // which may bounce back and forth until handled by the provider. +// +// Note this type is only used internally to the consumer CCV module. message SlashRecord { bool waiting_on_reply = 1; google.protobuf.Timestamp send_time = 2 [ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ]; -} \ No newline at end of file +} diff --git a/proto/interchain_security/ccv/consumer/v1/genesis.proto b/proto/interchain_security/ccv/consumer/v1/genesis.proto deleted file mode 100644 index 3511f3f349..0000000000 --- a/proto/interchain_security/ccv/consumer/v1/genesis.proto +++ /dev/null @@ -1,58 +0,0 @@ -syntax = "proto3"; - -package interchain_security.ccv.consumer.v1; - -option go_package = "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types"; - -import "interchain_security/ccv/v1/ccv.proto"; -import "interchain_security/ccv/consumer/v1/consumer.proto"; -import "tendermint/abci/types.proto"; -import "ibc/lightclients/tendermint/v1/tendermint.proto"; -import "ibc/core/channel/v1/channel.proto"; -import "google/protobuf/duration.proto"; -import "gogoproto/gogo.proto"; - -// GenesisState defines the CCV consumer chain genesis state -message GenesisState { - Params params = 1 [ (gogoproto.nullable) = false ]; - string provider_client_id = 2; // empty for a new chain, filled in on restart. - string provider_channel_id = - 3; // empty for a new chain, filled in on restart. - bool new_chain = - 4; // true for new chain GenesisState, false for chain restart. - // ProviderClientState filled in on new chain, nil on restart. - ibc.lightclients.tendermint.v1.ClientState provider_client_state = 5; - // ProviderConsensusState filled in on new chain, nil on restart. - ibc.lightclients.tendermint.v1.ConsensusState provider_consensus_state = 6; - // MaturingPackets nil on new chain, filled in on restart. - repeated interchain_security.ccv.consumer.v1.MaturingVSCPacket - maturing_packets = 7 [ (gogoproto.nullable) = false ]; - // InitialValset filled in on new chain and on restart. - repeated .tendermint.abci.ValidatorUpdate initial_val_set = 8 - [ (gogoproto.nullable) = false ]; - // HeightToValsetUpdateId nil on new chain, filled in on restart. - repeated HeightToValsetUpdateID height_to_valset_update_id = 9 - [ (gogoproto.nullable) = false ]; - // OutstandingDowntimes nil on new chain, filled in on restart. - repeated OutstandingDowntime outstanding_downtime_slashing = 10 - [ (gogoproto.nullable) = false ]; - // PendingConsumerPackets nil on new chain, filled in on restart. - interchain_security.ccv.v1.ConsumerPacketDataList pending_consumer_packets = - 11 [ (gogoproto.nullable) = false ]; - // LastTransmissionBlockHeight nil on new chain, filled in on restart. - interchain_security.ccv.consumer.v1.LastTransmissionBlockHeight - last_transmission_block_height = 12 [ (gogoproto.nullable) = false ]; - bool preCCV = 13; // flag indicating whether the consumer CCV module starts in - // pre-CCV state -} - -// HeightValsetUpdateID defines the genesis information for the mapping -// of each block height to a valset update id -message HeightToValsetUpdateID { - uint64 height = 1; - uint64 valset_update_id = 2; -} - -// OutstandingDowntime defines the genesis information for each validator -// flagged with an outstanding downtime slashing. -message OutstandingDowntime { string validator_consensus_address = 1; } diff --git a/proto/interchain_security/ccv/consumer/v1/query.proto b/proto/interchain_security/ccv/consumer/v1/query.proto index 43a7b0bccc..ff2a5901fe 100644 --- a/proto/interchain_security/ccv/consumer/v1/query.proto +++ b/proto/interchain_security/ccv/consumer/v1/query.proto @@ -1,6 +1,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/v3/x/ccv/consumer/types"; import "gogoproto/gogo.proto"; @@ -54,7 +55,7 @@ message QueryParamsRequest {} // QueryParamsResponse is response type for the Query/Params RPC method. message QueryParamsResponse { // params holds all the parameters of this module. - Params params = 1 [ (gogoproto.nullable) = false ]; + interchain_security.ccv.v1.Params params = 1 [ (gogoproto.nullable) = false ]; } message QueryProviderInfoRequest {} diff --git a/proto/interchain_security/ccv/provider/v1/genesis.proto b/proto/interchain_security/ccv/provider/v1/genesis.proto index 1bc412262c..22da5c4200 100644 --- a/proto/interchain_security/ccv/provider/v1/genesis.proto +++ b/proto/interchain_security/ccv/provider/v1/genesis.proto @@ -5,10 +5,9 @@ package interchain_security.ccv.provider.v1; option go_package = "github.com/cosmos/interchain-security/v3/x/ccv/provider/types"; import "gogoproto/gogo.proto"; -import "interchain_security/ccv/v1/ccv.proto"; +import "interchain_security/ccv/v1/shared_consumer.proto"; +import "interchain_security/ccv/v1/wire.proto"; import "interchain_security/ccv/provider/v1/provider.proto"; -import "interchain_security/ccv/consumer/v1/consumer.proto"; -import "interchain_security/ccv/consumer/v1/genesis.proto"; import "tendermint/crypto/keys.proto"; // GenesisState defines the CCV provider chain genesis state @@ -24,7 +23,7 @@ message GenesisState { repeated interchain_security.ccv.provider.v1.UnbondingOp unbonding_ops = 3 [ (gogoproto.nullable) = false ]; // empty for a new chain - interchain_security.ccv.v1.MaturedUnbondingOps mature_unbonding_ops = 4; + interchain_security.ccv.provider.v1.MaturedUnbondingOps mature_unbonding_ops = 4; // empty for a new chain repeated ValsetUpdateIdToHeight valset_update_id_to_height = 5 [ (gogoproto.nullable) = false ]; @@ -52,7 +51,9 @@ message GenesisState { [ (gogoproto.nullable) = false ]; } -// consumer chain +// The provider CCV module's knowledge of consumer state. +// +// Note this type is only used internally to the provider CCV module. message ConsumerState { // ChainID defines the chain ID for the consumer chain string chain_id = 1; @@ -63,7 +64,7 @@ message ConsumerState { // InitalHeight defines the initial block height for the consumer chain uint64 initial_height = 4; // ConsumerGenesis defines the initial consumer chain genesis states - interchain_security.ccv.consumer.v1.GenesisState consumer_genesis = 5 + interchain_security.ccv.v1.GenesisState consumer_genesis = 5 [ (gogoproto.nullable) = false ]; // PendingValsetChanges defines the pending validator set changes for the // consumer chain diff --git a/proto/interchain_security/ccv/provider/v1/provider.proto b/proto/interchain_security/ccv/provider/v1/provider.proto index 3c41e01c89..9423e1f924 100644 --- a/proto/interchain_security/ccv/provider/v1/provider.proto +++ b/proto/interchain_security/ccv/provider/v1/provider.proto @@ -4,6 +4,8 @@ package interchain_security.ccv.provider.v1; option go_package = "github.com/cosmos/interchain-security/v3/x/ccv/provider/types"; +import "interchain_security/ccv/v1/shared_consumer.proto"; +import "interchain_security/ccv/v1/wire.proto"; import "gogoproto/gogo.proto"; import "google/protobuf/timestamp.proto"; import "google/protobuf/duration.proto"; @@ -13,6 +15,11 @@ import "tendermint/crypto/keys.proto"; import "cosmos/evidence/v1beta1/evidence.proto"; import "cosmos/base/v1beta1/coin.proto"; +// +// Note any type defined in this file is ONLY used internally to the provider CCV module. +// These schemas can change with proper consideration of compatibility or migration. +// + // ConsumerAdditionProposal is a governance proposal on the provider chain to // spawn a new consumer chain. If it passes, then all validators on the provider // chain are expected to validate the consumer chain at spawn time or get @@ -96,6 +103,10 @@ message ConsumerRemovalProposal { [ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ]; } +// EquivocationProposal is a governance proposal on the provider chain to +// punish a validator for equivocation on a consumer chain. +// +// This type is only used internally to the consumer CCV module. message EquivocationProposal { // the title of the proposal string title = 1; @@ -164,13 +175,8 @@ message Params { [ (gogoproto.nullable) = false ]; } -message HandshakeMetadata { - string provider_fee_pool_addr = 1; - string version = 2; -} - // SlashAcks contains cons addresses of consumer chain validators -// successfully slashed on the provider chain +// successfully slashed on the provider chain. message SlashAcks { repeated string addresses = 1; } // ConsumerAdditionProposals holds pending governance proposals on the provider @@ -221,6 +227,16 @@ message VscSendTimestamp { [ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ]; } +// ValidatorSetChangePackets is a pb list of ccv.ValidatorSetChangePacketData. +message ValidatorSetChangePackets { + repeated interchain_security.ccv.v1.ValidatorSetChangePacketData list = 1 + [ (gogoproto.nullable) = false ]; +} + +// MaturedUnbondingOps defines a list of ids corresponding to ids of matured +// unbonding operations. +message MaturedUnbondingOps { repeated uint64 ids = 1; } + // ExportedVscSendTimestamps is VscSendTimestamp with chainID info for exporting to genesis message ExportedVscSendTimestamp { string chain_id = 1; diff --git a/proto/interchain_security/ccv/provider/v1/query.proto b/proto/interchain_security/ccv/provider/v1/query.proto index 431099be79..b0c1dc2b47 100644 --- a/proto/interchain_security/ccv/provider/v1/query.proto +++ b/proto/interchain_security/ccv/provider/v1/query.proto @@ -6,9 +6,9 @@ option go_package = "github.com/cosmos/interchain-security/v3/x/ccv/provider/typ import "google/api/annotations.proto"; import "gogoproto/gogo.proto"; import "google/protobuf/timestamp.proto"; -import "interchain_security/ccv/v1/ccv.proto"; -import "interchain_security/ccv/consumer/v1/genesis.proto"; import "interchain_security/ccv/provider/v1/provider.proto"; +import "interchain_security/ccv/v1/shared_consumer.proto"; +import "interchain_security/ccv/v1/wire.proto"; service Query { // ConsumerGenesis queries the genesis state needed to start a consumer chain @@ -86,7 +86,7 @@ service Query { message QueryConsumerGenesisRequest { string chain_id = 1; } message QueryConsumerGenesisResponse { - interchain_security.ccv.consumer.v1.GenesisState genesis_state = 1 + interchain_security.ccv.v1.GenesisState genesis_state = 1 [ (gogoproto.nullable) = false ]; } diff --git a/proto/interchain_security/ccv/v1/shared_consumer.proto b/proto/interchain_security/ccv/v1/shared_consumer.proto new file mode 100644 index 0000000000..825a84e346 --- /dev/null +++ b/proto/interchain_security/ccv/v1/shared_consumer.proto @@ -0,0 +1,156 @@ +syntax = "proto3"; + +package interchain_security.ccv.v1; + +option go_package = "github.com/cosmos/interchain-security/v3/x/ccv/types"; + +import "tendermint/abci/types.proto"; +import "ibc/lightclients/tendermint/v1/tendermint.proto"; +import "ibc/core/channel/v1/channel.proto"; +import "google/protobuf/duration.proto"; +import "gogoproto/gogo.proto"; +import "interchain_security/ccv/v1/wire.proto"; +import "google/protobuf/timestamp.proto"; + +// +// Note any type defined in this file is referenced/persisted in both the consumer and provider CCV modules, +// but not sent over the wire. These schemas could change, only with careful consideration of effects! +// + +// Params defines the parameters for CCV consumer module. +// +// Note this type is referenced in both the consumer and provider CCV modules, +// and persisted on the provider, see MakeConsumerGenesis and SetConsumerGenesis. +// +// TODO: Rename to ConsumerParams. See https://github.com/cosmos/interchain-security/issues/1206 +message Params { + // TODO: Remove enabled flag and find a better way to setup integration tests + // See: https://github.com/cosmos/interchain-security/issues/339 + bool enabled = 1; + + /////////////////////// + // Distribution Params + // Number of blocks between ibc-token-transfers from the consumer chain to + // the provider chain. Note that at this transmission event a fraction of + // the accumulated tokens are divided and sent consumer redistribution + // address. + int64 blocks_per_distribution_transmission = 2; + + // Channel, and provider-chain receiving address to send distribution token + // transfers over. These parameters is auto-set during the consumer <-> + // provider handshake procedure. + string distribution_transmission_channel = 3; + string provider_fee_pool_addr_str = 4; + // Sent CCV related IBC packets will timeout after this duration + google.protobuf.Duration ccv_timeout_period = 5 + [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; + + // Sent transfer related IBC packets will timeout after this duration + google.protobuf.Duration transfer_timeout_period = 6 + [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; + + // The fraction of tokens allocated to the consumer redistribution address + // during distribution events. The fraction is a string representing a + // decimal number. For example "0.75" would represent 75%. + string consumer_redistribution_fraction = 7; + + // The number of historical info entries to persist in store. + // This param is a part of the cosmos sdk staking module. In the case of + // a ccv enabled consumer chain, the ccv module acts as the staking module. + int64 historical_entries = 8; + + // Unbonding period for the consumer, + // which should be smaller than that of the provider in general. + google.protobuf.Duration unbonding_period = 9 + [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; + + // The threshold for the percentage of validators at the bottom of the set who + // can opt out of running the consumer chain without being punished. For + // example, a value of 0.05 means that the validators in the bottom 5% of the + // set can opt out + string soft_opt_out_threshold = 10; + + // Reward denoms. These are the denominations which are allowed to be sent to + // the provider as rewards. + repeated string reward_denoms = 11; + + // Provider-originated reward denoms. These are denoms coming from the + // provider which are allowed to be used as rewards. e.g. "uatom" + repeated string provider_reward_denoms = 12; +} + +// GenesisState defines the CCV consumer chain genesis state. +// +// Note this type is referenced in both the consumer and provider CCV modules, +// and persisted on the provider, see MakeConsumerGenesis and SetConsumerGenesis. +// +// TODO: Rename to ConsumerGenesisState. See https://github.com/cosmos/interchain-security/issues/1206 +message GenesisState { + Params params = 1 [ (gogoproto.nullable) = false ]; + string provider_client_id = 2; // empty for a new chain, filled in on restart. + string provider_channel_id = + 3; // empty for a new chain, filled in on restart. + bool new_chain = + 4; // true for new chain GenesisState, false for chain restart. + // ProviderClientState filled in on new chain, nil on restart. + ibc.lightclients.tendermint.v1.ClientState provider_client_state = 5; + // ProviderConsensusState filled in on new chain, nil on restart. + ibc.lightclients.tendermint.v1.ConsensusState provider_consensus_state = 6; + // MaturingPackets nil on new chain, filled in on restart. + repeated MaturingVSCPacket + maturing_packets = 7 [ (gogoproto.nullable) = false ]; + // InitialValset filled in on new chain and on restart. + repeated .tendermint.abci.ValidatorUpdate initial_val_set = 8 + [ (gogoproto.nullable) = false ]; + // HeightToValsetUpdateId nil on new chain, filled in on restart. + repeated HeightToValsetUpdateID height_to_valset_update_id = 9 + [ (gogoproto.nullable) = false ]; + // OutstandingDowntimes nil on new chain, filled in on restart. + repeated OutstandingDowntime outstanding_downtime_slashing = 10 + [ (gogoproto.nullable) = false ]; + // PendingConsumerPackets nil on new chain, filled in on restart. + ConsumerPacketDataList pending_consumer_packets = + 11 [ (gogoproto.nullable) = false ]; + // LastTransmissionBlockHeight nil on new chain, filled in on restart. + LastTransmissionBlockHeight + last_transmission_block_height = 12 [ (gogoproto.nullable) = false ]; + bool preCCV = 13; // flag indicating whether the consumer CCV module starts in + // pre-CCV state +} + +// HeightValsetUpdateID represents a mapping internal to the consumer CCV module +// AND used in shared consumer genesis state, which links a block height to each recv valset update id. +message HeightToValsetUpdateID { + uint64 height = 1; + uint64 valset_update_id = 2; +} + +// OutstandingDowntime defines the type used internally to the consumer CCV module, +// AND used in shared consumer genesis state, in order to not send multiple slashing +// requests for the same downtime infraction. +message OutstandingDowntime { string validator_consensus_address = 1; } + +// LastTransmissionBlockHeight is the last time validator holding +// pools were transmitted to the provider chain. This type is used internally +// to the consumer CCV module AND used in shared consumer genesis state. +message LastTransmissionBlockHeight { int64 height = 1; } + +// MaturingVSCPacket represents a vsc packet that is maturing internal to the +// consumer CCV module, where the consumer has not yet relayed a VSCMatured packet +// back to the provider. This type is used internally to the consumer CCV module +// AND used in shared consumer genesis state. +message MaturingVSCPacket { + uint64 vscId = 1; + google.protobuf.Timestamp maturity_time = 2 + [ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ]; +} + +// ConsumerPacketDataList is a list of consumer packet data packets. +// +// Note this type is is used internally to the consumer CCV module +// for exporting / importing state in InitGenesis and ExportGenesis, +// AND included in the consumer genesis type (reffed by provider and consumer modules), +// hence this is a shared type. +message ConsumerPacketDataList { + repeated interchain_security.ccv.v1.ConsumerPacketData list = 1 [ (gogoproto.nullable) = false ]; +} diff --git a/proto/interchain_security/ccv/v1/ccv.proto b/proto/interchain_security/ccv/v1/wire.proto similarity index 83% rename from proto/interchain_security/ccv/v1/ccv.proto rename to proto/interchain_security/ccv/v1/wire.proto index adf8f418de..57dcbc8847 100644 --- a/proto/interchain_security/ccv/v1/ccv.proto +++ b/proto/interchain_security/ccv/v1/wire.proto @@ -9,6 +9,12 @@ import "cosmos/staking/v1beta1/staking.proto"; import "gogoproto/gogo.proto"; import "tendermint/abci/types.proto"; +// +// Note any type defined in this file is used by both the consumer and provider +// AND SENT OVER THE WIRE via a ccv channel. Ideally these schemas should never change, or at least +// be backwards compatible if ever changed. +// + // This packet is sent from provider chain to consumer chain if the validator // set for consumer chain changes (due to new bonding/unbonding messages or // slashing events) A VSCMatured packet from consumer chain will be sent @@ -25,12 +31,6 @@ message ValidatorSetChangePacketData { repeated string slash_acks = 3; } -// List of ccv.ValidatorSetChangePacketData. -message ValidatorSetChangePackets { - repeated ValidatorSetChangePacketData list = 1 - [ (gogoproto.nullable) = false ]; -} - // This packet is sent from the consumer chain to the provider chain // to notify that a VSC packet reached maturity on the consumer chain. message VSCMaturedPacketData { @@ -52,11 +52,7 @@ message SlashPacketData { cosmos.staking.v1beta1.Infraction infraction = 3; } -// MaturedUnbondingOps defines a list of ids corresponding to ids of matured -// unbonding operations. -message MaturedUnbondingOps { repeated uint64 ids = 1; } - -// ConsumerPacketData contains a consumer packet data, type tag, and index for storage. +// ConsumerPacketData contains a consumer packet data and a type tag message ConsumerPacketData { ConsumerPacketDataType type = 1; @@ -66,13 +62,6 @@ message ConsumerPacketData { } } - -// ConsumerPacketDataList is a list of consumer packet data packets. -// NOTE: It is only used for exporting / importing state in InitGenesis and ExportGenesis. -message ConsumerPacketDataList { - repeated ConsumerPacketData list = 1 [ (gogoproto.nullable) = false ]; -} - // ConsumerPacketType indicates interchain security specific packet types. enum ConsumerPacketDataType { option (gogoproto.goproto_enum_prefix) = false; @@ -88,6 +77,12 @@ enum ConsumerPacketDataType { [ (gogoproto.enumvalue_customname) = "VscMaturedPacket" ]; } +// Note this type is used during IBC handshake methods for both the consumer and provider +message HandshakeMetadata { + string provider_fee_pool_addr = 1; + string version = 2; +} + // ConsumerPacketData contains a consumer packet data and a type tag // that is compatible with ICS v1 and v2 over the wire. It is not used for internal storage. message ConsumerPacketDataV1 { @@ -113,7 +108,7 @@ message SlashPacketDataV1 { } // InfractionType indicates the infraction type a validator commited. -// NOTE: ccv.InfractionType to maintain compatibility between ICS versions +// Note ccv.InfractionType to maintain compatibility between ICS versions // using different versions of the cosmos-sdk and ibc-go modules. enum InfractionType { option (gogoproto.goproto_enum_prefix) = false; diff --git a/tests/difference/core/driver/setup.go b/tests/difference/core/driver/setup.go index fb5bf6a611..9ca6d00b9f 100644 --- a/tests/difference/core/driver/setup.go +++ b/tests/difference/core/driver/setup.go @@ -206,7 +206,7 @@ func (b *Builder) getAppBytesAndSenders( bondDenom := sdk.DefaultBondDenom genesisStaking := stakingtypes.GenesisState{} - genesisConsumer := consumertypes.GenesisState{} + genesisConsumer := ccv.GenesisState{} if genesis[stakingtypes.ModuleName] != nil { // If staking module genesis already exists @@ -520,25 +520,25 @@ func (b *Builder) createConsumersLocalClientGenesis() *ibctmtypes.ClientState { ) } -func (b *Builder) createConsumerGenesis(client *ibctmtypes.ClientState) *consumertypes.GenesisState { +func (b *Builder) createConsumerGenesis(client *ibctmtypes.ClientState) *ccv.GenesisState { providerConsState := b.provider().LastHeader.ConsensusState() valUpdates := tmtypes.TM2PB.ValidatorUpdates(b.provider().Vals) - params := consumertypes.NewParams( + params := ccv.NewParams( true, 1000, // ignore distribution "", // ignore distribution "", // ignore distribution ccv.DefaultCCVTimeoutPeriod, - consumertypes.DefaultTransferTimeoutPeriod, - consumertypes.DefaultConsumerRedistributeFrac, - consumertypes.DefaultHistoricalEntries, + ccv.DefaultTransferTimeoutPeriod, + ccv.DefaultConsumerRedistributeFrac, + ccv.DefaultHistoricalEntries, b.initState.UnbondingC, "0", // disable soft opt-out []string{}, []string{}, ) - return consumertypes.NewInitialGenesisState(client, providerConsState, valUpdates, params) + return ccv.NewInitialGenesisState(client, providerConsState, valUpdates, params) } // The state of the data returned is equivalent to the state of two chains diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index e5ac465aa0..d7fba4a358 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -17,9 +17,9 @@ import ( evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" - consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" "github.com/cosmos/interchain-security/v3/x/ccv/provider/client" "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) type SendTokensAction struct { @@ -235,7 +235,7 @@ func (tr TestRun) submitConsumerAdditionProposal( verbose bool, ) { spawnTime := tr.containerConfig.now.Add(time.Duration(action.spawnTime) * time.Millisecond) - params := consumertypes.DefaultParams() + params := ccvtypes.DefaultParams() prop := client.ConsumerAdditionProposalJSON{ Title: "Propose the addition of a new chain", Summary: "Gonna be a great chain", diff --git a/tests/integration/distribution.go b/tests/integration/distribution.go index a896a6f22b..5d5c50220a 100644 --- a/tests/integration/distribution.go +++ b/tests/integration/distribution.go @@ -34,7 +34,7 @@ func (s *CCVTestSuite) TestRewardsDistribution() { // reward for the provider chain will be sent after each 2 blocks consumerParams := s.consumerApp.GetSubspace(consumertypes.ModuleName) - consumerParams.Set(s.consumerCtx(), consumertypes.KeyBlocksPerDistributionTransmission, int64(2)) + consumerParams.Set(s.consumerCtx(), ccv.KeyBlocksPerDistributionTransmission, int64(2)) s.consumerChain.NextBlock() consumerAccountKeeper := s.consumerApp.GetTestAccountKeeper() @@ -166,7 +166,7 @@ func (s *CCVTestSuite) TestSendRewardsRetries() { // reward for the provider chain will be sent after each 1000 blocks consumerParams := s.consumerApp.GetSubspace(consumertypes.ModuleName) - consumerParams.Set(s.consumerCtx(), consumertypes.KeyBlocksPerDistributionTransmission, int64(1000)) + consumerParams.Set(s.consumerCtx(), ccv.KeyBlocksPerDistributionTransmission, int64(1000)) // fill fee pool fees := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))) @@ -296,7 +296,7 @@ func (s *CCVTestSuite) TestEndBlockRD() { // reward for the provider chain will be sent after each 1000 blocks consumerParams := s.consumerApp.GetSubspace(consumertypes.ModuleName) - consumerParams.Set(s.consumerCtx(), consumertypes.KeyBlocksPerDistributionTransmission, int64(1000)) + consumerParams.Set(s.consumerCtx(), ccv.KeyBlocksPerDistributionTransmission, int64(1000)) // fill fee pool fees := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))) diff --git a/tests/integration/normal_operations.go b/tests/integration/normal_operations.go index b676689e89..cd8e07f323 100644 --- a/tests/integration/normal_operations.go +++ b/tests/integration/normal_operations.go @@ -6,6 +6,7 @@ import ( tmproto "github.com/cometbft/cometbft/proto/tendermint/types" consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) // Tests the tracking of historical info in the context of new blocks being committed @@ -73,7 +74,7 @@ func (k CCVTestSuite) TestHistoricalInfo() { //nolint:govet // this is a test so expLen: 0, }, { - height: initHeight + consumertypes.DefaultHistoricalEntries + 2, + height: initHeight + ccvtypes.DefaultHistoricalEntries + 2, found: true, expLen: initValsetLen + 2, }, diff --git a/tests/integration/setup.go b/tests/integration/setup.go index a18ff551e4..61cb8a96c9 100644 --- a/tests/integration/setup.go +++ b/tests/integration/setup.go @@ -16,7 +16,6 @@ import ( ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" icstestingutils "github.com/cosmos/interchain-security/v3/testutil/ibc_testing" testutil "github.com/cosmos/interchain-security/v3/testutil/integration" - consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) @@ -152,7 +151,7 @@ func (suite *CCVTestSuite) SetupTest() { func initConsumerChain( s *CCVTestSuite, chainID string, - genesisState *consumertypes.GenesisState, + genesisState *ccv.GenesisState, ) { providerKeeper := s.providerApp.GetProviderKeeper() bundle := s.consumerBundles[chainID] diff --git a/testutil/keeper/unit_test_helpers.go b/testutil/keeper/unit_test_helpers.go index 4ccb8a1861..b58d6d2471 100644 --- a/testutil/keeper/unit_test_helpers.go +++ b/testutil/keeper/unit_test_helpers.go @@ -274,13 +274,13 @@ func GetTestConsumerAdditionProp() *providertypes.ConsumerAdditionProposal { []byte("gen_hash"), []byte("bin_hash"), time.Now(), - consumertypes.DefaultConsumerRedistributeFrac, - consumertypes.DefaultBlocksPerDistributionTransmission, + types.DefaultConsumerRedistributeFrac, + types.DefaultBlocksPerDistributionTransmission, "", - consumertypes.DefaultHistoricalEntries, + types.DefaultHistoricalEntries, types.DefaultCCVTimeoutPeriod, - consumertypes.DefaultTransferTimeoutPeriod, - consumertypes.DefaultConsumerUnbondingPeriod, + types.DefaultTransferTimeoutPeriod, + types.DefaultConsumerUnbondingPeriod, ).(*providertypes.ConsumerAdditionProposal) return prop diff --git a/x/ccv/consumer/ibc_module.go b/x/ccv/consumer/ibc_module.go index 74c4cff27c..93b8096092 100644 --- a/x/ccv/consumer/ibc_module.go +++ b/x/ccv/consumer/ibc_module.go @@ -18,7 +18,6 @@ import ( "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" - providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" "github.com/cosmos/interchain-security/v3/x/ccv/types" ) @@ -127,7 +126,7 @@ func (am AppModule) OnChanOpenAck( "provider channel: %s already established", providerChannel) } - var md providertypes.HandshakeMetadata + var md types.HandshakeMetadata if err := (&md).Unmarshal([]byte(counterpartyMetadata)); err != nil { return errorsmod.Wrapf(types.ErrInvalidHandshakeMetadata, "error unmarshalling ibc-ack metadata: \n%v; \nmetadata: %v", err, counterpartyMetadata) diff --git a/x/ccv/consumer/ibc_module_test.go b/x/ccv/consumer/ibc_module_test.go index a451625230..25cbac58a2 100644 --- a/x/ccv/consumer/ibc_module_test.go +++ b/x/ccv/consumer/ibc_module_test.go @@ -16,7 +16,6 @@ import ( testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" "github.com/cosmos/interchain-security/v3/x/ccv/consumer" consumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" - providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) @@ -262,7 +261,7 @@ func TestOnChanOpenAck(t *testing.T) { { "invalid: mismatched serialized version", func(keeper *consumerkeeper.Keeper, params *params, mocks testkeeper.MockedKeepers) { - md := providertypes.HandshakeMetadata{ + md := ccv.HandshakeMetadata{ ProviderFeePoolAddr: "", // dummy address used Version: "bunkVersion", } @@ -288,7 +287,7 @@ func TestOnChanOpenAck(t *testing.T) { counterpartyChannelID: "providerCCVChannelID", } - metadata := providertypes.HandshakeMetadata{ + metadata := ccv.HandshakeMetadata{ ProviderFeePoolAddr: "someAcct", Version: ccv.Version, } diff --git a/x/ccv/consumer/keeper/distribution.go b/x/ccv/consumer/keeper/distribution.go index 48f1c5a1eb..5fe416ea2b 100644 --- a/x/ccv/consumer/keeper/distribution.go +++ b/x/ccv/consumer/keeper/distribution.go @@ -42,7 +42,7 @@ func (k Keeper) EndBlockRD(ctx sdk.Context) { } // Update LastTransmissionBlockHeight - newLtbh := types.LastTransmissionBlockHeight{ + newLtbh := ccv.LastTransmissionBlockHeight{ Height: ctx.BlockHeight(), } k.SetLastTransmissionBlockHeight(ctx, newLtbh) @@ -190,10 +190,10 @@ func (k Keeper) AllowedRewardDenoms(ctx sdk.Context) []string { return rewardDenoms } -func (k Keeper) GetLastTransmissionBlockHeight(ctx sdk.Context) types.LastTransmissionBlockHeight { +func (k Keeper) GetLastTransmissionBlockHeight(ctx sdk.Context) ccv.LastTransmissionBlockHeight { store := ctx.KVStore(k.storeKey) bz := store.Get(types.LastDistributionTransmissionKey()) - ltbh := types.LastTransmissionBlockHeight{} + ltbh := ccv.LastTransmissionBlockHeight{} if bz != nil { if err := ltbh.Unmarshal(bz); err != nil { panic(fmt.Errorf("failed to unmarshal LastTransmissionBlockHeight: %w", err)) @@ -202,7 +202,7 @@ func (k Keeper) GetLastTransmissionBlockHeight(ctx sdk.Context) types.LastTransm return ltbh } -func (k Keeper) SetLastTransmissionBlockHeight(ctx sdk.Context, ltbh types.LastTransmissionBlockHeight) { +func (k Keeper) SetLastTransmissionBlockHeight(ctx sdk.Context, ltbh ccv.LastTransmissionBlockHeight) { store := ctx.KVStore(k.storeKey) bz, err := ltbh.Marshal() if err != nil { diff --git a/x/ccv/consumer/keeper/distribution_test.go b/x/ccv/consumer/keeper/distribution_test.go index 71df5fd93d..4a611f2d1e 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/v3/testutil/keeper" "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) // TestGetEstimatedNextFeeDistribution tests next fee distribution parameters. @@ -25,7 +26,7 @@ func TestGetEstimatedNextFeeDistribution(t *testing.T) { mockAccountKeeper := mocks.MockAccountKeeper mockBankKeeper := mocks.MockBankKeeper consumerKeeper := testkeeper.NewInMemConsumerKeeper(keeperParams, mocks) - consumerKeeper.SetParams(ctx, types.DefaultParams()) + consumerKeeper.SetParams(ctx, ccvtypes.DefaultParams()) // Setup mock account balance fracParam := consumerKeeper.GetConsumerRedistributionFrac(ctx) @@ -76,7 +77,7 @@ func TestAllowedRewardDenoms(t *testing.T) { defer ctrl.Finish() mocks := testkeeper.NewMockedKeepers(ctrl) consumerKeeper := testkeeper.NewInMemConsumerKeeper(keeperParams, mocks) - params := types.DefaultParams() + params := ccvtypes.DefaultParams() params.RewardDenoms = []string{"ustake"} params.ProviderRewardDenoms = []string{"uatom"} consumerKeeper.SetParams(ctx, params) diff --git a/x/ccv/consumer/keeper/genesis.go b/x/ccv/consumer/keeper/genesis.go index a55184fd27..2ac38f650c 100644 --- a/x/ccv/consumer/keeper/genesis.go +++ b/x/ccv/consumer/keeper/genesis.go @@ -7,7 +7,6 @@ import ( abci "github.com/cometbft/cometbft/abci/types" - consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) @@ -17,7 +16,7 @@ import ( // 1. A client to the provider was never created, i.e. a new consumer chain is started for the first time. // 2. A consumer chain restarts after a client to the provider was created, but the CCV channel handshake is still in progress // 3. A consumer chain restarts after the CCV channel handshake was completed. -func (k Keeper) InitGenesis(ctx sdk.Context, state *consumertypes.GenesisState) []abci.ValidatorUpdate { +func (k Keeper) InitGenesis(ctx sdk.Context, state *ccv.GenesisState) []abci.ValidatorUpdate { // PreCCV is true during the process of a standalone to consumer changeover. // At the PreCCV point in the process, the standalone chain has just been upgraded to include // the consumer ccv module, but the standalone staking keeper is still managing the validator set. @@ -116,10 +115,10 @@ func (k Keeper) InitGenesis(ctx sdk.Context, state *consumertypes.GenesisState) } // ExportGenesis returns the CCV consumer module's exported genesis -func (k Keeper) ExportGenesis(ctx sdk.Context) (genesis *consumertypes.GenesisState) { +func (k Keeper) ExportGenesis(ctx sdk.Context) (genesis *ccv.GenesisState) { params := k.GetConsumerParams(ctx) if !params.Enabled { - return consumertypes.DefaultGenesisState() + return ccv.DefaultGenesisState() } // export the current validator set @@ -138,7 +137,7 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) (genesis *consumertypes.GenesisSt panic("provider client does not exist although provider channel does exist") } - genesis = consumertypes.NewRestartGenesisState( + genesis = ccv.NewRestartGenesisState( clientID, channelID, k.GetAllPacketMaturityTimes(ctx), @@ -154,11 +153,11 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) (genesis *consumertypes.GenesisSt // if provider clientID and channelID don't exist on the consumer chain, // then CCV protocol is disabled for this chain return a default genesis state if !ok { - return consumertypes.DefaultGenesisState() + return ccv.DefaultGenesisState() } // export client states and pending slashing requests into a new chain genesis - genesis = consumertypes.NewRestartGenesisState( + genesis = ccv.NewRestartGenesisState( clientID, "", nil, @@ -166,7 +165,7 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) (genesis *consumertypes.GenesisSt k.GetAllHeightToValsetUpdateIDs(ctx), pendingPacketsDepreciated, nil, - consumertypes.LastTransmissionBlockHeight{}, + ccv.LastTransmissionBlockHeight{}, params, ) } diff --git a/x/ccv/consumer/keeper/genesis_test.go b/x/ccv/consumer/keeper/genesis_test.go index 649505da0c..9cb489b3c0 100644 --- a/x/ccv/consumer/keeper/genesis_test.go +++ b/x/ccv/consumer/keeper/genesis_test.go @@ -61,7 +61,7 @@ func TestInitGenesis(t *testing.T) { []string{"upgrade", "upgradedIBCState"}, ) - matPackets := []consumertypes.MaturingVSCPacket{ + matPackets := []ccv.MaturingVSCPacket{ { VscId: 1, MaturityTime: time.Now().UTC(), @@ -84,15 +84,15 @@ func TestInitGenesis(t *testing.T) { }, } // mock height to valset update ID values - defaultHeightValsetUpdateIDs := []consumertypes.HeightToValsetUpdateID{ + defaultHeightValsetUpdateIDs := []ccv.HeightToValsetUpdateID{ {ValsetUpdateId: vscID, Height: blockHeight}, } updatedHeightValsetUpdateIDs := append(defaultHeightValsetUpdateIDs, - consumertypes.HeightToValsetUpdateID{ValsetUpdateId: vscID + 1, Height: blockHeight + 1}, + ccv.HeightToValsetUpdateID{ValsetUpdateId: vscID + 1, Height: blockHeight + 1}, ) // create default parameters for a new chain - params := consumertypes.DefaultParams() + params := ccv.DefaultParams() params.Enabled = true // define three test cases which respectively create a genesis struct, use it to call InitGenesis @@ -100,8 +100,8 @@ func TestInitGenesis(t *testing.T) { testCases := []struct { name string malleate func(sdk.Context, testkeeper.MockedKeepers) - genesis *consumertypes.GenesisState - assertStates func(sdk.Context, consumerkeeper.Keeper, *consumertypes.GenesisState) + genesis *ccv.GenesisState + assertStates func(sdk.Context, consumerkeeper.Keeper, *ccv.GenesisState) }{ { "start a new chain", @@ -112,13 +112,13 @@ func TestInitGenesis(t *testing.T) { testkeeper.ExpectGetCapabilityMock(ctx, mocks, 1), ) }, - consumertypes.NewInitialGenesisState( + ccv.NewInitialGenesisState( provClientState, provConsState, valset, params, ), - func(ctx sdk.Context, ck consumerkeeper.Keeper, gs *consumertypes.GenesisState) { + func(ctx sdk.Context, ck consumerkeeper.Keeper, gs *ccv.GenesisState) { assertConsumerPortIsBound(t, ctx, &ck) assertProviderClientID(t, ctx, &ck, provClientID) @@ -134,7 +134,7 @@ func TestInitGenesis(t *testing.T) { testkeeper.ExpectGetCapabilityMock(ctx, mocks, 2), ) }, - consumertypes.NewRestartGenesisState( + ccv.NewRestartGenesisState( provClientID, "", matPackets, @@ -142,10 +142,10 @@ func TestInitGenesis(t *testing.T) { defaultHeightValsetUpdateIDs, pendingDataPackets, nil, - consumertypes.LastTransmissionBlockHeight{}, + ccv.LastTransmissionBlockHeight{}, params, ), - func(ctx sdk.Context, ck consumerkeeper.Keeper, gs *consumertypes.GenesisState) { + func(ctx sdk.Context, ck consumerkeeper.Keeper, gs *ccv.GenesisState) { assertConsumerPortIsBound(t, ctx, &ck) obtainedPendingPackets := ck.GetPendingPackets(ctx) @@ -170,20 +170,20 @@ func TestInitGenesis(t *testing.T) { ) }, // create a genesis for a restarted chain - consumertypes.NewRestartGenesisState( + ccv.NewRestartGenesisState( provClientID, provChannelID, matPackets, valset, updatedHeightValsetUpdateIDs, pendingDataPackets, - []consumertypes.OutstandingDowntime{ + []ccv.OutstandingDowntime{ {ValidatorConsensusAddress: sdk.ConsAddress(validator.Bytes()).String()}, }, - consumertypes.LastTransmissionBlockHeight{Height: int64(100)}, + ccv.LastTransmissionBlockHeight{Height: int64(100)}, params, ), - func(ctx sdk.Context, ck consumerkeeper.Keeper, gs *consumertypes.GenesisState) { + func(ctx sdk.Context, ck consumerkeeper.Keeper, gs *ccv.GenesisState) { assertConsumerPortIsBound(t, ctx, &ck) gotChannelID, ok := ck.GetProviderChannel(ctx) @@ -239,7 +239,7 @@ func TestExportGenesis(t *testing.T) { vscID := uint64(0) blockHeight := uint64(0) - matPackets := []consumertypes.MaturingVSCPacket{ + matPackets := []ccv.MaturingVSCPacket{ { VscId: 1, MaturityTime: time.Now().UTC(), @@ -272,15 +272,15 @@ func TestExportGenesis(t *testing.T) { }, } // mock height to valset update ID values - defaultHeightValsetUpdateIDs := []consumertypes.HeightToValsetUpdateID{ + defaultHeightValsetUpdateIDs := []ccv.HeightToValsetUpdateID{ {ValsetUpdateId: vscID, Height: blockHeight}, } updatedHeightValsetUpdateIDs := append(defaultHeightValsetUpdateIDs, - consumertypes.HeightToValsetUpdateID{ValsetUpdateId: vscID + 1, Height: blockHeight + 1}, + ccv.HeightToValsetUpdateID{ValsetUpdateId: vscID + 1, Height: blockHeight + 1}, ) - ltbh := consumertypes.LastTransmissionBlockHeight{Height: int64(1000)} + ltbh := ccv.LastTransmissionBlockHeight{Height: int64(1000)} // create default parameters for a new chain - params := consumertypes.DefaultParams() + params := ccv.DefaultParams() params.Enabled = true // define two test cases which respectively populate the consumer chain store @@ -289,7 +289,7 @@ func TestExportGenesis(t *testing.T) { testCases := []struct { name string malleate func(sdk.Context, consumerkeeper.Keeper, testkeeper.MockedKeepers) - expGenesis *consumertypes.GenesisState + expGenesis *ccv.GenesisState }{ { "export a chain without an established CCV channel", @@ -307,7 +307,7 @@ func TestExportGenesis(t *testing.T) { ck.SetHeightValsetUpdateID(ctx, defaultHeightValsetUpdateIDs[0].Height, defaultHeightValsetUpdateIDs[0].ValsetUpdateId) }, - consumertypes.NewRestartGenesisState( + ccv.NewRestartGenesisState( provClientID, "", nil, @@ -315,7 +315,7 @@ func TestExportGenesis(t *testing.T) { defaultHeightValsetUpdateIDs, consPackets, nil, - consumertypes.LastTransmissionBlockHeight{}, + ccv.LastTransmissionBlockHeight{}, params, ), }, @@ -343,14 +343,14 @@ func TestExportGenesis(t *testing.T) { ck.SetOutstandingDowntime(ctx, sdk.ConsAddress(validator.Address.Bytes())) ck.SetLastTransmissionBlockHeight(ctx, ltbh) }, - consumertypes.NewRestartGenesisState( + ccv.NewRestartGenesisState( provClientID, provChannelID, matPackets, valset, updatedHeightValsetUpdateIDs, consPackets, - []consumertypes.OutstandingDowntime{ + []ccv.OutstandingDowntime{ {ValidatorConsensusAddress: sdk.ConsAddress(validator.Address.Bytes()).String()}, }, ltbh, @@ -394,7 +394,7 @@ func assertProviderClientID(t *testing.T, ctx sdk.Context, ck *consumerkeeper.Ke } // assert that the given input match the height to valset update ID mappings in the store -func assertHeightValsetUpdateIDs(t *testing.T, ctx sdk.Context, ck *consumerkeeper.Keeper, heighValsetUpdateIDs []consumertypes.HeightToValsetUpdateID) { +func assertHeightValsetUpdateIDs(t *testing.T, ctx sdk.Context, ck *consumerkeeper.Keeper, heighValsetUpdateIDs []ccv.HeightToValsetUpdateID) { t.Helper() ctr := 0 diff --git a/x/ccv/consumer/keeper/keeper.go b/x/ccv/consumer/keeper/keeper.go index 94d5c790fd..2d3e78e0f8 100644 --- a/x/ccv/consumer/keeper/keeper.go +++ b/x/ccv/consumer/keeper/keeper.go @@ -64,7 +64,7 @@ func NewKeeper( ) Keeper { // set KeyTable if it has not already been set if !paramSpace.HasKeyTable() { - paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) + paramSpace = paramSpace.WithKeyTable(ccv.ParamKeyTable()) } k := Keeper{ @@ -309,7 +309,7 @@ func (k Keeper) DeletePreCCV(ctx sdk.Context) { func (k Keeper) SetInitialValSet(ctx sdk.Context, initialValSet []tmtypes.ValidatorUpdate) { store := ctx.KVStore(k.storeKey) - initialValSetState := types.GenesisState{ + initialValSetState := ccv.GenesisState{ InitialValSet: initialValSet, } bz := k.cdc.MustMarshal(&initialValSetState) @@ -318,7 +318,7 @@ func (k Keeper) SetInitialValSet(ctx sdk.Context, initialValSet []tmtypes.Valida func (k Keeper) GetInitialValSet(ctx sdk.Context) []tmtypes.ValidatorUpdate { store := ctx.KVStore(k.storeKey) - initialValSet := types.GenesisState{} + initialValSet := ccv.GenesisState{} bz := store.Get(types.InitialValSetKey()) if bz != nil { k.cdc.MustUnmarshal(bz, &initialValSet) @@ -336,14 +336,14 @@ func (k Keeper) GetLastStandaloneValidators(ctx sdk.Context) []stakingtypes.Vali // GetElapsedPacketMaturityTimes returns a slice of already elapsed PacketMaturityTimes, sorted by maturity times, // i.e., the slice contains the IDs of the matured VSCPackets. -func (k Keeper) GetElapsedPacketMaturityTimes(ctx sdk.Context) (maturingVSCPackets []types.MaturingVSCPacket) { +func (k Keeper) GetElapsedPacketMaturityTimes(ctx sdk.Context) (maturingVSCPackets []ccv.MaturingVSCPacket) { store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, []byte{types.PacketMaturityTimeBytePrefix}) defer iterator.Close() for ; iterator.Valid(); iterator.Next() { - var maturingVSCPacket types.MaturingVSCPacket + var maturingVSCPacket ccv.MaturingVSCPacket if err := maturingVSCPacket.Unmarshal(iterator.Value()); err != nil { // An error here would indicate something is very wrong, // the MaturingVSCPackets are assumed to be correctly serialized in SetPacketMaturityTime. @@ -368,13 +368,13 @@ func (k Keeper) GetElapsedPacketMaturityTimes(ctx sdk.Context) (maturingVSCPacke // PacketMaturityTimeBytePrefix | maturityTime.UnixNano() | vscID // Thus, the returned array is in ascending order of maturityTimes. // If two entries have the same maturityTime, then they are ordered by vscID. -func (k Keeper) GetAllPacketMaturityTimes(ctx sdk.Context) (maturingVSCPackets []types.MaturingVSCPacket) { +func (k Keeper) GetAllPacketMaturityTimes(ctx sdk.Context) (maturingVSCPackets []ccv.MaturingVSCPacket) { store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, []byte{types.PacketMaturityTimeBytePrefix}) defer iterator.Close() for ; iterator.Valid(); iterator.Next() { - var maturingVSCPacket types.MaturingVSCPacket + var maturingVSCPacket ccv.MaturingVSCPacket if err := maturingVSCPacket.Unmarshal(iterator.Value()); err != nil { // An error here would indicate something is very wrong, // the MaturingVSCPackets are assumed to be correctly serialized in SetPacketMaturityTime. @@ -389,7 +389,7 @@ func (k Keeper) GetAllPacketMaturityTimes(ctx sdk.Context) (maturingVSCPackets [ // SetPacketMaturityTime sets the maturity time for a given received VSC packet id func (k Keeper) SetPacketMaturityTime(ctx sdk.Context, vscId uint64, maturityTime time.Time) { store := ctx.KVStore(k.storeKey) - maturingVSCPacket := types.MaturingVSCPacket{ + maturingVSCPacket := ccv.MaturingVSCPacket{ VscId: vscId, MaturityTime: maturityTime, } @@ -469,7 +469,7 @@ func (k Keeper) DeleteHeightValsetUpdateID(ctx sdk.Context, height uint64) { // Note that the block height to vscID mapping is stored under keys with the following format: // HeightValsetUpdateIDBytePrefix | height // Thus, the returned array is in ascending order of heights. -func (k Keeper) GetAllHeightToValsetUpdateIDs(ctx sdk.Context) (heightToValsetUpdateIDs []types.HeightToValsetUpdateID) { +func (k Keeper) GetAllHeightToValsetUpdateIDs(ctx sdk.Context) (heightToValsetUpdateIDs []ccv.HeightToValsetUpdateID) { store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, []byte{types.HeightValsetUpdateIDBytePrefix}) @@ -478,7 +478,7 @@ func (k Keeper) GetAllHeightToValsetUpdateIDs(ctx sdk.Context) (heightToValsetUp height := binary.BigEndian.Uint64(iterator.Key()[1:]) vscID := binary.BigEndian.Uint64(iterator.Value()) - heightToValsetUpdateIDs = append(heightToValsetUpdateIDs, types.HeightToValsetUpdateID{ + heightToValsetUpdateIDs = append(heightToValsetUpdateIDs, ccv.HeightToValsetUpdateID{ Height: height, ValsetUpdateId: vscID, }) @@ -515,7 +515,7 @@ func (k Keeper) DeleteOutstandingDowntime(ctx sdk.Context, consAddress string) { // Note that the outstanding downtime flags are stored under keys with the following format: // OutstandingDowntimeBytePrefix | consAddress // Thus, the returned array is in ascending order of consAddresses. -func (k Keeper) GetAllOutstandingDowntimes(ctx sdk.Context) (downtimes []types.OutstandingDowntime) { +func (k Keeper) GetAllOutstandingDowntimes(ctx sdk.Context) (downtimes []ccv.OutstandingDowntime) { store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, []byte{types.OutstandingDowntimeBytePrefix}) @@ -524,7 +524,7 @@ func (k Keeper) GetAllOutstandingDowntimes(ctx sdk.Context) (downtimes []types.O addrBytes := iterator.Key()[1:] addr := sdk.ConsAddress(addrBytes).String() - downtimes = append(downtimes, types.OutstandingDowntime{ + downtimes = append(downtimes, ccv.OutstandingDowntime{ ValidatorConsensusAddress: addr, }) } diff --git a/x/ccv/consumer/keeper/keeper_test.go b/x/ccv/consumer/keeper/keeper_test.go index 06fdeae082..4b536a071a 100644 --- a/x/ccv/consumer/keeper/keeper_test.go +++ b/x/ccv/consumer/keeper/keeper_test.go @@ -201,7 +201,7 @@ func TestPacketMaturityTime(t *testing.T) { defer ctrl.Finish() now := time.Now().UTC() - packets := []types.MaturingVSCPacket{ + packets := []ccv.MaturingVSCPacket{ { VscId: 2, MaturityTime: now, @@ -220,9 +220,9 @@ func TestPacketMaturityTime(t *testing.T) { }, } // sort by MaturityTime and not by VscId - expectedGetAllOrder := []types.MaturingVSCPacket{packets[2], packets[1], packets[0], packets[3]} + expectedGetAllOrder := []ccv.MaturingVSCPacket{packets[2], packets[1], packets[0], packets[3]} // only packets with MaturityTime before or equal to now - expectedGetElapsedOrder := []types.MaturingVSCPacket{packets[2], packets[1], packets[0]} + expectedGetElapsedOrder := []ccv.MaturingVSCPacket{packets[2], packets[1], packets[0]} // test SetPacketMaturityTime for _, packet := range packets { @@ -502,7 +502,7 @@ func TestGetAllHeightToValsetUpdateIDs(t *testing.T) { ck, ctx, ctrl, _ := testkeeper.GetConsumerKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - cases := []types.HeightToValsetUpdateID{ + cases := []ccv.HeightToValsetUpdateID{ { ValsetUpdateId: 2, Height: 22, @@ -549,9 +549,9 @@ func TestGetAllOutstandingDowntimes(t *testing.T) { sdk.ConsAddress([]byte("consAddress4")), sdk.ConsAddress([]byte("consAddress3")), } - expectedGetAllOrder := []types.OutstandingDowntime{} + expectedGetAllOrder := []ccv.OutstandingDowntime{} for _, addr := range addresses { - expectedGetAllOrder = append(expectedGetAllOrder, types.OutstandingDowntime{ValidatorConsensusAddress: addr.String()}) + expectedGetAllOrder = append(expectedGetAllOrder, ccv.OutstandingDowntime{ValidatorConsensusAddress: addr.String()}) } // sorting by ConsAddress sort.Slice(expectedGetAllOrder, func(i, j int) bool { diff --git a/x/ccv/consumer/keeper/params.go b/x/ccv/consumer/keeper/params.go index ccffd96ee5..770edf229e 100644 --- a/x/ccv/consumer/keeper/params.go +++ b/x/ccv/consumer/keeper/params.go @@ -6,14 +6,13 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) // GetParams returns the params for the consumer ccv module // NOTE: it is different from the GetParams method which is required to implement StakingKeeper interface -func (k Keeper) GetConsumerParams(ctx sdk.Context) types.Params { - return types.NewParams( +func (k Keeper) GetConsumerParams(ctx sdk.Context) ccvtypes.Params { + return ccvtypes.NewParams( k.GetEnabled(ctx), k.GetBlocksPerDistributionTransmission(ctx), k.GetDistributionTransmissionChannel(ctx), @@ -30,7 +29,7 @@ func (k Keeper) GetConsumerParams(ctx sdk.Context) types.Params { } // SetParams sets the paramset for the consumer module -func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { +func (k Keeper) SetParams(ctx sdk.Context, params ccvtypes.Params) { k.paramStore.SetParamSet(ctx, ¶ms) } @@ -45,38 +44,38 @@ func (k Keeper) GetParams(ctx sdk.Context) stakingtypes.Params { // GetEnabled returns the enabled flag for the consumer module func (k Keeper) GetEnabled(ctx sdk.Context) bool { var enabled bool - k.paramStore.Get(ctx, types.KeyEnabled, &enabled) + k.paramStore.Get(ctx, ccvtypes.KeyEnabled, &enabled) return enabled } func (k Keeper) GetBlocksPerDistributionTransmission(ctx sdk.Context) int64 { var bpdt int64 - k.paramStore.Get(ctx, types.KeyBlocksPerDistributionTransmission, &bpdt) + k.paramStore.Get(ctx, ccvtypes.KeyBlocksPerDistributionTransmission, &bpdt) return bpdt } func (k Keeper) SetBlocksPerDistributionTransmission(ctx sdk.Context, bpdt int64) { - k.paramStore.Set(ctx, types.KeyBlocksPerDistributionTransmission, bpdt) + k.paramStore.Set(ctx, ccvtypes.KeyBlocksPerDistributionTransmission, bpdt) } func (k Keeper) GetDistributionTransmissionChannel(ctx sdk.Context) string { var s string - k.paramStore.Get(ctx, types.KeyDistributionTransmissionChannel, &s) + k.paramStore.Get(ctx, ccvtypes.KeyDistributionTransmissionChannel, &s) return s } func (k Keeper) SetDistributionTransmissionChannel(ctx sdk.Context, channel string) { - k.paramStore.Set(ctx, types.KeyDistributionTransmissionChannel, channel) + k.paramStore.Set(ctx, ccvtypes.KeyDistributionTransmissionChannel, channel) } func (k Keeper) GetProviderFeePoolAddrStr(ctx sdk.Context) string { var s string - k.paramStore.Get(ctx, types.KeyProviderFeePoolAddrStr, &s) + k.paramStore.Get(ctx, ccvtypes.KeyProviderFeePoolAddrStr, &s) return s } func (k Keeper) SetProviderFeePoolAddrStr(ctx sdk.Context, addr string) { - k.paramStore.Set(ctx, types.KeyProviderFeePoolAddrStr, addr) + k.paramStore.Set(ctx, ccvtypes.KeyProviderFeePoolAddrStr, addr) } // GetCCVTimeoutPeriod returns the timeout period for sent ccv related ibc packets @@ -89,7 +88,7 @@ func (k Keeper) GetCCVTimeoutPeriod(ctx sdk.Context) time.Duration { // GetTransferTimeoutPeriod returns the timeout period for sent transfer related ibc packets func (k Keeper) GetTransferTimeoutPeriod(ctx sdk.Context) time.Duration { var p time.Duration - k.paramStore.Get(ctx, types.KeyTransferTimeoutPeriod, &p) + k.paramStore.Get(ctx, ccvtypes.KeyTransferTimeoutPeriod, &p) return p } @@ -98,25 +97,25 @@ func (k Keeper) GetTransferTimeoutPeriod(ctx sdk.Context) time.Duration { // decimal number. For example "0.75" would represent 75%. func (k Keeper) GetConsumerRedistributionFrac(ctx sdk.Context) string { var str string - k.paramStore.Get(ctx, types.KeyConsumerRedistributionFrac, &str) + k.paramStore.Get(ctx, ccvtypes.KeyConsumerRedistributionFrac, &str) return str } // GetHistoricalEntries returns the number of historical info entries to persist in store func (k Keeper) GetHistoricalEntries(ctx sdk.Context) int64 { var n int64 - k.paramStore.Get(ctx, types.KeyHistoricalEntries, &n) + k.paramStore.Get(ctx, ccvtypes.KeyHistoricalEntries, &n) return n } // Only used to set an unbonding period in diff tests func (k Keeper) SetUnbondingPeriod(ctx sdk.Context, period time.Duration) { - k.paramStore.Set(ctx, types.KeyConsumerUnbondingPeriod, period) + k.paramStore.Set(ctx, ccvtypes.KeyConsumerUnbondingPeriod, period) } func (k Keeper) GetUnbondingPeriod(ctx sdk.Context) time.Duration { var period time.Duration - k.paramStore.Get(ctx, types.KeyConsumerUnbondingPeriod, &period) + k.paramStore.Get(ctx, ccvtypes.KeyConsumerUnbondingPeriod, &period) return period } @@ -124,18 +123,18 @@ func (k Keeper) GetUnbondingPeriod(ctx sdk.Context) time.Duration { // that can opt out of running the consumer chain func (k Keeper) GetSoftOptOutThreshold(ctx sdk.Context) string { var str string - k.paramStore.Get(ctx, types.KeySoftOptOutThreshold, &str) + k.paramStore.Get(ctx, ccvtypes.KeySoftOptOutThreshold, &str) return str } func (k Keeper) GetRewardDenoms(ctx sdk.Context) []string { var denoms []string - k.paramStore.Get(ctx, types.KeyRewardDenoms, &denoms) + k.paramStore.Get(ctx, ccvtypes.KeyRewardDenoms, &denoms) return denoms } func (k Keeper) GetProviderRewardDenoms(ctx sdk.Context) []string { var denoms []string - k.paramStore.Get(ctx, types.KeyProviderRewardDenoms, &denoms) + k.paramStore.Get(ctx, ccvtypes.KeyProviderRewardDenoms, &denoms) return denoms } diff --git a/x/ccv/consumer/keeper/params_test.go b/x/ccv/consumer/keeper/params_test.go index ac6b112aa8..49b1816520 100644 --- a/x/ccv/consumer/keeper/params_test.go +++ b/x/ccv/consumer/keeper/params_test.go @@ -7,7 +7,6 @@ import ( "github.com/stretchr/testify/require" testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" - "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) @@ -15,21 +14,21 @@ import ( func TestParams(t *testing.T) { consumerKeeper, ctx, ctrl, _ := testkeeper.GetConsumerKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - consumerKeeper.SetParams(ctx, types.DefaultParams()) + consumerKeeper.SetParams(ctx, ccv.DefaultParams()) var rewardDenoms []string var provideRewardDenoms []string - expParams := types.NewParams( + expParams := ccv.NewParams( false, 1000, "", "", ccv.DefaultCCVTimeoutPeriod, - types.DefaultTransferTimeoutPeriod, - types.DefaultConsumerRedistributeFrac, - types.DefaultHistoricalEntries, - types.DefaultConsumerUnbondingPeriod, - types.DefaultSoftOptOutThreshold, + ccv.DefaultTransferTimeoutPeriod, + ccv.DefaultConsumerRedistributeFrac, + ccv.DefaultHistoricalEntries, + ccv.DefaultConsumerUnbondingPeriod, + ccv.DefaultSoftOptOutThreshold, rewardDenoms, provideRewardDenoms, ) // these are the default params, IBC suite independently sets enabled=true @@ -37,7 +36,7 @@ func TestParams(t *testing.T) { params := consumerKeeper.GetConsumerParams(ctx) require.Equal(t, expParams, params) - newParams := types.NewParams(false, 1000, + newParams := ccv.NewParams(false, 1000, "channel-2", "cosmos19pe9pg5dv9k5fzgzmsrgnw9rl9asf7ddwhu7lm", 7*24*time.Hour, 25*time.Hour, "0.5", 500, 24*21*time.Hour, "0.05", []string{"untrn"}, []string{"uatom"}) consumerKeeper.SetParams(ctx, newParams) diff --git a/x/ccv/consumer/keeper/relay_test.go b/x/ccv/consumer/keeper/relay_test.go index 09cf987fc0..d681a2fdc4 100644 --- a/x/ccv/consumer/keeper/relay_test.go +++ b/x/ccv/consumer/keeper/relay_test.go @@ -123,7 +123,7 @@ func TestOnRecvVSCPacket(t *testing.T) { consumerKeeper.SetProviderChannel(ctx, consumerCCVChannelID) // Set module params with custom unbonding period - moduleParams := consumertypes.DefaultParams() + moduleParams := types.DefaultParams() moduleParams.UnbondingPeriod = 100 * time.Hour consumerKeeper.SetParams(ctx, moduleParams) @@ -172,7 +172,7 @@ func TestOnRecvVSCPacketDuplicateUpdates(t *testing.T) { consumerKeeper, ctx, ctrl, _ := testkeeper.GetConsumerKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() consumerKeeper.SetProviderChannel(ctx, consumerCCVChannelID) - consumerKeeper.SetParams(ctx, consumertypes.DefaultParams()) + consumerKeeper.SetParams(ctx, types.DefaultParams()) // Construct packet/data with duplicate val updates for the same pub key cId := crypto.NewCryptoIdentityFromIntSeed(43278947) @@ -218,7 +218,7 @@ func TestSendPacketsFailure(t *testing.T) { consumerKeeper, ctx, ctrl, mocks := testkeeper.GetConsumerKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() consumerKeeper.SetProviderChannel(ctx, "consumerCCVChannelID") - consumerKeeper.SetParams(ctx, consumertypes.DefaultParams()) + consumerKeeper.SetParams(ctx, types.DefaultParams()) // Set some pending packets consumerKeeper.AppendPendingPacket(ctx, types.VscMaturedPacket, &types.ConsumerPacketData_VscMaturedPacketData{}) @@ -240,7 +240,7 @@ func TestSendPackets(t *testing.T) { // Keeper setup consumerKeeper, ctx, ctrl, mocks := testkeeper.GetConsumerKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) consumerKeeper.SetProviderChannel(ctx, "consumerCCVChannelID") - consumerKeeper.SetParams(ctx, consumertypes.DefaultParams()) + consumerKeeper.SetParams(ctx, types.DefaultParams()) // No slash record should exist _, found := consumerKeeper.GetSlashRecord(ctx) @@ -471,7 +471,7 @@ func TestSendPacketsDeletion(t *testing.T) { consumerKeeper, ctx, ctrl, mocks := testkeeper.GetConsumerKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() consumerKeeper.SetProviderChannel(ctx, "consumerCCVChannelID") - consumerKeeper.SetParams(ctx, consumertypes.DefaultParams()) + consumerKeeper.SetParams(ctx, types.DefaultParams()) // Queue two pending packets, vsc matured first consumerKeeper.AppendPendingPacket(ctx, types.VscMaturedPacket, &types.ConsumerPacketData_VscMaturedPacketData{ diff --git a/x/ccv/consumer/keeper/soft_opt_out_test.go b/x/ccv/consumer/keeper/soft_opt_out_test.go index c99d418ca6..6f2ee8ad4f 100644 --- a/x/ccv/consumer/keeper/soft_opt_out_test.go +++ b/x/ccv/consumer/keeper/soft_opt_out_test.go @@ -9,7 +9,7 @@ import ( "github.com/cosmos/interchain-security/v3/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" - "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) // Tests that UpdateSmallestNonOptOutPower updates the smallest validator power that cannot soft opt out. @@ -102,7 +102,7 @@ func TestUpdateSmallestNonOptOutPower(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { consumerKeeper, ctx, ctrl, _ := testkeeper.GetConsumerKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) - moduleParams := types.DefaultParams() + moduleParams := ccvtypes.DefaultParams() moduleParams.SoftOptOutThreshold = tc.optOutThresh consumerKeeper.SetParams(ctx, moduleParams) defer ctrl.Finish() diff --git a/x/ccv/consumer/module.go b/x/ccv/consumer/module.go index fe9b18a945..a9f4a4fc7e 100644 --- a/x/ccv/consumer/module.go +++ b/x/ccv/consumer/module.go @@ -22,6 +22,7 @@ import ( "github.com/cosmos/interchain-security/v3/x/ccv/consumer/client/cli" "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) var ( @@ -51,12 +52,12 @@ func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) // DefaultGenesis returns default genesis state as raw bytes for the ibc // consumer module. func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { - return cdc.MustMarshalJSON(consumertypes.DefaultGenesisState()) + return cdc.MustMarshalJSON(ccvtypes.DefaultGenesisState()) } // ValidateGenesis performs genesis state validation for the ibc consumer module. func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { - var data consumertypes.GenesisState + var data ccvtypes.GenesisState if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", consumertypes.ModuleName, err) } @@ -111,7 +112,7 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { // InitGenesis performs genesis initialization for the consumer module. It returns // no validator updates. func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { - var genesisState consumertypes.GenesisState + var genesisState ccvtypes.GenesisState cdc.MustUnmarshalJSON(data, &genesisState) return am.keeper.InitGenesis(ctx, &genesisState) } diff --git a/x/ccv/consumer/types/consumer.pb.go b/x/ccv/consumer/types/consumer.pb.go index b16b561b7b..c6c09166a5 100644 --- a/x/ccv/consumer/types/consumer.pb.go +++ b/x/ccv/consumer/types/consumer.pb.go @@ -31,215 +31,12 @@ var _ = time.Kitchen // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// Params defines the parameters for CCV consumer module -type Params struct { - // TODO: Remove enabled flag and find a better way to setup integration tests - // See: https://github.com/cosmos/interchain-security/issues/339 - Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` - /////////////////////// - // Distribution Params - // Number of blocks between ibc-token-transfers from the consumer chain to - // the provider chain. Note that at this transmission event a fraction of - // the accumulated tokens are divided and sent consumer redistribution - // address. - BlocksPerDistributionTransmission int64 `protobuf:"varint,2,opt,name=blocks_per_distribution_transmission,json=blocksPerDistributionTransmission,proto3" json:"blocks_per_distribution_transmission,omitempty"` - // Channel, and provider-chain receiving address to send distribution token - // transfers over. These parameters is auto-set during the consumer <-> - // provider handshake procedure. - DistributionTransmissionChannel string `protobuf:"bytes,3,opt,name=distribution_transmission_channel,json=distributionTransmissionChannel,proto3" json:"distribution_transmission_channel,omitempty"` - ProviderFeePoolAddrStr string `protobuf:"bytes,4,opt,name=provider_fee_pool_addr_str,json=providerFeePoolAddrStr,proto3" json:"provider_fee_pool_addr_str,omitempty"` - // Sent CCV related IBC packets will timeout after this duration - CcvTimeoutPeriod time.Duration `protobuf:"bytes,5,opt,name=ccv_timeout_period,json=ccvTimeoutPeriod,proto3,stdduration" json:"ccv_timeout_period"` - // Sent transfer related IBC packets will timeout after this duration - TransferTimeoutPeriod time.Duration `protobuf:"bytes,6,opt,name=transfer_timeout_period,json=transferTimeoutPeriod,proto3,stdduration" json:"transfer_timeout_period"` - // The fraction of tokens allocated to the consumer redistribution address - // during distribution events. The fraction is a string representing a - // decimal number. For example "0.75" would represent 75%. - ConsumerRedistributionFraction string `protobuf:"bytes,7,opt,name=consumer_redistribution_fraction,json=consumerRedistributionFraction,proto3" json:"consumer_redistribution_fraction,omitempty"` - // The number of historical info entries to persist in store. - // This param is a part of the cosmos sdk staking module. In the case of - // a ccv enabled consumer chain, the ccv module acts as the staking module. - HistoricalEntries int64 `protobuf:"varint,8,opt,name=historical_entries,json=historicalEntries,proto3" json:"historical_entries,omitempty"` - // Unbonding period for the consumer, - // which should be smaller than that of the provider in general. - UnbondingPeriod time.Duration `protobuf:"bytes,9,opt,name=unbonding_period,json=unbondingPeriod,proto3,stdduration" json:"unbonding_period"` - // The threshold for the percentage of validators at the bottom of the set who - // can opt out of running the consumer chain without being punished. For - // example, a value of 0.05 means that the validators in the bottom 5% of the - // set can opt out - SoftOptOutThreshold string `protobuf:"bytes,10,opt,name=soft_opt_out_threshold,json=softOptOutThreshold,proto3" json:"soft_opt_out_threshold,omitempty"` - // Reward denoms. These are the denominations which are allowed to be sent to - // the provider as rewards. - RewardDenoms []string `protobuf:"bytes,11,rep,name=reward_denoms,json=rewardDenoms,proto3" json:"reward_denoms,omitempty"` - // Provider-originated reward denoms. These are denoms coming from the - // provider which are allowed to be used as rewards. e.g. "uatom" - ProviderRewardDenoms []string `protobuf:"bytes,12,rep,name=provider_reward_denoms,json=providerRewardDenoms,proto3" json:"provider_reward_denoms,omitempty"` -} - -func (m *Params) Reset() { *m = Params{} } -func (m *Params) String() string { return proto.CompactTextString(m) } -func (*Params) ProtoMessage() {} -func (*Params) Descriptor() ([]byte, []int) { - return fileDescriptor_5b27a82b276e7f93, []int{0} -} -func (m *Params) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_Params.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 *Params) XXX_Merge(src proto.Message) { - xxx_messageInfo_Params.Merge(m, src) -} -func (m *Params) XXX_Size() int { - return m.Size() -} -func (m *Params) XXX_DiscardUnknown() { - xxx_messageInfo_Params.DiscardUnknown(m) -} - -var xxx_messageInfo_Params proto.InternalMessageInfo - -func (m *Params) GetEnabled() bool { - if m != nil { - return m.Enabled - } - return false -} - -func (m *Params) GetBlocksPerDistributionTransmission() int64 { - if m != nil { - return m.BlocksPerDistributionTransmission - } - return 0 -} - -func (m *Params) GetDistributionTransmissionChannel() string { - if m != nil { - return m.DistributionTransmissionChannel - } - return "" -} - -func (m *Params) GetProviderFeePoolAddrStr() string { - if m != nil { - return m.ProviderFeePoolAddrStr - } - return "" -} - -func (m *Params) GetCcvTimeoutPeriod() time.Duration { - if m != nil { - return m.CcvTimeoutPeriod - } - return 0 -} - -func (m *Params) GetTransferTimeoutPeriod() time.Duration { - if m != nil { - return m.TransferTimeoutPeriod - } - return 0 -} - -func (m *Params) GetConsumerRedistributionFraction() string { - if m != nil { - return m.ConsumerRedistributionFraction - } - return "" -} - -func (m *Params) GetHistoricalEntries() int64 { - if m != nil { - return m.HistoricalEntries - } - return 0 -} - -func (m *Params) GetUnbondingPeriod() time.Duration { - if m != nil { - return m.UnbondingPeriod - } - return 0 -} - -func (m *Params) GetSoftOptOutThreshold() string { - if m != nil { - return m.SoftOptOutThreshold - } - return "" -} - -func (m *Params) GetRewardDenoms() []string { - if m != nil { - return m.RewardDenoms - } - return nil -} - -func (m *Params) GetProviderRewardDenoms() []string { - if m != nil { - return m.ProviderRewardDenoms - } - return nil -} - -// LastTransmissionBlockHeight is the last time validator holding -// pools were transmitted to the provider chain -type LastTransmissionBlockHeight struct { - Height int64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"` -} - -func (m *LastTransmissionBlockHeight) Reset() { *m = LastTransmissionBlockHeight{} } -func (m *LastTransmissionBlockHeight) String() string { return proto.CompactTextString(m) } -func (*LastTransmissionBlockHeight) ProtoMessage() {} -func (*LastTransmissionBlockHeight) Descriptor() ([]byte, []int) { - return fileDescriptor_5b27a82b276e7f93, []int{1} -} -func (m *LastTransmissionBlockHeight) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *LastTransmissionBlockHeight) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_LastTransmissionBlockHeight.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 *LastTransmissionBlockHeight) XXX_Merge(src proto.Message) { - xxx_messageInfo_LastTransmissionBlockHeight.Merge(m, src) -} -func (m *LastTransmissionBlockHeight) XXX_Size() int { - return m.Size() -} -func (m *LastTransmissionBlockHeight) XXX_DiscardUnknown() { - xxx_messageInfo_LastTransmissionBlockHeight.DiscardUnknown(m) -} - -var xxx_messageInfo_LastTransmissionBlockHeight proto.InternalMessageInfo - -func (m *LastTransmissionBlockHeight) GetHeight() int64 { - if m != nil { - return m.Height - } - return 0 -} - -// CrossChainValidator defines the validators for CCV consumer module +// CrossChainValidator defines the type used to store validator information internal +// to the consumer CCV module. Note one cross chain validator entry is persisted for +// each consumer validator, where incoming VSC packets update this data, which is eventually +// forwarded to comet for consumer chain consensus. +// +// Note this type is only used internally to the consumer CCV module. type CrossChainValidator struct { Address []byte `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` Power int64 `protobuf:"varint,2,opt,name=power,proto3" json:"power,omitempty"` @@ -251,7 +48,7 @@ func (m *CrossChainValidator) Reset() { *m = CrossChainValidator{} } func (m *CrossChainValidator) String() string { return proto.CompactTextString(m) } func (*CrossChainValidator) ProtoMessage() {} func (*CrossChainValidator) Descriptor() ([]byte, []int) { - return fileDescriptor_5b27a82b276e7f93, []int{2} + return fileDescriptor_5b27a82b276e7f93, []int{0} } func (m *CrossChainValidator) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -301,61 +98,10 @@ func (m *CrossChainValidator) GetPubkey() *types.Any { return nil } -// MaturingVSCPacket contains the maturing time of a received VSCPacket -type MaturingVSCPacket struct { - VscId uint64 `protobuf:"varint,1,opt,name=vscId,proto3" json:"vscId,omitempty"` - MaturityTime time.Time `protobuf:"bytes,2,opt,name=maturity_time,json=maturityTime,proto3,stdtime" json:"maturity_time"` -} - -func (m *MaturingVSCPacket) Reset() { *m = MaturingVSCPacket{} } -func (m *MaturingVSCPacket) String() string { return proto.CompactTextString(m) } -func (*MaturingVSCPacket) ProtoMessage() {} -func (*MaturingVSCPacket) Descriptor() ([]byte, []int) { - return fileDescriptor_5b27a82b276e7f93, []int{3} -} -func (m *MaturingVSCPacket) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MaturingVSCPacket) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MaturingVSCPacket.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 *MaturingVSCPacket) XXX_Merge(src proto.Message) { - xxx_messageInfo_MaturingVSCPacket.Merge(m, src) -} -func (m *MaturingVSCPacket) XXX_Size() int { - return m.Size() -} -func (m *MaturingVSCPacket) XXX_DiscardUnknown() { - xxx_messageInfo_MaturingVSCPacket.DiscardUnknown(m) -} - -var xxx_messageInfo_MaturingVSCPacket proto.InternalMessageInfo - -func (m *MaturingVSCPacket) GetVscId() uint64 { - if m != nil { - return m.VscId - } - return 0 -} - -func (m *MaturingVSCPacket) GetMaturityTime() time.Time { - if m != nil { - return m.MaturityTime - } - return time.Time{} -} - // A record storing the state of a slash packet sent to the provider chain // which may bounce back and forth until handled by the provider. +// +// Note this type is only used internally to the consumer CCV module. type SlashRecord struct { WaitingOnReply bool `protobuf:"varint,1,opt,name=waiting_on_reply,json=waitingOnReply,proto3" json:"waiting_on_reply,omitempty"` SendTime time.Time `protobuf:"bytes,2,opt,name=send_time,json=sendTime,proto3,stdtime" json:"send_time"` @@ -365,7 +111,7 @@ func (m *SlashRecord) Reset() { *m = SlashRecord{} } func (m *SlashRecord) String() string { return proto.CompactTextString(m) } func (*SlashRecord) ProtoMessage() {} func (*SlashRecord) Descriptor() ([]byte, []int) { - return fileDescriptor_5b27a82b276e7f93, []int{4} + return fileDescriptor_5b27a82b276e7f93, []int{1} } func (m *SlashRecord) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -409,10 +155,7 @@ func (m *SlashRecord) GetSendTime() time.Time { } func init() { - proto.RegisterType((*Params)(nil), "interchain_security.ccv.consumer.v1.Params") - proto.RegisterType((*LastTransmissionBlockHeight)(nil), "interchain_security.ccv.consumer.v1.LastTransmissionBlockHeight") proto.RegisterType((*CrossChainValidator)(nil), "interchain_security.ccv.consumer.v1.CrossChainValidator") - proto.RegisterType((*MaturingVSCPacket)(nil), "interchain_security.ccv.consumer.v1.MaturingVSCPacket") proto.RegisterType((*SlashRecord)(nil), "interchain_security.ccv.consumer.v1.SlashRecord") } @@ -421,201 +164,34 @@ func init() { } var fileDescriptor_5b27a82b276e7f93 = []byte{ - // 836 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0xcf, 0x6e, 0xdb, 0x36, - 0x18, 0x8f, 0x96, 0xd6, 0x4d, 0xe8, 0x74, 0x4b, 0x59, 0x2f, 0x55, 0x33, 0xc0, 0x76, 0xdd, 0x1e, - 0x7c, 0x89, 0x8d, 0x26, 0xdb, 0xa5, 0xc0, 0x0e, 0xf9, 0xb3, 0xa2, 0xdd, 0xbf, 0x78, 0x4a, 0xd0, - 0x01, 0xdb, 0x81, 0xa0, 0xa8, 0xcf, 0x16, 0x11, 0x89, 0x14, 0x48, 0x4a, 0x99, 0x76, 0xde, 0x03, - 0xf4, 0xb8, 0x47, 0xd8, 0x03, 0xec, 0x21, 0x8a, 0x9d, 0x7a, 0xdc, 0xa9, 0x1b, 0x92, 0x37, 0xd8, - 0x13, 0x0c, 0xa4, 0x24, 0xd7, 0x4e, 0x17, 0xa0, 0xbb, 0xf1, 0xe3, 0xef, 0x8f, 0xf8, 0x7d, 0xfc, - 0xf8, 0x09, 0xed, 0x72, 0x61, 0x40, 0xb1, 0x98, 0x72, 0x41, 0x34, 0xb0, 0x5c, 0x71, 0x53, 0x8e, - 0x19, 0x2b, 0xc6, 0x4c, 0x0a, 0x9d, 0xa7, 0xa0, 0xc6, 0xc5, 0xe3, 0xf9, 0x7a, 0x94, 0x29, 0x69, - 0x24, 0x7e, 0xf8, 0x1f, 0x9a, 0x11, 0x63, 0xc5, 0x68, 0xce, 0x2b, 0x1e, 0x6f, 0x3f, 0xba, 0xce, - 0xd8, 0xfa, 0xb1, 0xa2, 0xb2, 0xda, 0xbe, 0x3f, 0x93, 0x72, 0x96, 0xc0, 0xd8, 0x45, 0x61, 0x3e, - 0x1d, 0x53, 0x51, 0xd6, 0x50, 0x67, 0x26, 0x67, 0xd2, 0x2d, 0xc7, 0x76, 0xd5, 0x08, 0x98, 0xd4, - 0xa9, 0xd4, 0xa4, 0x02, 0xaa, 0xa0, 0x86, 0xba, 0x57, 0xbd, 0xa2, 0x5c, 0x51, 0xc3, 0xa5, 0xa8, - 0xf1, 0xde, 0x55, 0xdc, 0xf0, 0x14, 0xb4, 0xa1, 0x69, 0x56, 0x11, 0x06, 0xbf, 0xb4, 0x50, 0x6b, - 0x42, 0x15, 0x4d, 0x35, 0xf6, 0xd1, 0x2d, 0x10, 0x34, 0x4c, 0x20, 0xf2, 0xbd, 0xbe, 0x37, 0x5c, - 0x0b, 0x9a, 0x10, 0x1f, 0xa3, 0x47, 0x61, 0x22, 0xd9, 0x99, 0x26, 0x19, 0x28, 0x12, 0x71, 0x6d, - 0x14, 0x0f, 0x73, 0xfb, 0x19, 0x62, 0x14, 0x15, 0x3a, 0xe5, 0x5a, 0x73, 0x29, 0xfc, 0x0f, 0xfa, - 0xde, 0x70, 0x35, 0x78, 0x50, 0x71, 0x27, 0xa0, 0x8e, 0x16, 0x98, 0xa7, 0x0b, 0x44, 0xfc, 0x25, - 0x7a, 0x70, 0xad, 0x0b, 0x61, 0x31, 0x15, 0x02, 0x12, 0x7f, 0xb5, 0xef, 0x0d, 0xd7, 0x83, 0x5e, - 0x74, 0x8d, 0xc9, 0x61, 0x45, 0xc3, 0x4f, 0xd0, 0x76, 0xa6, 0x64, 0xc1, 0x23, 0x50, 0x64, 0x0a, - 0x40, 0x32, 0x29, 0x13, 0x42, 0xa3, 0x48, 0x11, 0x6d, 0x94, 0x7f, 0xc3, 0x99, 0x6c, 0x35, 0x8c, - 0xa7, 0x00, 0x13, 0x29, 0x93, 0xfd, 0x28, 0x52, 0x27, 0x46, 0xe1, 0xef, 0x10, 0x66, 0xac, 0x20, - 0xb6, 0x28, 0x32, 0x37, 0x36, 0x3b, 0x2e, 0x23, 0xff, 0x66, 0xdf, 0x1b, 0xb6, 0x77, 0xef, 0x8f, - 0xaa, 0xda, 0x8d, 0x9a, 0xda, 0x8d, 0x8e, 0xea, 0xda, 0x1e, 0xac, 0xbd, 0x7a, 0xd3, 0x5b, 0xf9, - 0xf5, 0xaf, 0x9e, 0x17, 0x6c, 0x32, 0x56, 0x9c, 0x56, 0xea, 0x89, 0x13, 0xe3, 0x1f, 0xd1, 0x3d, - 0x97, 0xcd, 0x14, 0xd4, 0x55, 0xdf, 0xd6, 0xfb, 0xfb, 0x7e, 0xdc, 0x78, 0x2c, 0x9b, 0x3f, 0x43, - 0xfd, 0xa6, 0xdf, 0x88, 0x82, 0xa5, 0x12, 0x4e, 0x15, 0x65, 0x76, 0xe1, 0xdf, 0x72, 0x19, 0x77, - 0x1b, 0x5e, 0xb0, 0x44, 0x7b, 0x5a, 0xb3, 0xf0, 0x0e, 0xc2, 0x31, 0xd7, 0x46, 0x2a, 0xce, 0x68, - 0x42, 0x40, 0x18, 0xc5, 0x41, 0xfb, 0x6b, 0xee, 0x02, 0xef, 0xbc, 0x45, 0xbe, 0xa8, 0x00, 0xfc, - 0x2d, 0xda, 0xcc, 0x45, 0x28, 0x45, 0xc4, 0xc5, 0xac, 0x49, 0x67, 0xfd, 0xfd, 0xd3, 0xf9, 0x68, - 0x2e, 0xae, 0x13, 0xd9, 0x43, 0x5b, 0x5a, 0x4e, 0x0d, 0x91, 0x99, 0x21, 0xb6, 0x42, 0x26, 0x56, - 0xa0, 0x63, 0x99, 0x44, 0x3e, 0x72, 0xc7, 0xbf, 0x6b, 0xd1, 0xe3, 0xcc, 0x1c, 0xe7, 0xe6, 0xb4, - 0x81, 0xf0, 0x43, 0x74, 0x5b, 0xc1, 0x39, 0x55, 0x11, 0x89, 0x40, 0xc8, 0x54, 0xfb, 0xed, 0xfe, - 0xea, 0x70, 0x3d, 0xd8, 0xa8, 0x36, 0x8f, 0xdc, 0x1e, 0xfe, 0x14, 0xcd, 0x2f, 0x9b, 0x2c, 0xb3, - 0x37, 0x1c, 0xbb, 0xd3, 0xa0, 0xc1, 0x82, 0x6a, 0xf0, 0x19, 0xfa, 0xe4, 0x6b, 0xaa, 0xcd, 0x62, - 0x7f, 0x1d, 0xd8, 0x2e, 0x7e, 0x06, 0x7c, 0x16, 0x1b, 0xbc, 0x85, 0x5a, 0xb1, 0x5b, 0xb9, 0x97, - 0xb1, 0x1a, 0xd4, 0xd1, 0xe0, 0x37, 0x0f, 0xdd, 0x3d, 0x54, 0x52, 0xeb, 0x43, 0xfb, 0xe6, 0x5f, - 0xd0, 0x84, 0x47, 0xd4, 0x48, 0x65, 0x9f, 0x92, 0xed, 0x40, 0xd0, 0xda, 0x09, 0x36, 0x82, 0x26, - 0xc4, 0x1d, 0x74, 0x33, 0x93, 0xe7, 0xa0, 0xea, 0xb7, 0x52, 0x05, 0x98, 0xa2, 0x56, 0x96, 0x87, - 0x67, 0x50, 0xba, 0xa6, 0x6f, 0xef, 0x76, 0xde, 0x29, 0xea, 0xbe, 0x28, 0x0f, 0xf6, 0xfe, 0x79, - 0xd3, 0xbb, 0x57, 0xd2, 0x34, 0x79, 0x32, 0xb0, 0xb7, 0x0b, 0x42, 0xe7, 0x9a, 0x54, 0xba, 0xc1, - 0x1f, 0xbf, 0xef, 0x74, 0xea, 0xc9, 0xc0, 0x54, 0x99, 0x19, 0x39, 0x9a, 0xe4, 0xe1, 0x57, 0x50, - 0x06, 0xb5, 0xf1, 0xc0, 0xa0, 0x3b, 0xdf, 0x50, 0x93, 0x2b, 0x2e, 0x66, 0x2f, 0x4e, 0x0e, 0x27, - 0x94, 0x9d, 0x81, 0xb1, 0xa7, 0x29, 0x34, 0x7b, 0x5e, 0x3d, 0xf8, 0x1b, 0x41, 0x15, 0xe0, 0xe7, - 0xe8, 0x76, 0xea, 0xa8, 0xa6, 0x74, 0x2d, 0xec, 0xce, 0xda, 0xde, 0xdd, 0x7e, 0xe7, 0x50, 0xa7, - 0xcd, 0x30, 0xa9, 0xae, 0xfa, 0xa5, 0xbd, 0xea, 0x8d, 0x46, 0x6a, 0xc1, 0xc1, 0xcf, 0xa8, 0x7d, - 0x92, 0x50, 0x1d, 0x07, 0xc0, 0xa4, 0x8a, 0xf0, 0x10, 0x6d, 0x9e, 0x53, 0x6e, 0x6c, 0x13, 0x49, - 0x41, 0x14, 0x64, 0x49, 0x59, 0xcf, 0x9a, 0x0f, 0xeb, 0xfd, 0x63, 0x11, 0xd8, 0x5d, 0xbc, 0x8f, - 0xd6, 0x35, 0x88, 0xe8, 0xff, 0x7f, 0x7f, 0xcd, 0xca, 0x2c, 0x70, 0xf0, 0xfd, 0xab, 0x8b, 0xae, - 0xf7, 0xfa, 0xa2, 0xeb, 0xfd, 0x7d, 0xd1, 0xf5, 0x5e, 0x5e, 0x76, 0x57, 0x5e, 0x5f, 0x76, 0x57, - 0xfe, 0xbc, 0xec, 0xae, 0xfc, 0xf0, 0xf9, 0x8c, 0x9b, 0x38, 0x0f, 0x47, 0x4c, 0xa6, 0xf5, 0x38, - 0x1d, 0xbf, 0x9d, 0xdc, 0x3b, 0xf3, 0xc9, 0x5d, 0xec, 0x8d, 0x7f, 0x5a, 0xfe, 0x2f, 0x98, 0x32, - 0x03, 0x1d, 0xb6, 0xdc, 0x01, 0xf6, 0xfe, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x61, 0xb7, 0xcd, 0x97, - 0x48, 0x06, 0x00, 0x00, -} - -func (m *Params) 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 *Params) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.ProviderRewardDenoms) > 0 { - for iNdEx := len(m.ProviderRewardDenoms) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.ProviderRewardDenoms[iNdEx]) - copy(dAtA[i:], m.ProviderRewardDenoms[iNdEx]) - i = encodeVarintConsumer(dAtA, i, uint64(len(m.ProviderRewardDenoms[iNdEx]))) - i-- - dAtA[i] = 0x62 - } - } - if len(m.RewardDenoms) > 0 { - for iNdEx := len(m.RewardDenoms) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.RewardDenoms[iNdEx]) - copy(dAtA[i:], m.RewardDenoms[iNdEx]) - i = encodeVarintConsumer(dAtA, i, uint64(len(m.RewardDenoms[iNdEx]))) - i-- - dAtA[i] = 0x5a - } - } - if len(m.SoftOptOutThreshold) > 0 { - i -= len(m.SoftOptOutThreshold) - copy(dAtA[i:], m.SoftOptOutThreshold) - i = encodeVarintConsumer(dAtA, i, uint64(len(m.SoftOptOutThreshold))) - i-- - dAtA[i] = 0x52 - } - n1, err1 := github_com_cosmos_gogoproto_types.StdDurationMarshalTo(m.UnbondingPeriod, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.UnbondingPeriod):]) - if err1 != nil { - return 0, err1 - } - i -= n1 - i = encodeVarintConsumer(dAtA, i, uint64(n1)) - i-- - dAtA[i] = 0x4a - if m.HistoricalEntries != 0 { - i = encodeVarintConsumer(dAtA, i, uint64(m.HistoricalEntries)) - i-- - dAtA[i] = 0x40 - } - if len(m.ConsumerRedistributionFraction) > 0 { - i -= len(m.ConsumerRedistributionFraction) - copy(dAtA[i:], m.ConsumerRedistributionFraction) - i = encodeVarintConsumer(dAtA, i, uint64(len(m.ConsumerRedistributionFraction))) - i-- - dAtA[i] = 0x3a - } - n2, err2 := github_com_cosmos_gogoproto_types.StdDurationMarshalTo(m.TransferTimeoutPeriod, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.TransferTimeoutPeriod):]) - if err2 != nil { - return 0, err2 - } - i -= n2 - i = encodeVarintConsumer(dAtA, i, uint64(n2)) - i-- - dAtA[i] = 0x32 - n3, err3 := github_com_cosmos_gogoproto_types.StdDurationMarshalTo(m.CcvTimeoutPeriod, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.CcvTimeoutPeriod):]) - if err3 != nil { - return 0, err3 - } - i -= n3 - i = encodeVarintConsumer(dAtA, i, uint64(n3)) - i-- - dAtA[i] = 0x2a - if len(m.ProviderFeePoolAddrStr) > 0 { - i -= len(m.ProviderFeePoolAddrStr) - copy(dAtA[i:], m.ProviderFeePoolAddrStr) - i = encodeVarintConsumer(dAtA, i, uint64(len(m.ProviderFeePoolAddrStr))) - i-- - dAtA[i] = 0x22 - } - if len(m.DistributionTransmissionChannel) > 0 { - i -= len(m.DistributionTransmissionChannel) - copy(dAtA[i:], m.DistributionTransmissionChannel) - i = encodeVarintConsumer(dAtA, i, uint64(len(m.DistributionTransmissionChannel))) - i-- - dAtA[i] = 0x1a - } - if m.BlocksPerDistributionTransmission != 0 { - i = encodeVarintConsumer(dAtA, i, uint64(m.BlocksPerDistributionTransmission)) - i-- - dAtA[i] = 0x10 - } - if m.Enabled { - i-- - if m.Enabled { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - -func (m *LastTransmissionBlockHeight) 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 *LastTransmissionBlockHeight) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *LastTransmissionBlockHeight) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Height != 0 { - i = encodeVarintConsumer(dAtA, i, uint64(m.Height)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil + // 432 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x52, 0xcb, 0x8e, 0xd3, 0x30, + 0x14, 0xad, 0x19, 0x31, 0x94, 0x14, 0x21, 0x14, 0x2a, 0x51, 0xba, 0x48, 0xab, 0x22, 0xa4, 0x6e, + 0xc6, 0x56, 0xdb, 0x1d, 0x12, 0x8b, 0xe9, 0x2c, 0x59, 0x80, 0x02, 0x02, 0x89, 0x4d, 0xe4, 0x38, + 0x26, 0xb5, 0x48, 0x7c, 0x23, 0x3f, 0x52, 0xcc, 0x57, 0xcc, 0x67, 0xf0, 0x01, 0x7c, 0xc4, 0x88, + 0xd5, 0x2c, 0x59, 0x0d, 0xa8, 0xfd, 0x03, 0xbe, 0x00, 0xe5, 0x55, 0xc4, 0xc0, 0xec, 0xee, 0xf1, + 0xf1, 0x39, 0x3e, 0xf7, 0xfa, 0x7a, 0x4b, 0x21, 0x0d, 0x57, 0x6c, 0x43, 0x85, 0x8c, 0x34, 0x67, + 0x56, 0x09, 0xe3, 0x08, 0x63, 0x25, 0x61, 0x20, 0xb5, 0xcd, 0xb9, 0x22, 0xe5, 0xe2, 0x50, 0xe3, + 0x42, 0x81, 0x01, 0xff, 0xc9, 0x7f, 0x34, 0x98, 0xb1, 0x12, 0x1f, 0xee, 0x95, 0x8b, 0xf1, 0xd3, + 0x9b, 0x8c, 0xcb, 0x05, 0xd9, 0x0a, 0xc5, 0x1b, 0xaf, 0xf1, 0xe3, 0x14, 0x20, 0xcd, 0x38, 0xa9, + 0x51, 0x6c, 0x3f, 0x10, 0x2a, 0x5d, 0x4b, 0x0d, 0x53, 0x48, 0xa1, 0x2e, 0x49, 0x55, 0x75, 0x02, + 0x06, 0x3a, 0x07, 0x1d, 0x35, 0x44, 0x03, 0x5a, 0x2a, 0xb8, 0xee, 0x95, 0x58, 0x45, 0x8d, 0x00, + 0xd9, 0xf2, 0x93, 0xeb, 0xbc, 0x11, 0x39, 0xd7, 0x86, 0xe6, 0x45, 0x73, 0x61, 0xf6, 0x05, 0x79, + 0x0f, 0xcf, 0x14, 0x68, 0x7d, 0x56, 0xc5, 0x7e, 0x4b, 0x33, 0x91, 0x50, 0x03, 0xca, 0x1f, 0x79, + 0x77, 0x68, 0x92, 0x28, 0xae, 0xf5, 0x08, 0x4d, 0xd1, 0xfc, 0x5e, 0xd8, 0x41, 0x7f, 0xe8, 0xdd, + 0x2e, 0x60, 0xcb, 0xd5, 0xe8, 0xd6, 0x14, 0xcd, 0x8f, 0xc2, 0x06, 0xf8, 0xd4, 0x3b, 0x2e, 0x6c, + 0xfc, 0x91, 0xbb, 0xd1, 0xd1, 0x14, 0xcd, 0x07, 0xcb, 0x21, 0x6e, 0x5e, 0xc6, 0xdd, 0xcb, 0xf8, + 0x54, 0xba, 0xf5, 0xea, 0xd7, 0xd5, 0xe4, 0x91, 0xa3, 0x79, 0xf6, 0x6c, 0x56, 0x0d, 0x8e, 0x4b, + 0x6d, 0x75, 0xd4, 0xe8, 0x66, 0xdf, 0xbe, 0x9e, 0x0c, 0xdb, 0xde, 0x98, 0x72, 0x85, 0x01, 0xfc, + 0xca, 0xc6, 0x2f, 0xb8, 0x0b, 0x5b, 0xe3, 0xd9, 0x67, 0x6f, 0xf0, 0x3a, 0xa3, 0x7a, 0x13, 0x72, + 0x06, 0x2a, 0xf1, 0xe7, 0xde, 0x83, 0x2d, 0x15, 0x46, 0xc8, 0x34, 0x02, 0x19, 0x29, 0x5e, 0x64, + 0xae, 0x8e, 0xda, 0x0f, 0xef, 0xb7, 0xe7, 0x2f, 0x65, 0x58, 0x9d, 0xfa, 0xa7, 0xde, 0x5d, 0xcd, + 0x65, 0x12, 0x55, 0xbd, 0xd7, 0xa9, 0x07, 0xcb, 0xf1, 0x3f, 0xf1, 0xde, 0x74, 0x83, 0x59, 0xf7, + 0x2f, 0xae, 0x26, 0xbd, 0xf3, 0x1f, 0x13, 0x14, 0xf6, 0x2b, 0x59, 0x45, 0xac, 0xdf, 0x5d, 0xec, + 0x02, 0x74, 0xb9, 0x0b, 0xd0, 0xcf, 0x5d, 0x80, 0xce, 0xf7, 0x41, 0xef, 0x72, 0x1f, 0xf4, 0xbe, + 0xef, 0x83, 0xde, 0xfb, 0xe7, 0xa9, 0x30, 0x1b, 0x1b, 0x63, 0x06, 0x79, 0xfb, 0x35, 0xe4, 0xcf, + 0x1a, 0x9c, 0x1c, 0xd6, 0xa0, 0x5c, 0x91, 0x4f, 0x7f, 0x2f, 0x99, 0x71, 0x05, 0xd7, 0xf1, 0x71, + 0x1d, 0x60, 0xf5, 0x3b, 0x00, 0x00, 0xff, 0xff, 0x5c, 0xdb, 0x0f, 0x5e, 0x95, 0x02, 0x00, 0x00, } func (m *CrossChainValidator) Marshal() (dAtA []byte, err error) { @@ -665,42 +241,6 @@ func (m *CrossChainValidator) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *MaturingVSCPacket) 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 *MaturingVSCPacket) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MaturingVSCPacket) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - n5, err5 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.MaturityTime, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.MaturityTime):]) - if err5 != nil { - return 0, err5 - } - i -= n5 - i = encodeVarintConsumer(dAtA, i, uint64(n5)) - i-- - dAtA[i] = 0x12 - if m.VscId != 0 { - i = encodeVarintConsumer(dAtA, i, uint64(m.VscId)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - func (m *SlashRecord) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -721,12 +261,12 @@ func (m *SlashRecord) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - n6, err6 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.SendTime, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.SendTime):]) - if err6 != nil { - return 0, err6 + n2, err2 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.SendTime, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.SendTime):]) + if err2 != nil { + return 0, err2 } - i -= n6 - i = encodeVarintConsumer(dAtA, i, uint64(n6)) + i -= n2 + i = encodeVarintConsumer(dAtA, i, uint64(n2)) i-- dAtA[i] = 0x12 if m.WaitingOnReply { @@ -753,82 +293,18 @@ func encodeVarintConsumer(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } -func (m *Params) Size() (n int) { +func (m *CrossChainValidator) Size() (n int) { if m == nil { return 0 } var l int _ = l - if m.Enabled { - n += 2 - } - if m.BlocksPerDistributionTransmission != 0 { - n += 1 + sovConsumer(uint64(m.BlocksPerDistributionTransmission)) - } - l = len(m.DistributionTransmissionChannel) + l = len(m.Address) if l > 0 { n += 1 + l + sovConsumer(uint64(l)) } - l = len(m.ProviderFeePoolAddrStr) - if l > 0 { - n += 1 + l + sovConsumer(uint64(l)) - } - l = github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.CcvTimeoutPeriod) - n += 1 + l + sovConsumer(uint64(l)) - l = github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.TransferTimeoutPeriod) - n += 1 + l + sovConsumer(uint64(l)) - l = len(m.ConsumerRedistributionFraction) - if l > 0 { - n += 1 + l + sovConsumer(uint64(l)) - } - if m.HistoricalEntries != 0 { - n += 1 + sovConsumer(uint64(m.HistoricalEntries)) - } - l = github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.UnbondingPeriod) - n += 1 + l + sovConsumer(uint64(l)) - l = len(m.SoftOptOutThreshold) - if l > 0 { - n += 1 + l + sovConsumer(uint64(l)) - } - if len(m.RewardDenoms) > 0 { - for _, s := range m.RewardDenoms { - l = len(s) - n += 1 + l + sovConsumer(uint64(l)) - } - } - if len(m.ProviderRewardDenoms) > 0 { - for _, s := range m.ProviderRewardDenoms { - l = len(s) - n += 1 + l + sovConsumer(uint64(l)) - } - } - return n -} - -func (m *LastTransmissionBlockHeight) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Height != 0 { - n += 1 + sovConsumer(uint64(m.Height)) - } - return n -} - -func (m *CrossChainValidator) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Address) - if l > 0 { - n += 1 + l + sovConsumer(uint64(l)) - } - if m.Power != 0 { - n += 1 + sovConsumer(uint64(m.Power)) + if m.Power != 0 { + n += 1 + sovConsumer(uint64(m.Power)) } if m.Pubkey != nil { l = m.Pubkey.Size() @@ -837,20 +313,6 @@ func (m *CrossChainValidator) Size() (n int) { return n } -func (m *MaturingVSCPacket) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.VscId != 0 { - n += 1 + sovConsumer(uint64(m.VscId)) - } - l = github_com_cosmos_gogoproto_types.SizeOfStdTime(m.MaturityTime) - n += 1 + l + sovConsumer(uint64(l)) - return n -} - func (m *SlashRecord) Size() (n int) { if m == nil { return 0 @@ -871,7 +333,7 @@ func sovConsumer(x uint64) (n int) { func sozConsumer(x uint64) (n int) { return sovConsumer(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } -func (m *Params) Unmarshal(dAtA []byte) error { +func (m *CrossChainValidator) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -894,153 +356,17 @@ func (m *Params) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: Params: wiretype end group for non-group") + return fmt.Errorf("proto: CrossChainValidator: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: CrossChainValidator: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Enabled", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowConsumer - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.Enabled = bool(v != 0) - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field BlocksPerDistributionTransmission", wireType) - } - m.BlocksPerDistributionTransmission = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowConsumer - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.BlocksPerDistributionTransmission |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field DistributionTransmissionChannel", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowConsumer - } - 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 ErrInvalidLengthConsumer - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthConsumer - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.DistributionTransmissionChannel = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ProviderFeePoolAddrStr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowConsumer - } - 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 ErrInvalidLengthConsumer - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthConsumer - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ProviderFeePoolAddrStr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field CcvTimeoutPeriod", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowConsumer - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthConsumer - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthConsumer - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := github_com_cosmos_gogoproto_types.StdDurationUnmarshal(&m.CcvTimeoutPeriod, dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 6: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field TransferTimeoutPeriod", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) } - var msglen int + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowConsumer @@ -1050,62 +376,31 @@ func (m *Params) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + if byteLen < 0 { return ErrInvalidLengthConsumer } - postIndex := iNdEx + msglen + postIndex := iNdEx + byteLen if postIndex < 0 { return ErrInvalidLengthConsumer } if postIndex > l { return io.ErrUnexpectedEOF } - if err := github_com_cosmos_gogoproto_types.StdDurationUnmarshal(&m.TransferTimeoutPeriod, dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 7: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ConsumerRedistributionFraction", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowConsumer - } - 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 ErrInvalidLengthConsumer - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthConsumer - } - if postIndex > l { - return io.ErrUnexpectedEOF + m.Address = append(m.Address[:0], dAtA[iNdEx:postIndex]...) + if m.Address == nil { + m.Address = []byte{} } - m.ConsumerRedistributionFraction = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 8: + case 2: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field HistoricalEntries", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Power", wireType) } - m.HistoricalEntries = 0 + m.Power = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowConsumer @@ -1115,14 +410,14 @@ func (m *Params) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.HistoricalEntries |= int64(b&0x7F) << shift + m.Power |= int64(b&0x7F) << shift if b < 0x80 { break } } - case 9: + case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field UnbondingPeriod", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Pubkey", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1149,309 +444,8 @@ func (m *Params) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := github_com_cosmos_gogoproto_types.StdDurationUnmarshal(&m.UnbondingPeriod, dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 10: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field SoftOptOutThreshold", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowConsumer - } - 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 ErrInvalidLengthConsumer - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthConsumer - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.SoftOptOutThreshold = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 11: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field RewardDenoms", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowConsumer - } - 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 ErrInvalidLengthConsumer - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthConsumer - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.RewardDenoms = append(m.RewardDenoms, string(dAtA[iNdEx:postIndex])) - iNdEx = postIndex - case 12: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ProviderRewardDenoms", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowConsumer - } - 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 ErrInvalidLengthConsumer - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthConsumer - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ProviderRewardDenoms = append(m.ProviderRewardDenoms, string(dAtA[iNdEx:postIndex])) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipConsumer(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthConsumer - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *LastTransmissionBlockHeight) 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 ErrIntOverflowConsumer - } - 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: LastTransmissionBlockHeight: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: LastTransmissionBlockHeight: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) - } - m.Height = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowConsumer - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Height |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipConsumer(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthConsumer - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *CrossChainValidator) 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 ErrIntOverflowConsumer - } - 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: CrossChainValidator: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: CrossChainValidator: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowConsumer - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthConsumer - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthConsumer - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Address = append(m.Address[:0], dAtA[iNdEx:postIndex]...) - if m.Address == nil { - m.Address = []byte{} - } - iNdEx = postIndex - case 2: - 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 ErrIntOverflowConsumer - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Power |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Pubkey", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowConsumer - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthConsumer - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthConsumer - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Pubkey == nil { - m.Pubkey = &types.Any{} + if m.Pubkey == nil { + m.Pubkey = &types.Any{} } if err := m.Pubkey.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -1478,108 +472,6 @@ func (m *CrossChainValidator) Unmarshal(dAtA []byte) error { } return nil } -func (m *MaturingVSCPacket) 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 ErrIntOverflowConsumer - } - 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: MaturingVSCPacket: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MaturingVSCPacket: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field VscId", wireType) - } - m.VscId = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowConsumer - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.VscId |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field MaturityTime", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowConsumer - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthConsumer - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthConsumer - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(&m.MaturityTime, dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipConsumer(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthConsumer - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func (m *SlashRecord) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/x/ccv/consumer/types/genesis.pb.go b/x/ccv/consumer/types/genesis.pb.go deleted file mode 100644 index 7a503f0e77..0000000000 --- a/x/ccv/consumer/types/genesis.pb.go +++ /dev/null @@ -1,1394 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: interchain_security/ccv/consumer/v1/genesis.proto - -package types - -import ( - fmt "fmt" - types "github.com/cometbft/cometbft/abci/types" - _ "github.com/cosmos/gogoproto/gogoproto" - proto "github.com/cosmos/gogoproto/proto" - _ "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" - _07_tendermint "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - types1 "github.com/cosmos/interchain-security/v3/x/ccv/types" - _ "google.golang.org/protobuf/types/known/durationpb" - io "io" - math "math" - math_bits "math/bits" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -// GenesisState defines the CCV consumer chain genesis state -type GenesisState struct { - Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` - ProviderClientId string `protobuf:"bytes,2,opt,name=provider_client_id,json=providerClientId,proto3" json:"provider_client_id,omitempty"` - ProviderChannelId string `protobuf:"bytes,3,opt,name=provider_channel_id,json=providerChannelId,proto3" json:"provider_channel_id,omitempty"` - NewChain bool `protobuf:"varint,4,opt,name=new_chain,json=newChain,proto3" json:"new_chain,omitempty"` - // ProviderClientState filled in on new chain, nil on restart. - ProviderClientState *_07_tendermint.ClientState `protobuf:"bytes,5,opt,name=provider_client_state,json=providerClientState,proto3" json:"provider_client_state,omitempty"` - // ProviderConsensusState filled in on new chain, nil on restart. - ProviderConsensusState *_07_tendermint.ConsensusState `protobuf:"bytes,6,opt,name=provider_consensus_state,json=providerConsensusState,proto3" json:"provider_consensus_state,omitempty"` - // MaturingPackets nil on new chain, filled in on restart. - MaturingPackets []MaturingVSCPacket `protobuf:"bytes,7,rep,name=maturing_packets,json=maturingPackets,proto3" json:"maturing_packets"` - // InitialValset filled in on new chain and on restart. - InitialValSet []types.ValidatorUpdate `protobuf:"bytes,8,rep,name=initial_val_set,json=initialValSet,proto3" json:"initial_val_set"` - // HeightToValsetUpdateId nil on new chain, filled in on restart. - HeightToValsetUpdateId []HeightToValsetUpdateID `protobuf:"bytes,9,rep,name=height_to_valset_update_id,json=heightToValsetUpdateId,proto3" json:"height_to_valset_update_id"` - // OutstandingDowntimes nil on new chain, filled in on restart. - OutstandingDowntimeSlashing []OutstandingDowntime `protobuf:"bytes,10,rep,name=outstanding_downtime_slashing,json=outstandingDowntimeSlashing,proto3" json:"outstanding_downtime_slashing"` - // PendingConsumerPackets nil on new chain, filled in on restart. - PendingConsumerPackets types1.ConsumerPacketDataList `protobuf:"bytes,11,opt,name=pending_consumer_packets,json=pendingConsumerPackets,proto3" json:"pending_consumer_packets"` - // LastTransmissionBlockHeight nil on new chain, filled in on restart. - LastTransmissionBlockHeight LastTransmissionBlockHeight `protobuf:"bytes,12,opt,name=last_transmission_block_height,json=lastTransmissionBlockHeight,proto3" json:"last_transmission_block_height"` - PreCCV bool `protobuf:"varint,13,opt,name=preCCV,proto3" json:"preCCV,omitempty"` -} - -func (m *GenesisState) Reset() { *m = GenesisState{} } -func (m *GenesisState) String() string { return proto.CompactTextString(m) } -func (*GenesisState) ProtoMessage() {} -func (*GenesisState) Descriptor() ([]byte, []int) { - return fileDescriptor_2db73a6057a27482, []int{0} -} -func (m *GenesisState) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_GenesisState.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 *GenesisState) XXX_Merge(src proto.Message) { - xxx_messageInfo_GenesisState.Merge(m, src) -} -func (m *GenesisState) XXX_Size() int { - return m.Size() -} -func (m *GenesisState) XXX_DiscardUnknown() { - xxx_messageInfo_GenesisState.DiscardUnknown(m) -} - -var xxx_messageInfo_GenesisState proto.InternalMessageInfo - -func (m *GenesisState) GetParams() Params { - if m != nil { - return m.Params - } - return Params{} -} - -func (m *GenesisState) GetProviderClientId() string { - if m != nil { - return m.ProviderClientId - } - return "" -} - -func (m *GenesisState) GetProviderChannelId() string { - if m != nil { - return m.ProviderChannelId - } - return "" -} - -func (m *GenesisState) GetNewChain() bool { - if m != nil { - return m.NewChain - } - return false -} - -func (m *GenesisState) GetProviderClientState() *_07_tendermint.ClientState { - if m != nil { - return m.ProviderClientState - } - return nil -} - -func (m *GenesisState) GetProviderConsensusState() *_07_tendermint.ConsensusState { - if m != nil { - return m.ProviderConsensusState - } - return nil -} - -func (m *GenesisState) GetMaturingPackets() []MaturingVSCPacket { - if m != nil { - return m.MaturingPackets - } - return nil -} - -func (m *GenesisState) GetInitialValSet() []types.ValidatorUpdate { - if m != nil { - return m.InitialValSet - } - return nil -} - -func (m *GenesisState) GetHeightToValsetUpdateId() []HeightToValsetUpdateID { - if m != nil { - return m.HeightToValsetUpdateId - } - return nil -} - -func (m *GenesisState) GetOutstandingDowntimeSlashing() []OutstandingDowntime { - if m != nil { - return m.OutstandingDowntimeSlashing - } - return nil -} - -func (m *GenesisState) GetPendingConsumerPackets() types1.ConsumerPacketDataList { - if m != nil { - return m.PendingConsumerPackets - } - return types1.ConsumerPacketDataList{} -} - -func (m *GenesisState) GetLastTransmissionBlockHeight() LastTransmissionBlockHeight { - if m != nil { - return m.LastTransmissionBlockHeight - } - return LastTransmissionBlockHeight{} -} - -func (m *GenesisState) GetPreCCV() bool { - if m != nil { - return m.PreCCV - } - return false -} - -// HeightValsetUpdateID defines the genesis information for the mapping -// of each block height to a valset update id -type HeightToValsetUpdateID struct { - Height uint64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"` - ValsetUpdateId uint64 `protobuf:"varint,2,opt,name=valset_update_id,json=valsetUpdateId,proto3" json:"valset_update_id,omitempty"` -} - -func (m *HeightToValsetUpdateID) Reset() { *m = HeightToValsetUpdateID{} } -func (m *HeightToValsetUpdateID) String() string { return proto.CompactTextString(m) } -func (*HeightToValsetUpdateID) ProtoMessage() {} -func (*HeightToValsetUpdateID) Descriptor() ([]byte, []int) { - return fileDescriptor_2db73a6057a27482, []int{1} -} -func (m *HeightToValsetUpdateID) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *HeightToValsetUpdateID) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_HeightToValsetUpdateID.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 *HeightToValsetUpdateID) XXX_Merge(src proto.Message) { - xxx_messageInfo_HeightToValsetUpdateID.Merge(m, src) -} -func (m *HeightToValsetUpdateID) XXX_Size() int { - return m.Size() -} -func (m *HeightToValsetUpdateID) XXX_DiscardUnknown() { - xxx_messageInfo_HeightToValsetUpdateID.DiscardUnknown(m) -} - -var xxx_messageInfo_HeightToValsetUpdateID proto.InternalMessageInfo - -func (m *HeightToValsetUpdateID) GetHeight() uint64 { - if m != nil { - return m.Height - } - return 0 -} - -func (m *HeightToValsetUpdateID) GetValsetUpdateId() uint64 { - if m != nil { - return m.ValsetUpdateId - } - return 0 -} - -// OutstandingDowntime defines the genesis information for each validator -// flagged with an outstanding downtime slashing. -type OutstandingDowntime struct { - ValidatorConsensusAddress string `protobuf:"bytes,1,opt,name=validator_consensus_address,json=validatorConsensusAddress,proto3" json:"validator_consensus_address,omitempty"` -} - -func (m *OutstandingDowntime) Reset() { *m = OutstandingDowntime{} } -func (m *OutstandingDowntime) String() string { return proto.CompactTextString(m) } -func (*OutstandingDowntime) ProtoMessage() {} -func (*OutstandingDowntime) Descriptor() ([]byte, []int) { - return fileDescriptor_2db73a6057a27482, []int{2} -} -func (m *OutstandingDowntime) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *OutstandingDowntime) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_OutstandingDowntime.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 *OutstandingDowntime) XXX_Merge(src proto.Message) { - xxx_messageInfo_OutstandingDowntime.Merge(m, src) -} -func (m *OutstandingDowntime) XXX_Size() int { - return m.Size() -} -func (m *OutstandingDowntime) XXX_DiscardUnknown() { - xxx_messageInfo_OutstandingDowntime.DiscardUnknown(m) -} - -var xxx_messageInfo_OutstandingDowntime proto.InternalMessageInfo - -func (m *OutstandingDowntime) GetValidatorConsensusAddress() string { - if m != nil { - return m.ValidatorConsensusAddress - } - return "" -} - -func init() { - proto.RegisterType((*GenesisState)(nil), "interchain_security.ccv.consumer.v1.GenesisState") - proto.RegisterType((*HeightToValsetUpdateID)(nil), "interchain_security.ccv.consumer.v1.HeightToValsetUpdateID") - proto.RegisterType((*OutstandingDowntime)(nil), "interchain_security.ccv.consumer.v1.OutstandingDowntime") -} - -func init() { - proto.RegisterFile("interchain_security/ccv/consumer/v1/genesis.proto", fileDescriptor_2db73a6057a27482) -} - -var fileDescriptor_2db73a6057a27482 = []byte{ - // 786 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x55, 0x4b, 0x8f, 0xe3, 0x34, - 0x1c, 0x6f, 0x76, 0x87, 0xd2, 0x7a, 0x76, 0xd9, 0xc1, 0x03, 0x55, 0x68, 0x45, 0x28, 0x03, 0x87, - 0x4a, 0x40, 0xac, 0x76, 0x25, 0x84, 0x84, 0x40, 0x30, 0x1d, 0x09, 0x2a, 0x2d, 0xb0, 0x6a, 0x77, - 0x8b, 0xb4, 0x97, 0xc8, 0x75, 0x4c, 0x62, 0x6d, 0x62, 0x47, 0xb6, 0x93, 0x61, 0x0f, 0x5c, 0xb8, - 0x72, 0xe1, 0x63, 0xed, 0x71, 0x8f, 0x9c, 0x10, 0x9a, 0xf9, 0x0e, 0x9c, 0x51, 0x6c, 0xa7, 0x0f, - 0xa6, 0xa3, 0xed, 0x29, 0x71, 0xfe, 0xbf, 0xc7, 0xff, 0xe1, 0xd8, 0x60, 0xcc, 0xb8, 0xa6, 0x92, - 0xa4, 0x98, 0xf1, 0x48, 0x51, 0x52, 0x4a, 0xa6, 0x5f, 0x20, 0x42, 0x2a, 0x44, 0x04, 0x57, 0x65, - 0x4e, 0x25, 0xaa, 0xc6, 0x28, 0xa1, 0x9c, 0x2a, 0xa6, 0xc2, 0x42, 0x0a, 0x2d, 0xe0, 0x47, 0x7b, - 0x28, 0x21, 0x21, 0x55, 0xd8, 0x50, 0xc2, 0x6a, 0xdc, 0xff, 0xf8, 0x36, 0xdd, 0x6a, 0x5c, 0x3f, - 0xac, 0x54, 0x7f, 0x72, 0x88, 0xfb, 0x5a, 0xd6, 0x72, 0x06, 0x9a, 0xf2, 0x98, 0xca, 0x9c, 0x71, - 0x8d, 0xf0, 0x8a, 0x30, 0xa4, 0x5f, 0x14, 0xd4, 0xe5, 0xd6, 0x47, 0x6c, 0x45, 0x50, 0xc6, 0x92, - 0x54, 0x93, 0x8c, 0x51, 0xae, 0x15, 0xda, 0x42, 0x57, 0xe3, 0xad, 0x95, 0x23, 0x7c, 0x58, 0x13, - 0x88, 0x90, 0x14, 0x91, 0x14, 0x73, 0x4e, 0x33, 0xe3, 0x68, 0x5f, 0x1d, 0x24, 0x48, 0x84, 0x48, - 0x32, 0x8a, 0xcc, 0x6a, 0x55, 0xfe, 0x82, 0xe2, 0x52, 0x62, 0xcd, 0x04, 0x77, 0xf1, 0x77, 0x12, - 0x91, 0x08, 0xf3, 0x8a, 0xea, 0x37, 0xfb, 0xf5, 0xec, 0xdf, 0x0e, 0xb8, 0xf7, 0x9d, 0xed, 0xdb, - 0x42, 0x63, 0x4d, 0xe1, 0x0c, 0xb4, 0x0b, 0x2c, 0x71, 0xae, 0x7c, 0x6f, 0xe8, 0x8d, 0x8e, 0x27, - 0x9f, 0x84, 0x07, 0xf4, 0x31, 0x7c, 0x6c, 0x28, 0xe7, 0x47, 0x2f, 0xff, 0xfe, 0xa0, 0x35, 0x77, - 0x02, 0xf0, 0x53, 0x00, 0x0b, 0x29, 0x2a, 0x16, 0x53, 0x19, 0xd9, 0x3a, 0x23, 0x16, 0xfb, 0x77, - 0x86, 0xde, 0xa8, 0x3b, 0x3f, 0x69, 0x22, 0x53, 0x13, 0x98, 0xc5, 0x30, 0x04, 0xa7, 0x1b, 0xb4, - 0xad, 0xac, 0x86, 0xdf, 0x35, 0xf0, 0xb7, 0xd7, 0x70, 0x1b, 0x99, 0xc5, 0x70, 0x00, 0xba, 0x9c, - 0x5e, 0x46, 0x26, 0x31, 0xff, 0x68, 0xe8, 0x8d, 0x3a, 0xf3, 0x0e, 0xa7, 0x97, 0xd3, 0x7a, 0x0d, - 0x23, 0xf0, 0xee, 0xff, 0xad, 0x55, 0x5d, 0x9e, 0xff, 0x46, 0x53, 0xd4, 0x8a, 0x84, 0xdb, 0x03, - 0x08, 0xb7, 0x5a, 0x5e, 0x8d, 0x43, 0x9b, 0x95, 0xe9, 0xc8, 0xfc, 0x74, 0x37, 0x55, 0xdb, 0xa6, - 0x14, 0xf8, 0x1b, 0x03, 0xc1, 0x15, 0xe5, 0xaa, 0x54, 0xce, 0xa3, 0x6d, 0x3c, 0xc2, 0xd7, 0x7a, - 0x34, 0x34, 0x6b, 0xd3, 0x5b, 0xdb, 0xec, 0x7c, 0x87, 0x09, 0x38, 0xc9, 0xb1, 0x2e, 0x25, 0xe3, - 0x49, 0x54, 0x60, 0xf2, 0x9c, 0x6a, 0xe5, 0xbf, 0x39, 0xbc, 0x3b, 0x3a, 0x9e, 0x7c, 0x7e, 0xd0, - 0x68, 0x7e, 0x70, 0xe4, 0xe5, 0x62, 0xfa, 0xd8, 0xd0, 0xdd, 0x94, 0x1e, 0x34, 0xaa, 0xf6, 0xab, - 0x82, 0x3f, 0x82, 0x07, 0x8c, 0x33, 0xcd, 0x70, 0x16, 0x55, 0x38, 0x8b, 0x14, 0xd5, 0x7e, 0xc7, - 0xf8, 0x0c, 0xb7, 0x13, 0xaf, 0xf7, 0x72, 0xb8, 0xc4, 0x19, 0x8b, 0xb1, 0x16, 0xf2, 0x69, 0x11, - 0x63, 0x4d, 0x9d, 0xe2, 0x7d, 0x47, 0x5f, 0xe2, 0x6c, 0x41, 0x35, 0xfc, 0x0d, 0xf4, 0x53, 0x5a, - 0x97, 0x1f, 0x69, 0x51, 0x2b, 0x2a, 0xaa, 0xa3, 0xd2, 0xe0, 0xeb, 0xb9, 0x76, 0x8d, 0xf4, 0x97, - 0x07, 0x95, 0xf0, 0xbd, 0x91, 0x79, 0x22, 0x96, 0x46, 0xc4, 0x7a, 0xce, 0x2e, 0x9c, 0x6b, 0x2f, - 0xdd, 0x17, 0x8d, 0xe1, 0xef, 0x1e, 0x78, 0x5f, 0x94, 0x5a, 0x69, 0xcc, 0xe3, 0xba, 0x77, 0xb1, - 0xb8, 0xe4, 0x9a, 0xe5, 0x34, 0x52, 0x19, 0x56, 0x29, 0xe3, 0x89, 0x0f, 0x4c, 0x0a, 0x5f, 0x1c, - 0x94, 0xc2, 0x4f, 0x1b, 0xa5, 0x0b, 0x27, 0xe4, 0xfc, 0x07, 0xe2, 0x66, 0x68, 0xe1, 0x2c, 0xa0, - 0x04, 0x7e, 0x41, 0xad, 0x7f, 0xa3, 0xb6, 0x1e, 0xe2, 0xb1, 0xd9, 0x26, 0x93, 0x5b, 0xed, 0xdd, - 0x16, 0xa9, 0x39, 0x76, 0x44, 0x17, 0x58, 0xe3, 0x47, 0x4c, 0x35, 0x03, 0xec, 0x39, 0xe5, 0x5d, - 0x90, 0x82, 0x7f, 0x78, 0x20, 0xc8, 0xb0, 0xd2, 0x91, 0x96, 0x98, 0xab, 0x9c, 0x29, 0xc5, 0x04, - 0x8f, 0x56, 0x99, 0x20, 0xcf, 0x23, 0xdb, 0x2b, 0xff, 0x9e, 0xb1, 0xfe, 0xe6, 0xa0, 0xca, 0x1f, - 0x61, 0xa5, 0x9f, 0x6c, 0x29, 0x9d, 0xd7, 0x42, 0x76, 0x22, 0x4d, 0x07, 0xb2, 0xdb, 0x21, 0xb0, - 0x07, 0xda, 0x85, 0xa4, 0xd3, 0xe9, 0xd2, 0xbf, 0x6f, 0xfe, 0x51, 0xb7, 0x3a, 0x7b, 0x06, 0x7a, - 0xfb, 0xc7, 0x5a, 0x33, 0x5c, 0x9a, 0xf5, 0x09, 0x74, 0x34, 0x77, 0x2b, 0x38, 0x02, 0x27, 0x37, - 0x76, 0xd1, 0x1d, 0x83, 0x78, 0xab, 0xda, 0x19, 0xfd, 0xd9, 0x53, 0x70, 0xba, 0x67, 0x5e, 0xf0, - 0x6b, 0x30, 0xa8, 0x9a, 0x8d, 0xbb, 0xf5, 0xd3, 0xe2, 0x38, 0x96, 0x54, 0xd9, 0xf3, 0xae, 0x3b, - 0x7f, 0x6f, 0x0d, 0x59, 0xff, 0x87, 0xdf, 0x5a, 0xc0, 0xf9, 0xcf, 0x2f, 0xaf, 0x02, 0xef, 0xd5, - 0x55, 0xe0, 0xfd, 0x73, 0x15, 0x78, 0x7f, 0x5e, 0x07, 0xad, 0x57, 0xd7, 0x41, 0xeb, 0xaf, 0xeb, - 0xa0, 0xf5, 0xec, 0xab, 0x84, 0xe9, 0xb4, 0x5c, 0x85, 0x44, 0xe4, 0x88, 0x08, 0x95, 0x0b, 0x85, - 0x36, 0xad, 0xfd, 0x6c, 0x7d, 0x65, 0x54, 0x0f, 0xd1, 0xaf, 0xbb, 0xf7, 0x86, 0xb9, 0x14, 0x56, - 0x6d, 0x73, 0x16, 0x3f, 0xfc, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x8e, 0xd4, 0xcb, 0xc1, 0xe6, 0x06, - 0x00, 0x00, -} - -func (m *GenesisState) 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 *GenesisState) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.PreCCV { - i-- - if m.PreCCV { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x68 - } - { - size, err := m.LastTransmissionBlockHeight.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x62 - { - size, err := m.PendingConsumerPackets.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x5a - if len(m.OutstandingDowntimeSlashing) > 0 { - for iNdEx := len(m.OutstandingDowntimeSlashing) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.OutstandingDowntimeSlashing[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x52 - } - } - if len(m.HeightToValsetUpdateId) > 0 { - for iNdEx := len(m.HeightToValsetUpdateId) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.HeightToValsetUpdateId[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x4a - } - } - if len(m.InitialValSet) > 0 { - for iNdEx := len(m.InitialValSet) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.InitialValSet[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x42 - } - } - if len(m.MaturingPackets) > 0 { - for iNdEx := len(m.MaturingPackets) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.MaturingPackets[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x3a - } - } - if m.ProviderConsensusState != nil { - { - size, err := m.ProviderConsensusState.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x32 - } - if m.ProviderClientState != nil { - { - size, err := m.ProviderClientState.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x2a - } - if m.NewChain { - i-- - if m.NewChain { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x20 - } - if len(m.ProviderChannelId) > 0 { - i -= len(m.ProviderChannelId) - copy(dAtA[i:], m.ProviderChannelId) - i = encodeVarintGenesis(dAtA, i, uint64(len(m.ProviderChannelId))) - i-- - dAtA[i] = 0x1a - } - if len(m.ProviderClientId) > 0 { - i -= len(m.ProviderClientId) - copy(dAtA[i:], m.ProviderClientId) - i = encodeVarintGenesis(dAtA, i, uint64(len(m.ProviderClientId))) - i-- - dAtA[i] = 0x12 - } - { - size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil -} - -func (m *HeightToValsetUpdateID) 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 *HeightToValsetUpdateID) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *HeightToValsetUpdateID) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.ValsetUpdateId != 0 { - i = encodeVarintGenesis(dAtA, i, uint64(m.ValsetUpdateId)) - i-- - dAtA[i] = 0x10 - } - if m.Height != 0 { - i = encodeVarintGenesis(dAtA, i, uint64(m.Height)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - -func (m *OutstandingDowntime) 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 *OutstandingDowntime) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *OutstandingDowntime) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.ValidatorConsensusAddress) > 0 { - i -= len(m.ValidatorConsensusAddress) - copy(dAtA[i:], m.ValidatorConsensusAddress) - i = encodeVarintGenesis(dAtA, i, uint64(len(m.ValidatorConsensusAddress))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { - offset -= sovGenesis(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *GenesisState) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = m.Params.Size() - n += 1 + l + sovGenesis(uint64(l)) - l = len(m.ProviderClientId) - if l > 0 { - n += 1 + l + sovGenesis(uint64(l)) - } - l = len(m.ProviderChannelId) - if l > 0 { - n += 1 + l + sovGenesis(uint64(l)) - } - if m.NewChain { - n += 2 - } - if m.ProviderClientState != nil { - l = m.ProviderClientState.Size() - n += 1 + l + sovGenesis(uint64(l)) - } - if m.ProviderConsensusState != nil { - l = m.ProviderConsensusState.Size() - n += 1 + l + sovGenesis(uint64(l)) - } - if len(m.MaturingPackets) > 0 { - for _, e := range m.MaturingPackets { - l = e.Size() - n += 1 + l + sovGenesis(uint64(l)) - } - } - if len(m.InitialValSet) > 0 { - for _, e := range m.InitialValSet { - l = e.Size() - n += 1 + l + sovGenesis(uint64(l)) - } - } - if len(m.HeightToValsetUpdateId) > 0 { - for _, e := range m.HeightToValsetUpdateId { - l = e.Size() - n += 1 + l + sovGenesis(uint64(l)) - } - } - if len(m.OutstandingDowntimeSlashing) > 0 { - for _, e := range m.OutstandingDowntimeSlashing { - l = e.Size() - n += 1 + l + sovGenesis(uint64(l)) - } - } - l = m.PendingConsumerPackets.Size() - n += 1 + l + sovGenesis(uint64(l)) - l = m.LastTransmissionBlockHeight.Size() - n += 1 + l + sovGenesis(uint64(l)) - if m.PreCCV { - n += 2 - } - return n -} - -func (m *HeightToValsetUpdateID) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Height != 0 { - n += 1 + sovGenesis(uint64(m.Height)) - } - if m.ValsetUpdateId != 0 { - n += 1 + sovGenesis(uint64(m.ValsetUpdateId)) - } - return n -} - -func (m *OutstandingDowntime) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.ValidatorConsensusAddress) - if l > 0 { - n += 1 + l + sovGenesis(uint64(l)) - } - return n -} - -func sovGenesis(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozGenesis(x uint64) (n int) { - return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *GenesisState) 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 ErrIntOverflowGenesis - } - 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: GenesisState: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthGenesis - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ProviderClientId", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - 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 ErrInvalidLengthGenesis - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ProviderClientId = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ProviderChannelId", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - 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 ErrInvalidLengthGenesis - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ProviderChannelId = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field NewChain", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.NewChain = bool(v != 0) - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ProviderClientState", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthGenesis - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.ProviderClientState == nil { - m.ProviderClientState = &_07_tendermint.ClientState{} - } - if err := m.ProviderClientState.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 6: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ProviderConsensusState", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthGenesis - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.ProviderConsensusState == nil { - m.ProviderConsensusState = &_07_tendermint.ConsensusState{} - } - if err := m.ProviderConsensusState.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 7: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field MaturingPackets", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthGenesis - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.MaturingPackets = append(m.MaturingPackets, MaturingVSCPacket{}) - if err := m.MaturingPackets[len(m.MaturingPackets)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 8: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field InitialValSet", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthGenesis - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.InitialValSet = append(m.InitialValSet, types.ValidatorUpdate{}) - if err := m.InitialValSet[len(m.InitialValSet)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 9: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field HeightToValsetUpdateId", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthGenesis - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.HeightToValsetUpdateId = append(m.HeightToValsetUpdateId, HeightToValsetUpdateID{}) - if err := m.HeightToValsetUpdateId[len(m.HeightToValsetUpdateId)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 10: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field OutstandingDowntimeSlashing", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthGenesis - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.OutstandingDowntimeSlashing = append(m.OutstandingDowntimeSlashing, OutstandingDowntime{}) - if err := m.OutstandingDowntimeSlashing[len(m.OutstandingDowntimeSlashing)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 11: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PendingConsumerPackets", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthGenesis - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.PendingConsumerPackets.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 12: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field LastTransmissionBlockHeight", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthGenesis - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.LastTransmissionBlockHeight.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 13: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field PreCCV", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.PreCCV = bool(v != 0) - default: - iNdEx = preIndex - skippy, err := skipGenesis(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthGenesis - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *HeightToValsetUpdateID) 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 ErrIntOverflowGenesis - } - 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: HeightToValsetUpdateID: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: HeightToValsetUpdateID: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) - } - m.Height = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Height |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field ValsetUpdateId", wireType) - } - m.ValsetUpdateId = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.ValsetUpdateId |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipGenesis(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthGenesis - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *OutstandingDowntime) 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 ErrIntOverflowGenesis - } - 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: OutstandingDowntime: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: OutstandingDowntime: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ValidatorConsensusAddress", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - 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 ErrInvalidLengthGenesis - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ValidatorConsensusAddress = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipGenesis(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthGenesis - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipGenesis(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowGenesis - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowGenesis - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowGenesis - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthGenesis - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupGenesis - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthGenesis - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group") -) diff --git a/x/ccv/consumer/types/genesis_test.go b/x/ccv/consumer/types/genesis_test.go index 2f4b2fa504..453a3aab20 100644 --- a/x/ccv/consumer/types/genesis_test.go +++ b/x/ccv/consumer/types/genesis_test.go @@ -16,8 +16,7 @@ import ( tmtypes "github.com/cometbft/cometbft/types" "github.com/cosmos/interchain-security/v3/testutil/crypto" - "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" - ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" + types "github.com/cosmos/interchain-security/v3/x/ccv/types" ) const ( @@ -86,95 +85,95 @@ func TestValidateInitialGenesisState(t *testing.T) { { "invalid new consumer genesis state: client id not empty", &types.GenesisState{ - params, - "ccvclient", - "", - true, - cs, - consensusState, - nil, - valUpdates, - nil, - nil, - ccv.ConsumerPacketDataList{}, - types.LastTransmissionBlockHeight{}, - false, + Params: params, + ProviderClientId: "ccvclient", + ProviderChannelId: "", + NewChain: true, + ProviderClientState: cs, + ProviderConsensusState: consensusState, + MaturingPackets: nil, + InitialValSet: valUpdates, + HeightToValsetUpdateId: nil, + OutstandingDowntimeSlashing: nil, + PendingConsumerPackets: types.ConsumerPacketDataList{}, + LastTransmissionBlockHeight: types.LastTransmissionBlockHeight{}, + PreCCV: false, }, true, }, { "invalid new consumer genesis state: channel id not empty", &types.GenesisState{ - params, - "", - "ccvchannel", - true, - cs, - consensusState, - nil, - valUpdates, - nil, - nil, - ccv.ConsumerPacketDataList{}, - types.LastTransmissionBlockHeight{}, - false, + Params: params, + ProviderClientId: "", + ProviderChannelId: "ccvchannel", + NewChain: true, + ProviderClientState: cs, + ProviderConsensusState: consensusState, + MaturingPackets: nil, + InitialValSet: valUpdates, + HeightToValsetUpdateId: nil, + OutstandingDowntimeSlashing: nil, + PendingConsumerPackets: types.ConsumerPacketDataList{}, + LastTransmissionBlockHeight: types.LastTransmissionBlockHeight{}, + PreCCV: false, }, true, }, { "invalid new consumer genesis state: non-empty unbonding sequences", &types.GenesisState{ - params, - "", - "", - true, - cs, - consensusState, - []types.MaturingVSCPacket{{}}, - valUpdates, - nil, - nil, - ccv.ConsumerPacketDataList{}, - types.LastTransmissionBlockHeight{}, - false, + Params: params, + ProviderClientId: "", + ProviderChannelId: "", + NewChain: true, + ProviderClientState: cs, + ProviderConsensusState: consensusState, + MaturingPackets: []types.MaturingVSCPacket{{}}, + InitialValSet: valUpdates, + HeightToValsetUpdateId: nil, + OutstandingDowntimeSlashing: nil, + PendingConsumerPackets: types.ConsumerPacketDataList{}, + LastTransmissionBlockHeight: types.LastTransmissionBlockHeight{}, + PreCCV: false, }, true, }, { "invalid new consumer genesis state: non-empty last transmission packet", &types.GenesisState{ - params, - "", - "", - true, - cs, - consensusState, - nil, - valUpdates, - nil, - nil, - ccv.ConsumerPacketDataList{}, - types.LastTransmissionBlockHeight{Height: 1}, - false, + Params: params, + ProviderClientId: "", + ProviderChannelId: "", + NewChain: true, + ProviderClientState: cs, + ProviderConsensusState: consensusState, + MaturingPackets: nil, + InitialValSet: valUpdates, + HeightToValsetUpdateId: nil, + OutstandingDowntimeSlashing: nil, + PendingConsumerPackets: types.ConsumerPacketDataList{}, + LastTransmissionBlockHeight: types.LastTransmissionBlockHeight{Height: 1}, + PreCCV: false, }, true, }, { "invalid new consumer genesis state: non-empty pending consumer packets", &types.GenesisState{ - params, - "", - "", - true, - cs, - consensusState, - nil, - valUpdates, - nil, - nil, - ccv.ConsumerPacketDataList{List: []ccv.ConsumerPacketData{{}}}, - types.LastTransmissionBlockHeight{}, - false, + Params: params, + ProviderClientId: "", + ProviderChannelId: "", + NewChain: true, + ProviderClientState: cs, + ProviderConsensusState: consensusState, + MaturingPackets: nil, + InitialValSet: valUpdates, + HeightToValsetUpdateId: nil, + OutstandingDowntimeSlashing: nil, + PendingConsumerPackets: types.ConsumerPacketDataList{List: []types.ConsumerPacketData{{}}}, + LastTransmissionBlockHeight: types.LastTransmissionBlockHeight{}, + PreCCV: false, }, true, }, @@ -234,7 +233,7 @@ func TestValidateInitialGenesisState(t *testing.T) { types.DefaultBlocksPerDistributionTransmission, "badchannel/", "", - ccv.DefaultCCVTimeoutPeriod, + types.DefaultCCVTimeoutPeriod, types.DefaultTransferTimeoutPeriod, types.DefaultConsumerRedistributeFrac, types.DefaultHistoricalEntries, @@ -270,17 +269,17 @@ func TestValidateRestartGenesisState(t *testing.T) { valHash := valSet.Hash() valUpdates := tmtypes.TM2PB.ValidatorUpdates(valSet) - matConsumerPacket := ccv.ConsumerPacketData{ - Type: ccv.VscMaturedPacket, - Data: &ccv.ConsumerPacketData_VscMaturedPacketData{ - VscMaturedPacketData: ccv.NewVSCMaturedPacketData(1), + matConsumerPacket := types.ConsumerPacketData{ + Type: types.VscMaturedPacket, + Data: &types.ConsumerPacketData_VscMaturedPacketData{ + VscMaturedPacketData: types.NewVSCMaturedPacketData(1), }, } - slashConsumerPacket := ccv.ConsumerPacketData{ - Type: ccv.SlashPacket, - Data: &ccv.ConsumerPacketData_SlashPacketData{ - SlashPacketData: ccv.NewSlashPacketData( + slashConsumerPacket := types.ConsumerPacketData{ + Type: types.SlashPacket, + Data: &types.ConsumerPacketData_SlashPacketData{ + SlashPacketData: types.NewSlashPacketData( abci.Validator{Address: pubKey.Address(), Power: int64(1)}, 1, stakingtypes.Infraction_INFRACTION_DOWNTIME), @@ -306,122 +305,122 @@ func TestValidateRestartGenesisState(t *testing.T) { { "valid restart consumer genesis state: empty maturing packets", types.NewRestartGenesisState("ccvclient", "ccvchannel", nil, valUpdates, heightToValsetUpdateID, - ccv.ConsumerPacketDataList{List: []ccv.ConsumerPacketData{matConsumerPacket, slashConsumerPacket}}, + types.ConsumerPacketDataList{List: []types.ConsumerPacketData{matConsumerPacket, slashConsumerPacket}}, nil, types.LastTransmissionBlockHeight{Height: 100}, params), false, }, { "valid restart consumer genesis state: handshake in progress ", types.NewRestartGenesisState("ccvclient", "", nil, valUpdates, heightToValsetUpdateID, - ccv.ConsumerPacketDataList{List: []ccv.ConsumerPacketData{slashConsumerPacket}}, nil, types.LastTransmissionBlockHeight{}, params), + types.ConsumerPacketDataList{List: []types.ConsumerPacketData{slashConsumerPacket}}, nil, types.LastTransmissionBlockHeight{}, params), false, }, { "valid restart consumer genesis state: maturing packets", types.NewRestartGenesisState("ccvclient", "ccvchannel", []types.MaturingVSCPacket{ - {1, time.Now().UTC()}, - {3, time.Now().UTC()}, - {5, time.Now().UTC()}, - }, valUpdates, heightToValsetUpdateID, ccv.ConsumerPacketDataList{}, + {VscId: 1, MaturityTime: time.Now().UTC()}, + {VscId: 3, MaturityTime: time.Now().UTC()}, + {VscId: 5, MaturityTime: time.Now().UTC()}, + }, valUpdates, heightToValsetUpdateID, types.ConsumerPacketDataList{}, []types.OutstandingDowntime{{ValidatorConsensusAddress: sdk.ConsAddress(validator.Address.Bytes()).String()}}, types.LastTransmissionBlockHeight{}, params), false, }, { "invalid restart consumer genesis state: provider id is empty", - types.NewRestartGenesisState("", "ccvchannel", nil, valUpdates, heightToValsetUpdateID, ccv.ConsumerPacketDataList{}, nil, types.LastTransmissionBlockHeight{}, params), + types.NewRestartGenesisState("", "ccvchannel", nil, valUpdates, heightToValsetUpdateID, types.ConsumerPacketDataList{}, nil, types.LastTransmissionBlockHeight{}, params), true, }, { "invalid restart consumer genesis state: maturing packet vscId is invalid", types.NewRestartGenesisState("ccvclient", "ccvchannel", []types.MaturingVSCPacket{ - {0, time.Now().UTC()}, - }, valUpdates, nil, ccv.ConsumerPacketDataList{}, nil, types.LastTransmissionBlockHeight{}, params), + {VscId: 0, MaturityTime: time.Now().UTC()}, + }, valUpdates, nil, types.ConsumerPacketDataList{}, nil, types.LastTransmissionBlockHeight{}, params), true, }, { "invalid restart consumer genesis state: maturing packet time is invalid", types.NewRestartGenesisState("ccvclient", "ccvchannel", []types.MaturingVSCPacket{ - {1, time.Time{}}, - }, valUpdates, nil, ccv.ConsumerPacketDataList{}, nil, types.LastTransmissionBlockHeight{}, params), + {VscId: 1, MaturityTime: time.Time{}}, + }, valUpdates, nil, types.ConsumerPacketDataList{}, nil, types.LastTransmissionBlockHeight{}, params), true, }, { "invalid restart consumer genesis: client state defined", &types.GenesisState{ - params, - "ccvclient", - "ccvchannel", - false, - cs, - nil, - nil, - valUpdates, - nil, - nil, - ccv.ConsumerPacketDataList{}, - types.LastTransmissionBlockHeight{}, - false, + Params: params, + ProviderClientId: "ccvclient", + ProviderChannelId: "ccvchannel", + NewChain: false, + ProviderClientState: cs, + ProviderConsensusState: nil, + MaturingPackets: nil, + InitialValSet: valUpdates, + HeightToValsetUpdateId: nil, + OutstandingDowntimeSlashing: nil, + PendingConsumerPackets: types.ConsumerPacketDataList{}, + LastTransmissionBlockHeight: types.LastTransmissionBlockHeight{}, + PreCCV: false, }, true, }, { "invalid restart consumer genesis: consensus state defined", &types.GenesisState{ - params, - "ccvclient", - "ccvchannel", - false, - nil, - consensusState, - nil, - valUpdates, - nil, - nil, - ccv.ConsumerPacketDataList{}, - types.LastTransmissionBlockHeight{}, - false, + Params: params, + ProviderClientId: "ccvclient", + ProviderChannelId: "ccvchannel", + NewChain: false, + ProviderClientState: nil, + ProviderConsensusState: consensusState, + MaturingPackets: nil, + InitialValSet: valUpdates, + HeightToValsetUpdateId: nil, + OutstandingDowntimeSlashing: nil, + PendingConsumerPackets: types.ConsumerPacketDataList{}, + LastTransmissionBlockHeight: types.LastTransmissionBlockHeight{}, + PreCCV: false, }, true, }, { "invalid restart consumer genesis state: nil initial validator set", - types.NewRestartGenesisState("ccvclient", "ccvchannel", nil, nil, nil, ccv.ConsumerPacketDataList{}, nil, types.LastTransmissionBlockHeight{}, params), + types.NewRestartGenesisState("ccvclient", "ccvchannel", nil, nil, nil, types.ConsumerPacketDataList{}, nil, types.LastTransmissionBlockHeight{}, params), true, }, { "invalid restart consumer genesis state: nil height to validator set id mapping", types.NewRestartGenesisState("ccvclient", "", - []types.MaturingVSCPacket{{1, time.Time{}}}, valUpdates, nil, ccv.ConsumerPacketDataList{}, nil, types.LastTransmissionBlockHeight{}, params), + []types.MaturingVSCPacket{{VscId: 1, MaturityTime: time.Time{}}}, valUpdates, nil, types.ConsumerPacketDataList{}, nil, types.LastTransmissionBlockHeight{}, params), true, }, { "invalid restart consumer genesis state: maturing packet defined when handshake is still in progress", types.NewRestartGenesisState("ccvclient", "", - []types.MaturingVSCPacket{{1, time.Time{}}}, valUpdates, heightToValsetUpdateID, ccv.ConsumerPacketDataList{}, nil, types.LastTransmissionBlockHeight{}, params), + []types.MaturingVSCPacket{{VscId: 1, MaturityTime: time.Time{}}}, valUpdates, heightToValsetUpdateID, types.ConsumerPacketDataList{}, nil, types.LastTransmissionBlockHeight{}, params), true, }, { "invalid restart consumer genesis state: outstanding downtime defined when handshake is still in progress", types.NewRestartGenesisState("ccvclient", "", - nil, valUpdates, heightToValsetUpdateID, ccv.ConsumerPacketDataList{}, []types.OutstandingDowntime{{ValidatorConsensusAddress: "cosmosvalconsxxx"}}, + nil, valUpdates, heightToValsetUpdateID, types.ConsumerPacketDataList{}, []types.OutstandingDowntime{{ValidatorConsensusAddress: "cosmosvalconsxxx"}}, types.LastTransmissionBlockHeight{}, params), true, }, { "invalid restart consumer genesis state: last transmission block height defined when handshake is still in progress", types.NewRestartGenesisState("ccvclient", "", - nil, valUpdates, heightToValsetUpdateID, ccv.ConsumerPacketDataList{}, nil, types.LastTransmissionBlockHeight{Height: int64(1)}, params), + nil, valUpdates, heightToValsetUpdateID, types.ConsumerPacketDataList{}, nil, types.LastTransmissionBlockHeight{Height: int64(1)}, params), true, }, { "invalid restart consumer genesis state: pending maturing packets defined when handshake is still in progress", types.NewRestartGenesisState("ccvclient", "", - nil, valUpdates, heightToValsetUpdateID, ccv.ConsumerPacketDataList{ - List: []ccv.ConsumerPacketData{ + nil, valUpdates, heightToValsetUpdateID, types.ConsumerPacketDataList{ + List: []types.ConsumerPacketData{ { - Type: ccv.VscMaturedPacket, - Data: &ccv.ConsumerPacketData_VscMaturedPacketData{VscMaturedPacketData: ccv.NewVSCMaturedPacketData(1)}, + Type: types.VscMaturedPacket, + Data: &types.ConsumerPacketData_VscMaturedPacketData{VscMaturedPacketData: types.NewVSCMaturedPacketData(1)}, }, }, }, nil, types.LastTransmissionBlockHeight{Height: int64(1)}, params), @@ -429,7 +428,7 @@ func TestValidateRestartGenesisState(t *testing.T) { }, { "invalid restart consumer genesis state: invalid params", - types.NewRestartGenesisState("ccvclient", "ccvchannel", nil, valUpdates, nil, ccv.ConsumerPacketDataList{}, nil, types.LastTransmissionBlockHeight{}, + types.NewRestartGenesisState("ccvclient", "ccvchannel", nil, valUpdates, nil, types.ConsumerPacketDataList{}, nil, types.LastTransmissionBlockHeight{}, types.NewParams( true, types.DefaultBlocksPerDistributionTransmission, diff --git a/x/ccv/consumer/types/params_test.go b/x/ccv/consumer/types/params_test.go index 531f7e39f2..1690fc9f81 100644 --- a/x/ccv/consumer/types/params_test.go +++ b/x/ccv/consumer/types/params_test.go @@ -6,76 +6,76 @@ import ( "github.com/stretchr/testify/require" - consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) // Tests the validation of consumer params that happens at genesis func TestValidateParams(t *testing.T) { testCases := []struct { name string - params consumertypes.Params + params ccvtypes.Params expPass bool }{ - {"default params", consumertypes.DefaultParams(), true}, + {"default params", ccvtypes.DefaultParams(), true}, { "custom valid params", - consumertypes.NewParams(true, 5, "", "", 1004, 1005, "0.5", 1000, 24*21*time.Hour, "0.05", []string{"untrn"}, []string{"uatom"}), true, + ccvtypes.NewParams(true, 5, "", "", 1004, 1005, "0.5", 1000, 24*21*time.Hour, "0.05", []string{"untrn"}, []string{"uatom"}), true, }, { "custom invalid params, block per dist transmission", - consumertypes.NewParams(true, -5, "", "", 5, 1005, "0.5", 1000, 24*21*time.Hour, "0.05", []string{"untrn"}, []string{"uatom"}), false, + ccvtypes.NewParams(true, -5, "", "", 5, 1005, "0.5", 1000, 24*21*time.Hour, "0.05", []string{"untrn"}, []string{"uatom"}), false, }, { "custom invalid params, dist transmission channel", - consumertypes.NewParams(true, 5, "badchannel/", "", 5, 1005, "0.5", 1000, 24*21*time.Hour, "0.05", []string{"untrn"}, []string{"uatom"}), false, + ccvtypes.NewParams(true, 5, "badchannel/", "", 5, 1005, "0.5", 1000, 24*21*time.Hour, "0.05", []string{"untrn"}, []string{"uatom"}), false, }, { "custom invalid params, provider fee pool addr string", - consumertypes.NewParams(true, 5, "", "imabadaddress", 5, 1005, "0.5", 1000, 24*21*time.Hour, "0.05", []string{"untrn"}, []string{"uatom"}), false, + ccvtypes.NewParams(true, 5, "", "imabadaddress", 5, 1005, "0.5", 1000, 24*21*time.Hour, "0.05", []string{"untrn"}, []string{"uatom"}), false, }, { "custom invalid params, ccv timeout", - consumertypes.NewParams(true, 5, "", "", -5, 1005, "0.5", 1000, 24*21*time.Hour, "0.05", []string{"untrn"}, []string{"uatom"}), false, + ccvtypes.NewParams(true, 5, "", "", -5, 1005, "0.5", 1000, 24*21*time.Hour, "0.05", []string{"untrn"}, []string{"uatom"}), false, }, { "custom invalid params, transfer timeout", - consumertypes.NewParams(true, 5, "", "", 1004, -7, "0.5", 1000, 24*21*time.Hour, "0.05", []string{"untrn"}, []string{"uatom"}), false, + ccvtypes.NewParams(true, 5, "", "", 1004, -7, "0.5", 1000, 24*21*time.Hour, "0.05", []string{"untrn"}, []string{"uatom"}), false, }, { "custom invalid params, consumer redist fraction is negative", - consumertypes.NewParams(true, 5, "", "", 5, 1005, "-0.5", 1000, 24*21*time.Hour, "0.05", []string{"untrn"}, []string{"uatom"}), false, + ccvtypes.NewParams(true, 5, "", "", 5, 1005, "-0.5", 1000, 24*21*time.Hour, "0.05", []string{"untrn"}, []string{"uatom"}), false, }, { "custom invalid params, consumer redist fraction is over 1", - consumertypes.NewParams(true, 5, "", "", 5, 1005, "1.2", 1000, 24*21*time.Hour, "0.05", []string{"untrn"}, []string{"uatom"}), false, + ccvtypes.NewParams(true, 5, "", "", 5, 1005, "1.2", 1000, 24*21*time.Hour, "0.05", []string{"untrn"}, []string{"uatom"}), false, }, { "custom invalid params, bad consumer redist fraction ", - consumertypes.NewParams(true, 5, "", "", 5, 1005, "notFrac", 1000, 24*21*time.Hour, "0.05", []string{"untrn"}, []string{"uatom"}), false, + ccvtypes.NewParams(true, 5, "", "", 5, 1005, "notFrac", 1000, 24*21*time.Hour, "0.05", []string{"untrn"}, []string{"uatom"}), false, }, { "custom invalid params, negative num historical entries", - consumertypes.NewParams(true, 5, "", "", 5, 1005, "0.5", -100, 24*21*time.Hour, "0.05", []string{"untrn"}, []string{"uatom"}), false, + ccvtypes.NewParams(true, 5, "", "", 5, 1005, "0.5", -100, 24*21*time.Hour, "0.05", []string{"untrn"}, []string{"uatom"}), false, }, { "custom invalid params, negative unbonding period", - consumertypes.NewParams(true, 5, "", "", 5, 1005, "0.5", 1000, -24*21*time.Hour, "0.05", []string{"untrn"}, []string{"uatom"}), false, + ccvtypes.NewParams(true, 5, "", "", 5, 1005, "0.5", 1000, -24*21*time.Hour, "0.05", []string{"untrn"}, []string{"uatom"}), false, }, { "custom invalid params, invalid soft opt out threshold", - consumertypes.NewParams(true, 5, "", "", 5, 1005, "0.5", 1000, 24*21*time.Hour, "-0.05", []string{"u"}, []string{}), false, + ccvtypes.NewParams(true, 5, "", "", 5, 1005, "0.5", 1000, 24*21*time.Hour, "-0.05", []string{"u"}, []string{}), false, }, { "custom invalid params, invalid soft opt out threshold", - consumertypes.NewParams(true, 5, "", "", 5, 1005, "0.5", 1000, 24*21*time.Hour, "0.5", []string{"u"}, []string{}), false, + ccvtypes.NewParams(true, 5, "", "", 5, 1005, "0.5", 1000, 24*21*time.Hour, "0.5", []string{"u"}, []string{}), false, }, { "custom invalid params, invalid reward denom", - consumertypes.NewParams(true, 5, "", "", 5, 1005, "0.5", 1000, 24*21*time.Hour, "0.05", []string{"u"}, []string{}), false, + ccvtypes.NewParams(true, 5, "", "", 5, 1005, "0.5", 1000, 24*21*time.Hour, "0.05", []string{"u"}, []string{}), false, }, { "custom invalid params, invalid provider reward denom", - consumertypes.NewParams(true, 5, "", "", 5, 1005, "0.5", 1000, 24*21*time.Hour, "0.05", []string{}, []string{"a"}), false, + ccvtypes.NewParams(true, 5, "", "", 5, 1005, "0.5", 1000, 24*21*time.Hour, "0.05", []string{}, []string{"a"}), false, }, } diff --git a/x/ccv/consumer/types/query.pb.go b/x/ccv/consumer/types/query.pb.go index effe4757ef..5ed38da3f8 100644 --- a/x/ccv/consumer/types/query.pb.go +++ b/x/ccv/consumer/types/query.pb.go @@ -9,6 +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/v3/x/ccv/types" _ "google.golang.org/genproto/googleapis/api/annotations" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" @@ -252,7 +253,7 @@ var xxx_messageInfo_QueryParamsRequest proto.InternalMessageInfo // QueryParamsResponse is response type for the Query/Params RPC method. type QueryParamsResponse struct { // params holds all the parameters of this module. - Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` + Params types.Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` } func (m *QueryParamsResponse) Reset() { *m = QueryParamsResponse{} } @@ -288,11 +289,11 @@ func (m *QueryParamsResponse) XXX_DiscardUnknown() { var xxx_messageInfo_QueryParamsResponse proto.InternalMessageInfo -func (m *QueryParamsResponse) GetParams() Params { +func (m *QueryParamsResponse) GetParams() types.Params { if m != nil { return m.Params } - return Params{} + return types.Params{} } type QueryProviderInfoRequest struct { @@ -467,49 +468,50 @@ func init() { } var fileDescriptor_f627751d3cc10225 = []byte{ - // 672 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x55, 0x41, 0x6b, 0x13, 0x4f, - 0x14, 0xcf, 0xa6, 0x4d, 0xdb, 0xbc, 0xfe, 0xff, 0x07, 0xc7, 0x08, 0xeb, 0x5a, 0xd6, 0xb2, 0x0a, - 0x46, 0x25, 0xbb, 0xb6, 0x3d, 0x54, 0x0f, 0x55, 0xb1, 0xb1, 0x18, 0x50, 0xa9, 0x8b, 0x20, 0x78, - 0xa9, 0xd3, 0xe9, 0x34, 0x19, 0x48, 0x66, 0xd2, 0x9d, 0xd9, 0xd0, 0xde, 0x44, 0xf1, 0x2a, 0x82, - 0xdf, 0xc4, 0x2f, 0xe0, 0xb5, 0xe0, 0xa5, 0xe0, 0xc5, 0x93, 0x48, 0xeb, 0x87, 0xf0, 0x28, 0x3b, - 0x3b, 0x9b, 0x6e, 0x68, 0x69, 0xb7, 0xea, 0x6d, 0xe7, 0xfd, 0xde, 0xfb, 0xbd, 0xdf, 0x7b, 0xf3, - 0xde, 0x2c, 0x04, 0x8c, 0x2b, 0x1a, 0x91, 0x0e, 0x66, 0x7c, 0x4d, 0x52, 0x12, 0x47, 0x4c, 0xed, - 0x04, 0x84, 0x0c, 0x02, 0x22, 0xb8, 0x8c, 0x7b, 0x34, 0x0a, 0x06, 0x73, 0xc1, 0x56, 0x4c, 0xa3, - 0x1d, 0xbf, 0x1f, 0x09, 0x25, 0xd0, 0x95, 0x63, 0x02, 0x7c, 0x42, 0x06, 0x7e, 0x16, 0xe0, 0x0f, - 0xe6, 0x9c, 0x5a, 0x5b, 0xb4, 0x85, 0xf6, 0x0f, 0x92, 0xaf, 0x34, 0xd4, 0x99, 0x69, 0x0b, 0xd1, - 0xee, 0xd2, 0x00, 0xf7, 0x59, 0x80, 0x39, 0x17, 0x0a, 0x2b, 0x26, 0xb8, 0x34, 0xe8, 0x7c, 0x11, - 0x25, 0xc3, 0x24, 0x3a, 0xc6, 0x7b, 0x5f, 0x86, 0x4b, 0x4f, 0xe9, 0xb6, 0x5a, 0xa1, 0xb4, 0xc9, - 0xa4, 0x8a, 0xd8, 0x7a, 0x9c, 0x50, 0x3e, 0x94, 0x8a, 0xf5, 0xb0, 0xa2, 0xe8, 0x2a, 0xfc, 0x4f, - 0xe2, 0x28, 0xa2, 0x5c, 0x3d, 0xa2, 0xac, 0xdd, 0x51, 0xb6, 0x35, 0x6b, 0xd5, 0xc7, 0xc2, 0x51, - 0x23, 0x72, 0x01, 0xba, 0x58, 0x66, 0x2e, 0x65, 0xed, 0x92, 0xb3, 0x24, 0x38, 0xa7, 0xdb, 0x19, - 0x3e, 0x96, 0xe2, 0x87, 0x16, 0xb4, 0x00, 0x17, 0x36, 0x72, 0xd9, 0xd7, 0x36, 0x23, 0x4c, 0x92, - 0x0f, 0x7b, 0x7c, 0xd6, 0xaa, 0x57, 0xc3, 0x5a, 0x1e, 0x5c, 0x31, 0x18, 0xaa, 0x41, 0x45, 0x09, - 0x85, 0xbb, 0x76, 0x45, 0x3b, 0xa5, 0x87, 0x24, 0x95, 0x12, 0xab, 0x91, 0x18, 0xb0, 0x0d, 0x1a, - 0xd9, 0x13, 0x1a, 0xca, 0x59, 0x52, 0x7c, 0xd9, 0x34, 0xc1, 0x9e, 0xcc, 0xf0, 0xcc, 0xe2, 0x5d, - 0x87, 0x6b, 0xcf, 0x92, 0xcb, 0x3a, 0xa1, 0x29, 0x21, 0xdd, 0x8a, 0xa9, 0x54, 0xde, 0x6b, 0x0b, - 0xea, 0xa7, 0xfb, 0xca, 0xbe, 0xe0, 0x92, 0xa2, 0xe7, 0x30, 0xbe, 0x81, 0x15, 0xd6, 0xfd, 0x9b, - 0x9e, 0xbf, 0xef, 0x17, 0x18, 0x02, 0xff, 0x24, 0x5e, 0xcd, 0xe6, 0xd5, 0x00, 0x69, 0x05, 0xab, - 0x38, 0xc2, 0x3d, 0x99, 0x09, 0x7b, 0x05, 0xe7, 0x47, 0xac, 0x46, 0x42, 0x0b, 0x26, 0xfa, 0xda, - 0x62, 0x44, 0xdc, 0x2c, 0x24, 0x22, 0x25, 0x79, 0x30, 0xbe, 0xfb, 0xfd, 0x72, 0x29, 0x34, 0x04, - 0x9e, 0x03, 0x76, 0x9a, 0xc1, 0xb4, 0xb5, 0xc5, 0x37, 0x45, 0x96, 0xfd, 0xb3, 0x05, 0x17, 0x8f, - 0x01, 0x8d, 0x88, 0x55, 0x98, 0xca, 0xd8, 0x8d, 0x0c, 0xbf, 0x90, 0x8c, 0xe5, 0x04, 0x4e, 0x98, - 0x8c, 0x92, 0x21, 0x4b, 0xc2, 0xd8, 0xcf, 0xee, 0xbb, 0xfc, 0x37, 0x8c, 0x19, 0x8b, 0xf7, 0xd6, - 0x82, 0xea, 0x10, 0x45, 0x36, 0x4c, 0x6a, 0xa6, 0x56, 0x53, 0x0b, 0xae, 0x86, 0xd9, 0x11, 0x39, - 0x30, 0x45, 0xba, 0x8c, 0x72, 0xd5, 0x6a, 0xea, 0xcc, 0xd5, 0x70, 0x78, 0x46, 0x1e, 0xfc, 0x47, - 0x04, 0xe7, 0x54, 0xcf, 0x6a, 0xab, 0xa9, 0x87, 0xbe, 0x1a, 0x8e, 0xd8, 0xd0, 0x0c, 0x54, 0x49, - 0x07, 0x73, 0x4e, 0xbb, 0xad, 0xa6, 0x19, 0xf5, 0x43, 0xc3, 0xfc, 0xbb, 0x0a, 0x54, 0x74, 0x1f, - 0xd1, 0x2f, 0xcb, 0xb4, 0xfb, 0x98, 0x81, 0x40, 0x8f, 0x0b, 0x15, 0x5b, 0x70, 0xa6, 0x9d, 0x27, - 0xff, 0x88, 0x2d, 0xbd, 0x6d, 0xef, 0xde, 0x9b, 0xaf, 0x3f, 0x3f, 0x96, 0xef, 0xa0, 0xc5, 0xd3, - 0x5f, 0xc9, 0xe4, 0x39, 0x68, 0x6c, 0x52, 0xda, 0xc8, 0x2f, 0x3b, 0xfa, 0x64, 0xc1, 0x74, 0x6e, - 0x96, 0xd1, 0x62, 0x71, 0x7d, 0x23, 0x3b, 0xe1, 0xdc, 0x3e, 0x7b, 0xa0, 0xa9, 0xe1, 0x96, 0xae, - 0xe1, 0x06, 0xaa, 0x9f, 0x5e, 0x43, 0xba, 0x1d, 0xe8, 0x8b, 0x05, 0xe7, 0x8e, 0x6c, 0x00, 0x5a, - 0x3a, 0x83, 0x82, 0xa3, 0x6b, 0xe5, 0xdc, 0xfd, 0xd3, 0x70, 0x53, 0xc6, 0xa2, 0x2e, 0x63, 0x0e, - 0x05, 0x05, 0xca, 0x30, 0xf1, 0x0d, 0x96, 0x6c, 0xc7, 0x8b, 0xdd, 0x7d, 0xd7, 0xda, 0xdb, 0x77, - 0xad, 0x1f, 0xfb, 0xae, 0xf5, 0xe1, 0xc0, 0x2d, 0xed, 0x1d, 0xb8, 0xa5, 0x6f, 0x07, 0x6e, 0xe9, - 0xe5, 0x52, 0x9b, 0xa9, 0x4e, 0xbc, 0xee, 0x13, 0xd1, 0x0b, 0x88, 0x90, 0x3d, 0x21, 0x73, 0xdc, - 0x8d, 0x21, 0xf7, 0x60, 0x21, 0xd8, 0x1e, 0x4d, 0xa0, 0x76, 0xfa, 0x54, 0xae, 0x4f, 0xe8, 0x5f, - 0xd0, 0xc2, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0x78, 0x73, 0x9f, 0x0e, 0x42, 0x07, 0x00, 0x00, + // 686 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x55, 0x4f, 0x6b, 0x13, 0x41, + 0x14, 0xcf, 0xa6, 0x4d, 0xdb, 0x4c, 0xf5, 0xe0, 0x18, 0x21, 0xae, 0x65, 0x2d, 0xab, 0x60, 0x14, + 0xb2, 0xdb, 0xb4, 0x87, 0xea, 0xa1, 0x5a, 0x6c, 0x2c, 0x06, 0x54, 0xea, 0x22, 0x14, 0xbc, 0x94, + 0xe9, 0x64, 0x9a, 0x0c, 0x24, 0x33, 0xe9, 0xcc, 0xec, 0xd2, 0xde, 0x44, 0xf1, 0x2a, 0x82, 0xdf, + 0xc4, 0x2f, 0xe0, 0xb5, 0xe0, 0xa5, 0xe0, 0xc5, 0x93, 0x48, 0xeb, 0x87, 0xf0, 0x28, 0x3b, 0x3b, + 0x9b, 0x6e, 0xe8, 0xbf, 0xad, 0x7a, 0x9b, 0x79, 0xbf, 0xf7, 0x7e, 0xef, 0xf7, 0xde, 0xbc, 0xb7, + 0x0b, 0x7c, 0xca, 0x14, 0x11, 0xb8, 0x8b, 0x28, 0xdb, 0x90, 0x04, 0x87, 0x82, 0xaa, 0x5d, 0x1f, + 0xe3, 0xc8, 0xc7, 0x9c, 0xc9, 0xb0, 0x4f, 0x84, 0x1f, 0x35, 0xfc, 0xed, 0x90, 0x88, 0x5d, 0x6f, + 0x20, 0xb8, 0xe2, 0xf0, 0xd6, 0x09, 0x01, 0x1e, 0xc6, 0x91, 0x97, 0x06, 0x78, 0x51, 0xc3, 0x9e, + 0x3b, 0x8d, 0x35, 0x6a, 0xf8, 0xb2, 0x8b, 0x04, 0x69, 0x6f, 0x0c, 0xdd, 0x35, 0xad, 0x5d, 0xe9, + 0xf0, 0x0e, 0xd7, 0x47, 0x3f, 0x3e, 0x19, 0xeb, 0x4c, 0x87, 0xf3, 0x4e, 0x8f, 0xf8, 0x68, 0x40, + 0x7d, 0xc4, 0x18, 0x57, 0x48, 0x51, 0xce, 0xa4, 0x41, 0xe7, 0xf3, 0x68, 0x1f, 0xcd, 0xe3, 0x7e, + 0x28, 0x82, 0x1b, 0x2f, 0xc8, 0x8e, 0x5a, 0x25, 0xa4, 0x49, 0xa5, 0x12, 0x74, 0x33, 0x8c, 0x29, + 0x9f, 0x48, 0x45, 0xfb, 0x48, 0x11, 0x78, 0x1b, 0x5c, 0xc6, 0xa1, 0x10, 0x84, 0xa9, 0xa7, 0x84, + 0x76, 0xba, 0xaa, 0x6a, 0xcd, 0x5a, 0xb5, 0xb1, 0x60, 0xd4, 0x08, 0x1d, 0x00, 0x7a, 0x48, 0xa6, + 0x2e, 0x45, 0xed, 0x92, 0xb1, 0xc4, 0x38, 0x23, 0x3b, 0x29, 0x3e, 0x96, 0xe0, 0x47, 0x16, 0xb8, + 0x00, 0xae, 0xb5, 0x33, 0xd9, 0x37, 0xb6, 0x04, 0xc2, 0xf1, 0xa1, 0x3a, 0x3e, 0x6b, 0xd5, 0xca, + 0x41, 0x25, 0x0b, 0xae, 0x1a, 0x0c, 0x56, 0x40, 0x49, 0x71, 0x85, 0x7a, 0xd5, 0x92, 0x76, 0x4a, + 0x2e, 0x71, 0x2a, 0xc5, 0xd7, 0x04, 0x8f, 0x68, 0x9b, 0x88, 0xea, 0x84, 0x86, 0x32, 0x96, 0x04, + 0x5f, 0x31, 0x4d, 0xa8, 0x4e, 0xa6, 0x78, 0x6a, 0x71, 0xef, 0x82, 0x3b, 0x2f, 0xe3, 0xe7, 0x3d, + 0xa3, 0x29, 0x01, 0xd9, 0x0e, 0x89, 0x54, 0xee, 0x1b, 0x0b, 0xd4, 0xce, 0xf7, 0x95, 0x03, 0xce, + 0x24, 0x81, 0xaf, 0xc0, 0x78, 0x1b, 0x29, 0xa4, 0xfb, 0x37, 0x3d, 0xbf, 0xec, 0xe5, 0x18, 0x1b, + 0xef, 0x2c, 0x5e, 0xcd, 0xe6, 0x56, 0x00, 0xd4, 0x0a, 0xd6, 0x90, 0x40, 0x7d, 0x99, 0x0a, 0x5b, + 0x07, 0x57, 0x47, 0xac, 0x46, 0xc2, 0x32, 0x98, 0x18, 0x68, 0x8b, 0x11, 0xe1, 0x9e, 0x2a, 0x22, + 0x6a, 0x78, 0x49, 0xec, 0xe3, 0xf1, 0xbd, 0x1f, 0x37, 0x0b, 0x81, 0x89, 0x73, 0x6d, 0x50, 0x4d, + 0x88, 0x4d, 0x37, 0x5b, 0x6c, 0x8b, 0xa7, 0x49, 0xbf, 0x58, 0xe0, 0xfa, 0x09, 0xa0, 0xc9, 0xbd, + 0x06, 0xa6, 0xd2, 0xca, 0x4c, 0x76, 0x2f, 0x57, 0x0b, 0x56, 0x62, 0x38, 0x66, 0x32, 0x4a, 0x86, + 0x2c, 0x31, 0xe3, 0x20, 0x7d, 0xe6, 0xe2, 0xbf, 0x30, 0xa6, 0x2c, 0xee, 0x3b, 0x0b, 0x94, 0x87, + 0x28, 0xac, 0x82, 0x49, 0xcd, 0xd4, 0x6a, 0x6a, 0xc1, 0xe5, 0x20, 0xbd, 0x42, 0x1b, 0x4c, 0xe1, + 0x1e, 0x25, 0x4c, 0xb5, 0x9a, 0x3a, 0x73, 0x39, 0x18, 0xde, 0xa1, 0x0b, 0x2e, 0x61, 0xce, 0x18, + 0xd1, 0x23, 0xda, 0x6a, 0xea, 0x59, 0x2f, 0x07, 0x23, 0x36, 0x38, 0x03, 0xca, 0xb8, 0x8b, 0x18, + 0x23, 0xbd, 0x56, 0xd3, 0x4c, 0xf8, 0x91, 0x61, 0xfe, 0x7d, 0x09, 0x94, 0x74, 0x1f, 0xe1, 0x6f, + 0xcb, 0xb4, 0xfb, 0x84, 0x39, 0x80, 0xcf, 0x72, 0x15, 0x9b, 0x73, 0x94, 0xed, 0xe7, 0xff, 0x89, + 0x2d, 0x79, 0x6d, 0xf7, 0xd1, 0xdb, 0x6f, 0xbf, 0x3e, 0x15, 0x1f, 0xc0, 0xc5, 0xf3, 0x3f, 0xa7, + 0xf1, 0x57, 0xa0, 0xbe, 0x45, 0x48, 0x3d, 0xbb, 0xe3, 0xf0, 0xb3, 0x05, 0xa6, 0x33, 0x23, 0x0c, + 0x17, 0xf3, 0xeb, 0x1b, 0x59, 0x05, 0xfb, 0xfe, 0xc5, 0x03, 0x4d, 0x0d, 0x73, 0xba, 0x86, 0x7b, + 0xb0, 0x76, 0x7e, 0x0d, 0xc9, 0x76, 0xc0, 0xaf, 0x16, 0xb8, 0x72, 0x6c, 0x03, 0xe0, 0xd2, 0x05, + 0x14, 0x1c, 0x5f, 0x2b, 0xfb, 0xe1, 0xdf, 0x86, 0x9b, 0x32, 0x16, 0x75, 0x19, 0x0d, 0xe8, 0xe7, + 0x28, 0xc3, 0xc4, 0xd7, 0x69, 0xbc, 0x1d, 0xeb, 0x7b, 0x07, 0x8e, 0xb5, 0x7f, 0xe0, 0x58, 0x3f, + 0x0f, 0x1c, 0xeb, 0xe3, 0xa1, 0x53, 0xd8, 0x3f, 0x74, 0x0a, 0xdf, 0x0f, 0x9d, 0xc2, 0xeb, 0xa5, + 0x0e, 0x55, 0xdd, 0x70, 0xd3, 0xc3, 0xbc, 0xef, 0x63, 0x2e, 0xfb, 0x5c, 0x66, 0xb8, 0xeb, 0x43, + 0xee, 0x68, 0xc1, 0xdf, 0x19, 0x4d, 0xa0, 0x76, 0x07, 0x44, 0x6e, 0x4e, 0xe8, 0x3f, 0xcf, 0xc2, + 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x18, 0x69, 0x59, 0x43, 0x6b, 0x07, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/x/ccv/provider/ibc_module.go b/x/ccv/provider/ibc_module.go index efe113f895..a19fd7e5bb 100644 --- a/x/ccv/provider/ibc_module.go +++ b/x/ccv/provider/ibc_module.go @@ -83,7 +83,7 @@ func (am AppModule) OnChanOpenTry( return "", err } - md := providertypes.HandshakeMetadata{ + md := ccv.HandshakeMetadata{ // NOTE that the fee pool collector address string provided to the // the consumer chain must be excluded from the blocked addresses // blacklist or all all ibc-transfers from the consumer chain to the diff --git a/x/ccv/provider/ibc_module_test.go b/x/ccv/provider/ibc_module_test.go index 8b7c3f985c..571bed0471 100644 --- a/x/ccv/provider/ibc_module_test.go +++ b/x/ccv/provider/ibc_module_test.go @@ -168,7 +168,7 @@ func TestOnChanOpenTry(t *testing.T) { if tc.expPass { require.NoError(t, err) - md := &providertypes.HandshakeMetadata{} + md := &ccv.HandshakeMetadata{} err = md.Unmarshal([]byte(metadata)) require.NoError(t, err) require.Equal(t, moduleAcct.BaseAccount.Address, md.ProviderFeePoolAddr, diff --git a/x/ccv/provider/keeper/genesis.go b/x/ccv/provider/keeper/genesis.go index f201e6de50..e86035170c 100644 --- a/x/ccv/provider/keeper/genesis.go +++ b/x/ccv/provider/keeper/genesis.go @@ -158,7 +158,7 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { k.GetAllValsetUpdateBlockHeights(ctx), consumerStates, k.GetAllUnbondingOps(ctx), - &ccv.MaturedUnbondingOps{Ids: k.GetMaturedUnbondingOps(ctx)}, + &types.MaturedUnbondingOps{Ids: k.GetMaturedUnbondingOps(ctx)}, k.GetAllPendingConsumerAdditionProps(ctx), k.GetAllPendingConsumerRemovalProps(ctx), params, diff --git a/x/ccv/provider/keeper/genesis_test.go b/x/ccv/provider/keeper/genesis_test.go index 01a3845651..8b101a1ce9 100644 --- a/x/ccv/provider/keeper/genesis_test.go +++ b/x/ccv/provider/keeper/genesis_test.go @@ -13,7 +13,6 @@ import ( "github.com/cosmos/interchain-security/v3/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" - consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" @@ -72,7 +71,7 @@ func TestInitAndExportGenesis(t *testing.T) { expClientID, "channel", initHeight, - *consumertypes.DefaultGenesisState(), + *ccv.DefaultGenesisState(), []providertypes.VscUnbondingOps{ {VscId: vscID, UnbondingOpIds: ubdIndex}, }, @@ -84,7 +83,7 @@ func TestInitAndExportGenesis(t *testing.T) { expClientID, "", 0, - *consumertypes.DefaultGenesisState(), + *ccv.DefaultGenesisState(), nil, []ccv.ValidatorSetChangePacketData{{ValsetUpdateId: vscID}}, nil, @@ -94,7 +93,7 @@ func TestInitAndExportGenesis(t *testing.T) { Id: vscID, UnbondingConsumerChains: []string{cChainIDs[0]}, }}, - &ccv.MaturedUnbondingOps{Ids: ubdIndex}, + &providertypes.MaturedUnbondingOps{Ids: ubdIndex}, []providertypes.ConsumerAdditionProposal{{ ChainId: cChainIDs[0], SpawnTime: oneHourFromNow, @@ -219,7 +218,7 @@ func assertConsumerChainStates(t *testing.T, ctx sdk.Context, pk keeper.Keeper, chainID := cs.ChainId gen, found := pk.GetConsumerGenesis(ctx, chainID) require.True(t, found) - require.Equal(t, *consumertypes.DefaultGenesisState(), gen) + require.Equal(t, *ccv.DefaultGenesisState(), gen) clientID, found := pk.GetConsumerClientId(ctx, chainID) require.True(t, found) diff --git a/x/ccv/provider/keeper/keeper.go b/x/ccv/provider/keeper/keeper.go index 73785f1c17..bebef70c56 100644 --- a/x/ccv/provider/keeper/keeper.go +++ b/x/ccv/provider/keeper/keeper.go @@ -251,7 +251,7 @@ func (k Keeper) GetAllChannelToChains(ctx sdk.Context) (channels []types.Channel return channels } -func (k Keeper) SetConsumerGenesis(ctx sdk.Context, chainID string, gen consumertypes.GenesisState) error { +func (k Keeper) SetConsumerGenesis(ctx sdk.Context, chainID string, gen ccv.GenesisState) error { store := ctx.KVStore(k.storeKey) bz, err := gen.Marshal() if err != nil { @@ -262,14 +262,14 @@ func (k Keeper) SetConsumerGenesis(ctx sdk.Context, chainID string, gen consumer return nil } -func (k Keeper) GetConsumerGenesis(ctx sdk.Context, chainID string) (consumertypes.GenesisState, bool) { +func (k Keeper) GetConsumerGenesis(ctx sdk.Context, chainID string) (ccv.GenesisState, bool) { store := ctx.KVStore(k.storeKey) bz := store.Get(types.ConsumerGenesisKey(chainID)) if bz == nil { - return consumertypes.GenesisState{}, false + return ccv.GenesisState{}, false } - var data consumertypes.GenesisState + var data ccv.GenesisState if err := data.Unmarshal(bz); err != nil { // An error here would indicate something is very wrong, // the ConsumerGenesis is assumed to be correctly serialized in SetConsumerGenesis. @@ -575,7 +575,7 @@ func (k Keeper) GetMaturedUnbondingOps(ctx sdk.Context) (ids []uint64) { return nil } - var ops ccv.MaturedUnbondingOps + var ops types.MaturedUnbondingOps if err := ops.Unmarshal(bz); err != nil { // An error here would indicate something is very wrong, // the MaturedUnbondingOps are assumed to be correctly serialized in AppendMaturedUnbondingOps. @@ -590,7 +590,7 @@ func (k Keeper) AppendMaturedUnbondingOps(ctx sdk.Context, ids []uint64) { return } existingIds := k.GetMaturedUnbondingOps(ctx) - maturedOps := ccv.MaturedUnbondingOps{ + maturedOps := types.MaturedUnbondingOps{ Ids: append(existingIds, ids...), } @@ -814,7 +814,7 @@ func (k Keeper) DeleteInitChainHeight(ctx sdk.Context, chainID string) { // GetPendingVSCPackets returns the list of pending ValidatorSetChange packets stored under chain ID func (k Keeper) GetPendingVSCPackets(ctx sdk.Context, chainID string) []ccv.ValidatorSetChangePacketData { - var packets ccv.ValidatorSetChangePackets + var packets types.ValidatorSetChangePackets store := ctx.KVStore(k.storeKey) bz := store.Get(types.PendingVSCsKey(chainID)) @@ -835,7 +835,7 @@ func (k Keeper) AppendPendingVSCPackets(ctx sdk.Context, chainID string, newPack pds := append(k.GetPendingVSCPackets(ctx, chainID), newPackets...) store := ctx.KVStore(k.storeKey) - packets := ccv.ValidatorSetChangePackets{List: pds} + packets := types.ValidatorSetChangePackets{List: pds} buf, err := packets.Marshal() if err != nil { // An error here would indicate something is very wrong, diff --git a/x/ccv/provider/keeper/proposal.go b/x/ccv/provider/keeper/proposal.go index 11909ad685..7e4eb557f7 100644 --- a/x/ccv/provider/keeper/proposal.go +++ b/x/ccv/provider/keeper/proposal.go @@ -19,7 +19,6 @@ import ( abci "github.com/cometbft/cometbft/abci/types" tmtypes "github.com/cometbft/cometbft/types" - consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) @@ -239,7 +238,7 @@ func (k Keeper) StopConsumerChain(ctx sdk.Context, chainID string, closeChan boo func (k Keeper) MakeConsumerGenesis( ctx sdk.Context, prop *types.ConsumerAdditionProposal, -) (gen consumertypes.GenesisState, nextValidatorsHash []byte, err error) { +) (gen ccv.GenesisState, nextValidatorsHash []byte, err error) { chainID := prop.ChainId providerUnbondingPeriod := k.stakingKeeper.UnbondingTime(ctx) height := clienttypes.GetSelfHeight(ctx) @@ -302,7 +301,7 @@ func (k Keeper) MakeConsumerGenesis( } hash := tmtypes.NewValidatorSet(updatesAsValSet).Hash() - consumerGenesisParams := consumertypes.NewParams( + consumerGenesisParams := ccv.NewParams( true, prop.BlocksPerDistributionTransmission, prop.DistributionTransmissionChannel, @@ -317,7 +316,7 @@ func (k Keeper) MakeConsumerGenesis( []string{}, ) - gen = *consumertypes.NewInitialGenesisState( + gen = *ccv.NewInitialGenesisState( clientState, consState.(*ibctmtypes.ConsensusState), initialUpdatesWithConsumerKeys, diff --git a/x/ccv/provider/keeper/proposal_test.go b/x/ccv/provider/keeper/proposal_test.go index 0d7085068a..e6b8573e24 100644 --- a/x/ccv/provider/keeper/proposal_test.go +++ b/x/ccv/provider/keeper/proposal_test.go @@ -20,7 +20,6 @@ import ( cryptoutil "github.com/cosmos/interchain-security/v3/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" - consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" providerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" @@ -908,7 +907,7 @@ func TestMakeConsumerGenesis(t *testing.T) { ] }` - var expectedGenesis consumertypes.GenesisState + var expectedGenesis ccvtypes.GenesisState err = json.Unmarshal([]byte(jsonString), &expectedGenesis) // ignores tabs, newlines and spaces require.NoError(t, err) diff --git a/x/ccv/provider/types/consumer.go b/x/ccv/provider/types/consumer.go index 1a13123e88..b9eefc3b45 100644 --- a/x/ccv/provider/types/consumer.go +++ b/x/ccv/provider/types/consumer.go @@ -1,7 +1,6 @@ package types import ( - consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) @@ -10,7 +9,7 @@ func NewConsumerStates( clientID, channelID string, initialHeight uint64, - genesis consumertypes.GenesisState, + genesis ccv.GenesisState, unbondingOpsIndexes []VscUnbondingOps, pendingValsetChanges []ccv.ValidatorSetChangePacketData, slashDowntimeAck []string, diff --git a/x/ccv/provider/types/genesis.go b/x/ccv/provider/types/genesis.go index 2118f3143e..4718de40c1 100644 --- a/x/ccv/provider/types/genesis.go +++ b/x/ccv/provider/types/genesis.go @@ -17,7 +17,7 @@ func NewGenesisState( vscIdToHeights []ValsetUpdateIdToHeight, consumerStates []ConsumerState, unbondingOps []UnbondingOp, - matureUbdOps *ccv.MaturedUnbondingOps, + matureUbdOps *MaturedUnbondingOps, additionProposals []ConsumerAdditionProposal, removalProposals []ConsumerRemovalProposal, params Params, diff --git a/x/ccv/provider/types/genesis.pb.go b/x/ccv/provider/types/genesis.pb.go index ddd7d478b6..fa952b9b13 100644 --- a/x/ccv/provider/types/genesis.pb.go +++ b/x/ccv/provider/types/genesis.pb.go @@ -8,7 +8,6 @@ import ( _ "github.com/cometbft/cometbft/proto/tendermint/crypto" _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/cosmos/gogoproto/proto" - types1 "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" types "github.com/cosmos/interchain-security/v3/x/ccv/types" io "io" math "math" @@ -35,7 +34,7 @@ type GenesisState struct { // empty for a new chain UnbondingOps []UnbondingOp `protobuf:"bytes,3,rep,name=unbonding_ops,json=unbondingOps,proto3" json:"unbonding_ops"` // empty for a new chain - MatureUnbondingOps *types.MaturedUnbondingOps `protobuf:"bytes,4,opt,name=mature_unbonding_ops,json=matureUnbondingOps,proto3" json:"mature_unbonding_ops,omitempty"` + MatureUnbondingOps *MaturedUnbondingOps `protobuf:"bytes,4,opt,name=mature_unbonding_ops,json=matureUnbondingOps,proto3" json:"mature_unbonding_ops,omitempty"` // empty for a new chain ValsetUpdateIdToHeight []ValsetUpdateIdToHeight `protobuf:"bytes,5,rep,name=valset_update_id_to_height,json=valsetUpdateIdToHeight,proto3" json:"valset_update_id_to_height"` // empty for a new chain @@ -107,7 +106,7 @@ func (m *GenesisState) GetUnbondingOps() []UnbondingOp { return nil } -func (m *GenesisState) GetMatureUnbondingOps() *types.MaturedUnbondingOps { +func (m *GenesisState) GetMatureUnbondingOps() *MaturedUnbondingOps { if m != nil { return m.MatureUnbondingOps } @@ -177,7 +176,9 @@ func (m *GenesisState) GetExportedVscSendTimestamps() []ExportedVscSendTimestamp return nil } -// consumer chain +// The provider CCV module's knowledge of consumer state. +// +// Note this type is only used internally to the provider CCV module. type ConsumerState struct { // ChainID defines the chain ID for the consumer chain ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` @@ -188,7 +189,7 @@ type ConsumerState struct { // InitalHeight defines the initial block height for the consumer chain InitialHeight uint64 `protobuf:"varint,4,opt,name=initial_height,json=initialHeight,proto3" json:"initial_height,omitempty"` // ConsumerGenesis defines the initial consumer chain genesis states - ConsumerGenesis types1.GenesisState `protobuf:"bytes,5,opt,name=consumer_genesis,json=consumerGenesis,proto3" json:"consumer_genesis"` + ConsumerGenesis types.GenesisState `protobuf:"bytes,5,opt,name=consumer_genesis,json=consumerGenesis,proto3" json:"consumer_genesis"` // PendingValsetChanges defines the pending validator set changes for the // consumer chain PendingValsetChanges []types.ValidatorSetChangePacketData `protobuf:"bytes,6,rep,name=pending_valset_changes,json=pendingValsetChanges,proto3" json:"pending_valset_changes"` @@ -259,11 +260,11 @@ func (m *ConsumerState) GetInitialHeight() uint64 { return 0 } -func (m *ConsumerState) GetConsumerGenesis() types1.GenesisState { +func (m *ConsumerState) GetConsumerGenesis() types.GenesisState { if m != nil { return m.ConsumerGenesis } - return types1.GenesisState{} + return types.GenesisState{} } func (m *ConsumerState) GetPendingValsetChanges() []types.ValidatorSetChangePacketData { @@ -352,66 +353,66 @@ func init() { } var fileDescriptor_48411d9c7900d48e = []byte{ - // 930 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xdd, 0x6e, 0x23, 0x35, - 0x14, 0xee, 0xb4, 0xd9, 0x6e, 0xe3, 0xfe, 0x50, 0x4c, 0xc9, 0x4e, 0xd3, 0x25, 0x5b, 0x05, 0x90, - 0x2a, 0x01, 0x33, 0xa4, 0xcb, 0x05, 0x7f, 0x7b, 0xb1, 0xdd, 0x45, 0x10, 0x21, 0x44, 0x94, 0x76, - 0x8b, 0xb4, 0x5c, 0x58, 0x8e, 0x6d, 0x25, 0xa6, 0x33, 0xf6, 0x68, 0xec, 0x99, 0x6d, 0x84, 0x90, - 0x58, 0xc1, 0x03, 0xf0, 0x56, 0xec, 0xe5, 0x5e, 0x72, 0xb5, 0x42, 0xed, 0x1b, 0xf0, 0x04, 0x68, - 0x3c, 0x9e, 0xe9, 0x24, 0x24, 0x90, 0x70, 0x95, 0xcc, 0xf9, 0x7c, 0xbe, 0xef, 0x1c, 0x1f, 0xfb, - 0x1c, 0x83, 0x0e, 0x17, 0x9a, 0xc5, 0x64, 0x84, 0xb9, 0x40, 0x8a, 0x91, 0x24, 0xe6, 0x7a, 0xec, - 0x13, 0x92, 0xfa, 0x51, 0x2c, 0x53, 0x4e, 0x59, 0xec, 0xa7, 0x1d, 0x7f, 0xc8, 0x04, 0x53, 0x5c, - 0x79, 0x51, 0x2c, 0xb5, 0x84, 0x6f, 0xcf, 0x70, 0xf1, 0x08, 0x49, 0xbd, 0xc2, 0xc5, 0x4b, 0x3b, - 0xcd, 0xbd, 0xa1, 0x1c, 0x4a, 0xb3, 0xde, 0xcf, 0xfe, 0xe5, 0xae, 0xcd, 0x77, 0xe6, 0xa9, 0xa5, - 0x1d, 0xdf, 0x32, 0x68, 0xd9, 0x3c, 0x5e, 0x24, 0xa6, 0x52, 0xec, 0x3f, 0x7c, 0x88, 0x14, 0x2a, - 0x09, 0x73, 0x9f, 0xe2, 0xbf, 0xf5, 0xe9, 0x2c, 0xe2, 0x33, 0x91, 0x7b, 0xf3, 0xae, 0x66, 0x82, - 0xb2, 0x38, 0xe4, 0x42, 0xfb, 0x24, 0x1e, 0x47, 0x5a, 0xfa, 0x17, 0x6c, 0x6c, 0xd1, 0xf6, 0xef, - 0x9b, 0x60, 0xeb, 0xcb, 0x7c, 0xfd, 0xa9, 0xc6, 0x9a, 0xc1, 0x23, 0xb0, 0x9b, 0xe2, 0x40, 0x31, - 0x8d, 0x92, 0x88, 0x62, 0xcd, 0x10, 0xa7, 0xae, 0x73, 0xe8, 0x1c, 0xd5, 0xfa, 0x3b, 0xb9, 0xfd, - 0x89, 0x31, 0x77, 0x29, 0xfc, 0x11, 0xbc, 0x56, 0xa8, 0x22, 0x95, 0xf9, 0x2a, 0x77, 0xf5, 0x70, - 0xed, 0x68, 0xf3, 0xf8, 0xd8, 0x5b, 0x60, 0xbb, 0xbd, 0x47, 0xd6, 0xd7, 0xc8, 0x9e, 0xb4, 0x5e, - 0xbc, 0xba, 0xb7, 0xf2, 0xd7, 0xab, 0x7b, 0x8d, 0x31, 0x0e, 0x83, 0x4f, 0xdb, 0x53, 0xc4, 0xed, - 0xfe, 0x0e, 0xa9, 0x2e, 0x57, 0xf0, 0x7b, 0xb0, 0x9d, 0x88, 0x81, 0x14, 0x94, 0x8b, 0x21, 0x92, - 0x91, 0x72, 0xd7, 0x8c, 0xf4, 0x87, 0x0b, 0x49, 0x3f, 0x29, 0x3c, 0xbf, 0x8d, 0x4e, 0x6a, 0x99, - 0x70, 0x7f, 0x2b, 0xb9, 0x31, 0x29, 0x88, 0xc1, 0x5e, 0x88, 0x75, 0x12, 0x33, 0x34, 0xa9, 0x51, - 0x3b, 0x74, 0x8e, 0x36, 0x8f, 0xfd, 0xb9, 0x1a, 0x69, 0xc7, 0xfb, 0xc6, 0xf8, 0xd1, 0x8a, 0x82, - 0xea, 0xc3, 0x9c, 0xac, 0x6a, 0x83, 0x3f, 0x81, 0xe6, 0xf4, 0x36, 0x23, 0x2d, 0xd1, 0x88, 0xf1, - 0xe1, 0x48, 0xbb, 0xb7, 0x4c, 0x32, 0x9f, 0x2d, 0x94, 0xcc, 0xf9, 0x44, 0x55, 0xce, 0xe4, 0x57, - 0x86, 0xc2, 0xe6, 0xd5, 0x48, 0x67, 0xa2, 0xf0, 0x17, 0x07, 0x1c, 0x94, 0x7b, 0x8c, 0x29, 0xe5, - 0x9a, 0x4b, 0x81, 0xa2, 0x58, 0x46, 0x52, 0xe1, 0x40, 0xb9, 0xeb, 0x26, 0x80, 0x07, 0x4b, 0x15, - 0xf2, 0xa1, 0xa5, 0xe9, 0x59, 0x16, 0x1b, 0xc2, 0x3e, 0x99, 0x83, 0x2b, 0xf8, 0xb3, 0x03, 0x9a, - 0x65, 0x14, 0x31, 0x0b, 0x65, 0x8a, 0x83, 0x4a, 0x10, 0xb7, 0x4d, 0x10, 0x9f, 0x2f, 0x15, 0x44, - 0x3f, 0x67, 0x99, 0x8a, 0xc1, 0x25, 0xb3, 0x61, 0x05, 0xbb, 0x60, 0x3d, 0xc2, 0x31, 0x0e, 0x95, - 0xbb, 0x61, 0x8a, 0xfb, 0xde, 0x42, 0x6a, 0x3d, 0xe3, 0x62, 0xc9, 0x2d, 0x81, 0xc9, 0x26, 0xc5, - 0x01, 0xa7, 0x58, 0xcb, 0x18, 0x95, 0x79, 0x45, 0xc9, 0x20, 0xbb, 0x6f, 0x6e, 0x7d, 0x89, 0x6c, - 0xce, 0x0b, 0x9a, 0x22, 0xad, 0x5e, 0x32, 0xf8, 0x9a, 0x8d, 0x8b, 0x6c, 0xd2, 0x19, 0x70, 0xa6, - 0x01, 0x9f, 0x3b, 0xe0, 0xa0, 0x04, 0x15, 0x1a, 0x8c, 0x51, 0xb5, 0xc8, 0xb1, 0x0b, 0xfe, 0x4f, - 0x0c, 0x27, 0xe3, 0x4a, 0x85, 0xe3, 0x7f, 0xc4, 0xa0, 0x26, 0x71, 0x98, 0x82, 0x3b, 0x13, 0xa2, - 0x2a, 0x3b, 0xd7, 0x51, 0x9c, 0x08, 0xe6, 0x6e, 0x1a, 0xf9, 0x4f, 0x96, 0x3d, 0x55, 0xb1, 0x3a, - 0x93, 0xbd, 0x8c, 0xc0, 0x6a, 0xef, 0x91, 0x19, 0x18, 0x7c, 0x06, 0xee, 0x70, 0xc1, 0x35, 0xd2, - 0x3c, 0x64, 0x32, 0xc9, 0x7f, 0x95, 0xc6, 0x61, 0xa4, 0xdc, 0xad, 0x25, 0x74, 0xbb, 0x82, 0xeb, - 0xb3, 0x9c, 0xe2, 0xac, 0x60, 0xb0, 0xba, 0x6f, 0xf2, 0x19, 0x98, 0x82, 0xbf, 0x3a, 0xe0, 0x2e, - 0xbb, 0x8c, 0x64, 0xac, 0x19, 0x45, 0xa9, 0x22, 0x48, 0x31, 0x41, 0xab, 0xf2, 0xdb, 0x4b, 0x5c, - 0xa6, 0x2f, 0x2c, 0xd1, 0xb9, 0x22, 0xa7, 0x4c, 0xd0, 0xe9, 0x10, 0xf6, 0xd9, 0x1c, 0x5c, 0xb5, - 0x9f, 0xd7, 0xc0, 0xf6, 0x44, 0x4f, 0x85, 0xfb, 0x60, 0x23, 0x57, 0xb3, 0x2d, 0xbc, 0xde, 0xbf, - 0x6d, 0xbe, 0xbb, 0x14, 0xbe, 0x05, 0x00, 0x19, 0x61, 0x21, 0x58, 0x90, 0x81, 0xab, 0x06, 0xac, - 0x5b, 0x4b, 0x97, 0xc2, 0x03, 0x50, 0x27, 0x01, 0x67, 0x42, 0x67, 0xe8, 0x9a, 0x41, 0x37, 0x72, - 0x43, 0x97, 0xc2, 0x77, 0xc1, 0x4e, 0xb6, 0x11, 0x1c, 0x07, 0x45, 0xbb, 0xaa, 0x99, 0xf9, 0xb0, - 0x6d, 0xad, 0xb6, 0xc5, 0x0c, 0xc0, 0x6e, 0x79, 0x0e, 0xec, 0x44, 0x72, 0x6f, 0x99, 0x3b, 0xd6, - 0x99, 0xbb, 0x13, 0xe5, 0xb4, 0x4b, 0x3b, 0x5e, 0x75, 0x2a, 0xd9, 0xec, 0xcb, 0x79, 0x63, 0x31, - 0xa8, 0x41, 0x23, 0x62, 0x79, 0x7f, 0xb6, 0xdd, 0x34, 0xcb, 0x61, 0xc8, 0x8a, 0x06, 0xf6, 0xf1, - 0xbf, 0xb5, 0xea, 0xf2, 0x80, 0x9f, 0x32, 0xfd, 0xc8, 0xb8, 0xf5, 0x30, 0xb9, 0x60, 0xfa, 0x31, - 0xd6, 0xb8, 0x38, 0x69, 0x96, 0x3d, 0xef, 0xb1, 0xf9, 0x22, 0x05, 0xdf, 0x07, 0x50, 0x05, 0x58, - 0x8d, 0x10, 0x95, 0xcf, 0x44, 0x56, 0x67, 0x84, 0xc9, 0x85, 0xe9, 0x56, 0xf5, 0xfe, 0xae, 0x41, - 0x1e, 0x5b, 0xe0, 0x21, 0xb9, 0x80, 0x3f, 0x80, 0x37, 0x26, 0xa6, 0x08, 0xe2, 0x82, 0xb2, 0x4b, - 0x77, 0xc3, 0x04, 0xf8, 0xd1, 0x62, 0x57, 0x51, 0x91, 0xea, 0xf0, 0xb0, 0xc1, 0xbd, 0x5e, 0x9d, - 0x59, 0xdd, 0x8c, 0xb4, 0xfd, 0x14, 0x34, 0x66, 0x8f, 0x83, 0x25, 0xc6, 0x7a, 0x03, 0xac, 0xdb, - 0xb2, 0xae, 0x1a, 0xdc, 0x7e, 0x9d, 0x7c, 0xf7, 0xe2, 0xaa, 0xe5, 0xbc, 0xbc, 0x6a, 0x39, 0x7f, - 0x5e, 0xb5, 0x9c, 0xdf, 0xae, 0x5b, 0x2b, 0x2f, 0xaf, 0x5b, 0x2b, 0x7f, 0x5c, 0xb7, 0x56, 0x9e, - 0x3e, 0x18, 0x72, 0x3d, 0x4a, 0x06, 0x1e, 0x91, 0xa1, 0x4f, 0xa4, 0x0a, 0xa5, 0xf2, 0x6f, 0xb2, - 0xfa, 0xa0, 0x7c, 0xa6, 0xa4, 0xf7, 0xfd, 0xcb, 0xc9, 0x37, 0x91, 0x1e, 0x47, 0x4c, 0x0d, 0xd6, - 0xcd, 0x4b, 0xe4, 0xfe, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x4d, 0xe2, 0xfe, 0x45, 0xd8, 0x09, - 0x00, 0x00, + // 929 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xcd, 0x6e, 0x1b, 0x37, + 0x17, 0xf5, 0xd8, 0x8e, 0x63, 0xd1, 0x3f, 0x9f, 0x3f, 0xd6, 0x55, 0xc6, 0x76, 0xaa, 0x18, 0x2a, + 0x02, 0x08, 0x68, 0xab, 0x89, 0x9c, 0x2e, 0xd2, 0x9f, 0x2c, 0xe2, 0xa4, 0x68, 0x85, 0xa2, 0xa8, + 0x20, 0x3b, 0x2e, 0x9a, 0x2e, 0x08, 0x8a, 0x24, 0x24, 0xc6, 0x33, 0xe4, 0x80, 0xe4, 0x8c, 0x2d, + 0x14, 0x05, 0x5a, 0xb4, 0x0f, 0xd0, 0xc7, 0xca, 0xd2, 0xcb, 0xae, 0x82, 0xc2, 0x7e, 0x83, 0xae, + 0xba, 0x2c, 0x86, 0xc3, 0x99, 0x8c, 0x5c, 0x39, 0x90, 0xba, 0xb2, 0xc5, 0xc3, 0x7b, 0xce, 0xb9, + 0xbc, 0xe4, 0xbd, 0x03, 0x3a, 0x5c, 0x18, 0xa6, 0xc8, 0x08, 0x73, 0x81, 0x34, 0x23, 0x89, 0xe2, + 0x66, 0x1c, 0x10, 0x92, 0x06, 0xb1, 0x92, 0x29, 0xa7, 0x4c, 0x05, 0x69, 0x27, 0x18, 0x32, 0xc1, + 0x34, 0xd7, 0xed, 0x58, 0x49, 0x23, 0xe1, 0xfb, 0x53, 0x42, 0xda, 0x84, 0xa4, 0xed, 0x22, 0xa4, + 0x9d, 0x76, 0x76, 0xb7, 0x87, 0x72, 0x28, 0xed, 0xfe, 0x20, 0xfb, 0x2f, 0x0f, 0xdd, 0x7d, 0x70, + 0x93, 0x5a, 0xda, 0x09, 0xf4, 0x08, 0x2b, 0x46, 0x11, 0x91, 0x42, 0x27, 0x11, 0x53, 0x2e, 0xe2, + 0xfe, 0x5b, 0x22, 0xce, 0xb8, 0x62, 0x6e, 0xdb, 0xc1, 0x2c, 0x69, 0x94, 0xfe, 0xf2, 0x98, 0xbb, + 0x86, 0x09, 0xca, 0x54, 0xc4, 0x85, 0x09, 0x88, 0x1a, 0xc7, 0x46, 0x06, 0xa7, 0x6c, 0xec, 0xb2, + 0x6c, 0x5e, 0xac, 0x81, 0xf5, 0x2f, 0xf3, 0xbc, 0x8f, 0x0c, 0x36, 0x0c, 0xb6, 0xc0, 0x56, 0x8a, + 0x43, 0xcd, 0x0c, 0x4a, 0x62, 0x8a, 0x0d, 0x43, 0x9c, 0xfa, 0xde, 0xbe, 0xd7, 0x5a, 0xee, 0x6f, + 0xe6, 0xeb, 0xcf, 0xed, 0x72, 0x97, 0xc2, 0x1f, 0xc1, 0xff, 0x8a, 0x2c, 0x90, 0xce, 0x62, 0xb5, + 0xbf, 0xb8, 0xbf, 0xd4, 0x5a, 0x3b, 0x38, 0x68, 0xcf, 0x70, 0x74, 0xed, 0xa7, 0x2e, 0xd6, 0xca, + 0x1e, 0x36, 0x5e, 0xbd, 0xbe, 0xb7, 0xf0, 0xd7, 0xeb, 0x7b, 0xf5, 0x31, 0x8e, 0xc2, 0x4f, 0x9b, + 0xd7, 0x88, 0x9b, 0xfd, 0x4d, 0x52, 0xdd, 0xae, 0xe1, 0x0f, 0x60, 0x23, 0x11, 0x03, 0x29, 0x28, + 0x17, 0x43, 0x24, 0x63, 0xed, 0x2f, 0x59, 0xe9, 0x07, 0x33, 0x49, 0x3f, 0x2f, 0x22, 0xbf, 0x8d, + 0x0f, 0x97, 0x33, 0xe1, 0xfe, 0x7a, 0xf2, 0x66, 0x49, 0xc3, 0x97, 0x60, 0x3b, 0xc2, 0x26, 0x51, + 0x0c, 0x4d, 0x6a, 0x2c, 0xef, 0x7b, 0xad, 0xb5, 0x83, 0x47, 0x33, 0x69, 0x7c, 0x63, 0x09, 0x68, + 0x45, 0x4a, 0xf7, 0x61, 0xce, 0x5a, 0x5d, 0x83, 0x3f, 0x81, 0xdd, 0xeb, 0xe7, 0x8d, 0x8c, 0x44, + 0x23, 0xc6, 0x87, 0x23, 0xe3, 0xdf, 0xb2, 0x59, 0x7d, 0x36, 0x93, 0xe2, 0xc9, 0x44, 0x79, 0x8e, + 0xe5, 0x57, 0x96, 0xc2, 0x25, 0x58, 0x4f, 0xa7, 0xa2, 0xf0, 0x57, 0x0f, 0xec, 0x95, 0x87, 0x8d, + 0x29, 0xe5, 0x86, 0x4b, 0x81, 0x62, 0x25, 0x63, 0xa9, 0x71, 0xa8, 0xfd, 0x15, 0x6b, 0xe0, 0xf1, + 0x5c, 0x15, 0x7d, 0xe2, 0x68, 0x7a, 0x8e, 0xc5, 0x59, 0xd8, 0x21, 0x37, 0xe0, 0x1a, 0xfe, 0xec, + 0x81, 0xdd, 0xd2, 0x85, 0x62, 0x91, 0x4c, 0x71, 0x58, 0x31, 0x71, 0xdb, 0x9a, 0xf8, 0x7c, 0x2e, + 0x13, 0xfd, 0x9c, 0xe5, 0x9a, 0x07, 0x9f, 0x4c, 0x87, 0x35, 0xec, 0x82, 0x95, 0x18, 0x2b, 0x1c, + 0x69, 0x7f, 0xd5, 0x56, 0xf9, 0x83, 0x99, 0xd4, 0x7a, 0x36, 0xc4, 0x91, 0x3b, 0x02, 0x9b, 0x4d, + 0x8a, 0x43, 0x4e, 0xb1, 0x91, 0xaa, 0x7c, 0xe9, 0x28, 0x4e, 0x06, 0xd9, 0xc3, 0xf3, 0x6b, 0x73, + 0x64, 0x73, 0x52, 0xd0, 0x14, 0x69, 0xf5, 0x92, 0xc1, 0xd7, 0x6c, 0x5c, 0x64, 0x93, 0x4e, 0x81, + 0x33, 0x0d, 0xf8, 0x8b, 0x07, 0xf6, 0x4a, 0x50, 0xa3, 0xc1, 0x18, 0x55, 0x8b, 0xac, 0x7c, 0xf0, + 0x5f, 0x3c, 0x1c, 0x8e, 0x2b, 0x15, 0x56, 0xff, 0xf2, 0xa0, 0x27, 0x71, 0x98, 0x82, 0x3b, 0x13, + 0xa2, 0x3a, 0xbb, 0xd7, 0xb1, 0x4a, 0x04, 0xf3, 0xd7, 0xac, 0xfc, 0x27, 0xf3, 0xde, 0x2a, 0xa5, + 0x8f, 0x65, 0x2f, 0x23, 0x70, 0xda, 0xdb, 0x64, 0x0a, 0x06, 0xcf, 0xc0, 0x1d, 0x2e, 0xb8, 0x41, + 0x86, 0x47, 0x4c, 0x26, 0xf9, 0x5f, 0x6d, 0x70, 0x14, 0x6b, 0x7f, 0x7d, 0x0e, 0xdd, 0xae, 0xe0, + 0xe6, 0x38, 0xa7, 0x38, 0x2e, 0x18, 0x9c, 0xee, 0xbb, 0x7c, 0x0a, 0xa6, 0xe1, 0x6f, 0x1e, 0xb8, + 0xcb, 0xce, 0x63, 0xa9, 0x0c, 0xa3, 0x28, 0xd5, 0x04, 0x69, 0x26, 0x68, 0x55, 0x7e, 0x63, 0x8e, + 0xc7, 0xf4, 0x85, 0x23, 0x3a, 0xd1, 0xe4, 0x88, 0x09, 0x7a, 0xdd, 0xc2, 0x0e, 0xbb, 0x01, 0xd7, + 0xcd, 0xbf, 0x97, 0xc0, 0xc6, 0x44, 0x73, 0x85, 0x3b, 0x60, 0x35, 0x57, 0x73, 0xbd, 0xbc, 0xd6, + 0xbf, 0x6d, 0x7f, 0x77, 0x29, 0x7c, 0x0f, 0x00, 0x32, 0xc2, 0x42, 0xb0, 0x30, 0x03, 0x17, 0x2d, + 0x58, 0x73, 0x2b, 0x5d, 0x0a, 0xf7, 0x40, 0x8d, 0x84, 0x9c, 0x09, 0x93, 0xa1, 0x4b, 0x16, 0x5d, + 0xcd, 0x17, 0xba, 0x14, 0xde, 0x07, 0x9b, 0xd9, 0x41, 0x70, 0x1c, 0x16, 0xed, 0x6a, 0xd9, 0x0e, + 0x8a, 0x0d, 0xb7, 0xea, 0x5a, 0xcc, 0xf7, 0x60, 0xab, 0xbc, 0x07, 0x6e, 0xc4, 0xfa, 0xb7, 0xec, + 0x1b, 0x6b, 0xdd, 0x78, 0x12, 0x69, 0xa7, 0x5d, 0x9d, 0x4a, 0x2e, 0xe9, 0x72, 0xde, 0x38, 0x0c, + 0x1a, 0x50, 0x8f, 0x59, 0xde, 0x9f, 0x5d, 0x13, 0xcd, 0xac, 0x0f, 0x59, 0xd1, 0xb7, 0x1e, 0xbd, + 0x4d, 0xa0, 0xbc, 0xd7, 0x47, 0xcc, 0x3c, 0xb5, 0x61, 0x3d, 0x4c, 0x4e, 0x99, 0x79, 0x86, 0x0d, + 0x2e, 0x2e, 0x98, 0x63, 0xcf, 0x5b, 0x6b, 0xbe, 0x49, 0xc3, 0x0f, 0x01, 0xd4, 0x21, 0xd6, 0x23, + 0x44, 0xe5, 0x99, 0xc8, 0xca, 0x8b, 0x30, 0x39, 0xb5, 0x4d, 0xaa, 0xd6, 0xdf, 0xb2, 0xc8, 0x33, + 0x07, 0x3c, 0x21, 0xa7, 0xf0, 0x25, 0x78, 0x67, 0x62, 0x8a, 0x20, 0x2e, 0x28, 0x3b, 0xf7, 0x57, + 0xad, 0xc1, 0x8f, 0x67, 0x7b, 0x81, 0x9a, 0x54, 0x67, 0x86, 0x33, 0xf7, 0xff, 0xea, 0xcc, 0xea, + 0x66, 0xa4, 0xcd, 0x17, 0xa0, 0x3e, 0x7d, 0x0a, 0xcc, 0x31, 0xd6, 0xeb, 0x60, 0xc5, 0x55, 0x73, + 0xd1, 0xe2, 0xee, 0xd7, 0xe1, 0x77, 0xaf, 0x2e, 0x1b, 0xde, 0xc5, 0x65, 0xc3, 0xfb, 0xf3, 0xb2, + 0xe1, 0xfd, 0x7e, 0xd5, 0x58, 0xb8, 0xb8, 0x6a, 0x2c, 0xfc, 0x71, 0xd5, 0x58, 0x78, 0xf1, 0x78, + 0xc8, 0xcd, 0x28, 0x19, 0xb4, 0x89, 0x8c, 0x02, 0x22, 0x75, 0x24, 0x75, 0xf0, 0x26, 0xab, 0x8f, + 0xca, 0xef, 0x94, 0xf4, 0x61, 0x70, 0x3e, 0xf9, 0xb1, 0x62, 0xc6, 0x31, 0xd3, 0x83, 0x15, 0xfb, + 0x25, 0xf2, 0xf0, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x76, 0xce, 0xb9, 0x61, 0xa4, 0x09, 0x00, + 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -1033,7 +1034,7 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { return io.ErrUnexpectedEOF } if m.MatureUnbondingOps == nil { - m.MatureUnbondingOps = &types.MaturedUnbondingOps{} + m.MatureUnbondingOps = &MaturedUnbondingOps{} } if err := m.MatureUnbondingOps.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err diff --git a/x/ccv/provider/types/genesis_test.go b/x/ccv/provider/types/genesis_test.go index c4b5002f07..aba1a72e0e 100644 --- a/x/ccv/provider/types/genesis_test.go +++ b/x/ccv/provider/types/genesis_test.go @@ -15,7 +15,6 @@ import ( tmtypes "github.com/cometbft/cometbft/types" "github.com/cosmos/interchain-security/v3/testutil/crypto" - consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) @@ -453,7 +452,7 @@ func TestValidateGenesisState(t *testing.T) { nil, []types.ConsumerState{{ ChainId: "chainid", ChannelId: "channel-0", ClientId: "client-id", - ConsumerGenesis: consumertypes.GenesisState{}, + ConsumerGenesis: ccv.GenesisState{}, }}, nil, nil, @@ -758,7 +757,7 @@ func TestValidateGenesisState(t *testing.T) { } } -func getInitialConsumerGenesis(t *testing.T, chainID string) consumertypes.GenesisState { +func getInitialConsumerGenesis(t *testing.T, chainID string) ccv.GenesisState { t.Helper() // generate validator public key cId := crypto.NewCryptoIdentityFromIntSeed(239668) @@ -781,7 +780,7 @@ func getInitialConsumerGenesis(t *testing.T, chainID string) consumertypes.Genes []string{"upgrade", "upgradedIBCState"}) consensusState := ibctmtypes.NewConsensusState(time.Now(), commitmenttypes.NewMerkleRoot([]byte("apphash")), valHash) - params := consumertypes.DefaultParams() + params := ccv.DefaultParams() params.Enabled = true - return *consumertypes.NewInitialGenesisState(cs, consensusState, valUpdates, params) + return *ccv.NewInitialGenesisState(cs, consensusState, valUpdates, params) } diff --git a/x/ccv/provider/types/params.go b/x/ccv/provider/types/params.go index 515d8954ec..afb46694a3 100644 --- a/x/ccv/provider/types/params.go +++ b/x/ccv/provider/types/params.go @@ -11,7 +11,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) @@ -178,13 +177,13 @@ func ValidateTemplateClient(i interface{}) error { // populate zeroed fields with valid fields copiedClient.ChainId = "chainid" - trustPeriod, err := ccvtypes.CalculateTrustPeriod(consumertypes.DefaultConsumerUnbondingPeriod, DefaultTrustingPeriodFraction) + trustPeriod, err := ccvtypes.CalculateTrustPeriod(ccvtypes.DefaultConsumerUnbondingPeriod, DefaultTrustingPeriodFraction) if err != nil { return fmt.Errorf("invalid TrustPeriodFraction: %T", err) } copiedClient.TrustingPeriod = trustPeriod - copiedClient.UnbondingPeriod = consumertypes.DefaultConsumerUnbondingPeriod + copiedClient.UnbondingPeriod = ccvtypes.DefaultConsumerUnbondingPeriod copiedClient.LatestHeight = clienttypes.NewHeight(0, 1) if err := copiedClient.Validate(); err != nil { diff --git a/x/ccv/provider/types/provider.pb.go b/x/ccv/provider/types/provider.pb.go index 30dba16cdc..398010307c 100644 --- a/x/ccv/provider/types/provider.pb.go +++ b/x/ccv/provider/types/provider.pb.go @@ -13,6 +13,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/v3/x/ccv/types" _ "google.golang.org/protobuf/types/known/durationpb" _ "google.golang.org/protobuf/types/known/timestamppb" io "io" @@ -200,6 +201,10 @@ func (m *ConsumerRemovalProposal) GetStopTime() time.Time { return time.Time{} } +// EquivocationProposal is a governance proposal on the provider chain to +// punish a validator for equivocation on a consumer chain. +// +// This type is only used internally to the consumer CCV module. type EquivocationProposal struct { // the title of the proposal Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` @@ -469,60 +474,8 @@ func (m *Params) GetConsumerRewardDenomRegistrationFee() types2.Coin { return types2.Coin{} } -type HandshakeMetadata struct { - ProviderFeePoolAddr string `protobuf:"bytes,1,opt,name=provider_fee_pool_addr,json=providerFeePoolAddr,proto3" json:"provider_fee_pool_addr,omitempty"` - Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"` -} - -func (m *HandshakeMetadata) Reset() { *m = HandshakeMetadata{} } -func (m *HandshakeMetadata) String() string { return proto.CompactTextString(m) } -func (*HandshakeMetadata) ProtoMessage() {} -func (*HandshakeMetadata) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{5} -} -func (m *HandshakeMetadata) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *HandshakeMetadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_HandshakeMetadata.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 *HandshakeMetadata) XXX_Merge(src proto.Message) { - xxx_messageInfo_HandshakeMetadata.Merge(m, src) -} -func (m *HandshakeMetadata) XXX_Size() int { - return m.Size() -} -func (m *HandshakeMetadata) XXX_DiscardUnknown() { - xxx_messageInfo_HandshakeMetadata.DiscardUnknown(m) -} - -var xxx_messageInfo_HandshakeMetadata proto.InternalMessageInfo - -func (m *HandshakeMetadata) GetProviderFeePoolAddr() string { - if m != nil { - return m.ProviderFeePoolAddr - } - return "" -} - -func (m *HandshakeMetadata) GetVersion() string { - if m != nil { - return m.Version - } - return "" -} - // SlashAcks contains cons addresses of consumer chain validators -// successfully slashed on the provider chain +// successfully slashed on the provider chain. type SlashAcks struct { Addresses []string `protobuf:"bytes,1,rep,name=addresses,proto3" json:"addresses,omitempty"` } @@ -531,7 +484,7 @@ func (m *SlashAcks) Reset() { *m = SlashAcks{} } func (m *SlashAcks) String() string { return proto.CompactTextString(m) } func (*SlashAcks) ProtoMessage() {} func (*SlashAcks) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{6} + return fileDescriptor_f22ec409a72b7b72, []int{5} } func (m *SlashAcks) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -578,7 +531,7 @@ func (m *ConsumerAdditionProposals) Reset() { *m = ConsumerAdditionPropo func (m *ConsumerAdditionProposals) String() string { return proto.CompactTextString(m) } func (*ConsumerAdditionProposals) ProtoMessage() {} func (*ConsumerAdditionProposals) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{7} + return fileDescriptor_f22ec409a72b7b72, []int{6} } func (m *ConsumerAdditionProposals) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -625,7 +578,7 @@ func (m *ConsumerRemovalProposals) Reset() { *m = ConsumerRemovalProposa func (m *ConsumerRemovalProposals) String() string { return proto.CompactTextString(m) } func (*ConsumerRemovalProposals) ProtoMessage() {} func (*ConsumerRemovalProposals) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{8} + return fileDescriptor_f22ec409a72b7b72, []int{7} } func (m *ConsumerRemovalProposals) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -670,7 +623,7 @@ func (m *AddressList) Reset() { *m = AddressList{} } func (m *AddressList) String() string { return proto.CompactTextString(m) } func (*AddressList) ProtoMessage() {} func (*AddressList) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{9} + return fileDescriptor_f22ec409a72b7b72, []int{8} } func (m *AddressList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -715,7 +668,7 @@ func (m *ChannelToChain) Reset() { *m = ChannelToChain{} } func (m *ChannelToChain) String() string { return proto.CompactTextString(m) } func (*ChannelToChain) ProtoMessage() {} func (*ChannelToChain) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{10} + return fileDescriptor_f22ec409a72b7b72, []int{9} } func (m *ChannelToChain) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -769,7 +722,7 @@ func (m *VscUnbondingOps) Reset() { *m = VscUnbondingOps{} } func (m *VscUnbondingOps) String() string { return proto.CompactTextString(m) } func (*VscUnbondingOps) ProtoMessage() {} func (*VscUnbondingOps) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{11} + return fileDescriptor_f22ec409a72b7b72, []int{10} } func (m *VscUnbondingOps) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -824,7 +777,7 @@ func (m *UnbondingOp) Reset() { *m = UnbondingOp{} } func (m *UnbondingOp) String() string { return proto.CompactTextString(m) } func (*UnbondingOp) ProtoMessage() {} func (*UnbondingOp) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{12} + return fileDescriptor_f22ec409a72b7b72, []int{11} } func (m *UnbondingOp) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -876,7 +829,7 @@ func (m *InitTimeoutTimestamp) Reset() { *m = InitTimeoutTimestamp{} } func (m *InitTimeoutTimestamp) String() string { return proto.CompactTextString(m) } func (*InitTimeoutTimestamp) ProtoMessage() {} func (*InitTimeoutTimestamp) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{13} + return fileDescriptor_f22ec409a72b7b72, []int{12} } func (m *InitTimeoutTimestamp) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -928,7 +881,7 @@ func (m *VscSendTimestamp) Reset() { *m = VscSendTimestamp{} } func (m *VscSendTimestamp) String() string { return proto.CompactTextString(m) } func (*VscSendTimestamp) ProtoMessage() {} func (*VscSendTimestamp) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{14} + return fileDescriptor_f22ec409a72b7b72, []int{13} } func (m *VscSendTimestamp) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -971,6 +924,97 @@ func (m *VscSendTimestamp) GetTimestamp() time.Time { return time.Time{} } +// ValidatorSetChangePackets is a pb list of ccv.ValidatorSetChangePacketData. +type ValidatorSetChangePackets struct { + List []types3.ValidatorSetChangePacketData `protobuf:"bytes,1,rep,name=list,proto3" json:"list"` +} + +func (m *ValidatorSetChangePackets) Reset() { *m = ValidatorSetChangePackets{} } +func (m *ValidatorSetChangePackets) String() string { return proto.CompactTextString(m) } +func (*ValidatorSetChangePackets) ProtoMessage() {} +func (*ValidatorSetChangePackets) Descriptor() ([]byte, []int) { + return fileDescriptor_f22ec409a72b7b72, []int{14} +} +func (m *ValidatorSetChangePackets) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ValidatorSetChangePackets) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ValidatorSetChangePackets.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 *ValidatorSetChangePackets) XXX_Merge(src proto.Message) { + xxx_messageInfo_ValidatorSetChangePackets.Merge(m, src) +} +func (m *ValidatorSetChangePackets) XXX_Size() int { + return m.Size() +} +func (m *ValidatorSetChangePackets) XXX_DiscardUnknown() { + xxx_messageInfo_ValidatorSetChangePackets.DiscardUnknown(m) +} + +var xxx_messageInfo_ValidatorSetChangePackets proto.InternalMessageInfo + +func (m *ValidatorSetChangePackets) GetList() []types3.ValidatorSetChangePacketData { + if m != nil { + return m.List + } + return nil +} + +// MaturedUnbondingOps defines a list of ids corresponding to ids of matured +// unbonding operations. +type MaturedUnbondingOps struct { + Ids []uint64 `protobuf:"varint,1,rep,packed,name=ids,proto3" json:"ids,omitempty"` +} + +func (m *MaturedUnbondingOps) Reset() { *m = MaturedUnbondingOps{} } +func (m *MaturedUnbondingOps) String() string { return proto.CompactTextString(m) } +func (*MaturedUnbondingOps) ProtoMessage() {} +func (*MaturedUnbondingOps) Descriptor() ([]byte, []int) { + return fileDescriptor_f22ec409a72b7b72, []int{15} +} +func (m *MaturedUnbondingOps) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MaturedUnbondingOps) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MaturedUnbondingOps.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 *MaturedUnbondingOps) XXX_Merge(src proto.Message) { + xxx_messageInfo_MaturedUnbondingOps.Merge(m, src) +} +func (m *MaturedUnbondingOps) XXX_Size() int { + return m.Size() +} +func (m *MaturedUnbondingOps) XXX_DiscardUnknown() { + xxx_messageInfo_MaturedUnbondingOps.DiscardUnknown(m) +} + +var xxx_messageInfo_MaturedUnbondingOps proto.InternalMessageInfo + +func (m *MaturedUnbondingOps) GetIds() []uint64 { + if m != nil { + return m.Ids + } + return nil +} + // ExportedVscSendTimestamps is VscSendTimestamp with chainID info for exporting to genesis type ExportedVscSendTimestamp struct { ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` @@ -981,7 +1025,7 @@ func (m *ExportedVscSendTimestamp) Reset() { *m = ExportedVscSendTimesta func (m *ExportedVscSendTimestamp) String() string { return proto.CompactTextString(m) } func (*ExportedVscSendTimestamp) ProtoMessage() {} func (*ExportedVscSendTimestamp) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{15} + return fileDescriptor_f22ec409a72b7b72, []int{16} } func (m *ExportedVscSendTimestamp) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1034,7 +1078,7 @@ func (m *KeyAssignmentReplacement) Reset() { *m = KeyAssignmentReplaceme func (m *KeyAssignmentReplacement) String() string { return proto.CompactTextString(m) } func (*KeyAssignmentReplacement) ProtoMessage() {} func (*KeyAssignmentReplacement) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{16} + return fileDescriptor_f22ec409a72b7b72, []int{17} } func (m *KeyAssignmentReplacement) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1097,7 +1141,7 @@ func (m *ValidatorConsumerPubKey) Reset() { *m = ValidatorConsumerPubKey func (m *ValidatorConsumerPubKey) String() string { return proto.CompactTextString(m) } func (*ValidatorConsumerPubKey) ProtoMessage() {} func (*ValidatorConsumerPubKey) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{17} + return fileDescriptor_f22ec409a72b7b72, []int{18} } func (m *ValidatorConsumerPubKey) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1160,7 +1204,7 @@ func (m *ValidatorByConsumerAddr) Reset() { *m = ValidatorByConsumerAddr func (m *ValidatorByConsumerAddr) String() string { return proto.CompactTextString(m) } func (*ValidatorByConsumerAddr) ProtoMessage() {} func (*ValidatorByConsumerAddr) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{18} + return fileDescriptor_f22ec409a72b7b72, []int{19} } func (m *ValidatorByConsumerAddr) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1222,7 +1266,7 @@ func (m *ConsumerAddrsToPrune) Reset() { *m = ConsumerAddrsToPrune{} } func (m *ConsumerAddrsToPrune) String() string { return proto.CompactTextString(m) } func (*ConsumerAddrsToPrune) ProtoMessage() {} func (*ConsumerAddrsToPrune) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{19} + return fileDescriptor_f22ec409a72b7b72, []int{20} } func (m *ConsumerAddrsToPrune) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1278,7 +1322,6 @@ func init() { proto.RegisterType((*EquivocationProposal)(nil), "interchain_security.ccv.provider.v1.EquivocationProposal") proto.RegisterType((*GlobalSlashEntry)(nil), "interchain_security.ccv.provider.v1.GlobalSlashEntry") proto.RegisterType((*Params)(nil), "interchain_security.ccv.provider.v1.Params") - proto.RegisterType((*HandshakeMetadata)(nil), "interchain_security.ccv.provider.v1.HandshakeMetadata") proto.RegisterType((*SlashAcks)(nil), "interchain_security.ccv.provider.v1.SlashAcks") proto.RegisterType((*ConsumerAdditionProposals)(nil), "interchain_security.ccv.provider.v1.ConsumerAdditionProposals") proto.RegisterType((*ConsumerRemovalProposals)(nil), "interchain_security.ccv.provider.v1.ConsumerRemovalProposals") @@ -1288,6 +1331,8 @@ func init() { proto.RegisterType((*UnbondingOp)(nil), "interchain_security.ccv.provider.v1.UnbondingOp") proto.RegisterType((*InitTimeoutTimestamp)(nil), "interchain_security.ccv.provider.v1.InitTimeoutTimestamp") proto.RegisterType((*VscSendTimestamp)(nil), "interchain_security.ccv.provider.v1.VscSendTimestamp") + proto.RegisterType((*ValidatorSetChangePackets)(nil), "interchain_security.ccv.provider.v1.ValidatorSetChangePackets") + proto.RegisterType((*MaturedUnbondingOps)(nil), "interchain_security.ccv.provider.v1.MaturedUnbondingOps") proto.RegisterType((*ExportedVscSendTimestamp)(nil), "interchain_security.ccv.provider.v1.ExportedVscSendTimestamp") proto.RegisterType((*KeyAssignmentReplacement)(nil), "interchain_security.ccv.provider.v1.KeyAssignmentReplacement") proto.RegisterType((*ValidatorConsumerPubKey)(nil), "interchain_security.ccv.provider.v1.ValidatorConsumerPubKey") @@ -1300,110 +1345,112 @@ func init() { } var fileDescriptor_f22ec409a72b7b72 = []byte{ - // 1645 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0x4d, 0x73, 0x1b, 0xc7, - 0xd1, 0xe6, 0x12, 0xfc, 0xc2, 0x80, 0x1f, 0xe2, 0x92, 0xb2, 0x96, 0x7a, 0xf9, 0x82, 0xd0, 0x3a, - 0x71, 0x31, 0xe5, 0xf2, 0x22, 0xa4, 0x2a, 0x55, 0x29, 0x55, 0x5c, 0x2e, 0x12, 0x92, 0x2c, 0x9a, - 0xb1, 0x05, 0x2f, 0x19, 0xaa, 0x92, 0x1c, 0xb6, 0x66, 0x67, 0x5b, 0xc0, 0x14, 0x77, 0x77, 0x56, - 0x33, 0x83, 0x95, 0x70, 0xc9, 0x39, 0x47, 0xe7, 0xe6, 0x4a, 0x2e, 0x4e, 0xfe, 0x40, 0xfe, 0x86, - 0x8f, 0x3e, 0xe6, 0x64, 0xa7, 0xa4, 0x43, 0x0e, 0xf9, 0x13, 0xa9, 0x99, 0xfd, 0x04, 0x48, 0x2a, - 0x50, 0x25, 0xb9, 0xed, 0xf4, 0x74, 0x3f, 0xdd, 0x3d, 0xd3, 0xfd, 0xf4, 0x00, 0xe8, 0x90, 0xc6, - 0x12, 0x38, 0x19, 0x62, 0x1a, 0x7b, 0x02, 0xc8, 0x88, 0x53, 0x39, 0xee, 0x12, 0x92, 0x76, 0x13, - 0xce, 0x52, 0x1a, 0x00, 0xef, 0xa6, 0x07, 0xe5, 0xb7, 0x93, 0x70, 0x26, 0x99, 0xf9, 0xfe, 0x35, - 0x36, 0x0e, 0x21, 0xa9, 0x53, 0xea, 0xa5, 0x07, 0x77, 0xb7, 0x07, 0x6c, 0xc0, 0xb4, 0x7e, 0x57, - 0x7d, 0x65, 0xa6, 0x77, 0xf7, 0x06, 0x8c, 0x0d, 0x42, 0xe8, 0xea, 0x95, 0x3f, 0x7a, 0xde, 0x95, - 0x34, 0x02, 0x21, 0x71, 0x94, 0xe4, 0x0a, 0xed, 0x69, 0x85, 0x60, 0xc4, 0xb1, 0xa4, 0x2c, 0x2e, - 0x00, 0xa8, 0x4f, 0xba, 0x84, 0x71, 0xe8, 0x92, 0x90, 0x42, 0x2c, 0x55, 0x78, 0xd9, 0x57, 0xae, - 0xd0, 0x55, 0x0a, 0x21, 0x1d, 0x0c, 0x65, 0x26, 0x16, 0x5d, 0x09, 0x71, 0x00, 0x3c, 0xa2, 0x99, - 0x72, 0xb5, 0xca, 0x0d, 0x76, 0x6b, 0xfb, 0x84, 0x8f, 0x13, 0xc9, 0xba, 0x97, 0x30, 0x16, 0xf9, - 0xee, 0x07, 0x84, 0x89, 0x88, 0x89, 0x2e, 0xa8, 0xc4, 0x62, 0x02, 0xdd, 0xf4, 0xc0, 0x07, 0x89, - 0x0f, 0x4a, 0x41, 0x11, 0x77, 0xae, 0xe7, 0x63, 0x51, 0xe9, 0x10, 0x46, 0xf3, 0xb8, 0xed, 0x1f, - 0x96, 0x90, 0xd5, 0x63, 0xb1, 0x18, 0x45, 0xc0, 0x8f, 0x82, 0x80, 0xaa, 0x94, 0xfa, 0x9c, 0x25, - 0x4c, 0xe0, 0xd0, 0xdc, 0x46, 0x8b, 0x92, 0xca, 0x10, 0x2c, 0xa3, 0x63, 0xec, 0x37, 0xdd, 0x6c, - 0x61, 0x76, 0x50, 0x2b, 0x00, 0x41, 0x38, 0x4d, 0x94, 0xb2, 0x35, 0xaf, 0xf7, 0xea, 0x22, 0x73, - 0x07, 0xad, 0x64, 0xb7, 0x40, 0x03, 0xab, 0xa1, 0xb7, 0x97, 0xf5, 0xfa, 0x24, 0x30, 0x3f, 0x45, - 0xeb, 0x34, 0xa6, 0x92, 0xe2, 0xd0, 0x1b, 0x82, 0x3a, 0x0d, 0x6b, 0xa1, 0x63, 0xec, 0xb7, 0x0e, - 0xef, 0x3a, 0xd4, 0x27, 0x8e, 0x3a, 0x40, 0x27, 0x3f, 0xb6, 0xf4, 0xc0, 0x79, 0xa2, 0x35, 0x8e, - 0x17, 0xbe, 0xfd, 0x7e, 0x6f, 0xce, 0x5d, 0xcb, 0xed, 0x32, 0xa1, 0x79, 0x0f, 0xad, 0x0e, 0x20, - 0x06, 0x41, 0x85, 0x37, 0xc4, 0x62, 0x68, 0x2d, 0x76, 0x8c, 0xfd, 0x55, 0xb7, 0x95, 0xcb, 0x9e, - 0x60, 0x31, 0x34, 0xf7, 0x50, 0xcb, 0xa7, 0x31, 0xe6, 0xe3, 0x4c, 0x63, 0x49, 0x6b, 0xa0, 0x4c, - 0xa4, 0x15, 0x7a, 0x08, 0x89, 0x04, 0xbf, 0x8c, 0x3d, 0x75, 0xdb, 0xd6, 0x72, 0x1e, 0x48, 0x76, - 0xd3, 0x4e, 0x71, 0xd3, 0xce, 0x79, 0x51, 0x0a, 0xc7, 0x2b, 0x2a, 0x90, 0xaf, 0x7e, 0xd8, 0x33, - 0xdc, 0xa6, 0xb6, 0x53, 0x3b, 0xe6, 0x17, 0xe8, 0xd6, 0x28, 0xf6, 0x59, 0x1c, 0xd0, 0x78, 0xe0, - 0x25, 0xc0, 0x29, 0x0b, 0xac, 0x15, 0x0d, 0xb5, 0x73, 0x05, 0xea, 0x61, 0x5e, 0x34, 0x19, 0xd2, - 0xd7, 0x0a, 0x69, 0xa3, 0x34, 0xee, 0x6b, 0x5b, 0xf3, 0x4b, 0x64, 0x12, 0x92, 0xea, 0x90, 0xd8, - 0x48, 0x16, 0x88, 0xcd, 0xd9, 0x11, 0x6f, 0x11, 0x92, 0x9e, 0x67, 0xd6, 0x39, 0xe4, 0x6f, 0xd1, - 0x1d, 0xc9, 0x71, 0x2c, 0x9e, 0x03, 0x9f, 0xc6, 0x45, 0xb3, 0xe3, 0xde, 0x2e, 0x30, 0x26, 0xc1, - 0x9f, 0xa0, 0x0e, 0xc9, 0x0b, 0xc8, 0xe3, 0x10, 0x50, 0x21, 0x39, 0xf5, 0x47, 0xca, 0xd6, 0x7b, - 0xce, 0x31, 0xd1, 0x35, 0xd2, 0xd2, 0x45, 0xd0, 0x2e, 0xf4, 0xdc, 0x09, 0xb5, 0xc7, 0xb9, 0x96, - 0xf9, 0x14, 0xfd, 0xc8, 0x0f, 0x19, 0xb9, 0x14, 0x2a, 0x38, 0x6f, 0x02, 0x49, 0xbb, 0x8e, 0xa8, - 0x10, 0x0a, 0x6d, 0xb5, 0x63, 0xec, 0x37, 0xdc, 0x7b, 0x99, 0x6e, 0x1f, 0xf8, 0xc3, 0x9a, 0xe6, - 0x79, 0x4d, 0xd1, 0xfc, 0x08, 0x99, 0x43, 0x2a, 0x24, 0xe3, 0x94, 0xe0, 0xd0, 0x83, 0x58, 0x72, - 0x0a, 0xc2, 0x5a, 0xd3, 0xe6, 0x9b, 0xd5, 0xce, 0xa3, 0x6c, 0xc3, 0xfc, 0x0c, 0xdd, 0xbb, 0xd1, - 0xa9, 0x47, 0x86, 0x38, 0x8e, 0x21, 0xb4, 0xd6, 0x75, 0x2a, 0x7b, 0xc1, 0x0d, 0x3e, 0x7b, 0x99, - 0xda, 0x83, 0x95, 0xdf, 0x7f, 0xb3, 0x37, 0xf7, 0xf5, 0x37, 0x7b, 0x73, 0xf6, 0x5f, 0x0d, 0x74, - 0xa7, 0x57, 0x26, 0x1e, 0xb1, 0x14, 0x87, 0xff, 0xcb, 0x06, 0x3b, 0x42, 0x4d, 0x21, 0x59, 0x92, - 0x95, 0xf4, 0xc2, 0x3b, 0x94, 0xf4, 0x8a, 0x32, 0x53, 0x1b, 0xf6, 0x9f, 0x0c, 0xb4, 0xfd, 0xe8, - 0xc5, 0x88, 0xa6, 0x8c, 0xe0, 0xff, 0x0a, 0x1f, 0x9c, 0xa2, 0x35, 0xa8, 0xe1, 0x09, 0xab, 0xd1, - 0x69, 0xec, 0xb7, 0x0e, 0x7f, 0xec, 0x64, 0xe4, 0xe4, 0x94, 0x9c, 0x95, 0x13, 0x94, 0x53, 0xf7, - 0xee, 0x4e, 0xda, 0xda, 0xff, 0x34, 0xd0, 0xad, 0x4f, 0x43, 0xe6, 0xe3, 0xf0, 0x2c, 0xc4, 0x62, - 0xa8, 0x2e, 0x6f, 0xac, 0xb2, 0xe6, 0x90, 0x77, 0x8d, 0x8e, 0x6e, 0xe6, 0xac, 0x95, 0x99, 0xee, - 0xe3, 0x4f, 0xd0, 0x66, 0x59, 0xc7, 0xe5, 0xe1, 0xea, 0x64, 0x8e, 0xb7, 0x5e, 0x7f, 0xbf, 0xb7, - 0x51, 0xdc, 0x61, 0x4f, 0x1f, 0xf4, 0x43, 0x77, 0x83, 0x4c, 0x08, 0x02, 0xb3, 0x8d, 0x5a, 0xd4, - 0x27, 0x9e, 0x80, 0x17, 0x5e, 0x3c, 0x8a, 0xf4, 0xbd, 0x2c, 0xb8, 0x4d, 0xea, 0x93, 0x33, 0x78, - 0xf1, 0xc5, 0x28, 0x32, 0xef, 0xa3, 0xf7, 0x8a, 0x41, 0xe4, 0xa5, 0x38, 0xf4, 0x94, 0xbd, 0x87, - 0x83, 0x80, 0xeb, 0x6b, 0x5a, 0x75, 0xb7, 0x8a, 0xdd, 0x0b, 0x1c, 0x2a, 0x67, 0x47, 0x41, 0xc0, - 0xed, 0x7f, 0x2c, 0xa2, 0xa5, 0x3e, 0xe6, 0x38, 0x12, 0xe6, 0x39, 0xda, 0x90, 0x10, 0x25, 0x21, - 0x96, 0xe0, 0x65, 0x1c, 0x99, 0x67, 0xfa, 0xa1, 0xe6, 0xce, 0xfa, 0x6c, 0x71, 0x6a, 0xd3, 0x24, - 0x3d, 0x70, 0x7a, 0x5a, 0x7a, 0x26, 0xb1, 0x04, 0x77, 0xbd, 0xc0, 0xc8, 0x84, 0xe6, 0xcf, 0x91, - 0x25, 0xf9, 0x48, 0xc8, 0x8a, 0xbd, 0xaa, 0xb6, 0xcd, 0xae, 0xf2, 0xbd, 0x62, 0x3f, 0x6b, 0xf8, - 0xb2, 0x5d, 0xaf, 0x27, 0xaa, 0xc6, 0x7f, 0x42, 0x54, 0x67, 0x68, 0x4b, 0xb1, 0xfc, 0x34, 0xe6, - 0xc2, 0xec, 0x98, 0x9b, 0xca, 0x7e, 0x12, 0xf4, 0x4b, 0x64, 0xa6, 0x82, 0x4c, 0x63, 0x2e, 0xbe, - 0x43, 0x9c, 0xa9, 0x20, 0x93, 0x90, 0x01, 0xda, 0x15, 0xaa, 0xf8, 0xbc, 0x08, 0xa4, 0xa6, 0xbd, - 0x24, 0x84, 0x98, 0x8a, 0x61, 0x01, 0xbe, 0x34, 0x3b, 0xf8, 0x8e, 0x06, 0xfa, 0x5c, 0xe1, 0xb8, - 0x05, 0x4c, 0xee, 0xa5, 0x87, 0xda, 0xd7, 0x7b, 0x29, 0x2f, 0x68, 0x59, 0x5f, 0xd0, 0xff, 0x5d, - 0x03, 0x51, 0xde, 0xd2, 0x21, 0xba, 0x1d, 0xe1, 0x57, 0x9e, 0x1c, 0x72, 0x26, 0x65, 0x08, 0x81, - 0x97, 0x60, 0x72, 0x09, 0x52, 0xe8, 0x19, 0xd5, 0x70, 0xb7, 0x22, 0xfc, 0xea, 0xbc, 0xd8, 0xeb, - 0x67, 0x5b, 0xa6, 0x40, 0x1f, 0xd4, 0x28, 0xfd, 0x25, 0xe6, 0x81, 0x17, 0x40, 0xcc, 0x22, 0x8f, - 0xc3, 0x40, 0xf1, 0x1e, 0xce, 0xd8, 0x1d, 0xa0, 0x1c, 0x4b, 0x79, 0x23, 0xab, 0x57, 0x46, 0xd9, - 0xc4, 0x3d, 0x46, 0xe3, 0x7c, 0x76, 0xdb, 0x15, 0xf3, 0x2b, 0xb4, 0x87, 0x0a, 0xcc, 0xad, 0x61, - 0x3d, 0x06, 0xb0, 0x7d, 0xb4, 0xf9, 0x04, 0xc7, 0x81, 0x18, 0xe2, 0x4b, 0xf8, 0x1c, 0x24, 0x0e, - 0xb0, 0xc4, 0x13, 0x3d, 0xf3, 0x1c, 0xc0, 0x4b, 0x18, 0x0b, 0xb3, 0x9e, 0xc9, 0x28, 0xa8, 0xec, - 0x99, 0xc7, 0x00, 0x7d, 0xc6, 0x42, 0xd5, 0x33, 0xa6, 0x85, 0x96, 0x53, 0xe0, 0xa2, 0xaa, 0xe0, - 0x62, 0x69, 0xff, 0x04, 0x35, 0x35, 0x69, 0x1c, 0x91, 0x4b, 0x61, 0xee, 0xa2, 0xa6, 0x42, 0x02, - 0x21, 0x40, 0x58, 0x46, 0xa7, 0xb1, 0xdf, 0x74, 0x2b, 0x81, 0x2d, 0xd1, 0xce, 0x4d, 0xef, 0x22, - 0x61, 0x3e, 0x43, 0xcb, 0x09, 0xe8, 0xa1, 0xad, 0x0d, 0x5b, 0x87, 0x1f, 0x3b, 0x33, 0xbc, 0x3d, - 0x9d, 0x9b, 0x00, 0xdd, 0x02, 0xcd, 0xe6, 0xd5, 0x6b, 0x6c, 0x6a, 0x56, 0x08, 0xf3, 0x62, 0xda, - 0xe9, 0x2f, 0xde, 0xc9, 0xe9, 0x14, 0x5e, 0xe5, 0xf3, 0x43, 0xd4, 0x3a, 0xca, 0xd2, 0xfe, 0x25, - 0x15, 0xf2, 0xea, 0xb1, 0xac, 0xd6, 0x8f, 0xe5, 0x33, 0xb4, 0x9e, 0x8f, 0xb8, 0x73, 0xa6, 0x89, - 0xcf, 0xfc, 0x7f, 0x84, 0xf2, 0xd9, 0xa8, 0x08, 0x33, 0xbb, 0x96, 0x66, 0x2e, 0x39, 0x09, 0x26, - 0x46, 0xd5, 0xfc, 0xc4, 0xa8, 0xb2, 0x5d, 0xb4, 0x71, 0x21, 0xc8, 0xaf, 0x8a, 0xf7, 0xcf, 0xd3, - 0x44, 0x98, 0xb7, 0xd1, 0x92, 0xea, 0xd5, 0x1c, 0x68, 0xc1, 0x5d, 0x4c, 0x05, 0x39, 0x09, 0xcc, - 0xfd, 0xfa, 0x1b, 0x8b, 0x25, 0x1e, 0x0d, 0x84, 0x35, 0xdf, 0x69, 0xec, 0x2f, 0xb8, 0xeb, 0xa3, - 0xca, 0xfc, 0x24, 0x10, 0xf6, 0xaf, 0x51, 0xab, 0x06, 0x68, 0xae, 0xa3, 0xf9, 0x12, 0x6b, 0x9e, - 0x06, 0xe6, 0x03, 0xb4, 0x53, 0x01, 0x4d, 0xd2, 0x7d, 0x86, 0xd8, 0x74, 0xef, 0x94, 0x0a, 0x13, - 0x8c, 0x2f, 0xec, 0xa7, 0x68, 0xfb, 0xa4, 0x22, 0x97, 0x72, 0x98, 0x4c, 0x64, 0x68, 0x4c, 0x0e, - 0xe3, 0x5d, 0xd4, 0x2c, 0x7f, 0x48, 0xe8, 0xec, 0x17, 0xdc, 0x4a, 0x60, 0x47, 0xe8, 0xd6, 0x85, - 0x20, 0x67, 0x10, 0x07, 0x15, 0xd8, 0x0d, 0x07, 0x70, 0x3c, 0x0d, 0x34, 0xf3, 0x43, 0xb5, 0x72, - 0xf7, 0x17, 0x03, 0x59, 0x8f, 0x5e, 0x25, 0x8c, 0x4b, 0x08, 0xae, 0xf8, 0x7d, 0x4b, 0x12, 0x97, - 0x68, 0x4b, 0x85, 0x24, 0x20, 0x0e, 0xbc, 0x12, 0x2d, 0x3b, 0xad, 0xd6, 0xe1, 0xcf, 0x66, 0xaa, - 0xc1, 0x69, 0x77, 0x39, 0x2d, 0x6c, 0xa6, 0x53, 0x72, 0x61, 0xff, 0xc1, 0x40, 0xd6, 0x29, 0x8c, - 0x8f, 0x84, 0xa0, 0x83, 0x38, 0x82, 0x58, 0x2a, 0x46, 0xc3, 0x04, 0xd4, 0xa7, 0xf9, 0x3e, 0x5a, - 0x2b, 0xd9, 0xa0, 0x24, 0x81, 0x55, 0x77, 0xb5, 0x10, 0xea, 0xee, 0x7f, 0x80, 0x50, 0xc2, 0x21, - 0xf5, 0x88, 0x77, 0x09, 0xe3, 0xfc, 0xac, 0x76, 0xeb, 0x03, 0x31, 0xfb, 0x31, 0xe5, 0xf4, 0x47, - 0x7e, 0x48, 0xc9, 0x29, 0x8c, 0xdd, 0x15, 0xa5, 0xdf, 0x3b, 0x85, 0xb1, 0x7a, 0xe0, 0x24, 0xec, - 0x25, 0x70, 0x3d, 0xc5, 0x1a, 0x6e, 0xb6, 0xb0, 0xff, 0x68, 0xa0, 0x3b, 0x17, 0x38, 0xa4, 0x01, - 0x96, 0x8c, 0x17, 0x45, 0xd1, 0x1f, 0xf9, 0xca, 0xe2, 0x2d, 0xe7, 0x76, 0x25, 0xda, 0xf9, 0x6b, - 0xa2, 0xfd, 0x04, 0xad, 0x96, 0x65, 0xa8, 0xe2, 0x6d, 0xcc, 0x10, 0x6f, 0xab, 0xb0, 0x38, 0x85, - 0xb1, 0xfd, 0xbb, 0x5a, 0x6c, 0xc7, 0xe3, 0x1a, 0xc3, 0xf0, 0x7f, 0x13, 0x5b, 0xe9, 0xb6, 0x1e, - 0x1b, 0xa9, 0xdb, 0x5f, 0x49, 0xa0, 0x71, 0x35, 0x01, 0xfb, 0xcf, 0x06, 0xda, 0xae, 0x7b, 0x15, - 0xe7, 0xac, 0xcf, 0x47, 0x31, 0xbc, 0xcd, 0x7b, 0x55, 0xe4, 0xf3, 0xf5, 0x22, 0x7f, 0x86, 0xd6, - 0x27, 0x82, 0x12, 0xf9, 0x69, 0xfc, 0x74, 0xa6, 0x1a, 0xab, 0x71, 0x98, 0xbb, 0x56, 0xcf, 0x43, - 0x1c, 0x3f, 0xfb, 0xf6, 0x75, 0xdb, 0xf8, 0xee, 0x75, 0xdb, 0xf8, 0xfb, 0xeb, 0xb6, 0xf1, 0xd5, - 0x9b, 0xf6, 0xdc, 0x77, 0x6f, 0xda, 0x73, 0x7f, 0x7b, 0xd3, 0x9e, 0xfb, 0xcd, 0xc7, 0x03, 0x2a, - 0x87, 0x23, 0xdf, 0x21, 0x2c, 0xea, 0xe6, 0xbf, 0x94, 0x2b, 0x5f, 0x1f, 0x95, 0x7f, 0x3c, 0xa4, - 0xf7, 0xbb, 0xaf, 0x26, 0xff, 0x7d, 0x90, 0xe3, 0x04, 0x84, 0xbf, 0xa4, 0x7b, 0xef, 0xfe, 0xbf, - 0x02, 0x00, 0x00, 0xff, 0xff, 0x2b, 0x34, 0xfa, 0x5d, 0xae, 0x10, 0x00, 0x00, + // 1674 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, 0xea, 0x9f, 0x57, 0x72, 0x4c, 0xb9, 0x2a, 0x45, 0x6f, 0x9a, + 0x54, 0x45, 0x90, 0x65, 0x24, 0xa3, 0x40, 0x60, 0x34, 0x08, 0x24, 0xca, 0x89, 0x15, 0x35, 0xb1, + 0xb2, 0x52, 0x65, 0xb4, 0x3d, 0x2c, 0x86, 0xb3, 0x63, 0x72, 0xa0, 0xdd, 0x9d, 0xf5, 0xcc, 0xec, + 0xda, 0xbc, 0xf4, 0xdc, 0x63, 0x7a, 0x0b, 0xda, 0x4b, 0xda, 0x2f, 0xd0, 0xaf, 0x91, 0x63, 0x8e, + 0x3d, 0x25, 0x85, 0x7d, 0xe8, 0xa1, 0x5f, 0xa2, 0x98, 0xd9, 0xbf, 0xa4, 0x44, 0x95, 0x46, 0x9b, + 0xdb, 0xec, 0x9b, 0xf7, 0x7e, 0xef, 0xff, 0x7b, 0x43, 0xc2, 0x3e, 0x0d, 0x25, 0xe1, 0x78, 0x88, + 0x68, 0xe8, 0x0a, 0x82, 0x63, 0x4e, 0xe5, 0xa8, 0x8b, 0x71, 0xd2, 0x8d, 0x38, 0x4b, 0xa8, 0x47, + 0x78, 0x37, 0xd9, 0x2b, 0xce, 0x76, 0xc4, 0x99, 0x64, 0xe6, 0xdb, 0xd7, 0xc8, 0xd8, 0x18, 0x27, + 0x76, 0xc1, 0x97, 0xec, 0xdd, 0xfb, 0x60, 0x1a, 0x70, 0xb2, 0xd7, 0x15, 0x43, 0xc4, 0x89, 0xe7, + 0x62, 0x16, 0x8a, 0x38, 0xc8, 0x61, 0xef, 0xbd, 0x73, 0x83, 0xc4, 0x0b, 0xca, 0x49, 0xc6, 0xb6, + 0x39, 0x60, 0x03, 0xa6, 0x8f, 0x5d, 0x75, 0xca, 0xa8, 0x3b, 0x03, 0xc6, 0x06, 0x3e, 0xe9, 0xea, + 0xaf, 0x7e, 0xfc, 0xac, 0x2b, 0x69, 0x40, 0x84, 0x44, 0x41, 0x94, 0x31, 0xb4, 0x27, 0x19, 0xbc, + 0x98, 0x23, 0x49, 0x59, 0x98, 0x03, 0xd0, 0x3e, 0xee, 0x62, 0xc6, 0x49, 0x17, 0xfb, 0x94, 0x84, + 0x52, 0x69, 0x4d, 0x4f, 0x19, 0x43, 0x57, 0x31, 0xf8, 0x74, 0x30, 0x94, 0x29, 0x59, 0x74, 0x25, + 0x09, 0x3d, 0xc2, 0x03, 0x9a, 0x32, 0x97, 0x5f, 0x99, 0xc0, 0x76, 0xe5, 0x1e, 0xf3, 0x51, 0x24, + 0x59, 0xf7, 0x92, 0x8c, 0x44, 0x76, 0xfb, 0x2e, 0x66, 0x22, 0x60, 0xa2, 0x4b, 0x54, 0xc4, 0x42, + 0x4c, 0xba, 0xc9, 0x5e, 0x9f, 0x48, 0xb4, 0x57, 0x10, 0x72, 0xbb, 0x33, 0xbe, 0x3e, 0x12, 0x25, + 0x0f, 0x66, 0x34, 0xb3, 0xdb, 0xfa, 0x61, 0x11, 0x5a, 0xbd, 0x2c, 0x90, 0x07, 0x9e, 0x47, 0x95, + 0x4b, 0xa7, 0x9c, 0x45, 0x4c, 0x20, 0xdf, 0xdc, 0x84, 0x05, 0x49, 0xa5, 0x4f, 0x5a, 0x46, 0xc7, + 0xd8, 0x6d, 0x38, 0xe9, 0x87, 0xd9, 0x81, 0xa6, 0x47, 0x04, 0xe6, 0x34, 0x52, 0xcc, 0xad, 0x79, + 0x7d, 0x57, 0x25, 0x99, 0x5b, 0xb0, 0x94, 0xe6, 0x81, 0x7a, 0xad, 0x9a, 0xbe, 0xbe, 0xa5, 0xbf, + 0x8f, 0x3d, 0xf3, 0x53, 0x58, 0xa5, 0x21, 0x95, 0x14, 0xf9, 0xee, 0x90, 0xa8, 0x68, 0xb4, 0xea, + 0x1d, 0x63, 0xb7, 0xb9, 0x7f, 0xcf, 0xa6, 0x7d, 0x6c, 0xab, 0x00, 0xda, 0x59, 0xd8, 0x92, 0x3d, + 0xfb, 0xb1, 0xe6, 0x38, 0xac, 0x7f, 0xfb, 0xfd, 0xce, 0x9c, 0xb3, 0x92, 0xc9, 0xa5, 0x44, 0xf3, + 0x3e, 0x2c, 0x0f, 0x48, 0x48, 0x04, 0x15, 0xee, 0x10, 0x89, 0x61, 0x6b, 0xa1, 0x63, 0xec, 0x2e, + 0x3b, 0xcd, 0x8c, 0xf6, 0x18, 0x89, 0xa1, 0xb9, 0x03, 0xcd, 0x3e, 0x0d, 0x11, 0x1f, 0xa5, 0x1c, + 0x8b, 0x9a, 0x03, 0x52, 0x92, 0x66, 0xe8, 0x01, 0x88, 0x08, 0xbd, 0x08, 0x5d, 0x95, 0xed, 0xd6, + 0xad, 0xcc, 0x90, 0x34, 0xd3, 0x76, 0x9e, 0x69, 0xfb, 0x3c, 0x2f, 0x85, 0xc3, 0x25, 0x65, 0xc8, + 0x57, 0x3f, 0xec, 0x18, 0x4e, 0x43, 0xcb, 0xa9, 0x1b, 0xf3, 0x0b, 0x58, 0x8f, 0xc3, 0x3e, 0x0b, + 0x3d, 0x1a, 0x0e, 0xdc, 0x88, 0x70, 0xca, 0xbc, 0xd6, 0x92, 0x86, 0xda, 0xba, 0x02, 0x75, 0x94, + 0x15, 0x4d, 0x8a, 0xf4, 0xb5, 0x42, 0x5a, 0x2b, 0x84, 0x4f, 0xb5, 0xac, 0xf9, 0x25, 0x98, 0x18, + 0x27, 0xda, 0x24, 0x16, 0xcb, 0x1c, 0xb1, 0x31, 0x3b, 0xe2, 0x3a, 0xc6, 0xc9, 0x79, 0x2a, 0x9d, + 0x41, 0xfe, 0x1e, 0xee, 0x4a, 0x8e, 0x42, 0xf1, 0x8c, 0xf0, 0x49, 0x5c, 0x98, 0x1d, 0xf7, 0x4e, + 0x8e, 0x31, 0x0e, 0xfe, 0x18, 0x3a, 0x79, 0x27, 0xba, 0x9c, 0x78, 0x54, 0x48, 0x4e, 0xfb, 0xb1, + 0x92, 0x75, 0x9f, 0x71, 0x84, 0x75, 0x8d, 0x34, 0x75, 0x11, 0xb4, 0x73, 0x3e, 0x67, 0x8c, 0xed, + 0x93, 0x8c, 0xcb, 0x7c, 0x02, 0x3f, 0xeb, 0xfb, 0x0c, 0x5f, 0x0a, 0x65, 0x9c, 0x3b, 0x86, 0xa4, + 0x55, 0x07, 0x54, 0x08, 0x85, 0xb6, 0xdc, 0x31, 0x76, 0x6b, 0xce, 0xfd, 0x94, 0xf7, 0x94, 0xf0, + 0xa3, 0x0a, 0xe7, 0x79, 0x85, 0xd1, 0x7c, 0x1f, 0xcc, 0x21, 0x15, 0x92, 0x71, 0x8a, 0x91, 0xef, + 0x92, 0x50, 0x72, 0x4a, 0x44, 0x6b, 0x45, 0x8b, 0xdf, 0x2e, 0x6f, 0x1e, 0xa5, 0x17, 0xe6, 0x67, + 0x70, 0x7f, 0xaa, 0x52, 0x17, 0x0f, 0x51, 0x18, 0x12, 0xbf, 0xb5, 0xaa, 0x5d, 0xd9, 0xf1, 0xa6, + 0xe8, 0xec, 0xa5, 0x6c, 0x0f, 0x97, 0xfe, 0xf8, 0xcd, 0xce, 0xdc, 0xd7, 0xdf, 0xec, 0xcc, 0x59, + 0x7f, 0x37, 0xe0, 0x6e, 0xaf, 0x70, 0x3c, 0x60, 0x09, 0xf2, 0x7f, 0xcc, 0x06, 0x3b, 0x80, 0x86, + 0x90, 0x2c, 0x4a, 0x4b, 0xba, 0xfe, 0x06, 0x25, 0xbd, 0xa4, 0xc4, 0xd4, 0x85, 0xf5, 0x17, 0x03, + 0x36, 0x1f, 0x3d, 0x8f, 0x69, 0xc2, 0x30, 0xfa, 0xbf, 0xcc, 0x83, 0x13, 0x58, 0x21, 0x15, 0x3c, + 0xd1, 0xaa, 0x75, 0x6a, 0xbb, 0xcd, 0xfd, 0x77, 0xec, 0x74, 0x38, 0xd9, 0xc5, 0xcc, 0xca, 0x06, + 0x94, 0x5d, 0xd5, 0xee, 0x8c, 0xcb, 0x5a, 0xff, 0x36, 0x60, 0xfd, 0x53, 0x9f, 0xf5, 0x91, 0x7f, + 0xe6, 0x23, 0x31, 0x54, 0xc9, 0x1b, 0x29, 0xaf, 0x39, 0xc9, 0xba, 0x46, 0x5b, 0x37, 0xb3, 0xd7, + 0x4a, 0x4c, 0xf7, 0xf1, 0xc7, 0x70, 0xbb, 0xa8, 0xe3, 0x22, 0xb8, 0xda, 0x99, 0xc3, 0x8d, 0x57, + 0xdf, 0xef, 0xac, 0xe5, 0x39, 0xec, 0xe9, 0x40, 0x1f, 0x39, 0x6b, 0x78, 0x8c, 0xe0, 0x99, 0x6d, + 0x68, 0xd2, 0x3e, 0x76, 0x05, 0x79, 0xee, 0x86, 0x71, 0xa0, 0xf3, 0x52, 0x77, 0x1a, 0xb4, 0x8f, + 0xcf, 0xc8, 0xf3, 0x2f, 0xe2, 0xc0, 0x7c, 0x00, 0x6f, 0xe5, 0x1b, 0xce, 0x4d, 0x90, 0xaf, 0xf7, + 0x97, 0x8b, 0x3c, 0x8f, 0xeb, 0x34, 0x2d, 0x3b, 0x1b, 0xf9, 0xed, 0x05, 0xf2, 0x95, 0xb2, 0x03, + 0xcf, 0xe3, 0xd6, 0xbf, 0x16, 0x60, 0xf1, 0x14, 0x71, 0x14, 0x08, 0xf3, 0x1c, 0xd6, 0x24, 0x09, + 0x22, 0x1f, 0x49, 0xe2, 0xa6, 0x33, 0x32, 0xf3, 0xf4, 0x3d, 0x3d, 0x3b, 0xab, 0xbb, 0xc5, 0xae, + 0x6c, 0x93, 0x64, 0xcf, 0xee, 0x69, 0xea, 0x99, 0x44, 0x92, 0x38, 0xab, 0x39, 0x46, 0x4a, 0x34, + 0x3f, 0x84, 0x96, 0xe4, 0xb1, 0x90, 0xe5, 0xf4, 0x2a, 0xdb, 0x36, 0x4d, 0xe5, 0x5b, 0xf9, 0x7d, + 0xda, 0xf0, 0x45, 0xbb, 0x5e, 0x3f, 0xa8, 0x6a, 0xff, 0xcb, 0xa0, 0x3a, 0x83, 0x0d, 0x35, 0xe5, + 0x27, 0x31, 0xeb, 0xb3, 0x63, 0xde, 0x56, 0xf2, 0xe3, 0xa0, 0x5f, 0x82, 0x99, 0x08, 0x3c, 0x89, + 0xb9, 0xf0, 0x06, 0x76, 0x26, 0x02, 0x8f, 0x43, 0x7a, 0xb0, 0x2d, 0x54, 0xf1, 0xb9, 0x01, 0x91, + 0x7a, 0xec, 0x45, 0x3e, 0x09, 0xa9, 0x18, 0xe6, 0xe0, 0x8b, 0xb3, 0x83, 0x6f, 0x69, 0xa0, 0xcf, + 0x15, 0x8e, 0x93, 0xc3, 0x64, 0x5a, 0x7a, 0xd0, 0xbe, 0x5e, 0x4b, 0x91, 0xa0, 0x5b, 0x3a, 0x41, + 0x3f, 0xb9, 0x06, 0xa2, 0xc8, 0xd2, 0x3e, 0xdc, 0x09, 0xd0, 0x4b, 0x57, 0x0e, 0x39, 0x93, 0xd2, + 0x27, 0x9e, 0x1b, 0x21, 0x7c, 0x49, 0xa4, 0xd0, 0x3b, 0xaa, 0xe6, 0x6c, 0x04, 0xe8, 0xe5, 0x79, + 0x7e, 0x77, 0x9a, 0x5e, 0x99, 0x02, 0xde, 0xad, 0x8c, 0xf4, 0x17, 0x88, 0x7b, 0xae, 0x47, 0x42, + 0x16, 0xb8, 0x9c, 0x0c, 0xd4, 0xdc, 0x43, 0xe9, 0x74, 0x27, 0xa4, 0x58, 0x4b, 0x59, 0x23, 0xab, + 0x57, 0x46, 0xd1, 0xc4, 0x3d, 0x46, 0xc3, 0x6c, 0x77, 0x5b, 0xe5, 0xe4, 0x57, 0x68, 0x47, 0x0a, + 0xcc, 0xa9, 0x60, 0x7d, 0x42, 0x88, 0xf5, 0x0b, 0x68, 0xe8, 0x86, 0x3e, 0xc0, 0x97, 0xc2, 0xdc, + 0x86, 0x86, 0xea, 0x0c, 0x22, 0x04, 0x11, 0x2d, 0xa3, 0x53, 0xdb, 0x6d, 0x38, 0x25, 0xc1, 0x92, + 0xb0, 0x35, 0xed, 0xcd, 0x22, 0xcc, 0xa7, 0x70, 0x2b, 0x22, 0x7a, 0xa1, 0x6a, 0xc1, 0xe6, 0xfe, + 0x47, 0xf6, 0x0c, 0x0f, 0x4e, 0x7b, 0x1a, 0xa0, 0x93, 0xa3, 0x59, 0xbc, 0x7c, 0x29, 0x4d, 0xcc, + 0x71, 0x61, 0x5e, 0x4c, 0x2a, 0xfd, 0xd5, 0x1b, 0x29, 0x9d, 0xc0, 0x2b, 0x75, 0xbe, 0x07, 0xcd, + 0x83, 0xd4, 0xed, 0x5f, 0x53, 0x21, 0xaf, 0x86, 0x65, 0xb9, 0x1a, 0x96, 0xcf, 0x60, 0x35, 0x5b, + 0x3f, 0xe7, 0x4c, 0x0f, 0x25, 0xf3, 0xa7, 0x00, 0xd9, 0xde, 0x52, 0xc3, 0x2c, 0x9d, 0xda, 0x8d, + 0x8c, 0x72, 0xec, 0x8d, 0xad, 0x91, 0xf9, 0xb1, 0x35, 0x62, 0x39, 0xb0, 0x76, 0x21, 0xf0, 0x6f, + 0xf2, 0xb7, 0xc9, 0x93, 0x48, 0x98, 0x77, 0x60, 0x51, 0xf5, 0x51, 0x06, 0x54, 0x77, 0x16, 0x12, + 0x81, 0x8f, 0x3d, 0x73, 0xb7, 0xfa, 0xfe, 0x61, 0x91, 0x4b, 0x3d, 0xd1, 0x9a, 0xef, 0xd4, 0x76, + 0xeb, 0xce, 0x6a, 0x5c, 0x8a, 0x1f, 0x7b, 0xc2, 0xfa, 0x2d, 0x34, 0x2b, 0x80, 0xe6, 0x2a, 0xcc, + 0x17, 0x58, 0xf3, 0xd4, 0x33, 0x1f, 0xc2, 0x56, 0x09, 0x34, 0x3e, 0x8a, 0x53, 0xc4, 0x86, 0x73, + 0xb7, 0x60, 0x18, 0x9b, 0xc6, 0xc2, 0x7a, 0x02, 0x9b, 0xc7, 0x65, 0xe3, 0x17, 0x83, 0x7e, 0xcc, + 0x43, 0x63, 0x7c, 0x51, 0x6e, 0x43, 0xa3, 0x78, 0xe4, 0x6b, 0xef, 0xeb, 0x4e, 0x49, 0xb0, 0x02, + 0x58, 0xbf, 0x10, 0xf8, 0x8c, 0x84, 0x5e, 0x09, 0x36, 0x25, 0x00, 0x87, 0x93, 0x40, 0x33, 0x3f, + 0x22, 0x4b, 0x75, 0x0c, 0xb6, 0x2e, 0x90, 0x4f, 0x3d, 0x24, 0x19, 0x3f, 0x23, 0x52, 0xa5, 0x71, + 0x40, 0xf2, 0x76, 0x74, 0xa0, 0xee, 0x53, 0x21, 0xb3, 0xca, 0xfa, 0x70, 0x6a, 0x65, 0x25, 0x7b, + 0xf6, 0x34, 0x90, 0x23, 0x24, 0x51, 0xd6, 0x8b, 0x1a, 0xcb, 0xfa, 0x39, 0x6c, 0x7c, 0x8e, 0x64, + 0xcc, 0x89, 0x37, 0x96, 0xe3, 0x75, 0xa8, 0xa9, 0xfc, 0x19, 0x3a, 0x7f, 0xea, 0x68, 0xfd, 0xcd, + 0x80, 0xd6, 0xa3, 0x97, 0x11, 0xe3, 0x92, 0x78, 0x57, 0x22, 0x72, 0x43, 0x78, 0x2f, 0x61, 0x43, + 0x05, 0x4b, 0x90, 0xd0, 0x73, 0x0b, 0x3f, 0xd3, 0x3c, 0x36, 0xf7, 0x7f, 0x39, 0x53, 0x77, 0x4c, + 0xaa, 0xcb, 0x1c, 0xb8, 0x9d, 0x4c, 0xd0, 0x85, 0xf5, 0x27, 0x03, 0x5a, 0x27, 0x64, 0x74, 0x20, + 0x04, 0x1d, 0x84, 0x01, 0x09, 0xa5, 0x9a, 0x83, 0x08, 0x13, 0x75, 0x34, 0xdf, 0x86, 0x95, 0x62, + 0xef, 0xea, 0x75, 0x6b, 0xe8, 0x75, 0xbb, 0x9c, 0x13, 0x55, 0x83, 0x99, 0x0f, 0x01, 0x22, 0x4e, + 0x12, 0x17, 0xbb, 0x97, 0x64, 0x94, 0x65, 0x71, 0xbb, 0xba, 0x46, 0xd3, 0x9f, 0x60, 0xf6, 0x69, + 0xdc, 0xf7, 0x29, 0x3e, 0x21, 0x23, 0x67, 0x49, 0xf1, 0xf7, 0x4e, 0xc8, 0x48, 0x3d, 0x8b, 0x22, + 0xf6, 0x82, 0x70, 0xbd, 0xfb, 0x6a, 0x4e, 0xfa, 0x61, 0xfd, 0xd9, 0x80, 0xbb, 0x45, 0x3a, 0xf2, + 0x72, 0x3d, 0x8d, 0xfb, 0x4a, 0xe2, 0x86, 0xb8, 0x5d, 0xb1, 0x76, 0xfe, 0x1a, 0x6b, 0x3f, 0x86, + 0xe5, 0xa2, 0x41, 0x94, 0xbd, 0xb5, 0x19, 0xec, 0x6d, 0xe6, 0x12, 0x27, 0x64, 0x64, 0xfd, 0xa1, + 0x62, 0xdb, 0xe1, 0xa8, 0x32, 0xfb, 0xf8, 0x7f, 0xb1, 0xad, 0x50, 0x5b, 0xb5, 0x0d, 0x57, 0xe5, + 0xaf, 0x38, 0x50, 0xbb, 0xea, 0x80, 0xf5, 0x57, 0x03, 0x36, 0xab, 0x5a, 0xc5, 0x39, 0x3b, 0xe5, + 0x71, 0x48, 0x6e, 0xd2, 0x5e, 0xb6, 0xdf, 0x7c, 0xb5, 0xfd, 0x9e, 0xc2, 0xea, 0x98, 0x51, 0x22, + 0x8b, 0xc6, 0x07, 0x33, 0xd5, 0x58, 0x65, 0xba, 0x3a, 0x2b, 0x55, 0x3f, 0xc4, 0xe1, 0xd3, 0x6f, + 0x5f, 0xb5, 0x8d, 0xef, 0x5e, 0xb5, 0x8d, 0x7f, 0xbe, 0x6a, 0x1b, 0x5f, 0xbd, 0x6e, 0xcf, 0x7d, + 0xf7, 0xba, 0x3d, 0xf7, 0x8f, 0xd7, 0xed, 0xb9, 0xdf, 0x7d, 0x34, 0xa0, 0x72, 0x18, 0xf7, 0x6d, + 0xcc, 0x82, 0x6e, 0xf6, 0xfb, 0xba, 0xd4, 0xf5, 0x7e, 0xf1, 0xe7, 0x43, 0xf2, 0xa0, 0xfb, 0x72, + 0xfc, 0xcf, 0x10, 0x39, 0x8a, 0x88, 0xe8, 0x2f, 0xea, 0xa9, 0xf0, 0xe0, 0x3f, 0x01, 0x00, 0x00, + 0xff, 0xff, 0xcb, 0x43, 0xd2, 0x10, 0x3d, 0x11, 0x00, 0x00, } func (m *ConsumerAdditionProposal) Marshal() (dAtA []byte, err error) { @@ -1779,43 +1826,6 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *HandshakeMetadata) 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 *HandshakeMetadata) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *HandshakeMetadata) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Version) > 0 { - i -= len(m.Version) - copy(dAtA[i:], m.Version) - i = encodeVarintProvider(dAtA, i, uint64(len(m.Version))) - i-- - dAtA[i] = 0x12 - } - if len(m.ProviderFeePoolAddr) > 0 { - i -= len(m.ProviderFeePoolAddr) - copy(dAtA[i:], m.ProviderFeePoolAddr) - i = encodeVarintProvider(dAtA, i, uint64(len(m.ProviderFeePoolAddr))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - func (m *SlashAcks) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -2145,6 +2155,84 @@ func (m *VscSendTimestamp) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *ValidatorSetChangePackets) 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 *ValidatorSetChangePackets) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ValidatorSetChangePackets) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.List) > 0 { + for iNdEx := len(m.List) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.List[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 (m *MaturedUnbondingOps) 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 *MaturedUnbondingOps) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MaturedUnbondingOps) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Ids) > 0 { + dAtA18 := make([]byte, len(m.Ids)*10) + var j17 int + for _, num := range m.Ids { + for num >= 1<<7 { + dAtA18[j17] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j17++ + } + dAtA18[j17] = uint8(num) + j17++ + } + i -= j17 + copy(dAtA[i:], dAtA18[:j17]) + i = encodeVarintProvider(dAtA, i, uint64(j17)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *ExportedVscSendTimestamp) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -2542,23 +2630,6 @@ func (m *Params) Size() (n int) { return n } -func (m *HandshakeMetadata) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.ProviderFeePoolAddr) - if l > 0 { - n += 1 + l + sovProvider(uint64(l)) - } - l = len(m.Version) - if l > 0 { - n += 1 + l + sovProvider(uint64(l)) - } - return n -} - func (m *SlashAcks) Size() (n int) { if m == nil { return 0 @@ -2703,6 +2774,37 @@ func (m *VscSendTimestamp) Size() (n int) { return n } +func (m *ValidatorSetChangePackets) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.List) > 0 { + for _, e := range m.List { + l = e.Size() + n += 1 + l + sovProvider(uint64(l)) + } + } + return n +} + +func (m *MaturedUnbondingOps) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Ids) > 0 { + l = 0 + for _, e := range m.Ids { + l += sovProvider(uint64(e)) + } + n += 1 + sovProvider(uint64(l)) + l + } + return n +} + func (m *ExportedVscSendTimestamp) Size() (n int) { if m == nil { return 0 @@ -4120,7 +4222,7 @@ func (m *Params) Unmarshal(dAtA []byte) error { } return nil } -func (m *HandshakeMetadata) Unmarshal(dAtA []byte) error { +func (m *SlashAcks) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -4143,15 +4245,15 @@ func (m *HandshakeMetadata) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: HandshakeMetadata: wiretype end group for non-group") + return fmt.Errorf("proto: SlashAcks: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: HandshakeMetadata: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: SlashAcks: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ProviderFeePoolAddr", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Addresses", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -4179,127 +4281,13 @@ func (m *HandshakeMetadata) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ProviderFeePoolAddr = string(dAtA[iNdEx:postIndex]) + m.Addresses = append(m.Addresses, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Version", 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.Version = string(dAtA[iNdEx:postIndex]) - 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 (m *SlashAcks) 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: SlashAcks: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: SlashAcks: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Addresses", 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.Addresses = append(m.Addresses, string(dAtA[iNdEx:postIndex])) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipProvider(dAtA[iNdEx:]) - if err != nil { - return err + default: + iNdEx = preIndex + skippy, err := skipProvider(dAtA[iNdEx:]) + if err != nil { + return err } if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthProvider @@ -5129,6 +5117,216 @@ func (m *VscSendTimestamp) Unmarshal(dAtA []byte) error { } return nil } +func (m *ValidatorSetChangePackets) 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: ValidatorSetChangePackets: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ValidatorSetChangePackets: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field List", 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.List = append(m.List, types3.ValidatorSetChangePacketData{}) + if err := m.List[len(m.List)-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 (m *MaturedUnbondingOps) 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: MaturedUnbondingOps: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MaturedUnbondingOps: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType == 0 { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProvider + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Ids = append(m.Ids, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProvider + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return ErrInvalidLengthProvider + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return ErrInvalidLengthProvider + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.Ids) == 0 { + m.Ids = make([]uint64, 0, elementCount) + } + for iNdEx < postIndex { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProvider + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Ids = append(m.Ids, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field Ids", wireType) + } + 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 (m *ExportedVscSendTimestamp) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/x/ccv/provider/types/query.pb.go b/x/ccv/provider/types/query.pb.go index f82376da05..9fc9178e09 100644 --- a/x/ccv/provider/types/query.pb.go +++ b/x/ccv/provider/types/query.pb.go @@ -10,8 +10,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/v3/x/ccv/consumer/types" - types1 "github.com/cosmos/interchain-security/v3/x/ccv/types" + types "github.com/cosmos/interchain-security/v3/x/ccv/types" _ "google.golang.org/genproto/googleapis/api/annotations" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" @@ -814,8 +813,8 @@ func (m *QueryThrottledConsumerPacketDataResponse) GetPacketDataInstances() []Th // A query wrapper type for the global entry and data relevant to a throttled // slash packet. type ThrottledSlashPacket struct { - GlobalEntry GlobalSlashEntry `protobuf:"bytes,1,opt,name=global_entry,json=globalEntry,proto3" json:"global_entry"` - Data types1.SlashPacketData `protobuf:"bytes,2,opt,name=data,proto3" json:"data"` + GlobalEntry GlobalSlashEntry `protobuf:"bytes,1,opt,name=global_entry,json=globalEntry,proto3" json:"global_entry"` + Data types.SlashPacketData `protobuf:"bytes,2,opt,name=data,proto3" json:"data"` } func (m *ThrottledSlashPacket) Reset() { *m = ThrottledSlashPacket{} } @@ -858,11 +857,11 @@ func (m *ThrottledSlashPacket) GetGlobalEntry() GlobalSlashEntry { return GlobalSlashEntry{} } -func (m *ThrottledSlashPacket) GetData() types1.SlashPacketData { +func (m *ThrottledSlashPacket) GetData() types.SlashPacketData { if m != nil { return m.Data } - return types1.SlashPacketData{} + return types.SlashPacketData{} } // ThrottledPacketDataWrapper contains either SlashPacketData or @@ -914,10 +913,10 @@ type isThrottledPacketDataWrapper_Data interface { } type ThrottledPacketDataWrapper_SlashPacket struct { - SlashPacket *types1.SlashPacketData `protobuf:"bytes,1,opt,name=slash_packet,json=slashPacket,proto3,oneof" json:"slash_packet,omitempty"` + SlashPacket *types.SlashPacketData `protobuf:"bytes,1,opt,name=slash_packet,json=slashPacket,proto3,oneof" json:"slash_packet,omitempty"` } type ThrottledPacketDataWrapper_VscMaturedPacket struct { - VscMaturedPacket *types1.VSCMaturedPacketData `protobuf:"bytes,2,opt,name=vsc_matured_packet,json=vscMaturedPacket,proto3,oneof" json:"vsc_matured_packet,omitempty"` + VscMaturedPacket *types.VSCMaturedPacketData `protobuf:"bytes,2,opt,name=vsc_matured_packet,json=vscMaturedPacket,proto3,oneof" json:"vsc_matured_packet,omitempty"` } func (*ThrottledPacketDataWrapper_SlashPacket) isThrottledPacketDataWrapper_Data() {} @@ -930,14 +929,14 @@ func (m *ThrottledPacketDataWrapper) GetData() isThrottledPacketDataWrapper_Data return nil } -func (m *ThrottledPacketDataWrapper) GetSlashPacket() *types1.SlashPacketData { +func (m *ThrottledPacketDataWrapper) GetSlashPacket() *types.SlashPacketData { if x, ok := m.GetData().(*ThrottledPacketDataWrapper_SlashPacket); ok { return x.SlashPacket } return nil } -func (m *ThrottledPacketDataWrapper) GetVscMaturedPacket() *types1.VSCMaturedPacketData { +func (m *ThrottledPacketDataWrapper) GetVscMaturedPacket() *types.VSCMaturedPacketData { if x, ok := m.GetData().(*ThrottledPacketDataWrapper_VscMaturedPacket); ok { return x.VscMaturedPacket } @@ -1069,90 +1068,90 @@ func init() { } var fileDescriptor_422512d7b7586cd7 = []byte{ - // 1322 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x57, 0xcf, 0x6f, 0xdc, 0x44, - 0x18, 0x5d, 0x6f, 0xd2, 0x34, 0x99, 0x14, 0x5a, 0xa6, 0xa5, 0x6c, 0xdd, 0x6a, 0xb7, 0xb8, 0x08, - 0xd2, 0x16, 0xec, 0xee, 0x56, 0x48, 0x4d, 0x20, 0xdd, 0xec, 0x26, 0x21, 0x8d, 0xda, 0xa8, 0xc1, - 0xa9, 0x5a, 0x09, 0x50, 0xcd, 0xc4, 0x1e, 0x36, 0x16, 0x5e, 0x8f, 0xeb, 0x99, 0x75, 0x1a, 0x7e, - 0x1c, 0x00, 0x09, 0x7a, 0xac, 0x84, 0xb8, 0x71, 0xe8, 0x89, 0xff, 0x82, 0x7b, 0x6f, 0x54, 0xf4, - 0xd2, 0x53, 0x41, 0x09, 0x07, 0x8e, 0x88, 0x3b, 0x12, 0xf2, 0x78, 0xbc, 0x3f, 0xb2, 0xde, 0x5d, - 0xef, 0x36, 0xb7, 0xdd, 0xf1, 0x7c, 0xef, 0x7b, 0xef, 0xe9, 0x9b, 0xf1, 0x33, 0xd0, 0x6c, 0x97, - 0x61, 0xdf, 0xdc, 0x42, 0xb6, 0x6b, 0x50, 0x6c, 0x36, 0x7c, 0x9b, 0xed, 0x68, 0xa6, 0x19, 0x68, - 0x9e, 0x4f, 0x02, 0xdb, 0xc2, 0xbe, 0x16, 0x14, 0xb5, 0x7b, 0x0d, 0xec, 0xef, 0xa8, 0x9e, 0x4f, - 0x18, 0x81, 0xe7, 0x12, 0x0a, 0x54, 0xd3, 0x0c, 0xd4, 0xb8, 0x40, 0x0d, 0x8a, 0xf2, 0x99, 0x1a, - 0x21, 0x35, 0x07, 0x6b, 0xc8, 0xb3, 0x35, 0xe4, 0xba, 0x84, 0x21, 0x66, 0x13, 0x97, 0x46, 0x10, - 0xf2, 0x89, 0x1a, 0xa9, 0x11, 0xfe, 0x53, 0x0b, 0x7f, 0x89, 0xd5, 0x82, 0xa8, 0xe1, 0xff, 0x36, - 0x1b, 0x9f, 0x69, 0xcc, 0xae, 0x63, 0xca, 0x50, 0xdd, 0x13, 0x1b, 0xde, 0xe8, 0x45, 0x35, 0x28, - 0x6a, 0x82, 0x00, 0x23, 0x72, 0xb1, 0xd7, 0x2e, 0x93, 0xb8, 0xb4, 0x51, 0x8f, 0x04, 0xd5, 0xb0, - 0x8b, 0xa9, 0x1d, 0xf3, 0x29, 0xa5, 0xf1, 0xa0, 0x29, 0x8f, 0xd7, 0x28, 0x57, 0xc0, 0xe9, 0x0f, - 0x43, 0x57, 0x16, 0x05, 0xea, 0x4a, 0x84, 0xa8, 0xe3, 0x7b, 0x0d, 0x4c, 0x19, 0x3c, 0x05, 0x26, - 0x23, 0x3c, 0xdb, 0xca, 0x49, 0x67, 0xa5, 0x99, 0x29, 0xfd, 0x30, 0xff, 0xbf, 0x6a, 0x29, 0x5f, - 0x81, 0x33, 0xc9, 0x95, 0xd4, 0x23, 0x2e, 0xc5, 0xf0, 0x13, 0xf0, 0x92, 0xa0, 0x67, 0x50, 0x86, - 0x18, 0xe6, 0xf5, 0xd3, 0xa5, 0xa2, 0xda, 0xcb, 0xf8, 0x58, 0x98, 0x1a, 0x14, 0x55, 0x01, 0xb6, - 0x11, 0x16, 0x56, 0xc7, 0x1f, 0x3f, 0x2f, 0x64, 0xf4, 0x23, 0xb5, 0xb6, 0x35, 0xe5, 0x0c, 0x90, - 0x3b, 0xba, 0x2f, 0x86, 0x78, 0x31, 0x6d, 0x05, 0xed, 0x53, 0x15, 0x3f, 0x15, 0xd4, 0xaa, 0x60, - 0x82, 0xf7, 0xa7, 0x39, 0xe9, 0xec, 0xd8, 0xcc, 0x74, 0xe9, 0x82, 0x9a, 0x62, 0x18, 0x54, 0x0e, - 0xa2, 0x8b, 0x4a, 0xe5, 0x3c, 0x78, 0xab, 0xbb, 0xc5, 0x06, 0x43, 0x3e, 0x5b, 0xf7, 0x89, 0x47, - 0x28, 0x72, 0x9a, 0x6c, 0x1e, 0x48, 0x60, 0x66, 0xf0, 0xde, 0xa6, 0x6d, 0x53, 0x5e, 0xbc, 0x28, - 0x2c, 0xbb, 0x9a, 0x8e, 0x9e, 0x00, 0xaf, 0x58, 0x96, 0x1d, 0x4e, 0x69, 0x0b, 0xba, 0x05, 0xa8, - 0xcc, 0x80, 0x37, 0x93, 0x98, 0x10, 0xaf, 0x8b, 0xf4, 0xf7, 0x52, 0xb2, 0xc0, 0x8e, 0xad, 0x82, - 0xf3, 0xc7, 0xdd, 0x9c, 0xe7, 0x87, 0xe2, 0xac, 0xe3, 0x3a, 0x09, 0x90, 0x93, 0x48, 0xb9, 0x0c, - 0x0e, 0xf1, 0xd6, 0x7d, 0x66, 0x11, 0x9e, 0x06, 0x53, 0xa6, 0x63, 0x63, 0x97, 0x85, 0xcf, 0xb2, - 0xfc, 0xd9, 0x64, 0xb4, 0xb0, 0x6a, 0x29, 0x3f, 0x48, 0xe0, 0x75, 0xae, 0xe4, 0x36, 0x72, 0x6c, - 0x0b, 0x31, 0xe2, 0xb7, 0x59, 0xe5, 0x0f, 0x9e, 0x74, 0x38, 0x0f, 0x8e, 0xc5, 0xa4, 0x0d, 0x64, - 0x59, 0x3e, 0xa6, 0x34, 0x6a, 0x52, 0x85, 0xff, 0x3e, 0x2f, 0xbc, 0xbc, 0x83, 0xea, 0xce, 0x9c, - 0x22, 0x1e, 0x28, 0xfa, 0xd1, 0x78, 0x6f, 0x25, 0x5a, 0x99, 0x9b, 0x7c, 0xf0, 0xa8, 0x90, 0xf9, - 0xfb, 0x51, 0x21, 0xa3, 0xdc, 0x04, 0x4a, 0x3f, 0x22, 0xc2, 0xcd, 0xf3, 0xe0, 0x58, 0x7c, 0x14, - 0x9a, 0xed, 0x22, 0x46, 0x47, 0xcd, 0xb6, 0xfd, 0x61, 0xb3, 0x6e, 0x69, 0xeb, 0x6d, 0xcd, 0xd3, - 0x49, 0xeb, 0xea, 0xd5, 0x47, 0xda, 0xbe, 0xfe, 0xfd, 0xa4, 0x75, 0x12, 0x69, 0x49, 0xeb, 0x72, - 0x52, 0x48, 0xdb, 0xe7, 0x9a, 0x72, 0x1a, 0x9c, 0xe2, 0x80, 0xb7, 0xb6, 0x7c, 0xc2, 0x98, 0x83, - 0xf9, 0xb1, 0x8f, 0x87, 0xf3, 0x97, 0xac, 0x38, 0xfe, 0xfb, 0x9e, 0x8a, 0x36, 0x05, 0x30, 0x4d, - 0x1d, 0x44, 0xb7, 0x8c, 0x3a, 0x66, 0xd8, 0xe7, 0x1d, 0xc6, 0x74, 0xc0, 0x97, 0xd6, 0xc2, 0x15, - 0x58, 0x02, 0xaf, 0xb6, 0x6d, 0x30, 0x90, 0xe3, 0x90, 0x6d, 0xe4, 0x9a, 0x98, 0x6b, 0x1f, 0xd3, - 0x8f, 0xb7, 0xb6, 0x56, 0xe2, 0x47, 0xf0, 0x2e, 0xc8, 0xb9, 0xf8, 0x3e, 0x33, 0x7c, 0xec, 0x39, - 0xd8, 0xb5, 0xe9, 0x96, 0x61, 0x22, 0xd7, 0x0a, 0xc5, 0xe2, 0xdc, 0x18, 0x9f, 0x79, 0x59, 0x8d, - 0xae, 0x7e, 0x35, 0xbe, 0xfa, 0xd5, 0x5b, 0xf1, 0xd5, 0x5f, 0x9d, 0x0c, 0xef, 0xb0, 0x87, 0x7f, - 0x14, 0x24, 0xfd, 0x64, 0x88, 0xa2, 0xc7, 0x20, 0x8b, 0x31, 0x06, 0xdc, 0x00, 0x87, 0x3d, 0x64, - 0x7e, 0x8e, 0x19, 0xcd, 0x8d, 0xf3, 0x5b, 0x69, 0x36, 0xd5, 0x11, 0x8a, 0x1d, 0xb0, 0x36, 0x42, - 0xce, 0xeb, 0x1c, 0x41, 0x8f, 0x91, 0x94, 0x25, 0x71, 0x88, 0x9b, 0xbb, 0xe2, 0x89, 0x8b, 0x36, - 0x2e, 0x21, 0x86, 0x52, 0x5c, 0xf5, 0xbf, 0xc7, 0x17, 0x58, 0x5f, 0x18, 0x61, 0x7e, 0x9f, 0x69, - 0x83, 0x60, 0x9c, 0xda, 0x5f, 0x44, 0x2e, 0x8f, 0xeb, 0xfc, 0x37, 0xdc, 0x06, 0xc7, 0xbd, 0x26, - 0xc8, 0xaa, 0x4b, 0x59, 0x68, 0x36, 0xcd, 0x8d, 0x71, 0x0b, 0xca, 0xc3, 0x59, 0xd0, 0x62, 0x73, - 0xc7, 0x47, 0x9e, 0x87, 0x7d, 0xf1, 0xea, 0x48, 0xea, 0xa0, 0xfc, 0x2a, 0x81, 0x13, 0x49, 0xe6, - 0xc1, 0xbb, 0xe0, 0x48, 0xcd, 0x21, 0x9b, 0xc8, 0x31, 0xb0, 0xcb, 0xfc, 0x1d, 0x71, 0xa1, 0xbd, - 0x9b, 0x8a, 0xca, 0x0a, 0x2f, 0xe4, 0x68, 0xcb, 0x61, 0xb1, 0x20, 0x30, 0x1d, 0x01, 0xf2, 0x25, - 0xb8, 0x0c, 0xc6, 0x2d, 0xc4, 0x10, 0x77, 0x61, 0xba, 0x74, 0xb1, 0x27, 0x6e, 0x50, 0x54, 0xdb, - 0x68, 0x85, 0xe4, 0x05, 0x1a, 0x2f, 0x57, 0x9e, 0x49, 0x40, 0xee, 0xad, 0x1c, 0xae, 0x83, 0x23, - 0xd1, 0x88, 0x47, 0xda, 0x85, 0x8a, 0x61, 0xba, 0x5d, 0xcb, 0xe8, 0xd1, 0x31, 0x12, 0xbe, 0x7c, - 0x0a, 0x60, 0x40, 0x4d, 0xa3, 0x8e, 0x58, 0xc3, 0xc7, 0x56, 0x8c, 0x1b, 0xa9, 0xb8, 0xd4, 0x0f, - 0xf7, 0xf6, 0xc6, 0xe2, 0x5a, 0x54, 0xd4, 0x01, 0x7e, 0x2c, 0xa0, 0x66, 0xc7, 0x7a, 0x75, 0x22, - 0x72, 0x46, 0x79, 0x1b, 0x5c, 0xe0, 0xe3, 0xa6, 0xe3, 0x9a, 0x4d, 0x19, 0xf6, 0x5b, 0xf3, 0xa6, - 0xe3, 0x6d, 0xe4, 0x5b, 0x4b, 0xd8, 0x25, 0xf5, 0xe6, 0x9b, 0x6a, 0x19, 0x5c, 0x4c, 0xb5, 0x5b, - 0xcc, 0xe7, 0x49, 0x30, 0x61, 0xf1, 0x15, 0xfe, 0xf2, 0x9f, 0xd2, 0xc5, 0xbf, 0xd2, 0xcf, 0xaf, - 0x80, 0x43, 0x1c, 0x07, 0xee, 0x4a, 0xe0, 0x44, 0x52, 0xb4, 0x81, 0x0b, 0xa9, 0x66, 0xa0, 0x4f, - 0x9e, 0x92, 0x2b, 0x2f, 0x80, 0x10, 0xf1, 0x57, 0x96, 0xbf, 0x7d, 0xfa, 0xd7, 0x8f, 0xd9, 0x32, - 0x9c, 0x1f, 0x1c, 0x79, 0x9b, 0x57, 0xbb, 0x88, 0x4e, 0xda, 0x97, 0xf1, 0xc9, 0xfc, 0x1a, 0x3e, - 0x95, 0xc0, 0xf1, 0x84, 0x8c, 0x04, 0xcb, 0xc3, 0x33, 0xec, 0xc8, 0x5e, 0xf2, 0xc2, 0xe8, 0x00, - 0x42, 0xe1, 0x2c, 0x57, 0x78, 0x19, 0x16, 0x87, 0x50, 0x18, 0xa5, 0x32, 0xf8, 0x4d, 0x16, 0xe4, - 0x7a, 0x44, 0x2d, 0x0a, 0x6f, 0x8c, 0xc8, 0x2c, 0x31, 0xd5, 0xc9, 0x6b, 0x07, 0x84, 0x26, 0x44, - 0x5f, 0xe3, 0xa2, 0xab, 0x70, 0x61, 0x58, 0xd1, 0x61, 0xba, 0xf6, 0x99, 0xd1, 0x0c, 0x4c, 0xf0, - 0x3f, 0x09, 0xbc, 0x96, 0x9c, 0xdc, 0x28, 0xbc, 0x3e, 0x32, 0xe9, 0xee, 0x88, 0x28, 0xdf, 0x38, - 0x18, 0x30, 0x61, 0xc0, 0x0a, 0x37, 0xa0, 0x02, 0xcb, 0x23, 0x18, 0x40, 0xbc, 0x36, 0xfd, 0xff, - 0x48, 0x22, 0x1c, 0x24, 0xc6, 0x2c, 0xf8, 0x41, 0x7a, 0xd6, 0xfd, 0x02, 0xa3, 0xbc, 0xf2, 0xc2, - 0x38, 0x42, 0x78, 0x85, 0x0b, 0x7f, 0x0f, 0xce, 0xa6, 0xf8, 0x86, 0x8d, 0x81, 0x8c, 0x8e, 0xd4, - 0x96, 0x20, 0xb9, 0x3d, 0x7e, 0x8d, 0x24, 0x39, 0x21, 0x48, 0x8e, 0x24, 0x39, 0x29, 0x07, 0x8e, - 0x26, 0xb9, 0x23, 0x39, 0xc2, 0xdf, 0x24, 0x00, 0xbb, 0x23, 0x20, 0xbc, 0x9a, 0x9e, 0x62, 0x52, - 0xb2, 0x94, 0xcb, 0x23, 0xd7, 0x0b, 0x69, 0x57, 0xb8, 0xb4, 0x12, 0xbc, 0x34, 0x58, 0x1a, 0x13, - 0x00, 0xd1, 0xf7, 0x31, 0xfc, 0x2e, 0x0b, 0xce, 0x0e, 0x4a, 0x59, 0xc3, 0xdc, 0x61, 0x83, 0x33, - 0xdf, 0x30, 0x77, 0x58, 0x8a, 0xe8, 0xa7, 0x54, 0xb9, 0xf6, 0xf7, 0xe1, 0xdc, 0x60, 0xed, 0x1e, - 0x76, 0x2d, 0xdb, 0xad, 0xb5, 0xe6, 0x58, 0x24, 0x56, 0xf8, 0x53, 0x16, 0x9c, 0x4b, 0xf1, 0x3a, - 0x87, 0x37, 0xd3, 0x53, 0x4f, 0x15, 0x23, 0xe4, 0xf5, 0x83, 0x03, 0x14, 0x76, 0x5c, 0xe7, 0x76, - 0x2c, 0xc3, 0xc5, 0xc1, 0x76, 0xf8, 0x4d, 0xc4, 0x96, 0x23, 0x3e, 0xc7, 0x34, 0xa2, 0x78, 0x52, - 0xbd, 0xf3, 0x78, 0x37, 0x2f, 0x3d, 0xd9, 0xcd, 0x4b, 0x7f, 0xee, 0xe6, 0xa5, 0x87, 0x7b, 0xf9, - 0xcc, 0x93, 0xbd, 0x7c, 0xe6, 0xd9, 0x5e, 0x3e, 0xf3, 0xd1, 0x7c, 0xcd, 0x66, 0x5b, 0x8d, 0x4d, - 0xd5, 0x24, 0x75, 0xcd, 0x24, 0xb4, 0x4e, 0x68, 0x5b, 0xbf, 0x77, 0x9a, 0xfd, 0x82, 0xcb, 0xda, - 0xfd, 0x7d, 0xf3, 0xb7, 0xe3, 0x61, 0xba, 0x39, 0xc1, 0xbf, 0x56, 0x2e, 0xff, 0x1f, 0x00, 0x00, - 0xff, 0xff, 0xbf, 0xd4, 0x24, 0xd7, 0x42, 0x13, 0x00, 0x00, + // 1323 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x57, 0xcf, 0x6f, 0x1b, 0xc5, + 0x1f, 0xf5, 0x3a, 0x69, 0x9a, 0x4c, 0xfa, 0xfd, 0xb6, 0x4c, 0x4b, 0x71, 0xb7, 0x95, 0x5d, 0xb6, + 0x02, 0xd2, 0x16, 0x76, 0x1b, 0x57, 0x48, 0x6d, 0x21, 0x75, 0xed, 0x24, 0xa4, 0x51, 0x1b, 0x35, + 0xac, 0xab, 0x56, 0x02, 0xd4, 0x65, 0xb2, 0x3b, 0xd8, 0x2b, 0xd6, 0x3b, 0xdb, 0x99, 0xb1, 0xd3, + 0x80, 0x38, 0x00, 0x12, 0xf4, 0x58, 0x09, 0x71, 0xe3, 0xd0, 0x13, 0xff, 0x05, 0xf7, 0xde, 0xa8, + 0xe8, 0xa5, 0xa7, 0x82, 0x12, 0x0e, 0x1c, 0x11, 0x77, 0x24, 0xb4, 0xb3, 0xb3, 0xfe, 0x11, 0x6f, + 0xec, 0xb5, 0x9b, 0x9b, 0x3d, 0x3b, 0x9f, 0xf7, 0x79, 0xef, 0xe9, 0x33, 0xb3, 0x6f, 0x81, 0xe1, + 0xfa, 0x1c, 0x53, 0xbb, 0x8e, 0x5c, 0xdf, 0x62, 0xd8, 0x6e, 0x52, 0x97, 0x6f, 0x19, 0xb6, 0xdd, + 0x32, 0x02, 0x4a, 0x5a, 0xae, 0x83, 0xa9, 0xd1, 0x9a, 0x37, 0xee, 0x37, 0x31, 0xdd, 0xd2, 0x03, + 0x4a, 0x38, 0x81, 0x67, 0x12, 0x0a, 0x74, 0xdb, 0x6e, 0xe9, 0x71, 0x81, 0xde, 0x9a, 0x57, 0x4f, + 0xd5, 0x08, 0xa9, 0x79, 0xd8, 0x40, 0x81, 0x6b, 0x20, 0xdf, 0x27, 0x1c, 0x71, 0x97, 0xf8, 0x2c, + 0x82, 0x50, 0x8f, 0xd5, 0x48, 0x8d, 0x88, 0x9f, 0x46, 0xf8, 0x4b, 0xae, 0x16, 0x64, 0x8d, 0xf8, + 0xb7, 0xd1, 0xfc, 0xcc, 0xe0, 0x6e, 0x03, 0x33, 0x8e, 0x1a, 0x81, 0xdc, 0x50, 0x4c, 0x43, 0xb5, + 0xcd, 0x22, 0xaa, 0xb9, 0xb0, 0x57, 0x4d, 0x6b, 0xde, 0x60, 0x75, 0x44, 0xb1, 0x63, 0xd9, 0xc4, + 0x67, 0xcd, 0x46, 0xbb, 0xe2, 0x8d, 0x01, 0x15, 0x9b, 0x2e, 0xc5, 0xd1, 0x36, 0xed, 0x12, 0x38, + 0xf9, 0x61, 0xe8, 0xca, 0xa2, 0xac, 0x5e, 0xc1, 0x3e, 0x66, 0x2e, 0x33, 0xf1, 0xfd, 0x26, 0x66, + 0x1c, 0x9e, 0x00, 0xd3, 0x11, 0x84, 0xeb, 0xe4, 0x94, 0xd3, 0xca, 0xdc, 0x8c, 0x79, 0x50, 0xfc, + 0x5f, 0x75, 0x34, 0x06, 0x4e, 0x25, 0x57, 0xb2, 0x80, 0xf8, 0x0c, 0xc3, 0x2a, 0xf8, 0x5f, 0x2d, + 0x5a, 0xb2, 0x18, 0x47, 0x1c, 0x8b, 0xfa, 0xd9, 0xe2, 0x9c, 0xbe, 0x97, 0xf1, 0xad, 0x79, 0x5d, + 0x62, 0x54, 0xc3, 0xfd, 0x95, 0xc9, 0x27, 0x2f, 0x0a, 0x19, 0xf3, 0x50, 0xad, 0x6b, 0x4d, 0x3b, + 0x05, 0xd4, 0x9e, 0xa6, 0x8b, 0x21, 0x4c, 0xcc, 0x56, 0x43, 0xbb, 0xc4, 0xc4, 0x4f, 0x25, 0xa3, + 0x0a, 0x98, 0x12, 0x6d, 0x59, 0x4e, 0x39, 0x3d, 0x31, 0x37, 0x5b, 0x3c, 0xa7, 0xa7, 0x98, 0x01, + 0x5d, 0x80, 0x98, 0xb2, 0x52, 0x3b, 0x0b, 0xde, 0xea, 0x6f, 0x51, 0xe5, 0x88, 0xf2, 0x75, 0x4a, + 0x02, 0xc2, 0x90, 0xd7, 0x66, 0xf3, 0x50, 0x01, 0x73, 0xc3, 0xf7, 0x4a, 0x6e, 0x9f, 0x80, 0x99, + 0x20, 0x5e, 0x94, 0x4e, 0x5d, 0x4d, 0x47, 0x4f, 0x82, 0x97, 0x1d, 0xc7, 0x0d, 0x87, 0xb3, 0x03, + 0xdd, 0x01, 0xd4, 0xe6, 0xc0, 0x9b, 0x49, 0x4c, 0x48, 0xd0, 0x47, 0xfa, 0x3b, 0x25, 0x59, 0x60, + 0xcf, 0x56, 0xc9, 0xf9, 0xe3, 0x7e, 0xce, 0x0b, 0x23, 0x71, 0x36, 0x71, 0x83, 0xb4, 0x90, 0x97, + 0x48, 0xb9, 0x04, 0x0e, 0x88, 0xd6, 0x03, 0x46, 0x10, 0x9e, 0x04, 0x33, 0xb6, 0xe7, 0x62, 0x9f, + 0x87, 0xcf, 0xb2, 0xe2, 0xd9, 0x74, 0xb4, 0xb0, 0xea, 0x68, 0xdf, 0x2b, 0xe0, 0x75, 0xa1, 0xe4, + 0x0e, 0xf2, 0x5c, 0x07, 0x71, 0x42, 0xbb, 0xac, 0xa2, 0xc3, 0x07, 0x1c, 0x2e, 0x80, 0x23, 0x31, + 0x69, 0x0b, 0x39, 0x0e, 0xc5, 0x8c, 0x45, 0x4d, 0x2a, 0xf0, 0x9f, 0x17, 0x85, 0xff, 0x6f, 0xa1, + 0x86, 0x77, 0x45, 0x93, 0x0f, 0x34, 0xf3, 0x70, 0xbc, 0xb7, 0x1c, 0xad, 0x5c, 0x99, 0x7e, 0xf8, + 0xb8, 0x90, 0xf9, 0xeb, 0x71, 0x21, 0xa3, 0xdd, 0x02, 0xda, 0x20, 0x22, 0xd2, 0xcd, 0xb3, 0xe0, + 0x48, 0x7c, 0x84, 0xdb, 0xed, 0x22, 0x46, 0x87, 0xed, 0xae, 0xfd, 0x61, 0xb3, 0x7e, 0x69, 0xeb, + 0x5d, 0xcd, 0xd3, 0x49, 0xeb, 0xeb, 0x35, 0x40, 0xda, 0xae, 0xfe, 0x83, 0xa4, 0xf5, 0x12, 0xe9, + 0x48, 0xeb, 0x73, 0x52, 0x4a, 0xdb, 0xe5, 0x9a, 0x76, 0x12, 0x9c, 0x10, 0x80, 0xb7, 0xeb, 0x94, + 0x70, 0xee, 0x61, 0x71, 0xec, 0xe3, 0xe1, 0xfc, 0x39, 0x2b, 0x8f, 0xff, 0xae, 0xa7, 0xb2, 0x4d, + 0x01, 0xcc, 0x32, 0x0f, 0xb1, 0xba, 0xd5, 0xc0, 0x1c, 0x53, 0xd1, 0x61, 0xc2, 0x04, 0x62, 0x69, + 0x2d, 0x5c, 0x81, 0x45, 0xf0, 0x6a, 0xd7, 0x06, 0x0b, 0x79, 0x1e, 0xd9, 0x44, 0xbe, 0x8d, 0x85, + 0xf6, 0x09, 0xf3, 0x68, 0x67, 0x6b, 0x39, 0x7e, 0x04, 0xef, 0x81, 0x9c, 0x8f, 0x1f, 0x70, 0x8b, + 0xe2, 0xc0, 0xc3, 0xbe, 0xcb, 0xea, 0x96, 0x8d, 0x7c, 0x27, 0x14, 0x8b, 0x73, 0x13, 0x62, 0xe6, + 0x55, 0x3d, 0xba, 0xf1, 0xf5, 0xf8, 0xc6, 0xd7, 0x6f, 0xc7, 0x37, 0x7e, 0x65, 0x3a, 0xbc, 0xc3, + 0x1e, 0xfd, 0x5e, 0x50, 0xcc, 0xe3, 0x21, 0x8a, 0x19, 0x83, 0x2c, 0xc6, 0x18, 0xb0, 0x0a, 0x0e, + 0x06, 0xc8, 0xfe, 0x1c, 0x73, 0x96, 0x9b, 0x14, 0xb7, 0xd2, 0xe5, 0x54, 0x47, 0x28, 0x76, 0xc0, + 0xa9, 0x86, 0x9c, 0xd7, 0x05, 0x82, 0x19, 0x23, 0x69, 0x4b, 0xf2, 0x10, 0xb7, 0x77, 0xc5, 0x13, + 0x17, 0x6d, 0x5c, 0x42, 0x1c, 0xa5, 0xb8, 0xe1, 0x7f, 0x8b, 0x2f, 0xb0, 0x81, 0x30, 0xd2, 0xfc, + 0x01, 0xd3, 0x06, 0xc1, 0x24, 0x73, 0xbf, 0x88, 0x5c, 0x9e, 0x34, 0xc5, 0x6f, 0xb8, 0x09, 0x8e, + 0x06, 0x6d, 0x90, 0x55, 0x9f, 0xf1, 0xd0, 0x6c, 0x96, 0x9b, 0x10, 0x16, 0x94, 0x46, 0xb3, 0xa0, + 0xc3, 0xe6, 0x2e, 0x45, 0x41, 0x80, 0xa9, 0x7c, 0x75, 0x24, 0x75, 0xd0, 0x7e, 0x51, 0xc0, 0xb1, + 0x24, 0xf3, 0xe0, 0x3d, 0x70, 0xa8, 0xe6, 0x91, 0x0d, 0xe4, 0x59, 0xd8, 0xe7, 0x74, 0x4b, 0x5e, + 0x68, 0xef, 0xa6, 0xa2, 0xb2, 0x22, 0x0a, 0x05, 0xda, 0x72, 0x58, 0x2c, 0x09, 0xcc, 0x46, 0x80, + 0x62, 0x09, 0x2e, 0x83, 0x49, 0x07, 0x71, 0x24, 0x5c, 0x98, 0x2d, 0x9e, 0x1f, 0xf4, 0x1a, 0xec, + 0xa2, 0x15, 0x92, 0x97, 0x68, 0xa2, 0x5c, 0x7b, 0xae, 0x00, 0x75, 0x6f, 0xe5, 0x70, 0x1d, 0x1c, + 0x8a, 0x46, 0x3c, 0xd2, 0x2e, 0x55, 0x8c, 0xd2, 0xed, 0x7a, 0xc6, 0x8c, 0x8e, 0x91, 0xf4, 0xe5, + 0x53, 0x00, 0x5b, 0xcc, 0xb6, 0x1a, 0x88, 0x37, 0xc3, 0x98, 0x21, 0x71, 0x23, 0x15, 0x17, 0x06, + 0xe1, 0xde, 0xa9, 0x2e, 0xae, 0x45, 0x45, 0x3d, 0xe0, 0x47, 0x5a, 0xcc, 0xee, 0x59, 0xaf, 0x4c, + 0x45, 0xce, 0x68, 0x6f, 0x83, 0x73, 0x62, 0xdc, 0x4c, 0x5c, 0x73, 0x19, 0xc7, 0xb4, 0x33, 0x6f, + 0x26, 0xde, 0x44, 0xd4, 0x59, 0xc2, 0x3e, 0x69, 0xb4, 0xdf, 0x54, 0xcb, 0xe0, 0x7c, 0xaa, 0xdd, + 0x72, 0x3e, 0x8f, 0x83, 0x29, 0x47, 0xac, 0x88, 0x97, 0xff, 0x8c, 0x29, 0xff, 0x15, 0x7f, 0x7a, + 0x05, 0x1c, 0x10, 0x38, 0x70, 0x5b, 0x01, 0xc7, 0x92, 0x12, 0x0d, 0xbc, 0x96, 0x6a, 0x06, 0x06, + 0xc4, 0x28, 0xb5, 0xfc, 0x12, 0x08, 0x11, 0x7f, 0x6d, 0xf9, 0x9b, 0x67, 0x7f, 0xfe, 0x90, 0x2d, + 0xc1, 0x85, 0xe1, 0x49, 0xb7, 0x7d, 0xb5, 0xcb, 0xe8, 0x64, 0x7c, 0x19, 0x9f, 0xcc, 0xaf, 0xe0, + 0x33, 0x05, 0x1c, 0x4d, 0xc8, 0x48, 0xb0, 0x34, 0x3a, 0xc3, 0x9e, 0xec, 0xa5, 0x5e, 0x1b, 0x1f, + 0x40, 0x2a, 0xbc, 0x2c, 0x14, 0x5e, 0x84, 0xf3, 0x23, 0x28, 0x8c, 0x52, 0x19, 0xfc, 0x3a, 0x0b, + 0x72, 0x7b, 0x44, 0x2d, 0x06, 0x6f, 0x8e, 0xc9, 0x2c, 0x31, 0xd5, 0xa9, 0x6b, 0xfb, 0x84, 0x26, + 0x45, 0x5f, 0x17, 0xa2, 0x2b, 0xf0, 0xda, 0xa8, 0xa2, 0xc3, 0x50, 0x4d, 0xb9, 0xd5, 0x0e, 0x4c, + 0xf0, 0x5f, 0x05, 0xbc, 0x96, 0x9c, 0xdc, 0x18, 0xbc, 0x31, 0x36, 0xe9, 0xfe, 0x88, 0xa8, 0xde, + 0xdc, 0x1f, 0x30, 0x69, 0xc0, 0x8a, 0x30, 0xa0, 0x0c, 0x4b, 0x63, 0x18, 0x40, 0x82, 0x2e, 0xfd, + 0x7f, 0x2b, 0x32, 0x1c, 0x24, 0xc6, 0x2c, 0xf8, 0x41, 0x7a, 0xd6, 0x83, 0x02, 0xa3, 0xba, 0xf2, + 0xd2, 0x38, 0x52, 0x78, 0x59, 0x08, 0x7f, 0x0f, 0x5e, 0x4e, 0xf1, 0xe9, 0x1a, 0x03, 0x59, 0x3d, + 0xa9, 0x2d, 0x41, 0x72, 0x77, 0xfc, 0x1a, 0x4b, 0x72, 0x42, 0x90, 0x1c, 0x4b, 0x72, 0x52, 0x0e, + 0x1c, 0x4f, 0x72, 0x4f, 0x72, 0x84, 0xbf, 0x2a, 0x00, 0xf6, 0x47, 0x40, 0x78, 0x35, 0x3d, 0xc5, + 0xa4, 0x64, 0xa9, 0x96, 0xc6, 0xae, 0x97, 0xd2, 0x2e, 0x09, 0x69, 0x45, 0x78, 0x61, 0xb8, 0x34, + 0x2e, 0x01, 0xa2, 0xcf, 0x62, 0xf8, 0x6d, 0x16, 0x9c, 0x1e, 0x96, 0xb2, 0x46, 0xb9, 0xc3, 0x86, + 0x67, 0xbe, 0x51, 0xee, 0xb0, 0x14, 0xd1, 0x4f, 0xab, 0x08, 0xed, 0xef, 0xc3, 0x2b, 0xc3, 0xb5, + 0x07, 0xd8, 0x77, 0x5c, 0xbf, 0xd6, 0x99, 0x63, 0x99, 0x58, 0xe1, 0x8f, 0x59, 0x70, 0x26, 0xc5, + 0xeb, 0x1c, 0xde, 0x4a, 0x4f, 0x3d, 0x55, 0x8c, 0x50, 0xd7, 0xf7, 0x0f, 0x50, 0xda, 0x71, 0x43, + 0xd8, 0xb1, 0x0c, 0x17, 0x87, 0xdb, 0x41, 0xdb, 0x88, 0x1d, 0x47, 0xa8, 0xc0, 0xb4, 0xa2, 0x78, + 0x52, 0xb9, 0xfb, 0x64, 0x3b, 0xaf, 0x3c, 0xdd, 0xce, 0x2b, 0x7f, 0x6c, 0xe7, 0x95, 0x47, 0x3b, + 0xf9, 0xcc, 0xd3, 0x9d, 0x7c, 0xe6, 0xf9, 0x4e, 0x3e, 0xf3, 0xd1, 0x42, 0xcd, 0xe5, 0xf5, 0xe6, + 0x86, 0x6e, 0x93, 0x86, 0x61, 0x13, 0xd6, 0x20, 0xac, 0xab, 0xdf, 0x3b, 0xed, 0x7e, 0xad, 0x8b, + 0xc6, 0x83, 0x5d, 0xf3, 0xb7, 0x15, 0x60, 0xb6, 0x31, 0x25, 0xbe, 0x56, 0x2e, 0xfe, 0x17, 0x00, + 0x00, 0xff, 0xff, 0x84, 0xab, 0xda, 0x7b, 0x39, 0x13, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -4293,7 +4292,7 @@ func (m *ThrottledPacketDataWrapper) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &types1.SlashPacketData{} + v := &types.SlashPacketData{} if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -4328,7 +4327,7 @@ func (m *ThrottledPacketDataWrapper) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &types1.VSCMaturedPacketData{} + v := &types.VSCMaturedPacketData{} if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } diff --git a/x/ccv/consumer/types/genesis.go b/x/ccv/types/genesis.go similarity index 67% rename from x/ccv/consumer/types/genesis.go rename to x/ccv/types/genesis.go index 3a8769939b..ff18480ecb 100644 --- a/x/ccv/consumer/types/genesis.go +++ b/x/ccv/types/genesis.go @@ -6,8 +6,6 @@ import ( errorsmod "cosmossdk.io/errors" abci "github.com/cometbft/cometbft/abci/types" - - ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) // NewInitialGenesisState returns a consumer GenesisState for a completely new consumer chain. @@ -29,7 +27,7 @@ func NewRestartGenesisState( maturingPackets []MaturingVSCPacket, initValSet []abci.ValidatorUpdate, heightToValsetUpdateIDs []HeightToValsetUpdateID, - pendingConsumerPackets ccv.ConsumerPacketDataList, + pendingConsumerPackets ConsumerPacketDataList, outstandingDowntimes []OutstandingDowntime, lastTransBlockHeight LastTransmissionBlockHeight, params Params, @@ -78,7 +76,7 @@ func (gs GenesisState) Validate() error { return nil } if len(gs.InitialValSet) == 0 { - return errorsmod.Wrap(ccv.ErrInvalidGenesis, "initial validator set is empty") + return errorsmod.Wrap(ErrInvalidGenesis, "initial validator set is empty") } if err := gs.Params.Validate(); err != nil { return err @@ -86,68 +84,68 @@ func (gs GenesisState) Validate() error { if gs.NewChain { if gs.ProviderClientState == nil { - return errorsmod.Wrap(ccv.ErrInvalidGenesis, "provider client state cannot be nil for new chain") + return errorsmod.Wrap(ErrInvalidGenesis, "provider client state cannot be nil for new chain") } if err := gs.ProviderClientState.Validate(); err != nil { - return errorsmod.Wrapf(ccv.ErrInvalidGenesis, "provider client state invalid for new chain %s", err.Error()) + return errorsmod.Wrapf(ErrInvalidGenesis, "provider client state invalid for new chain %s", err.Error()) } if gs.ProviderConsensusState == nil { - return errorsmod.Wrap(ccv.ErrInvalidGenesis, "provider consensus state cannot be nil for new chain") + return errorsmod.Wrap(ErrInvalidGenesis, "provider consensus state cannot be nil for new chain") } if err := gs.ProviderConsensusState.ValidateBasic(); err != nil { - return errorsmod.Wrapf(ccv.ErrInvalidGenesis, "provider consensus state invalid for new chain %s", err.Error()) + return errorsmod.Wrapf(ErrInvalidGenesis, "provider consensus state invalid for new chain %s", err.Error()) } if gs.ProviderClientId != "" { - return errorsmod.Wrap(ccv.ErrInvalidGenesis, "provider client id cannot be set for new chain. It must be established on handshake") + return errorsmod.Wrap(ErrInvalidGenesis, "provider client id cannot be set for new chain. It must be established on handshake") } if gs.ProviderChannelId != "" { - return errorsmod.Wrap(ccv.ErrInvalidGenesis, "provider channel id cannot be set for new chain. It must be established on handshake") + return errorsmod.Wrap(ErrInvalidGenesis, "provider channel id cannot be set for new chain. It must be established on handshake") } if len(gs.MaturingPackets) != 0 { - return errorsmod.Wrap(ccv.ErrInvalidGenesis, "maturing packets must be empty for new chain") + return errorsmod.Wrap(ErrInvalidGenesis, "maturing packets must be empty for new chain") } if len(gs.PendingConsumerPackets.List) != 0 { - return errorsmod.Wrap(ccv.ErrInvalidGenesis, "pending consumer packets must be empty for new chain") + return errorsmod.Wrap(ErrInvalidGenesis, "pending consumer packets must be empty for new chain") } if gs.LastTransmissionBlockHeight.Height != 0 { - return errorsmod.Wrap(ccv.ErrInvalidGenesis, "last transmission block height must be empty for new chain") + return errorsmod.Wrap(ErrInvalidGenesis, "last transmission block height must be empty for new chain") } } else { // NOTE: For restart genesis, we will verify initial validator set in InitGenesis. if gs.ProviderClientId == "" { - return errorsmod.Wrap(ccv.ErrInvalidGenesis, "provider client id must be set for a restarting consumer genesis state") + return errorsmod.Wrap(ErrInvalidGenesis, "provider client id must be set for a restarting consumer genesis state") } // handshake is still in progress handshakeInProgress := gs.ProviderChannelId == "" if handshakeInProgress { if len(gs.MaturingPackets) != 0 { return errorsmod.Wrap( - ccv.ErrInvalidGenesis, "maturing packets must be empty when handshake isn't completed") + ErrInvalidGenesis, "maturing packets must be empty when handshake isn't completed") } if len(gs.OutstandingDowntimeSlashing) != 0 { return errorsmod.Wrap( - ccv.ErrInvalidGenesis, "outstanding downtime must be empty when handshake isn't completed") + ErrInvalidGenesis, "outstanding downtime must be empty when handshake isn't completed") } if gs.LastTransmissionBlockHeight.Height != 0 { return errorsmod.Wrap( - ccv.ErrInvalidGenesis, "last transmission block height must be zero when handshake isn't completed") + ErrInvalidGenesis, "last transmission block height must be zero when handshake isn't completed") } if len(gs.PendingConsumerPackets.List) != 0 { for _, packet := range gs.PendingConsumerPackets.List { - if packet.Type == ccv.VscMaturedPacket { - return errorsmod.Wrap(ccv.ErrInvalidGenesis, "pending maturing packets must be empty when handshake isn't completed") + if packet.Type == VscMaturedPacket { + return errorsmod.Wrap(ErrInvalidGenesis, "pending maturing packets must be empty when handshake isn't completed") } } } } if gs.HeightToValsetUpdateId == nil { return errorsmod.Wrap( - ccv.ErrInvalidGenesis, + ErrInvalidGenesis, "empty height to validator set update id mapping", ) } if gs.ProviderClientState != nil || gs.ProviderConsensusState != nil { - return errorsmod.Wrap(ccv.ErrInvalidGenesis, "provider client state and consensus state must be nil for a restarting genesis state") + return errorsmod.Wrap(ErrInvalidGenesis, "provider client state and consensus state must be nil for a restarting genesis state") } for _, mat := range gs.MaturingPackets { if err := mat.Validate(); err != nil { @@ -160,10 +158,10 @@ func (gs GenesisState) Validate() error { func (mat MaturingVSCPacket) Validate() error { if mat.MaturityTime.IsZero() { - return errorsmod.Wrap(ccv.ErrInvalidVSCMaturedTime, "cannot have 0 maturity time") + return errorsmod.Wrap(ErrInvalidVSCMaturedTime, "cannot have 0 maturity time") } if mat.VscId == 0 { - return errorsmod.Wrap(ccv.ErrInvalidVSCMaturedId, "cannot have 0 maturity time") + return errorsmod.Wrap(ErrInvalidVSCMaturedId, "cannot have 0 maturity time") } return nil } diff --git a/x/ccv/consumer/types/params.go b/x/ccv/types/params.go similarity index 83% rename from x/ccv/consumer/types/params.go rename to x/ccv/types/params.go index a9b4e61285..e8ea0a8765 100644 --- a/x/ccv/consumer/types/params.go +++ b/x/ccv/types/params.go @@ -7,8 +7,6 @@ import ( sdktypes "github.com/cosmos/cosmos-sdk/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - - ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) const ( @@ -95,7 +93,7 @@ func DefaultParams() Params { DefaultBlocksPerDistributionTransmission, "", "", - ccvtypes.DefaultCCVTimeoutPeriod, + DefaultCCVTimeoutPeriod, DefaultTransferTimeoutPeriod, DefaultConsumerRedistributeFrac, DefaultHistoricalEntries, @@ -108,31 +106,31 @@ func DefaultParams() Params { // Validate all ccv-consumer module parameters func (p Params) Validate() error { - if err := ccvtypes.ValidateBool(p.Enabled); err != nil { + if err := ValidateBool(p.Enabled); err != nil { return err } - if err := ccvtypes.ValidatePositiveInt64(p.BlocksPerDistributionTransmission); err != nil { + if err := ValidatePositiveInt64(p.BlocksPerDistributionTransmission); err != nil { return err } - if err := ccvtypes.ValidateDistributionTransmissionChannel(p.DistributionTransmissionChannel); err != nil { + if err := ValidateDistributionTransmissionChannel(p.DistributionTransmissionChannel); err != nil { return err } if err := ValidateProviderFeePoolAddrStr(p.ProviderFeePoolAddrStr); err != nil { return err } - if err := ccvtypes.ValidateDuration(p.CcvTimeoutPeriod); err != nil { + if err := ValidateDuration(p.CcvTimeoutPeriod); err != nil { return err } - if err := ccvtypes.ValidateDuration(p.TransferTimeoutPeriod); err != nil { + if err := ValidateDuration(p.TransferTimeoutPeriod); err != nil { return err } - if err := ccvtypes.ValidateStringFraction(p.ConsumerRedistributionFraction); err != nil { + if err := ValidateStringFraction(p.ConsumerRedistributionFraction); err != nil { return err } - if err := ccvtypes.ValidatePositiveInt64(p.HistoricalEntries); err != nil { + if err := ValidatePositiveInt64(p.HistoricalEntries); err != nil { return err } - if err := ccvtypes.ValidateDuration(p.UnbondingPeriod); err != nil { + if err := ValidateDuration(p.UnbondingPeriod); err != nil { return err } if err := ValidateSoftOptOutThreshold(p.SoftOptOutThreshold); err != nil { @@ -150,23 +148,23 @@ func (p Params) Validate() error { // ParamSetPairs implements params.ParamSet func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { return paramtypes.ParamSetPairs{ - paramtypes.NewParamSetPair(KeyEnabled, p.Enabled, ccvtypes.ValidateBool), + paramtypes.NewParamSetPair(KeyEnabled, p.Enabled, ValidateBool), paramtypes.NewParamSetPair(KeyBlocksPerDistributionTransmission, - p.BlocksPerDistributionTransmission, ccvtypes.ValidatePositiveInt64), + p.BlocksPerDistributionTransmission, ValidatePositiveInt64), paramtypes.NewParamSetPair(KeyDistributionTransmissionChannel, - p.DistributionTransmissionChannel, ccvtypes.ValidateDistributionTransmissionChannel), + p.DistributionTransmissionChannel, ValidateDistributionTransmissionChannel), paramtypes.NewParamSetPair(KeyProviderFeePoolAddrStr, p.ProviderFeePoolAddrStr, ValidateProviderFeePoolAddrStr), - paramtypes.NewParamSetPair(ccvtypes.KeyCCVTimeoutPeriod, - p.CcvTimeoutPeriod, ccvtypes.ValidateDuration), + paramtypes.NewParamSetPair(KeyCCVTimeoutPeriod, + p.CcvTimeoutPeriod, ValidateDuration), paramtypes.NewParamSetPair(KeyTransferTimeoutPeriod, - p.TransferTimeoutPeriod, ccvtypes.ValidateDuration), + p.TransferTimeoutPeriod, ValidateDuration), paramtypes.NewParamSetPair(KeyConsumerRedistributionFrac, - p.ConsumerRedistributionFraction, ccvtypes.ValidateStringFraction), + p.ConsumerRedistributionFraction, ValidateStringFraction), paramtypes.NewParamSetPair(KeyHistoricalEntries, - p.HistoricalEntries, ccvtypes.ValidatePositiveInt64), + p.HistoricalEntries, ValidatePositiveInt64), paramtypes.NewParamSetPair(KeyConsumerUnbondingPeriod, - p.UnbondingPeriod, ccvtypes.ValidateDuration), + p.UnbondingPeriod, ValidateDuration), paramtypes.NewParamSetPair(KeySoftOptOutThreshold, p.SoftOptOutThreshold, ValidateSoftOptOutThreshold), paramtypes.NewParamSetPair(KeyRewardDenoms, @@ -182,7 +180,7 @@ func ValidateProviderFeePoolAddrStr(i interface{}) error { return nil } // Otherwise validate as usual for a bech32 address - return ccvtypes.ValidateBech32(i) + return ValidateBech32(i) } func ValidateSoftOptOutThreshold(i interface{}) error { diff --git a/x/ccv/types/shared_consumer.pb.go b/x/ccv/types/shared_consumer.pb.go new file mode 100644 index 0000000000..4cf8860269 --- /dev/null +++ b/x/ccv/types/shared_consumer.pb.go @@ -0,0 +1,2712 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: interchain_security/ccv/v1/shared_consumer.proto + +package types + +import ( + fmt "fmt" + types "github.com/cometbft/cometbft/abci/types" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + github_com_cosmos_gogoproto_types "github.com/cosmos/gogoproto/types" + _ "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + _07_tendermint "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + _ "google.golang.org/protobuf/types/known/durationpb" + _ "google.golang.org/protobuf/types/known/timestamppb" + io "io" + math "math" + math_bits "math/bits" + time "time" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf +var _ = time.Kitchen + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Params defines the parameters for CCV consumer module. +// +// Note this type is referenced in both the consumer and provider CCV modules, +// and persisted on the provider, see MakeConsumerGenesis and SetConsumerGenesis. +// +// TODO: Rename to ConsumerParams. See https://github.com/cosmos/interchain-security/issues/1206 +type Params struct { + // TODO: Remove enabled flag and find a better way to setup integration tests + // See: https://github.com/cosmos/interchain-security/issues/339 + Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` + /////////////////////// + // Distribution Params + // Number of blocks between ibc-token-transfers from the consumer chain to + // the provider chain. Note that at this transmission event a fraction of + // the accumulated tokens are divided and sent consumer redistribution + // address. + BlocksPerDistributionTransmission int64 `protobuf:"varint,2,opt,name=blocks_per_distribution_transmission,json=blocksPerDistributionTransmission,proto3" json:"blocks_per_distribution_transmission,omitempty"` + // Channel, and provider-chain receiving address to send distribution token + // transfers over. These parameters is auto-set during the consumer <-> + // provider handshake procedure. + DistributionTransmissionChannel string `protobuf:"bytes,3,opt,name=distribution_transmission_channel,json=distributionTransmissionChannel,proto3" json:"distribution_transmission_channel,omitempty"` + ProviderFeePoolAddrStr string `protobuf:"bytes,4,opt,name=provider_fee_pool_addr_str,json=providerFeePoolAddrStr,proto3" json:"provider_fee_pool_addr_str,omitempty"` + // Sent CCV related IBC packets will timeout after this duration + CcvTimeoutPeriod time.Duration `protobuf:"bytes,5,opt,name=ccv_timeout_period,json=ccvTimeoutPeriod,proto3,stdduration" json:"ccv_timeout_period"` + // Sent transfer related IBC packets will timeout after this duration + TransferTimeoutPeriod time.Duration `protobuf:"bytes,6,opt,name=transfer_timeout_period,json=transferTimeoutPeriod,proto3,stdduration" json:"transfer_timeout_period"` + // The fraction of tokens allocated to the consumer redistribution address + // during distribution events. The fraction is a string representing a + // decimal number. For example "0.75" would represent 75%. + ConsumerRedistributionFraction string `protobuf:"bytes,7,opt,name=consumer_redistribution_fraction,json=consumerRedistributionFraction,proto3" json:"consumer_redistribution_fraction,omitempty"` + // The number of historical info entries to persist in store. + // This param is a part of the cosmos sdk staking module. In the case of + // a ccv enabled consumer chain, the ccv module acts as the staking module. + HistoricalEntries int64 `protobuf:"varint,8,opt,name=historical_entries,json=historicalEntries,proto3" json:"historical_entries,omitempty"` + // Unbonding period for the consumer, + // which should be smaller than that of the provider in general. + UnbondingPeriod time.Duration `protobuf:"bytes,9,opt,name=unbonding_period,json=unbondingPeriod,proto3,stdduration" json:"unbonding_period"` + // The threshold for the percentage of validators at the bottom of the set who + // can opt out of running the consumer chain without being punished. For + // example, a value of 0.05 means that the validators in the bottom 5% of the + // set can opt out + SoftOptOutThreshold string `protobuf:"bytes,10,opt,name=soft_opt_out_threshold,json=softOptOutThreshold,proto3" json:"soft_opt_out_threshold,omitempty"` + // Reward denoms. These are the denominations which are allowed to be sent to + // the provider as rewards. + RewardDenoms []string `protobuf:"bytes,11,rep,name=reward_denoms,json=rewardDenoms,proto3" json:"reward_denoms,omitempty"` + // Provider-originated reward denoms. These are denoms coming from the + // provider which are allowed to be used as rewards. e.g. "uatom" + ProviderRewardDenoms []string `protobuf:"bytes,12,rep,name=provider_reward_denoms,json=providerRewardDenoms,proto3" json:"provider_reward_denoms,omitempty"` +} + +func (m *Params) Reset() { *m = Params{} } +func (m *Params) String() string { return proto.CompactTextString(m) } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_d0a8be0efc64dfbc, []int{0} +} +func (m *Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Params.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 *Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_Params.Merge(m, src) +} +func (m *Params) XXX_Size() int { + return m.Size() +} +func (m *Params) XXX_DiscardUnknown() { + xxx_messageInfo_Params.DiscardUnknown(m) +} + +var xxx_messageInfo_Params proto.InternalMessageInfo + +func (m *Params) GetEnabled() bool { + if m != nil { + return m.Enabled + } + return false +} + +func (m *Params) GetBlocksPerDistributionTransmission() int64 { + if m != nil { + return m.BlocksPerDistributionTransmission + } + return 0 +} + +func (m *Params) GetDistributionTransmissionChannel() string { + if m != nil { + return m.DistributionTransmissionChannel + } + return "" +} + +func (m *Params) GetProviderFeePoolAddrStr() string { + if m != nil { + return m.ProviderFeePoolAddrStr + } + return "" +} + +func (m *Params) GetCcvTimeoutPeriod() time.Duration { + if m != nil { + return m.CcvTimeoutPeriod + } + return 0 +} + +func (m *Params) GetTransferTimeoutPeriod() time.Duration { + if m != nil { + return m.TransferTimeoutPeriod + } + return 0 +} + +func (m *Params) GetConsumerRedistributionFraction() string { + if m != nil { + return m.ConsumerRedistributionFraction + } + return "" +} + +func (m *Params) GetHistoricalEntries() int64 { + if m != nil { + return m.HistoricalEntries + } + return 0 +} + +func (m *Params) GetUnbondingPeriod() time.Duration { + if m != nil { + return m.UnbondingPeriod + } + return 0 +} + +func (m *Params) GetSoftOptOutThreshold() string { + if m != nil { + return m.SoftOptOutThreshold + } + return "" +} + +func (m *Params) GetRewardDenoms() []string { + if m != nil { + return m.RewardDenoms + } + return nil +} + +func (m *Params) GetProviderRewardDenoms() []string { + if m != nil { + return m.ProviderRewardDenoms + } + return nil +} + +// GenesisState defines the CCV consumer chain genesis state. +// +// Note this type is referenced in both the consumer and provider CCV modules, +// and persisted on the provider, see MakeConsumerGenesis and SetConsumerGenesis. +// +// TODO: Rename to ConsumerGenesisState. See https://github.com/cosmos/interchain-security/issues/1206 +type GenesisState struct { + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` + ProviderClientId string `protobuf:"bytes,2,opt,name=provider_client_id,json=providerClientId,proto3" json:"provider_client_id,omitempty"` + ProviderChannelId string `protobuf:"bytes,3,opt,name=provider_channel_id,json=providerChannelId,proto3" json:"provider_channel_id,omitempty"` + NewChain bool `protobuf:"varint,4,opt,name=new_chain,json=newChain,proto3" json:"new_chain,omitempty"` + // ProviderClientState filled in on new chain, nil on restart. + ProviderClientState *_07_tendermint.ClientState `protobuf:"bytes,5,opt,name=provider_client_state,json=providerClientState,proto3" json:"provider_client_state,omitempty"` + // ProviderConsensusState filled in on new chain, nil on restart. + ProviderConsensusState *_07_tendermint.ConsensusState `protobuf:"bytes,6,opt,name=provider_consensus_state,json=providerConsensusState,proto3" json:"provider_consensus_state,omitempty"` + // MaturingPackets nil on new chain, filled in on restart. + MaturingPackets []MaturingVSCPacket `protobuf:"bytes,7,rep,name=maturing_packets,json=maturingPackets,proto3" json:"maturing_packets"` + // InitialValset filled in on new chain and on restart. + InitialValSet []types.ValidatorUpdate `protobuf:"bytes,8,rep,name=initial_val_set,json=initialValSet,proto3" json:"initial_val_set"` + // HeightToValsetUpdateId nil on new chain, filled in on restart. + HeightToValsetUpdateId []HeightToValsetUpdateID `protobuf:"bytes,9,rep,name=height_to_valset_update_id,json=heightToValsetUpdateId,proto3" json:"height_to_valset_update_id"` + // OutstandingDowntimes nil on new chain, filled in on restart. + OutstandingDowntimeSlashing []OutstandingDowntime `protobuf:"bytes,10,rep,name=outstanding_downtime_slashing,json=outstandingDowntimeSlashing,proto3" json:"outstanding_downtime_slashing"` + // PendingConsumerPackets nil on new chain, filled in on restart. + PendingConsumerPackets ConsumerPacketDataList `protobuf:"bytes,11,opt,name=pending_consumer_packets,json=pendingConsumerPackets,proto3" json:"pending_consumer_packets"` + // LastTransmissionBlockHeight nil on new chain, filled in on restart. + LastTransmissionBlockHeight LastTransmissionBlockHeight `protobuf:"bytes,12,opt,name=last_transmission_block_height,json=lastTransmissionBlockHeight,proto3" json:"last_transmission_block_height"` + PreCCV bool `protobuf:"varint,13,opt,name=preCCV,proto3" json:"preCCV,omitempty"` +} + +func (m *GenesisState) Reset() { *m = GenesisState{} } +func (m *GenesisState) String() string { return proto.CompactTextString(m) } +func (*GenesisState) ProtoMessage() {} +func (*GenesisState) Descriptor() ([]byte, []int) { + return fileDescriptor_d0a8be0efc64dfbc, []int{1} +} +func (m *GenesisState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisState.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 *GenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisState.Merge(m, src) +} +func (m *GenesisState) XXX_Size() int { + return m.Size() +} +func (m *GenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisState.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisState proto.InternalMessageInfo + +func (m *GenesisState) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +func (m *GenesisState) GetProviderClientId() string { + if m != nil { + return m.ProviderClientId + } + return "" +} + +func (m *GenesisState) GetProviderChannelId() string { + if m != nil { + return m.ProviderChannelId + } + return "" +} + +func (m *GenesisState) GetNewChain() bool { + if m != nil { + return m.NewChain + } + return false +} + +func (m *GenesisState) GetProviderClientState() *_07_tendermint.ClientState { + if m != nil { + return m.ProviderClientState + } + return nil +} + +func (m *GenesisState) GetProviderConsensusState() *_07_tendermint.ConsensusState { + if m != nil { + return m.ProviderConsensusState + } + return nil +} + +func (m *GenesisState) GetMaturingPackets() []MaturingVSCPacket { + if m != nil { + return m.MaturingPackets + } + return nil +} + +func (m *GenesisState) GetInitialValSet() []types.ValidatorUpdate { + if m != nil { + return m.InitialValSet + } + return nil +} + +func (m *GenesisState) GetHeightToValsetUpdateId() []HeightToValsetUpdateID { + if m != nil { + return m.HeightToValsetUpdateId + } + return nil +} + +func (m *GenesisState) GetOutstandingDowntimeSlashing() []OutstandingDowntime { + if m != nil { + return m.OutstandingDowntimeSlashing + } + return nil +} + +func (m *GenesisState) GetPendingConsumerPackets() ConsumerPacketDataList { + if m != nil { + return m.PendingConsumerPackets + } + return ConsumerPacketDataList{} +} + +func (m *GenesisState) GetLastTransmissionBlockHeight() LastTransmissionBlockHeight { + if m != nil { + return m.LastTransmissionBlockHeight + } + return LastTransmissionBlockHeight{} +} + +func (m *GenesisState) GetPreCCV() bool { + if m != nil { + return m.PreCCV + } + return false +} + +// HeightValsetUpdateID represents a mapping internal to the consumer CCV module +// AND used in shared consumer genesis state, which links a block height to each recv valset update id. +type HeightToValsetUpdateID struct { + Height uint64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"` + ValsetUpdateId uint64 `protobuf:"varint,2,opt,name=valset_update_id,json=valsetUpdateId,proto3" json:"valset_update_id,omitempty"` +} + +func (m *HeightToValsetUpdateID) Reset() { *m = HeightToValsetUpdateID{} } +func (m *HeightToValsetUpdateID) String() string { return proto.CompactTextString(m) } +func (*HeightToValsetUpdateID) ProtoMessage() {} +func (*HeightToValsetUpdateID) Descriptor() ([]byte, []int) { + return fileDescriptor_d0a8be0efc64dfbc, []int{2} +} +func (m *HeightToValsetUpdateID) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *HeightToValsetUpdateID) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_HeightToValsetUpdateID.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 *HeightToValsetUpdateID) XXX_Merge(src proto.Message) { + xxx_messageInfo_HeightToValsetUpdateID.Merge(m, src) +} +func (m *HeightToValsetUpdateID) XXX_Size() int { + return m.Size() +} +func (m *HeightToValsetUpdateID) XXX_DiscardUnknown() { + xxx_messageInfo_HeightToValsetUpdateID.DiscardUnknown(m) +} + +var xxx_messageInfo_HeightToValsetUpdateID proto.InternalMessageInfo + +func (m *HeightToValsetUpdateID) GetHeight() uint64 { + if m != nil { + return m.Height + } + return 0 +} + +func (m *HeightToValsetUpdateID) GetValsetUpdateId() uint64 { + if m != nil { + return m.ValsetUpdateId + } + return 0 +} + +// OutstandingDowntime defines the type used internally to the consumer CCV module, +// AND used in shared consumer genesis state, in order to not send multiple slashing +// requests for the same downtime infraction. +type OutstandingDowntime struct { + ValidatorConsensusAddress string `protobuf:"bytes,1,opt,name=validator_consensus_address,json=validatorConsensusAddress,proto3" json:"validator_consensus_address,omitempty"` +} + +func (m *OutstandingDowntime) Reset() { *m = OutstandingDowntime{} } +func (m *OutstandingDowntime) String() string { return proto.CompactTextString(m) } +func (*OutstandingDowntime) ProtoMessage() {} +func (*OutstandingDowntime) Descriptor() ([]byte, []int) { + return fileDescriptor_d0a8be0efc64dfbc, []int{3} +} +func (m *OutstandingDowntime) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *OutstandingDowntime) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_OutstandingDowntime.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 *OutstandingDowntime) XXX_Merge(src proto.Message) { + xxx_messageInfo_OutstandingDowntime.Merge(m, src) +} +func (m *OutstandingDowntime) XXX_Size() int { + return m.Size() +} +func (m *OutstandingDowntime) XXX_DiscardUnknown() { + xxx_messageInfo_OutstandingDowntime.DiscardUnknown(m) +} + +var xxx_messageInfo_OutstandingDowntime proto.InternalMessageInfo + +func (m *OutstandingDowntime) GetValidatorConsensusAddress() string { + if m != nil { + return m.ValidatorConsensusAddress + } + return "" +} + +// LastTransmissionBlockHeight is the last time validator holding +// pools were transmitted to the provider chain. This type is used internally +// to the consumer CCV module AND used in shared consumer genesis state. +type LastTransmissionBlockHeight struct { + Height int64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"` +} + +func (m *LastTransmissionBlockHeight) Reset() { *m = LastTransmissionBlockHeight{} } +func (m *LastTransmissionBlockHeight) String() string { return proto.CompactTextString(m) } +func (*LastTransmissionBlockHeight) ProtoMessage() {} +func (*LastTransmissionBlockHeight) Descriptor() ([]byte, []int) { + return fileDescriptor_d0a8be0efc64dfbc, []int{4} +} +func (m *LastTransmissionBlockHeight) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *LastTransmissionBlockHeight) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_LastTransmissionBlockHeight.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 *LastTransmissionBlockHeight) XXX_Merge(src proto.Message) { + xxx_messageInfo_LastTransmissionBlockHeight.Merge(m, src) +} +func (m *LastTransmissionBlockHeight) XXX_Size() int { + return m.Size() +} +func (m *LastTransmissionBlockHeight) XXX_DiscardUnknown() { + xxx_messageInfo_LastTransmissionBlockHeight.DiscardUnknown(m) +} + +var xxx_messageInfo_LastTransmissionBlockHeight proto.InternalMessageInfo + +func (m *LastTransmissionBlockHeight) GetHeight() int64 { + if m != nil { + return m.Height + } + return 0 +} + +// MaturingVSCPacket represents a vsc packet that is maturing internal to the +// consumer CCV module, where the consumer has not yet relayed a VSCMatured packet +// back to the provider. This type is used internally to the consumer CCV module +// AND used in shared consumer genesis state. +type MaturingVSCPacket struct { + VscId uint64 `protobuf:"varint,1,opt,name=vscId,proto3" json:"vscId,omitempty"` + MaturityTime time.Time `protobuf:"bytes,2,opt,name=maturity_time,json=maturityTime,proto3,stdtime" json:"maturity_time"` +} + +func (m *MaturingVSCPacket) Reset() { *m = MaturingVSCPacket{} } +func (m *MaturingVSCPacket) String() string { return proto.CompactTextString(m) } +func (*MaturingVSCPacket) ProtoMessage() {} +func (*MaturingVSCPacket) Descriptor() ([]byte, []int) { + return fileDescriptor_d0a8be0efc64dfbc, []int{5} +} +func (m *MaturingVSCPacket) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MaturingVSCPacket) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MaturingVSCPacket.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 *MaturingVSCPacket) XXX_Merge(src proto.Message) { + xxx_messageInfo_MaturingVSCPacket.Merge(m, src) +} +func (m *MaturingVSCPacket) XXX_Size() int { + return m.Size() +} +func (m *MaturingVSCPacket) XXX_DiscardUnknown() { + xxx_messageInfo_MaturingVSCPacket.DiscardUnknown(m) +} + +var xxx_messageInfo_MaturingVSCPacket proto.InternalMessageInfo + +func (m *MaturingVSCPacket) GetVscId() uint64 { + if m != nil { + return m.VscId + } + return 0 +} + +func (m *MaturingVSCPacket) GetMaturityTime() time.Time { + if m != nil { + return m.MaturityTime + } + return time.Time{} +} + +// ConsumerPacketDataList is a list of consumer packet data packets. +// +// Note this type is is used internally to the consumer CCV module +// for exporting / importing state in InitGenesis and ExportGenesis, +// AND included in the consumer genesis type (reffed by provider and consumer modules), +// hence this is a shared type. +type ConsumerPacketDataList struct { + List []ConsumerPacketData `protobuf:"bytes,1,rep,name=list,proto3" json:"list"` +} + +func (m *ConsumerPacketDataList) Reset() { *m = ConsumerPacketDataList{} } +func (m *ConsumerPacketDataList) String() string { return proto.CompactTextString(m) } +func (*ConsumerPacketDataList) ProtoMessage() {} +func (*ConsumerPacketDataList) Descriptor() ([]byte, []int) { + return fileDescriptor_d0a8be0efc64dfbc, []int{6} +} +func (m *ConsumerPacketDataList) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ConsumerPacketDataList) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ConsumerPacketDataList.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 *ConsumerPacketDataList) XXX_Merge(src proto.Message) { + xxx_messageInfo_ConsumerPacketDataList.Merge(m, src) +} +func (m *ConsumerPacketDataList) XXX_Size() int { + return m.Size() +} +func (m *ConsumerPacketDataList) XXX_DiscardUnknown() { + xxx_messageInfo_ConsumerPacketDataList.DiscardUnknown(m) +} + +var xxx_messageInfo_ConsumerPacketDataList proto.InternalMessageInfo + +func (m *ConsumerPacketDataList) GetList() []ConsumerPacketData { + if m != nil { + return m.List + } + return nil +} + +func init() { + proto.RegisterType((*Params)(nil), "interchain_security.ccv.v1.Params") + proto.RegisterType((*GenesisState)(nil), "interchain_security.ccv.v1.GenesisState") + proto.RegisterType((*HeightToValsetUpdateID)(nil), "interchain_security.ccv.v1.HeightToValsetUpdateID") + proto.RegisterType((*OutstandingDowntime)(nil), "interchain_security.ccv.v1.OutstandingDowntime") + proto.RegisterType((*LastTransmissionBlockHeight)(nil), "interchain_security.ccv.v1.LastTransmissionBlockHeight") + proto.RegisterType((*MaturingVSCPacket)(nil), "interchain_security.ccv.v1.MaturingVSCPacket") + proto.RegisterType((*ConsumerPacketDataList)(nil), "interchain_security.ccv.v1.ConsumerPacketDataList") +} + +func init() { + proto.RegisterFile("interchain_security/ccv/v1/shared_consumer.proto", fileDescriptor_d0a8be0efc64dfbc) +} + +var fileDescriptor_d0a8be0efc64dfbc = []byte{ + // 1178 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x56, 0x4d, 0x6f, 0x1b, 0x45, + 0x18, 0x8e, 0x9b, 0x34, 0xb5, 0x27, 0x09, 0x4d, 0x27, 0xad, 0xd9, 0x26, 0xc2, 0x71, 0x0d, 0x48, + 0x96, 0xa0, 0xbb, 0x24, 0x2d, 0x42, 0xe2, 0x80, 0x68, 0x6c, 0x4a, 0x83, 0x4a, 0x13, 0x36, 0x69, + 0x0e, 0x45, 0x62, 0x34, 0x9e, 0x99, 0xd8, 0xa3, 0xae, 0x67, 0xac, 0x99, 0xd9, 0x0d, 0xb9, 0x22, + 0x7e, 0x40, 0x8f, 0xfc, 0xa4, 0x1e, 0x7b, 0xe4, 0x04, 0xa8, 0xfd, 0x23, 0x68, 0x3e, 0xd6, 0xb1, + 0xf3, 0x61, 0xca, 0x6d, 0x67, 0xde, 0xe7, 0x79, 0xbf, 0xdf, 0x79, 0x17, 0x7c, 0xc1, 0x85, 0x61, + 0x8a, 0x0c, 0x30, 0x17, 0x48, 0x33, 0x92, 0x2b, 0x6e, 0x4e, 0x13, 0x42, 0x8a, 0xa4, 0xd8, 0x4a, + 0xf4, 0x00, 0x2b, 0x46, 0x11, 0x91, 0x42, 0xe7, 0x43, 0xa6, 0xe2, 0x91, 0x92, 0x46, 0xc2, 0xf5, + 0x4b, 0x18, 0x31, 0x21, 0x45, 0x5c, 0x6c, 0xad, 0x6f, 0x18, 0x26, 0x28, 0x53, 0x43, 0x2e, 0x4c, + 0x82, 0x7b, 0x84, 0x27, 0xe6, 0x74, 0xc4, 0xb4, 0x27, 0xae, 0x27, 0xbc, 0x47, 0x92, 0x8c, 0xf7, + 0x07, 0x86, 0x64, 0x9c, 0x09, 0xa3, 0x93, 0x09, 0x74, 0xb1, 0x35, 0x71, 0x0a, 0x84, 0x7b, 0x96, + 0x40, 0xa4, 0x62, 0x09, 0x19, 0x60, 0x21, 0x58, 0x66, 0x51, 0xe1, 0x33, 0x40, 0x1a, 0x7d, 0x29, + 0xfb, 0x19, 0x4b, 0xdc, 0xa9, 0x97, 0x1f, 0x27, 0x34, 0x57, 0xd8, 0x70, 0x29, 0x82, 0xfc, 0x76, + 0x5f, 0xf6, 0xa5, 0xfb, 0x4c, 0xec, 0x57, 0xb8, 0xfd, 0x74, 0x46, 0xd0, 0x27, 0x5c, 0xb1, 0x00, + 0xdb, 0x3c, 0xaf, 0xdc, 0xf0, 0x21, 0xd3, 0x06, 0x0f, 0x47, 0x1e, 0xd0, 0xfa, 0x7d, 0x11, 0x2c, + 0xee, 0x63, 0x85, 0x87, 0x1a, 0x46, 0xe0, 0x06, 0x13, 0xb8, 0x97, 0x31, 0x1a, 0x55, 0x9a, 0x95, + 0x76, 0x35, 0x2d, 0x8f, 0x70, 0x0f, 0x7c, 0xd2, 0xcb, 0x24, 0x79, 0xa9, 0xd1, 0x88, 0x29, 0x44, + 0xb9, 0x36, 0x8a, 0xf7, 0x72, 0xeb, 0x23, 0x32, 0x0a, 0x0b, 0x3d, 0xe4, 0x5a, 0x73, 0x29, 0xa2, + 0x6b, 0xcd, 0x4a, 0x7b, 0x3e, 0xbd, 0xe7, 0xb1, 0xfb, 0x4c, 0x75, 0x27, 0x90, 0x87, 0x13, 0x40, + 0xf8, 0x03, 0xb8, 0x77, 0xa5, 0x16, 0x14, 0xd2, 0x13, 0xcd, 0x37, 0x2b, 0xed, 0x5a, 0xba, 0x49, + 0xaf, 0x50, 0xd2, 0xf1, 0x30, 0xf8, 0x35, 0x58, 0x1f, 0x29, 0x59, 0x70, 0xca, 0x14, 0x3a, 0x66, + 0x0c, 0x8d, 0xa4, 0xcc, 0x10, 0xa6, 0x54, 0x21, 0x6d, 0x54, 0xb4, 0xe0, 0x94, 0xd4, 0x4b, 0xc4, + 0x63, 0xc6, 0xf6, 0xa5, 0xcc, 0x1e, 0x51, 0xaa, 0x0e, 0x8c, 0x82, 0x3f, 0x01, 0x48, 0x48, 0x81, + 0x6c, 0x52, 0x64, 0x6e, 0x6c, 0x74, 0x5c, 0xd2, 0xe8, 0x7a, 0xb3, 0xd2, 0x5e, 0xda, 0xbe, 0x1b, + 0xfb, 0xdc, 0xc5, 0x65, 0xee, 0xe2, 0x6e, 0x28, 0xcc, 0x4e, 0xf5, 0xf5, 0x5f, 0x9b, 0x73, 0x7f, + 0xfc, 0xbd, 0x59, 0x49, 0x57, 0x09, 0x29, 0x0e, 0x3d, 0x7b, 0xdf, 0x91, 0xe1, 0xcf, 0xe0, 0x43, + 0x17, 0xcd, 0x31, 0x53, 0xe7, 0xf5, 0x2e, 0xbe, 0xbf, 0xde, 0x3b, 0xa5, 0x8e, 0x69, 0xe5, 0x4f, + 0x40, 0xb3, 0x6c, 0x65, 0xa4, 0xd8, 0x54, 0x0a, 0x8f, 0x15, 0x26, 0xf6, 0x23, 0xba, 0xe1, 0x22, + 0x6e, 0x94, 0xb8, 0x74, 0x0a, 0xf6, 0x38, 0xa0, 0xe0, 0x7d, 0x00, 0x07, 0x5c, 0x1b, 0xa9, 0x38, + 0xc1, 0x19, 0x62, 0xc2, 0x28, 0xce, 0x74, 0x54, 0x75, 0x05, 0xbc, 0x75, 0x26, 0xf9, 0xce, 0x0b, + 0xe0, 0x33, 0xb0, 0x9a, 0x8b, 0x9e, 0x14, 0x94, 0x8b, 0x7e, 0x19, 0x4e, 0xed, 0xfd, 0xc3, 0xb9, + 0x39, 0x26, 0x87, 0x40, 0x1e, 0x80, 0xba, 0x96, 0xc7, 0x06, 0xc9, 0x91, 0x41, 0x36, 0x43, 0x66, + 0xa0, 0x98, 0x1e, 0xc8, 0x8c, 0x46, 0xc0, 0xb9, 0xbf, 0x66, 0xa5, 0x7b, 0x23, 0xb3, 0x97, 0x9b, + 0xc3, 0x52, 0x04, 0x3f, 0x06, 0x2b, 0x8a, 0x9d, 0x60, 0x45, 0x11, 0x65, 0x42, 0x0e, 0x75, 0xb4, + 0xd4, 0x9c, 0x6f, 0xd7, 0xd2, 0x65, 0x7f, 0xd9, 0x75, 0x77, 0xf0, 0x21, 0x18, 0x17, 0x1b, 0x4d, + 0xa3, 0x97, 0x1d, 0xfa, 0x76, 0x29, 0x4d, 0x27, 0x58, 0xad, 0xd7, 0x55, 0xb0, 0xfc, 0x3d, 0x13, + 0x4c, 0x73, 0x7d, 0x60, 0xb0, 0x61, 0xf0, 0x5b, 0xb0, 0x38, 0x72, 0x63, 0xe1, 0x66, 0x61, 0x69, + 0xbb, 0x15, 0x5f, 0xfd, 0x66, 0xc4, 0x7e, 0x80, 0x76, 0x16, 0x6c, 0xbc, 0x69, 0xe0, 0xc1, 0xcf, + 0x01, 0x1c, 0x3b, 0xe2, 0x5f, 0x0b, 0xc4, 0xa9, 0x1b, 0x91, 0x5a, 0xba, 0x5a, 0x4a, 0x3a, 0x4e, + 0xb0, 0x4b, 0x61, 0x0c, 0xd6, 0xce, 0xd0, 0xbe, 0xb3, 0x2d, 0xdc, 0xcf, 0xc0, 0xad, 0x31, 0xdc, + 0x4b, 0x76, 0x29, 0xdc, 0x00, 0x35, 0xc1, 0x4e, 0x90, 0xf3, 0xc7, 0x35, 0x79, 0x35, 0xad, 0x0a, + 0x76, 0xd2, 0xb1, 0x67, 0x88, 0xc0, 0x9d, 0xf3, 0xa6, 0xb5, 0x8d, 0x2a, 0x74, 0xf6, 0x67, 0x31, + 0xef, 0x91, 0x78, 0xf2, 0x19, 0x8b, 0x27, 0x1e, 0xae, 0x62, 0x2b, 0xf6, 0x5e, 0xb9, 0x44, 0xa4, + 0x6b, 0xd3, 0xae, 0xfa, 0xec, 0x0c, 0x40, 0x74, 0x66, 0x40, 0x0a, 0xcd, 0x84, 0xce, 0x75, 0xb0, + 0xe1, 0xbb, 0x3c, 0xfe, 0x4f, 0x1b, 0x25, 0xcd, 0x9b, 0x19, 0x17, 0x6d, 0xfa, 0x1e, 0xfe, 0x02, + 0x56, 0x87, 0xd8, 0xe4, 0xca, 0xf5, 0x1d, 0x26, 0x2f, 0x99, 0xd1, 0xd1, 0x8d, 0xe6, 0x7c, 0x7b, + 0x69, 0xfb, 0xfe, 0xac, 0x8a, 0xfc, 0x18, 0x38, 0x47, 0x07, 0x9d, 0x7d, 0xc7, 0x0a, 0xc5, 0xb9, + 0x59, 0x2a, 0xf3, 0xb7, 0xb6, 0xb1, 0x6f, 0x72, 0xc1, 0x0d, 0xc7, 0x19, 0x2a, 0x70, 0x86, 0x34, + 0x33, 0x51, 0xd5, 0xa9, 0x6f, 0x4e, 0xfa, 0x6b, 0x17, 0x41, 0x7c, 0x84, 0x33, 0x4e, 0xb1, 0x91, + 0xea, 0xf9, 0x88, 0x62, 0xc3, 0x82, 0xc6, 0x95, 0x40, 0x3f, 0xc2, 0xd9, 0x01, 0x33, 0xd0, 0x80, + 0xf5, 0x01, 0xb3, 0x51, 0x23, 0x23, 0xad, 0x46, 0xcd, 0x0c, 0xca, 0x1d, 0xde, 0x96, 0xb3, 0xe6, + 0x54, 0x6f, 0xcf, 0xf2, 0xfc, 0x89, 0x63, 0x1f, 0xca, 0x23, 0xc7, 0xf5, 0xa6, 0x76, 0xbb, 0xc1, + 0x58, 0x7d, 0x70, 0x99, 0x94, 0xc2, 0x53, 0xf0, 0x91, 0xcc, 0x8d, 0x36, 0xd8, 0x0f, 0x28, 0x95, + 0x27, 0xc2, 0xbe, 0x3d, 0x48, 0x67, 0x58, 0x0f, 0xb8, 0xe8, 0x47, 0xc0, 0x19, 0x4e, 0x66, 0x19, + 0xde, 0x3b, 0x53, 0xd0, 0x0d, 0xfc, 0x60, 0x75, 0x43, 0x5e, 0x14, 0x1d, 0x04, 0xcd, 0x50, 0x81, + 0x68, 0xc4, 0xbc, 0xd9, 0xf1, 0xd3, 0x54, 0x16, 0x6a, 0xc9, 0xb5, 0xc2, 0xcc, 0x70, 0x3b, 0x81, + 0xe3, 0xeb, 0xd1, 0xc5, 0x06, 0x3f, 0xe5, 0xba, 0xac, 0x56, 0x3d, 0x68, 0x9e, 0x06, 0x69, 0xf8, + 0x5b, 0x05, 0x34, 0x32, 0xac, 0xcd, 0xf4, 0xde, 0x70, 0x6b, 0x07, 0xf9, 0x0c, 0x45, 0xcb, 0xce, + 0xf4, 0x57, 0xb3, 0x4c, 0x3f, 0xc5, 0xda, 0x4c, 0x2e, 0x94, 0x1d, 0xcb, 0xf7, 0xe9, 0x2f, 0x03, + 0xcf, 0xae, 0x86, 0xc0, 0x3a, 0x58, 0x1c, 0x29, 0xd6, 0xe9, 0x1c, 0x45, 0x2b, 0x6e, 0xfc, 0xc2, + 0xa9, 0xf5, 0x02, 0xd4, 0x2f, 0xaf, 0xa1, 0x65, 0x04, 0xef, 0xec, 0x9b, 0xb2, 0x90, 0x86, 0x13, + 0x6c, 0x83, 0xd5, 0x0b, 0x9d, 0x72, 0xcd, 0x21, 0x3e, 0x28, 0xa6, 0xea, 0xdc, 0x7a, 0x0e, 0xd6, + 0x2e, 0x29, 0x13, 0xfc, 0x06, 0x6c, 0x14, 0x65, 0x73, 0x4e, 0xcc, 0xa3, 0x5d, 0x82, 0x4c, 0xfb, + 0x17, 0xac, 0x96, 0xde, 0x1d, 0x43, 0xc6, 0x23, 0xf6, 0xc8, 0x03, 0x5a, 0x5f, 0x82, 0x8d, 0xa7, + 0xb3, 0x23, 0x9d, 0xf0, 0x7b, 0xbe, 0xf4, 0xbb, 0x65, 0xc0, 0xad, 0x0b, 0x73, 0x06, 0x6f, 0x83, + 0xeb, 0x85, 0x26, 0xbb, 0x34, 0xc4, 0xe8, 0x0f, 0x70, 0x17, 0xac, 0xf8, 0xc9, 0x33, 0xa7, 0x6e, + 0x2b, 0xba, 0xf8, 0x96, 0xb6, 0xd7, 0x2f, 0x2c, 0x8f, 0xc3, 0xf2, 0xff, 0xc4, 0x6f, 0x8f, 0x57, + 0x76, 0x7b, 0x2c, 0x97, 0x54, 0x2b, 0x6c, 0xf5, 0x40, 0xfd, 0xf2, 0xa6, 0x81, 0x4f, 0xc0, 0x42, + 0xc6, 0xb5, 0xf5, 0x72, 0xde, 0xbf, 0x40, 0xff, 0xa7, 0xed, 0x42, 0xc9, 0x9d, 0x86, 0x9d, 0x67, + 0xaf, 0xdf, 0x36, 0x2a, 0x6f, 0xde, 0x36, 0x2a, 0xff, 0xbc, 0x6d, 0x54, 0x5e, 0xbd, 0x6b, 0xcc, + 0xbd, 0x79, 0xd7, 0x98, 0xfb, 0xf3, 0x5d, 0x63, 0xee, 0xc5, 0xc3, 0x3e, 0x37, 0x83, 0xbc, 0x17, + 0x13, 0x39, 0x4c, 0x88, 0xd4, 0x43, 0xa9, 0x93, 0x33, 0x33, 0xf7, 0xc7, 0x7f, 0x62, 0xc5, 0x83, + 0xe4, 0x57, 0xf7, 0x3b, 0xe6, 0xfe, 0x1e, 0x7b, 0x8b, 0x2e, 0xbe, 0x07, 0xff, 0x06, 0x00, 0x00, + 0xff, 0xff, 0xd1, 0x28, 0xd8, 0xb6, 0xab, 0x0a, 0x00, 0x00, +} + +func (m *Params) 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 *Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ProviderRewardDenoms) > 0 { + for iNdEx := len(m.ProviderRewardDenoms) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.ProviderRewardDenoms[iNdEx]) + copy(dAtA[i:], m.ProviderRewardDenoms[iNdEx]) + i = encodeVarintSharedConsumer(dAtA, i, uint64(len(m.ProviderRewardDenoms[iNdEx]))) + i-- + dAtA[i] = 0x62 + } + } + if len(m.RewardDenoms) > 0 { + for iNdEx := len(m.RewardDenoms) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.RewardDenoms[iNdEx]) + copy(dAtA[i:], m.RewardDenoms[iNdEx]) + i = encodeVarintSharedConsumer(dAtA, i, uint64(len(m.RewardDenoms[iNdEx]))) + i-- + dAtA[i] = 0x5a + } + } + if len(m.SoftOptOutThreshold) > 0 { + i -= len(m.SoftOptOutThreshold) + copy(dAtA[i:], m.SoftOptOutThreshold) + i = encodeVarintSharedConsumer(dAtA, i, uint64(len(m.SoftOptOutThreshold))) + i-- + dAtA[i] = 0x52 + } + n1, err1 := github_com_cosmos_gogoproto_types.StdDurationMarshalTo(m.UnbondingPeriod, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.UnbondingPeriod):]) + if err1 != nil { + return 0, err1 + } + i -= n1 + i = encodeVarintSharedConsumer(dAtA, i, uint64(n1)) + i-- + dAtA[i] = 0x4a + if m.HistoricalEntries != 0 { + i = encodeVarintSharedConsumer(dAtA, i, uint64(m.HistoricalEntries)) + i-- + dAtA[i] = 0x40 + } + if len(m.ConsumerRedistributionFraction) > 0 { + i -= len(m.ConsumerRedistributionFraction) + copy(dAtA[i:], m.ConsumerRedistributionFraction) + i = encodeVarintSharedConsumer(dAtA, i, uint64(len(m.ConsumerRedistributionFraction))) + i-- + dAtA[i] = 0x3a + } + n2, err2 := github_com_cosmos_gogoproto_types.StdDurationMarshalTo(m.TransferTimeoutPeriod, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.TransferTimeoutPeriod):]) + if err2 != nil { + return 0, err2 + } + i -= n2 + i = encodeVarintSharedConsumer(dAtA, i, uint64(n2)) + i-- + dAtA[i] = 0x32 + n3, err3 := github_com_cosmos_gogoproto_types.StdDurationMarshalTo(m.CcvTimeoutPeriod, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.CcvTimeoutPeriod):]) + if err3 != nil { + return 0, err3 + } + i -= n3 + i = encodeVarintSharedConsumer(dAtA, i, uint64(n3)) + i-- + dAtA[i] = 0x2a + if len(m.ProviderFeePoolAddrStr) > 0 { + i -= len(m.ProviderFeePoolAddrStr) + copy(dAtA[i:], m.ProviderFeePoolAddrStr) + i = encodeVarintSharedConsumer(dAtA, i, uint64(len(m.ProviderFeePoolAddrStr))) + i-- + dAtA[i] = 0x22 + } + if len(m.DistributionTransmissionChannel) > 0 { + i -= len(m.DistributionTransmissionChannel) + copy(dAtA[i:], m.DistributionTransmissionChannel) + i = encodeVarintSharedConsumer(dAtA, i, uint64(len(m.DistributionTransmissionChannel))) + i-- + dAtA[i] = 0x1a + } + if m.BlocksPerDistributionTransmission != 0 { + i = encodeVarintSharedConsumer(dAtA, i, uint64(m.BlocksPerDistributionTransmission)) + i-- + dAtA[i] = 0x10 + } + if m.Enabled { + i-- + if m.Enabled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *GenesisState) 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 *GenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.PreCCV { + i-- + if m.PreCCV { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x68 + } + { + size, err := m.LastTransmissionBlockHeight.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSharedConsumer(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x62 + { + size, err := m.PendingConsumerPackets.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSharedConsumer(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x5a + if len(m.OutstandingDowntimeSlashing) > 0 { + for iNdEx := len(m.OutstandingDowntimeSlashing) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.OutstandingDowntimeSlashing[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSharedConsumer(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x52 + } + } + if len(m.HeightToValsetUpdateId) > 0 { + for iNdEx := len(m.HeightToValsetUpdateId) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.HeightToValsetUpdateId[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSharedConsumer(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x4a + } + } + if len(m.InitialValSet) > 0 { + for iNdEx := len(m.InitialValSet) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.InitialValSet[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSharedConsumer(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x42 + } + } + if len(m.MaturingPackets) > 0 { + for iNdEx := len(m.MaturingPackets) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.MaturingPackets[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSharedConsumer(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + } + } + if m.ProviderConsensusState != nil { + { + size, err := m.ProviderConsensusState.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSharedConsumer(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + if m.ProviderClientState != nil { + { + size, err := m.ProviderClientState.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSharedConsumer(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + if m.NewChain { + i-- + if m.NewChain { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x20 + } + if len(m.ProviderChannelId) > 0 { + i -= len(m.ProviderChannelId) + copy(dAtA[i:], m.ProviderChannelId) + i = encodeVarintSharedConsumer(dAtA, i, uint64(len(m.ProviderChannelId))) + i-- + dAtA[i] = 0x1a + } + if len(m.ProviderClientId) > 0 { + i -= len(m.ProviderClientId) + copy(dAtA[i:], m.ProviderClientId) + i = encodeVarintSharedConsumer(dAtA, i, uint64(len(m.ProviderClientId))) + i-- + dAtA[i] = 0x12 + } + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSharedConsumer(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *HeightToValsetUpdateID) 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 *HeightToValsetUpdateID) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *HeightToValsetUpdateID) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.ValsetUpdateId != 0 { + i = encodeVarintSharedConsumer(dAtA, i, uint64(m.ValsetUpdateId)) + i-- + dAtA[i] = 0x10 + } + if m.Height != 0 { + i = encodeVarintSharedConsumer(dAtA, i, uint64(m.Height)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *OutstandingDowntime) 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 *OutstandingDowntime) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *OutstandingDowntime) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ValidatorConsensusAddress) > 0 { + i -= len(m.ValidatorConsensusAddress) + copy(dAtA[i:], m.ValidatorConsensusAddress) + i = encodeVarintSharedConsumer(dAtA, i, uint64(len(m.ValidatorConsensusAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *LastTransmissionBlockHeight) 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 *LastTransmissionBlockHeight) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *LastTransmissionBlockHeight) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Height != 0 { + i = encodeVarintSharedConsumer(dAtA, i, uint64(m.Height)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *MaturingVSCPacket) 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 *MaturingVSCPacket) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MaturingVSCPacket) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + n9, err9 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.MaturityTime, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.MaturityTime):]) + if err9 != nil { + return 0, err9 + } + i -= n9 + i = encodeVarintSharedConsumer(dAtA, i, uint64(n9)) + i-- + dAtA[i] = 0x12 + if m.VscId != 0 { + i = encodeVarintSharedConsumer(dAtA, i, uint64(m.VscId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *ConsumerPacketDataList) 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 *ConsumerPacketDataList) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ConsumerPacketDataList) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.List) > 0 { + for iNdEx := len(m.List) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.List[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSharedConsumer(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintSharedConsumer(dAtA []byte, offset int, v uint64) int { + offset -= sovSharedConsumer(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Enabled { + n += 2 + } + if m.BlocksPerDistributionTransmission != 0 { + n += 1 + sovSharedConsumer(uint64(m.BlocksPerDistributionTransmission)) + } + l = len(m.DistributionTransmissionChannel) + if l > 0 { + n += 1 + l + sovSharedConsumer(uint64(l)) + } + l = len(m.ProviderFeePoolAddrStr) + if l > 0 { + n += 1 + l + sovSharedConsumer(uint64(l)) + } + l = github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.CcvTimeoutPeriod) + n += 1 + l + sovSharedConsumer(uint64(l)) + l = github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.TransferTimeoutPeriod) + n += 1 + l + sovSharedConsumer(uint64(l)) + l = len(m.ConsumerRedistributionFraction) + if l > 0 { + n += 1 + l + sovSharedConsumer(uint64(l)) + } + if m.HistoricalEntries != 0 { + n += 1 + sovSharedConsumer(uint64(m.HistoricalEntries)) + } + l = github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.UnbondingPeriod) + n += 1 + l + sovSharedConsumer(uint64(l)) + l = len(m.SoftOptOutThreshold) + if l > 0 { + n += 1 + l + sovSharedConsumer(uint64(l)) + } + if len(m.RewardDenoms) > 0 { + for _, s := range m.RewardDenoms { + l = len(s) + n += 1 + l + sovSharedConsumer(uint64(l)) + } + } + if len(m.ProviderRewardDenoms) > 0 { + for _, s := range m.ProviderRewardDenoms { + l = len(s) + n += 1 + l + sovSharedConsumer(uint64(l)) + } + } + return n +} + +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovSharedConsumer(uint64(l)) + l = len(m.ProviderClientId) + if l > 0 { + n += 1 + l + sovSharedConsumer(uint64(l)) + } + l = len(m.ProviderChannelId) + if l > 0 { + n += 1 + l + sovSharedConsumer(uint64(l)) + } + if m.NewChain { + n += 2 + } + if m.ProviderClientState != nil { + l = m.ProviderClientState.Size() + n += 1 + l + sovSharedConsumer(uint64(l)) + } + if m.ProviderConsensusState != nil { + l = m.ProviderConsensusState.Size() + n += 1 + l + sovSharedConsumer(uint64(l)) + } + if len(m.MaturingPackets) > 0 { + for _, e := range m.MaturingPackets { + l = e.Size() + n += 1 + l + sovSharedConsumer(uint64(l)) + } + } + if len(m.InitialValSet) > 0 { + for _, e := range m.InitialValSet { + l = e.Size() + n += 1 + l + sovSharedConsumer(uint64(l)) + } + } + if len(m.HeightToValsetUpdateId) > 0 { + for _, e := range m.HeightToValsetUpdateId { + l = e.Size() + n += 1 + l + sovSharedConsumer(uint64(l)) + } + } + if len(m.OutstandingDowntimeSlashing) > 0 { + for _, e := range m.OutstandingDowntimeSlashing { + l = e.Size() + n += 1 + l + sovSharedConsumer(uint64(l)) + } + } + l = m.PendingConsumerPackets.Size() + n += 1 + l + sovSharedConsumer(uint64(l)) + l = m.LastTransmissionBlockHeight.Size() + n += 1 + l + sovSharedConsumer(uint64(l)) + if m.PreCCV { + n += 2 + } + return n +} + +func (m *HeightToValsetUpdateID) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Height != 0 { + n += 1 + sovSharedConsumer(uint64(m.Height)) + } + if m.ValsetUpdateId != 0 { + n += 1 + sovSharedConsumer(uint64(m.ValsetUpdateId)) + } + return n +} + +func (m *OutstandingDowntime) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ValidatorConsensusAddress) + if l > 0 { + n += 1 + l + sovSharedConsumer(uint64(l)) + } + return n +} + +func (m *LastTransmissionBlockHeight) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Height != 0 { + n += 1 + sovSharedConsumer(uint64(m.Height)) + } + return n +} + +func (m *MaturingVSCPacket) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.VscId != 0 { + n += 1 + sovSharedConsumer(uint64(m.VscId)) + } + l = github_com_cosmos_gogoproto_types.SizeOfStdTime(m.MaturityTime) + n += 1 + l + sovSharedConsumer(uint64(l)) + return n +} + +func (m *ConsumerPacketDataList) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.List) > 0 { + for _, e := range m.List { + l = e.Size() + n += 1 + l + sovSharedConsumer(uint64(l)) + } + } + return n +} + +func sovSharedConsumer(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozSharedConsumer(x uint64) (n int) { + return sovSharedConsumer(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Params) 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 ErrIntOverflowSharedConsumer + } + 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: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Enabled", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Enabled = bool(v != 0) + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field BlocksPerDistributionTransmission", wireType) + } + m.BlocksPerDistributionTransmission = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.BlocksPerDistributionTransmission |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DistributionTransmissionChannel", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + 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 ErrInvalidLengthSharedConsumer + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSharedConsumer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DistributionTransmissionChannel = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProviderFeePoolAddrStr", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + 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 ErrInvalidLengthSharedConsumer + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSharedConsumer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProviderFeePoolAddrStr = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CcvTimeoutPeriod", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSharedConsumer + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSharedConsumer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_cosmos_gogoproto_types.StdDurationUnmarshal(&m.CcvTimeoutPeriod, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TransferTimeoutPeriod", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSharedConsumer + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSharedConsumer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_cosmos_gogoproto_types.StdDurationUnmarshal(&m.TransferTimeoutPeriod, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConsumerRedistributionFraction", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + 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 ErrInvalidLengthSharedConsumer + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSharedConsumer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConsumerRedistributionFraction = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field HistoricalEntries", wireType) + } + m.HistoricalEntries = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.HistoricalEntries |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UnbondingPeriod", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSharedConsumer + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSharedConsumer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_cosmos_gogoproto_types.StdDurationUnmarshal(&m.UnbondingPeriod, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SoftOptOutThreshold", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + 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 ErrInvalidLengthSharedConsumer + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSharedConsumer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SoftOptOutThreshold = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RewardDenoms", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + 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 ErrInvalidLengthSharedConsumer + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSharedConsumer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RewardDenoms = append(m.RewardDenoms, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProviderRewardDenoms", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + 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 ErrInvalidLengthSharedConsumer + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSharedConsumer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProviderRewardDenoms = append(m.ProviderRewardDenoms, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipSharedConsumer(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSharedConsumer + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GenesisState) 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 ErrIntOverflowSharedConsumer + } + 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: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSharedConsumer + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSharedConsumer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProviderClientId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + 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 ErrInvalidLengthSharedConsumer + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSharedConsumer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProviderClientId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProviderChannelId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + 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 ErrInvalidLengthSharedConsumer + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSharedConsumer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProviderChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NewChain", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.NewChain = bool(v != 0) + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProviderClientState", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSharedConsumer + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSharedConsumer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.ProviderClientState == nil { + m.ProviderClientState = &_07_tendermint.ClientState{} + } + if err := m.ProviderClientState.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProviderConsensusState", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSharedConsumer + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSharedConsumer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.ProviderConsensusState == nil { + m.ProviderConsensusState = &_07_tendermint.ConsensusState{} + } + if err := m.ProviderConsensusState.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MaturingPackets", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSharedConsumer + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSharedConsumer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MaturingPackets = append(m.MaturingPackets, MaturingVSCPacket{}) + if err := m.MaturingPackets[len(m.MaturingPackets)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InitialValSet", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSharedConsumer + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSharedConsumer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.InitialValSet = append(m.InitialValSet, types.ValidatorUpdate{}) + if err := m.InitialValSet[len(m.InitialValSet)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field HeightToValsetUpdateId", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSharedConsumer + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSharedConsumer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.HeightToValsetUpdateId = append(m.HeightToValsetUpdateId, HeightToValsetUpdateID{}) + if err := m.HeightToValsetUpdateId[len(m.HeightToValsetUpdateId)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OutstandingDowntimeSlashing", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSharedConsumer + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSharedConsumer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.OutstandingDowntimeSlashing = append(m.OutstandingDowntimeSlashing, OutstandingDowntime{}) + if err := m.OutstandingDowntimeSlashing[len(m.OutstandingDowntimeSlashing)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PendingConsumerPackets", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSharedConsumer + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSharedConsumer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.PendingConsumerPackets.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LastTransmissionBlockHeight", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSharedConsumer + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSharedConsumer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.LastTransmissionBlockHeight.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 13: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PreCCV", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.PreCCV = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipSharedConsumer(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSharedConsumer + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *HeightToValsetUpdateID) 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 ErrIntOverflowSharedConsumer + } + 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: HeightToValsetUpdateID: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: HeightToValsetUpdateID: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) + } + m.Height = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Height |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ValsetUpdateId", wireType) + } + m.ValsetUpdateId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ValsetUpdateId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipSharedConsumer(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSharedConsumer + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *OutstandingDowntime) 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 ErrIntOverflowSharedConsumer + } + 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: OutstandingDowntime: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: OutstandingDowntime: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorConsensusAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + 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 ErrInvalidLengthSharedConsumer + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSharedConsumer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ValidatorConsensusAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipSharedConsumer(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSharedConsumer + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *LastTransmissionBlockHeight) 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 ErrIntOverflowSharedConsumer + } + 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: LastTransmissionBlockHeight: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: LastTransmissionBlockHeight: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) + } + m.Height = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Height |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipSharedConsumer(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSharedConsumer + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MaturingVSCPacket) 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 ErrIntOverflowSharedConsumer + } + 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: MaturingVSCPacket: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MaturingVSCPacket: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field VscId", wireType) + } + m.VscId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.VscId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MaturityTime", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSharedConsumer + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSharedConsumer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(&m.MaturityTime, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipSharedConsumer(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSharedConsumer + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ConsumerPacketDataList) 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 ErrIntOverflowSharedConsumer + } + 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: ConsumerPacketDataList: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ConsumerPacketDataList: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field List", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSharedConsumer + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSharedConsumer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.List = append(m.List, ConsumerPacketData{}) + if err := m.List[len(m.List)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipSharedConsumer(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSharedConsumer + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipSharedConsumer(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowSharedConsumer + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowSharedConsumer + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowSharedConsumer + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthSharedConsumer + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupSharedConsumer + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthSharedConsumer + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthSharedConsumer = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowSharedConsumer = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupSharedConsumer = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/ccv/types/ccv.go b/x/ccv/types/wire.go similarity index 100% rename from x/ccv/types/ccv.go rename to x/ccv/types/wire.go diff --git a/x/ccv/types/ccv.pb.go b/x/ccv/types/wire.pb.go similarity index 66% rename from x/ccv/types/ccv.pb.go rename to x/ccv/types/wire.pb.go index aa0f7da10e..82768cf805 100644 --- a/x/ccv/types/ccv.pb.go +++ b/x/ccv/types/wire.pb.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: interchain_security/ccv/v1/ccv.proto +// source: interchain_security/ccv/v1/wire.proto package types @@ -54,11 +54,11 @@ func (x ConsumerPacketDataType) String() string { } func (ConsumerPacketDataType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_68bd5f3242e6f29c, []int{0} + return fileDescriptor_8fd0dc67df6b10ed, []int{0} } // InfractionType indicates the infraction type a validator commited. -// NOTE: ccv.InfractionType to maintain compatibility between ICS versions +// Note ccv.InfractionType to maintain compatibility between ICS versions // using different versions of the cosmos-sdk and ibc-go modules. type InfractionType int32 @@ -88,7 +88,7 @@ func (x InfractionType) String() string { } func (InfractionType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_68bd5f3242e6f29c, []int{1} + return fileDescriptor_8fd0dc67df6b10ed, []int{1} } // This packet is sent from provider chain to consumer chain if the validator @@ -108,7 +108,7 @@ func (m *ValidatorSetChangePacketData) Reset() { *m = ValidatorSetChange func (m *ValidatorSetChangePacketData) String() string { return proto.CompactTextString(m) } func (*ValidatorSetChangePacketData) ProtoMessage() {} func (*ValidatorSetChangePacketData) Descriptor() ([]byte, []int) { - return fileDescriptor_68bd5f3242e6f29c, []int{0} + return fileDescriptor_8fd0dc67df6b10ed, []int{0} } func (m *ValidatorSetChangePacketData) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -158,51 +158,6 @@ func (m *ValidatorSetChangePacketData) GetSlashAcks() []string { return nil } -// List of ccv.ValidatorSetChangePacketData. -type ValidatorSetChangePackets struct { - List []ValidatorSetChangePacketData `protobuf:"bytes,1,rep,name=list,proto3" json:"list"` -} - -func (m *ValidatorSetChangePackets) Reset() { *m = ValidatorSetChangePackets{} } -func (m *ValidatorSetChangePackets) String() string { return proto.CompactTextString(m) } -func (*ValidatorSetChangePackets) ProtoMessage() {} -func (*ValidatorSetChangePackets) Descriptor() ([]byte, []int) { - return fileDescriptor_68bd5f3242e6f29c, []int{1} -} -func (m *ValidatorSetChangePackets) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *ValidatorSetChangePackets) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_ValidatorSetChangePackets.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 *ValidatorSetChangePackets) XXX_Merge(src proto.Message) { - xxx_messageInfo_ValidatorSetChangePackets.Merge(m, src) -} -func (m *ValidatorSetChangePackets) XXX_Size() int { - return m.Size() -} -func (m *ValidatorSetChangePackets) XXX_DiscardUnknown() { - xxx_messageInfo_ValidatorSetChangePackets.DiscardUnknown(m) -} - -var xxx_messageInfo_ValidatorSetChangePackets proto.InternalMessageInfo - -func (m *ValidatorSetChangePackets) GetList() []ValidatorSetChangePacketData { - if m != nil { - return m.List - } - return nil -} - // This packet is sent from the consumer chain to the provider chain // to notify that a VSC packet reached maturity on the consumer chain. type VSCMaturedPacketData struct { @@ -214,7 +169,7 @@ func (m *VSCMaturedPacketData) Reset() { *m = VSCMaturedPacketData{} } func (m *VSCMaturedPacketData) String() string { return proto.CompactTextString(m) } func (*VSCMaturedPacketData) ProtoMessage() {} func (*VSCMaturedPacketData) Descriptor() ([]byte, []int) { - return fileDescriptor_68bd5f3242e6f29c, []int{2} + return fileDescriptor_8fd0dc67df6b10ed, []int{1} } func (m *VSCMaturedPacketData) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -265,7 +220,7 @@ func (m *SlashPacketData) Reset() { *m = SlashPacketData{} } func (m *SlashPacketData) String() string { return proto.CompactTextString(m) } func (*SlashPacketData) ProtoMessage() {} func (*SlashPacketData) Descriptor() ([]byte, []int) { - return fileDescriptor_68bd5f3242e6f29c, []int{3} + return fileDescriptor_8fd0dc67df6b10ed, []int{2} } func (m *SlashPacketData) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -315,53 +270,7 @@ func (m *SlashPacketData) GetInfraction() types1.Infraction { return types1.Infraction_INFRACTION_UNSPECIFIED } -// MaturedUnbondingOps defines a list of ids corresponding to ids of matured -// unbonding operations. -type MaturedUnbondingOps struct { - Ids []uint64 `protobuf:"varint,1,rep,packed,name=ids,proto3" json:"ids,omitempty"` -} - -func (m *MaturedUnbondingOps) Reset() { *m = MaturedUnbondingOps{} } -func (m *MaturedUnbondingOps) String() string { return proto.CompactTextString(m) } -func (*MaturedUnbondingOps) ProtoMessage() {} -func (*MaturedUnbondingOps) Descriptor() ([]byte, []int) { - return fileDescriptor_68bd5f3242e6f29c, []int{4} -} -func (m *MaturedUnbondingOps) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MaturedUnbondingOps) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MaturedUnbondingOps.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 *MaturedUnbondingOps) XXX_Merge(src proto.Message) { - xxx_messageInfo_MaturedUnbondingOps.Merge(m, src) -} -func (m *MaturedUnbondingOps) XXX_Size() int { - return m.Size() -} -func (m *MaturedUnbondingOps) XXX_DiscardUnknown() { - xxx_messageInfo_MaturedUnbondingOps.DiscardUnknown(m) -} - -var xxx_messageInfo_MaturedUnbondingOps proto.InternalMessageInfo - -func (m *MaturedUnbondingOps) GetIds() []uint64 { - if m != nil { - return m.Ids - } - return nil -} - -// ConsumerPacketData contains a consumer packet data, type tag, and index for storage. +// ConsumerPacketData contains a consumer packet data and a type tag type ConsumerPacketData struct { Type ConsumerPacketDataType `protobuf:"varint,1,opt,name=type,proto3,enum=interchain_security.ccv.v1.ConsumerPacketDataType" json:"type,omitempty"` // Types that are valid to be assigned to Data: @@ -374,7 +283,7 @@ func (m *ConsumerPacketData) Reset() { *m = ConsumerPacketData{} } func (m *ConsumerPacketData) String() string { return proto.CompactTextString(m) } func (*ConsumerPacketData) ProtoMessage() {} func (*ConsumerPacketData) Descriptor() ([]byte, []int) { - return fileDescriptor_68bd5f3242e6f29c, []int{5} + return fileDescriptor_8fd0dc67df6b10ed, []int{3} } func (m *ConsumerPacketData) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -455,24 +364,24 @@ func (*ConsumerPacketData) XXX_OneofWrappers() []interface{} { } } -// ConsumerPacketDataList is a list of consumer packet data packets. -// NOTE: It is only used for exporting / importing state in InitGenesis and ExportGenesis. -type ConsumerPacketDataList struct { - List []ConsumerPacketData `protobuf:"bytes,1,rep,name=list,proto3" json:"list"` +// Note this type is used during IBC handshake methods for both the consumer and provider +type HandshakeMetadata struct { + ProviderFeePoolAddr string `protobuf:"bytes,1,opt,name=provider_fee_pool_addr,json=providerFeePoolAddr,proto3" json:"provider_fee_pool_addr,omitempty"` + Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"` } -func (m *ConsumerPacketDataList) Reset() { *m = ConsumerPacketDataList{} } -func (m *ConsumerPacketDataList) String() string { return proto.CompactTextString(m) } -func (*ConsumerPacketDataList) ProtoMessage() {} -func (*ConsumerPacketDataList) Descriptor() ([]byte, []int) { - return fileDescriptor_68bd5f3242e6f29c, []int{6} +func (m *HandshakeMetadata) Reset() { *m = HandshakeMetadata{} } +func (m *HandshakeMetadata) String() string { return proto.CompactTextString(m) } +func (*HandshakeMetadata) ProtoMessage() {} +func (*HandshakeMetadata) Descriptor() ([]byte, []int) { + return fileDescriptor_8fd0dc67df6b10ed, []int{4} } -func (m *ConsumerPacketDataList) XXX_Unmarshal(b []byte) error { +func (m *HandshakeMetadata) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *ConsumerPacketDataList) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *HandshakeMetadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_ConsumerPacketDataList.Marshal(b, m, deterministic) + return xxx_messageInfo_HandshakeMetadata.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -482,23 +391,30 @@ func (m *ConsumerPacketDataList) XXX_Marshal(b []byte, deterministic bool) ([]by return b[:n], nil } } -func (m *ConsumerPacketDataList) XXX_Merge(src proto.Message) { - xxx_messageInfo_ConsumerPacketDataList.Merge(m, src) +func (m *HandshakeMetadata) XXX_Merge(src proto.Message) { + xxx_messageInfo_HandshakeMetadata.Merge(m, src) } -func (m *ConsumerPacketDataList) XXX_Size() int { +func (m *HandshakeMetadata) XXX_Size() int { return m.Size() } -func (m *ConsumerPacketDataList) XXX_DiscardUnknown() { - xxx_messageInfo_ConsumerPacketDataList.DiscardUnknown(m) +func (m *HandshakeMetadata) XXX_DiscardUnknown() { + xxx_messageInfo_HandshakeMetadata.DiscardUnknown(m) } -var xxx_messageInfo_ConsumerPacketDataList proto.InternalMessageInfo +var xxx_messageInfo_HandshakeMetadata proto.InternalMessageInfo -func (m *ConsumerPacketDataList) GetList() []ConsumerPacketData { +func (m *HandshakeMetadata) GetProviderFeePoolAddr() string { if m != nil { - return m.List + return m.ProviderFeePoolAddr } - return nil + return "" +} + +func (m *HandshakeMetadata) GetVersion() string { + if m != nil { + return m.Version + } + return "" } // ConsumerPacketData contains a consumer packet data and a type tag @@ -515,7 +431,7 @@ func (m *ConsumerPacketDataV1) Reset() { *m = ConsumerPacketDataV1{} } func (m *ConsumerPacketDataV1) String() string { return proto.CompactTextString(m) } func (*ConsumerPacketDataV1) ProtoMessage() {} func (*ConsumerPacketDataV1) Descriptor() ([]byte, []int) { - return fileDescriptor_68bd5f3242e6f29c, []int{7} + return fileDescriptor_8fd0dc67df6b10ed, []int{5} } func (m *ConsumerPacketDataV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -610,7 +526,7 @@ func (m *SlashPacketDataV1) Reset() { *m = SlashPacketDataV1{} } func (m *SlashPacketDataV1) String() string { return proto.CompactTextString(m) } func (*SlashPacketDataV1) ProtoMessage() {} func (*SlashPacketDataV1) Descriptor() ([]byte, []int) { - return fileDescriptor_68bd5f3242e6f29c, []int{8} + return fileDescriptor_8fd0dc67df6b10ed, []int{6} } func (m *SlashPacketDataV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -664,75 +580,73 @@ func init() { proto.RegisterEnum("interchain_security.ccv.v1.ConsumerPacketDataType", ConsumerPacketDataType_name, ConsumerPacketDataType_value) proto.RegisterEnum("interchain_security.ccv.v1.InfractionType", InfractionType_name, InfractionType_value) proto.RegisterType((*ValidatorSetChangePacketData)(nil), "interchain_security.ccv.v1.ValidatorSetChangePacketData") - proto.RegisterType((*ValidatorSetChangePackets)(nil), "interchain_security.ccv.v1.ValidatorSetChangePackets") proto.RegisterType((*VSCMaturedPacketData)(nil), "interchain_security.ccv.v1.VSCMaturedPacketData") proto.RegisterType((*SlashPacketData)(nil), "interchain_security.ccv.v1.SlashPacketData") - proto.RegisterType((*MaturedUnbondingOps)(nil), "interchain_security.ccv.v1.MaturedUnbondingOps") proto.RegisterType((*ConsumerPacketData)(nil), "interchain_security.ccv.v1.ConsumerPacketData") - proto.RegisterType((*ConsumerPacketDataList)(nil), "interchain_security.ccv.v1.ConsumerPacketDataList") + proto.RegisterType((*HandshakeMetadata)(nil), "interchain_security.ccv.v1.HandshakeMetadata") proto.RegisterType((*ConsumerPacketDataV1)(nil), "interchain_security.ccv.v1.ConsumerPacketDataV1") proto.RegisterType((*SlashPacketDataV1)(nil), "interchain_security.ccv.v1.SlashPacketDataV1") } func init() { - proto.RegisterFile("interchain_security/ccv/v1/ccv.proto", fileDescriptor_68bd5f3242e6f29c) -} - -var fileDescriptor_68bd5f3242e6f29c = []byte{ - // 836 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x56, 0xcf, 0x6e, 0xe2, 0x46, - 0x1c, 0xb6, 0x01, 0xad, 0x9a, 0xa1, 0x22, 0xce, 0x2c, 0xad, 0x58, 0x6f, 0xcb, 0x5a, 0xd6, 0x4a, - 0x45, 0xa9, 0xd6, 0x2e, 0x64, 0x0f, 0x55, 0x7b, 0x69, 0x00, 0xa7, 0x71, 0x9b, 0x90, 0xc8, 0x06, - 0x56, 0xdb, 0x8b, 0x35, 0xd8, 0x13, 0x32, 0x0a, 0xd8, 0xc8, 0x33, 0xb8, 0xe5, 0x0d, 0x2a, 0x4e, - 0x7d, 0x01, 0x4e, 0x55, 0x0f, 0xfb, 0x18, 0xbd, 0xed, 0x71, 0xa5, 0x5e, 0xf6, 0xd2, 0xa8, 0x4a, - 0xde, 0xa0, 0x4f, 0x50, 0xd9, 0xfc, 0xc7, 0x06, 0x29, 0x52, 0xa5, 0xf6, 0x84, 0x19, 0xff, 0xbe, - 0x4f, 0xf3, 0xfd, 0x19, 0x79, 0xc0, 0x73, 0xe2, 0x32, 0xec, 0xdb, 0xd7, 0x88, 0xb8, 0x16, 0xc5, - 0xf6, 0xd0, 0x27, 0x6c, 0xa4, 0xda, 0x76, 0xa0, 0x06, 0xe5, 0xf0, 0x47, 0x19, 0xf8, 0x1e, 0xf3, - 0xa0, 0x98, 0x30, 0xa5, 0x84, 0xaf, 0x83, 0xb2, 0xf8, 0xdc, 0xf6, 0x68, 0xdf, 0xa3, 0x2a, 0x65, - 0xe8, 0x86, 0xb8, 0x5d, 0x35, 0x28, 0x77, 0x30, 0x43, 0xe5, 0xf9, 0xff, 0x29, 0x83, 0x98, 0xef, - 0x7a, 0x5d, 0x2f, 0x7a, 0x54, 0xc3, 0xa7, 0xd9, 0xea, 0x53, 0x86, 0x5d, 0x07, 0xfb, 0x7d, 0xe2, - 0x32, 0x15, 0x75, 0x6c, 0xa2, 0xb2, 0xd1, 0x00, 0xd3, 0xe9, 0x4b, 0xf9, 0x3d, 0x0f, 0x3e, 0x69, - 0xa3, 0x1e, 0x71, 0x10, 0xf3, 0x7c, 0x13, 0xb3, 0xda, 0x35, 0x72, 0xbb, 0xf8, 0x12, 0xd9, 0x37, - 0x98, 0xd5, 0x11, 0x43, 0xd0, 0x03, 0x07, 0xc1, 0xfc, 0xbd, 0x35, 0x1c, 0x38, 0x88, 0x61, 0x5a, - 0xe0, 0xa5, 0x74, 0x29, 0x5b, 0x91, 0x94, 0x25, 0xb3, 0x12, 0x32, 0x2b, 0x0b, 0xa6, 0x56, 0x34, - 0x58, 0x95, 0xde, 0xde, 0x3e, 0xe3, 0xfe, 0xbe, 0x7d, 0x56, 0x18, 0xa1, 0x7e, 0xef, 0x2b, 0x39, - 0x46, 0x24, 0x1b, 0x42, 0xb0, 0x0e, 0xa1, 0xb0, 0x04, 0xc2, 0x35, 0x8a, 0xd9, 0x6c, 0xc8, 0x22, - 0x4e, 0x21, 0x25, 0xf1, 0xa5, 0x8c, 0x91, 0x9b, 0xae, 0x4f, 0x07, 0x75, 0x07, 0x7e, 0x0a, 0x00, - 0xed, 0x21, 0x7a, 0x6d, 0x21, 0xfb, 0x86, 0x16, 0xd2, 0x52, 0xba, 0xb4, 0x67, 0xec, 0x45, 0x2b, - 0xc7, 0xf6, 0x0d, 0x95, 0x3d, 0xf0, 0x64, 0x9b, 0x32, 0x0a, 0x0d, 0x90, 0xe9, 0x11, 0xca, 0x66, - 0x4a, 0xbe, 0x54, 0xb6, 0x7b, 0xaf, 0xec, 0xb2, 0xa7, 0x9a, 0x09, 0x15, 0x1a, 0x11, 0x97, 0xfc, - 0x0d, 0xc8, 0xb7, 0xcd, 0xda, 0x39, 0x62, 0x43, 0x1f, 0x3b, 0x2b, 0x16, 0x26, 0x29, 0xe2, 0x93, - 0x14, 0xc9, 0x7f, 0xf0, 0x60, 0xdf, 0x0c, 0x05, 0xac, 0xa0, 0x0d, 0xb0, 0xb7, 0xf0, 0x28, 0x82, - 0x65, 0x2b, 0xe2, 0x76, 0xe3, 0xab, 0x85, 0x99, 0xe5, 0xc2, 0x86, 0xe5, 0xb2, 0xb1, 0xa4, 0x79, - 0x80, 0xc7, 0x55, 0x00, 0x88, 0x7b, 0xe5, 0x23, 0x9b, 0x11, 0xcf, 0x2d, 0xa4, 0x25, 0xbe, 0x94, - 0xab, 0xc8, 0xca, 0xb4, 0x8d, 0xca, 0xbc, 0x7d, 0xb3, 0x36, 0x2a, 0xfa, 0x62, 0xd2, 0x58, 0x41, - 0xc9, 0x9f, 0x81, 0xc7, 0x33, 0x53, 0x5a, 0x6e, 0xc7, 0x73, 0x1d, 0xe2, 0x76, 0x2f, 0x06, 0x14, - 0x0a, 0x20, 0x4d, 0x9c, 0x69, 0x97, 0x32, 0x46, 0xf8, 0x28, 0xff, 0x96, 0x02, 0xb0, 0xe6, 0xb9, - 0x74, 0xd8, 0xc7, 0xfe, 0x8a, 0x03, 0x27, 0x20, 0x13, 0x56, 0x36, 0x12, 0x9f, 0xab, 0x54, 0x76, - 0x65, 0x15, 0x47, 0x37, 0x47, 0x03, 0x6c, 0x44, 0x78, 0xf8, 0x0a, 0xec, 0xd3, 0x75, 0x73, 0x23, - 0xd1, 0xd9, 0xca, 0xe7, 0xbb, 0x28, 0x37, 0xf2, 0x38, 0xe5, 0x8c, 0x4d, 0x16, 0x78, 0x05, 0xf2, - 0x01, 0xb5, 0x63, 0xc1, 0x47, 0x76, 0x65, 0x2b, 0x5f, 0xec, 0x2c, 0x57, 0x42, 0x61, 0x4e, 0x39, - 0x23, 0x91, 0xaf, 0xfa, 0x08, 0x64, 0x1c, 0xc4, 0x90, 0xdc, 0x01, 0x1f, 0xc7, 0x85, 0x9e, 0x11, - 0xca, 0xe0, 0xe9, 0x5a, 0xad, 0x95, 0x87, 0x59, 0xb5, 0x56, 0xe6, 0x37, 0x29, 0x90, 0x8f, 0x8f, - 0xb4, 0xcb, 0xff, 0x5a, 0x1a, 0xaf, 0xb7, 0xa5, 0xf1, 0xe2, 0x01, 0x69, 0xb4, 0xcb, 0xff, 0x87, - 0x3c, 0xfe, 0xe4, 0xc1, 0x41, 0x6c, 0x63, 0xff, 0xf1, 0xc1, 0xfd, 0x2e, 0xe1, 0xe0, 0x1e, 0xee, - 0x52, 0xbe, 0x3c, 0xbc, 0x51, 0x48, 0x2b, 0xe8, 0xc3, 0xdf, 0xf9, 0xa4, 0xc2, 0x85, 0x63, 0xf0, - 0x6b, 0x20, 0xd5, 0x2e, 0x1a, 0x66, 0xeb, 0x5c, 0x33, 0xac, 0xcb, 0xe3, 0xda, 0xf7, 0x5a, 0xd3, - 0x6a, 0xbe, 0xbe, 0xd4, 0xac, 0x56, 0xc3, 0xbc, 0xd4, 0x6a, 0xfa, 0x89, 0xae, 0xd5, 0x05, 0x4e, - 0xfc, 0x68, 0x3c, 0x91, 0x0e, 0x5a, 0x2e, 0x1d, 0x60, 0x9b, 0x5c, 0x91, 0xb9, 0x87, 0x50, 0x05, - 0x62, 0x22, 0xd8, 0x3c, 0x3b, 0x36, 0x4f, 0x05, 0x5e, 0xdc, 0x1f, 0x4f, 0xa4, 0xec, 0x8a, 0xb1, - 0xf0, 0x08, 0x3c, 0x49, 0x04, 0x84, 0xa9, 0x09, 0x29, 0x31, 0x3f, 0x9e, 0x48, 0x42, 0x7b, 0x23, - 0x29, 0x31, 0xf3, 0xf3, 0xaf, 0x45, 0xee, 0xf0, 0x0d, 0x0f, 0x72, 0xeb, 0x12, 0xe1, 0x4b, 0xf0, - 0x54, 0x6f, 0x9c, 0x18, 0xc7, 0xb5, 0xa6, 0x7e, 0xd1, 0x48, 0xda, 0xf6, 0xe3, 0xf1, 0x44, 0xda, - 0x5f, 0x82, 0xb4, 0xfe, 0x80, 0x8d, 0xa0, 0x1a, 0x47, 0xd5, 0x2f, 0x5a, 0xd5, 0x33, 0xcd, 0x32, - 0xf5, 0x6f, 0x1b, 0x02, 0x2f, 0xe6, 0xc6, 0x13, 0x09, 0xd4, 0xbd, 0x61, 0xa7, 0x87, 0x4d, 0xd2, - 0x75, 0xe1, 0x21, 0x28, 0xc4, 0x01, 0xaf, 0x1a, 0x4d, 0xfd, 0x5c, 0x13, 0x52, 0xe2, 0x87, 0xe3, - 0x89, 0xf4, 0x41, 0xdd, 0xfb, 0xd1, 0x65, 0xa4, 0x8f, 0xa7, 0x7b, 0xad, 0x36, 0xde, 0xde, 0x15, - 0xf9, 0x77, 0x77, 0x45, 0xfe, 0xaf, 0xbb, 0x22, 0xff, 0xcb, 0x7d, 0x91, 0x7b, 0x77, 0x5f, 0xe4, - 0xde, 0xdf, 0x17, 0xb9, 0x1f, 0x5e, 0x76, 0x09, 0xbb, 0x1e, 0x76, 0x14, 0xdb, 0xeb, 0xab, 0xb3, - 0x2b, 0xc1, 0x32, 0xd2, 0x17, 0x8b, 0xbb, 0x45, 0x70, 0xa4, 0xfe, 0x14, 0x5d, 0x30, 0xa2, 0x4f, - 0x7d, 0xe7, 0x51, 0xf4, 0xad, 0x3f, 0xfa, 0x27, 0x00, 0x00, 0xff, 0xff, 0x8f, 0xbf, 0xfc, 0xd2, - 0x88, 0x08, 0x00, 0x00, + proto.RegisterFile("interchain_security/ccv/v1/wire.proto", fileDescriptor_8fd0dc67df6b10ed) +} + +var fileDescriptor_8fd0dc67df6b10ed = []byte{ + // 833 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x55, 0xcd, 0x6e, 0xe3, 0x54, + 0x14, 0xb6, 0xd3, 0x6a, 0xa0, 0x37, 0x28, 0x75, 0x3d, 0x61, 0x64, 0x3c, 0x90, 0xb1, 0x2c, 0x90, + 0xa2, 0xa2, 0xb1, 0x49, 0x3a, 0x2b, 0xd8, 0x90, 0x1f, 0x97, 0x1a, 0xa6, 0x69, 0x64, 0x27, 0x19, + 0x0d, 0x1b, 0xeb, 0xc6, 0xbe, 0x4d, 0xae, 0x92, 0xf8, 0x5a, 0xbe, 0x37, 0x1e, 0xf2, 0x06, 0x28, + 0x2b, 0x5e, 0x20, 0x2b, 0xc4, 0x62, 0x1e, 0x83, 0xdd, 0x2c, 0x47, 0x62, 0x33, 0x1b, 0x46, 0xa8, + 0x7d, 0x03, 0x9e, 0x00, 0xd9, 0xf9, 0x6d, 0xe2, 0x56, 0xaa, 0x84, 0x04, 0x3b, 0xfb, 0xdc, 0xf3, + 0x7d, 0xf7, 0x9c, 0xef, 0x3b, 0x57, 0x07, 0x7c, 0x81, 0x7d, 0x86, 0x42, 0xb7, 0x0f, 0xb1, 0xef, + 0x50, 0xe4, 0x8e, 0x43, 0xcc, 0x26, 0xba, 0xeb, 0x46, 0x7a, 0x54, 0xd2, 0x5f, 0xe1, 0x10, 0x69, + 0x41, 0x48, 0x18, 0x11, 0xe5, 0x94, 0x34, 0xcd, 0x75, 0x23, 0x2d, 0x2a, 0xc9, 0x9f, 0xbb, 0x84, + 0x8e, 0x08, 0xd5, 0x29, 0x83, 0x03, 0xec, 0xf7, 0xf4, 0xa8, 0xd4, 0x45, 0x0c, 0x96, 0x96, 0xff, + 0x73, 0x06, 0x39, 0xdf, 0x23, 0x3d, 0x92, 0x7c, 0xea, 0xf1, 0xd7, 0x22, 0xfa, 0x98, 0x21, 0xdf, + 0x43, 0xe1, 0x08, 0xfb, 0x4c, 0x87, 0x5d, 0x17, 0xeb, 0x6c, 0x12, 0x20, 0x3a, 0x3f, 0x54, 0xdf, + 0xf1, 0xe0, 0xd3, 0x0e, 0x1c, 0x62, 0x0f, 0x32, 0x12, 0xda, 0x88, 0xd5, 0xfa, 0xd0, 0xef, 0xa1, + 0x26, 0x74, 0x07, 0x88, 0xd5, 0x21, 0x83, 0x22, 0x01, 0x47, 0xd1, 0xf2, 0xdc, 0x19, 0x07, 0x1e, + 0x64, 0x88, 0x4a, 0xbc, 0xb2, 0x57, 0xcc, 0x96, 0x15, 0x6d, 0xcd, 0xac, 0xc5, 0xcc, 0xda, 0x8a, + 0xa9, 0x9d, 0x24, 0x56, 0x95, 0x37, 0xef, 0x9f, 0x70, 0x7f, 0xbf, 0x7f, 0x22, 0x4d, 0xe0, 0x68, + 0xf8, 0xb5, 0xba, 0x43, 0xa4, 0x5a, 0x42, 0x74, 0x13, 0x42, 0xc5, 0x22, 0x88, 0x63, 0x14, 0xb1, + 0x45, 0x92, 0x83, 0x3d, 0x29, 0xa3, 0xf0, 0xc5, 0x7d, 0x2b, 0x37, 0x8f, 0xcf, 0x13, 0x4d, 0x4f, + 0xfc, 0x0c, 0x00, 0x3a, 0x84, 0xb4, 0xef, 0x40, 0x77, 0x40, 0xa5, 0x3d, 0x65, 0xaf, 0x78, 0x60, + 0x1d, 0x24, 0x91, 0x8a, 0x3b, 0xa0, 0xea, 0xb7, 0x20, 0xdf, 0xb1, 0x6b, 0xe7, 0x90, 0x8d, 0x43, + 0xe4, 0x6d, 0x74, 0x94, 0x76, 0x01, 0x9f, 0x76, 0x81, 0xfa, 0x07, 0x0f, 0x0e, 0xed, 0x98, 0x6f, + 0x03, 0x6d, 0x81, 0x83, 0x55, 0xc9, 0x09, 0x2c, 0x5b, 0x96, 0x6f, 0xd7, 0xa1, 0x2a, 0x2d, 0x14, + 0x10, 0xb6, 0x14, 0x50, 0xad, 0x35, 0xcd, 0x3d, 0x5a, 0xae, 0x02, 0x80, 0xfd, 0xcb, 0x10, 0xba, + 0x0c, 0x13, 0x5f, 0xda, 0x53, 0xf8, 0x62, 0xae, 0xac, 0x6a, 0xf3, 0xe1, 0xd0, 0x96, 0xc3, 0xb0, + 0x18, 0x0e, 0xcd, 0x5c, 0x65, 0x5a, 0x1b, 0x28, 0xf5, 0xb7, 0x0c, 0x10, 0x6b, 0xc4, 0xa7, 0xe3, + 0x11, 0x0a, 0x37, 0x1a, 0x3b, 0x05, 0xfb, 0xf1, 0x60, 0x24, 0x3d, 0xe5, 0xca, 0x65, 0xed, 0xf6, + 0x69, 0xd4, 0x76, 0xd1, 0xad, 0x49, 0x80, 0xac, 0x04, 0x2f, 0xbe, 0x00, 0x87, 0xf4, 0xa6, 0x66, + 0x49, 0x2f, 0xd9, 0xf2, 0x97, 0x77, 0x51, 0x6e, 0xc9, 0x7c, 0xc6, 0x59, 0xdb, 0x2c, 0xe2, 0x25, + 0xc8, 0x47, 0xd4, 0xdd, 0xf1, 0x33, 0x51, 0x21, 0x5b, 0xfe, 0xea, 0x2e, 0xf6, 0xb4, 0x39, 0x38, + 0xe3, 0xac, 0x54, 0xbe, 0xea, 0x03, 0xb0, 0xef, 0x41, 0x06, 0xd5, 0x2e, 0x38, 0x3a, 0x83, 0xbe, + 0x47, 0xfb, 0x70, 0x80, 0xce, 0x11, 0x83, 0x71, 0x50, 0x3c, 0x01, 0x8f, 0x82, 0x90, 0x44, 0xd8, + 0x43, 0xa1, 0x73, 0x89, 0x90, 0x13, 0x10, 0x32, 0x74, 0xa0, 0xe7, 0xcd, 0x67, 0xe1, 0xc0, 0x7a, + 0xb8, 0x3c, 0x3d, 0x45, 0xa8, 0x49, 0xc8, 0xb0, 0xe2, 0x79, 0xa1, 0x28, 0x81, 0x0f, 0x22, 0x14, + 0xd2, 0xd8, 0xb2, 0x4c, 0x92, 0xb5, 0xfc, 0x55, 0x5f, 0x67, 0x40, 0x7e, 0x57, 0xcd, 0x4e, 0xe9, + 0x5f, 0x73, 0xe3, 0xe5, 0x6d, 0x6e, 0x3c, 0xbd, 0x87, 0x1b, 0x9d, 0xd2, 0xff, 0xc1, 0x8f, 0x3f, + 0x79, 0x70, 0xb4, 0x53, 0xd8, 0x7f, 0xfc, 0x1e, 0xbf, 0x4f, 0x79, 0x8f, 0xc7, 0x77, 0x75, 0xbe, + 0x7e, 0x93, 0x89, 0x49, 0x1b, 0xe8, 0xe3, 0xdf, 0x79, 0xf0, 0x28, 0xdd, 0x4b, 0xf1, 0x1b, 0xa0, + 0xd4, 0x2e, 0x1a, 0x76, 0xfb, 0xdc, 0xb0, 0x9c, 0x66, 0xa5, 0xf6, 0x83, 0xd1, 0x72, 0x5a, 0x2f, + 0x9b, 0x86, 0xd3, 0x6e, 0xd8, 0x4d, 0xa3, 0x66, 0x9e, 0x9a, 0x46, 0x5d, 0xe0, 0xe4, 0x8f, 0xa7, + 0x33, 0xe5, 0xa8, 0xed, 0xd3, 0x00, 0xb9, 0xf8, 0x12, 0x2f, 0x35, 0x14, 0x75, 0x20, 0xa7, 0x82, + 0xed, 0xe7, 0x15, 0xfb, 0x4c, 0xe0, 0xe5, 0xc3, 0xe9, 0x4c, 0xc9, 0x6e, 0x08, 0x2b, 0x9e, 0x80, + 0x4f, 0x52, 0x01, 0xb1, 0x6b, 0x42, 0x46, 0xce, 0x4f, 0x67, 0x8a, 0xd0, 0xd9, 0x72, 0x4a, 0xde, + 0xff, 0xf9, 0xd7, 0x02, 0x77, 0xfc, 0x9a, 0x07, 0xb9, 0x9b, 0x2d, 0x8a, 0xcf, 0xc0, 0x63, 0xb3, + 0x71, 0x6a, 0x55, 0x6a, 0x2d, 0xf3, 0xa2, 0x91, 0x56, 0xf6, 0xc3, 0xe9, 0x4c, 0x39, 0x5c, 0x83, + 0x8c, 0x51, 0xc0, 0x26, 0xa2, 0xbe, 0x8b, 0xaa, 0x5f, 0xb4, 0xab, 0xcf, 0x0d, 0xc7, 0x36, 0xbf, + 0x6b, 0x08, 0xbc, 0x9c, 0x9b, 0xce, 0x14, 0x50, 0x27, 0xe3, 0xee, 0x10, 0xd9, 0xb8, 0xe7, 0x8b, + 0xc7, 0x40, 0xda, 0x05, 0xbc, 0x68, 0xb4, 0xcc, 0x73, 0x43, 0xc8, 0xc8, 0x1f, 0x4d, 0x67, 0xca, + 0x87, 0x75, 0xf2, 0xca, 0x67, 0x78, 0x84, 0xe6, 0xb5, 0x56, 0x1b, 0x6f, 0xae, 0x0a, 0xfc, 0xdb, + 0xab, 0x02, 0xff, 0xd7, 0x55, 0x81, 0xff, 0xe5, 0xba, 0xc0, 0xbd, 0xbd, 0x2e, 0x70, 0xef, 0xae, + 0x0b, 0xdc, 0x8f, 0xcf, 0x7a, 0x98, 0xf5, 0xc7, 0x5d, 0xcd, 0x25, 0x23, 0x7d, 0xb1, 0x78, 0xd7, + 0x96, 0x3e, 0x5d, 0xad, 0xf0, 0xe8, 0x44, 0xff, 0x29, 0xd9, 0xe3, 0xc9, 0x42, 0xed, 0x3e, 0x48, + 0x36, 0xea, 0xc9, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x17, 0x85, 0x90, 0x57, 0xef, 0x07, 0x00, + 0x00, } func (m *ValidatorSetChangePacketData) Marshal() (dAtA []byte, err error) { @@ -759,13 +673,13 @@ func (m *ValidatorSetChangePacketData) MarshalToSizedBuffer(dAtA []byte) (int, e for iNdEx := len(m.SlashAcks) - 1; iNdEx >= 0; iNdEx-- { i -= len(m.SlashAcks[iNdEx]) copy(dAtA[i:], m.SlashAcks[iNdEx]) - i = encodeVarintCcv(dAtA, i, uint64(len(m.SlashAcks[iNdEx]))) + i = encodeVarintWire(dAtA, i, uint64(len(m.SlashAcks[iNdEx]))) i-- dAtA[i] = 0x1a } } if m.ValsetUpdateId != 0 { - i = encodeVarintCcv(dAtA, i, uint64(m.ValsetUpdateId)) + i = encodeVarintWire(dAtA, i, uint64(m.ValsetUpdateId)) i-- dAtA[i] = 0x10 } @@ -777,44 +691,7 @@ func (m *ValidatorSetChangePacketData) MarshalToSizedBuffer(dAtA []byte) (int, e return 0, err } i -= size - i = encodeVarintCcv(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - } - return len(dAtA) - i, nil -} - -func (m *ValidatorSetChangePackets) 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 *ValidatorSetChangePackets) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *ValidatorSetChangePackets) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.List) > 0 { - for iNdEx := len(m.List) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.List[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintCcv(dAtA, i, uint64(size)) + i = encodeVarintWire(dAtA, i, uint64(size)) } i-- dAtA[i] = 0xa @@ -844,7 +721,7 @@ func (m *VSCMaturedPacketData) MarshalToSizedBuffer(dAtA []byte) (int, error) { var l int _ = l if m.ValsetUpdateId != 0 { - i = encodeVarintCcv(dAtA, i, uint64(m.ValsetUpdateId)) + i = encodeVarintWire(dAtA, i, uint64(m.ValsetUpdateId)) i-- dAtA[i] = 0x8 } @@ -872,12 +749,12 @@ func (m *SlashPacketData) MarshalToSizedBuffer(dAtA []byte) (int, error) { var l int _ = l if m.Infraction != 0 { - i = encodeVarintCcv(dAtA, i, uint64(m.Infraction)) + i = encodeVarintWire(dAtA, i, uint64(m.Infraction)) i-- dAtA[i] = 0x18 } if m.ValsetUpdateId != 0 { - i = encodeVarintCcv(dAtA, i, uint64(m.ValsetUpdateId)) + i = encodeVarintWire(dAtA, i, uint64(m.ValsetUpdateId)) i-- dAtA[i] = 0x10 } @@ -887,54 +764,13 @@ func (m *SlashPacketData) MarshalToSizedBuffer(dAtA []byte) (int, error) { return 0, err } i -= size - i = encodeVarintCcv(dAtA, i, uint64(size)) + i = encodeVarintWire(dAtA, i, uint64(size)) } i-- dAtA[i] = 0xa return len(dAtA) - i, nil } -func (m *MaturedUnbondingOps) 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 *MaturedUnbondingOps) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MaturedUnbondingOps) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Ids) > 0 { - dAtA3 := make([]byte, len(m.Ids)*10) - var j2 int - for _, num := range m.Ids { - for num >= 1<<7 { - dAtA3[j2] = uint8(uint64(num)&0x7f | 0x80) - num >>= 7 - j2++ - } - dAtA3[j2] = uint8(num) - j2++ - } - i -= j2 - copy(dAtA[i:], dAtA3[:j2]) - i = encodeVarintCcv(dAtA, i, uint64(j2)) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - func (m *ConsumerPacketData) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -965,7 +801,7 @@ func (m *ConsumerPacketData) MarshalToSizedBuffer(dAtA []byte) (int, error) { } } if m.Type != 0 { - i = encodeVarintCcv(dAtA, i, uint64(m.Type)) + i = encodeVarintWire(dAtA, i, uint64(m.Type)) i-- dAtA[i] = 0x8 } @@ -986,7 +822,7 @@ func (m *ConsumerPacketData_SlashPacketData) MarshalToSizedBuffer(dAtA []byte) ( return 0, err } i -= size - i = encodeVarintCcv(dAtA, i, uint64(size)) + i = encodeVarintWire(dAtA, i, uint64(size)) } i-- dAtA[i] = 0x12 @@ -1007,14 +843,14 @@ func (m *ConsumerPacketData_VscMaturedPacketData) MarshalToSizedBuffer(dAtA []by return 0, err } i -= size - i = encodeVarintCcv(dAtA, i, uint64(size)) + i = encodeVarintWire(dAtA, i, uint64(size)) } i-- dAtA[i] = 0x1a } return len(dAtA) - i, nil } -func (m *ConsumerPacketDataList) Marshal() (dAtA []byte, err error) { +func (m *HandshakeMetadata) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -1024,29 +860,29 @@ func (m *ConsumerPacketDataList) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *ConsumerPacketDataList) MarshalTo(dAtA []byte) (int, error) { +func (m *HandshakeMetadata) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *ConsumerPacketDataList) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *HandshakeMetadata) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if len(m.List) > 0 { - for iNdEx := len(m.List) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.List[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintCcv(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } + if len(m.Version) > 0 { + i -= len(m.Version) + copy(dAtA[i:], m.Version) + i = encodeVarintWire(dAtA, i, uint64(len(m.Version))) + i-- + dAtA[i] = 0x12 + } + if len(m.ProviderFeePoolAddr) > 0 { + i -= len(m.ProviderFeePoolAddr) + copy(dAtA[i:], m.ProviderFeePoolAddr) + i = encodeVarintWire(dAtA, i, uint64(len(m.ProviderFeePoolAddr))) + i-- + dAtA[i] = 0xa } return len(dAtA) - i, nil } @@ -1081,7 +917,7 @@ func (m *ConsumerPacketDataV1) MarshalToSizedBuffer(dAtA []byte) (int, error) { } } if m.Type != 0 { - i = encodeVarintCcv(dAtA, i, uint64(m.Type)) + i = encodeVarintWire(dAtA, i, uint64(m.Type)) i-- dAtA[i] = 0x8 } @@ -1102,7 +938,7 @@ func (m *ConsumerPacketDataV1_SlashPacketData) MarshalToSizedBuffer(dAtA []byte) return 0, err } i -= size - i = encodeVarintCcv(dAtA, i, uint64(size)) + i = encodeVarintWire(dAtA, i, uint64(size)) } i-- dAtA[i] = 0x12 @@ -1123,7 +959,7 @@ func (m *ConsumerPacketDataV1_VscMaturedPacketData) MarshalToSizedBuffer(dAtA [] return 0, err } i -= size - i = encodeVarintCcv(dAtA, i, uint64(size)) + i = encodeVarintWire(dAtA, i, uint64(size)) } i-- dAtA[i] = 0x1a @@ -1151,12 +987,12 @@ func (m *SlashPacketDataV1) MarshalToSizedBuffer(dAtA []byte) (int, error) { var l int _ = l if m.Infraction != 0 { - i = encodeVarintCcv(dAtA, i, uint64(m.Infraction)) + i = encodeVarintWire(dAtA, i, uint64(m.Infraction)) i-- dAtA[i] = 0x18 } if m.ValsetUpdateId != 0 { - i = encodeVarintCcv(dAtA, i, uint64(m.ValsetUpdateId)) + i = encodeVarintWire(dAtA, i, uint64(m.ValsetUpdateId)) i-- dAtA[i] = 0x10 } @@ -1166,15 +1002,15 @@ func (m *SlashPacketDataV1) MarshalToSizedBuffer(dAtA []byte) (int, error) { return 0, err } i -= size - i = encodeVarintCcv(dAtA, i, uint64(size)) + i = encodeVarintWire(dAtA, i, uint64(size)) } i-- dAtA[i] = 0xa return len(dAtA) - i, nil } -func encodeVarintCcv(dAtA []byte, offset int, v uint64) int { - offset -= sovCcv(v) +func encodeVarintWire(dAtA []byte, offset int, v uint64) int { + offset -= sovWire(v) base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) @@ -1193,31 +1029,16 @@ func (m *ValidatorSetChangePacketData) Size() (n int) { if len(m.ValidatorUpdates) > 0 { for _, e := range m.ValidatorUpdates { l = e.Size() - n += 1 + l + sovCcv(uint64(l)) + n += 1 + l + sovWire(uint64(l)) } } if m.ValsetUpdateId != 0 { - n += 1 + sovCcv(uint64(m.ValsetUpdateId)) + n += 1 + sovWire(uint64(m.ValsetUpdateId)) } if len(m.SlashAcks) > 0 { for _, s := range m.SlashAcks { l = len(s) - n += 1 + l + sovCcv(uint64(l)) - } - } - return n -} - -func (m *ValidatorSetChangePackets) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.List) > 0 { - for _, e := range m.List { - l = e.Size() - n += 1 + l + sovCcv(uint64(l)) + n += 1 + l + sovWire(uint64(l)) } } return n @@ -1230,7 +1051,7 @@ func (m *VSCMaturedPacketData) Size() (n int) { var l int _ = l if m.ValsetUpdateId != 0 { - n += 1 + sovCcv(uint64(m.ValsetUpdateId)) + n += 1 + sovWire(uint64(m.ValsetUpdateId)) } return n } @@ -1242,28 +1063,12 @@ func (m *SlashPacketData) Size() (n int) { var l int _ = l l = m.Validator.Size() - n += 1 + l + sovCcv(uint64(l)) + n += 1 + l + sovWire(uint64(l)) if m.ValsetUpdateId != 0 { - n += 1 + sovCcv(uint64(m.ValsetUpdateId)) + n += 1 + sovWire(uint64(m.ValsetUpdateId)) } if m.Infraction != 0 { - n += 1 + sovCcv(uint64(m.Infraction)) - } - return n -} - -func (m *MaturedUnbondingOps) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.Ids) > 0 { - l = 0 - for _, e := range m.Ids { - l += sovCcv(uint64(e)) - } - n += 1 + sovCcv(uint64(l)) + l + n += 1 + sovWire(uint64(m.Infraction)) } return n } @@ -1275,7 +1080,7 @@ func (m *ConsumerPacketData) Size() (n int) { var l int _ = l if m.Type != 0 { - n += 1 + sovCcv(uint64(m.Type)) + n += 1 + sovWire(uint64(m.Type)) } if m.Data != nil { n += m.Data.Size() @@ -1291,7 +1096,7 @@ func (m *ConsumerPacketData_SlashPacketData) Size() (n int) { _ = l if m.SlashPacketData != nil { l = m.SlashPacketData.Size() - n += 1 + l + sovCcv(uint64(l)) + n += 1 + l + sovWire(uint64(l)) } return n } @@ -1303,21 +1108,23 @@ func (m *ConsumerPacketData_VscMaturedPacketData) Size() (n int) { _ = l if m.VscMaturedPacketData != nil { l = m.VscMaturedPacketData.Size() - n += 1 + l + sovCcv(uint64(l)) + n += 1 + l + sovWire(uint64(l)) } return n } -func (m *ConsumerPacketDataList) Size() (n int) { +func (m *HandshakeMetadata) Size() (n int) { if m == nil { return 0 } var l int _ = l - if len(m.List) > 0 { - for _, e := range m.List { - l = e.Size() - n += 1 + l + sovCcv(uint64(l)) - } + l = len(m.ProviderFeePoolAddr) + if l > 0 { + n += 1 + l + sovWire(uint64(l)) + } + l = len(m.Version) + if l > 0 { + n += 1 + l + sovWire(uint64(l)) } return n } @@ -1329,7 +1136,7 @@ func (m *ConsumerPacketDataV1) Size() (n int) { var l int _ = l if m.Type != 0 { - n += 1 + sovCcv(uint64(m.Type)) + n += 1 + sovWire(uint64(m.Type)) } if m.Data != nil { n += m.Data.Size() @@ -1345,7 +1152,7 @@ func (m *ConsumerPacketDataV1_SlashPacketData) Size() (n int) { _ = l if m.SlashPacketData != nil { l = m.SlashPacketData.Size() - n += 1 + l + sovCcv(uint64(l)) + n += 1 + l + sovWire(uint64(l)) } return n } @@ -1357,7 +1164,7 @@ func (m *ConsumerPacketDataV1_VscMaturedPacketData) Size() (n int) { _ = l if m.VscMaturedPacketData != nil { l = m.VscMaturedPacketData.Size() - n += 1 + l + sovCcv(uint64(l)) + n += 1 + l + sovWire(uint64(l)) } return n } @@ -1368,21 +1175,21 @@ func (m *SlashPacketDataV1) Size() (n int) { var l int _ = l l = m.Validator.Size() - n += 1 + l + sovCcv(uint64(l)) + n += 1 + l + sovWire(uint64(l)) if m.ValsetUpdateId != 0 { - n += 1 + sovCcv(uint64(m.ValsetUpdateId)) + n += 1 + sovWire(uint64(m.ValsetUpdateId)) } if m.Infraction != 0 { - n += 1 + sovCcv(uint64(m.Infraction)) + n += 1 + sovWire(uint64(m.Infraction)) } return n } -func sovCcv(x uint64) (n int) { +func sovWire(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } -func sozCcv(x uint64) (n int) { - return sovCcv(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +func sozWire(x uint64) (n int) { + return sovWire(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } func (m *ValidatorSetChangePacketData) Unmarshal(dAtA []byte) error { l := len(dAtA) @@ -1392,7 +1199,7 @@ func (m *ValidatorSetChangePacketData) Unmarshal(dAtA []byte) error { var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCcv + return ErrIntOverflowWire } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -1420,7 +1227,7 @@ func (m *ValidatorSetChangePacketData) Unmarshal(dAtA []byte) error { var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCcv + return ErrIntOverflowWire } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -1433,11 +1240,11 @@ func (m *ValidatorSetChangePacketData) Unmarshal(dAtA []byte) error { } } if msglen < 0 { - return ErrInvalidLengthCcv + return ErrInvalidLengthWire } postIndex := iNdEx + msglen if postIndex < 0 { - return ErrInvalidLengthCcv + return ErrInvalidLengthWire } if postIndex > l { return io.ErrUnexpectedEOF @@ -1454,7 +1261,7 @@ func (m *ValidatorSetChangePacketData) Unmarshal(dAtA []byte) error { m.ValsetUpdateId = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCcv + return ErrIntOverflowWire } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -1473,7 +1280,7 @@ func (m *ValidatorSetChangePacketData) Unmarshal(dAtA []byte) error { var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCcv + return ErrIntOverflowWire } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -1487,11 +1294,11 @@ func (m *ValidatorSetChangePacketData) Unmarshal(dAtA []byte) error { } intStringLen := int(stringLen) if intStringLen < 0 { - return ErrInvalidLengthCcv + return ErrInvalidLengthWire } postIndex := iNdEx + intStringLen if postIndex < 0 { - return ErrInvalidLengthCcv + return ErrInvalidLengthWire } if postIndex > l { return io.ErrUnexpectedEOF @@ -1500,96 +1307,12 @@ func (m *ValidatorSetChangePacketData) Unmarshal(dAtA []byte) error { iNdEx = postIndex default: iNdEx = preIndex - skippy, err := skipCcv(dAtA[iNdEx:]) + skippy, err := skipWire(dAtA[iNdEx:]) if err != nil { return err } if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthCcv - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *ValidatorSetChangePackets) 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 ErrIntOverflowCcv - } - 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: ValidatorSetChangePackets: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: ValidatorSetChangePackets: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field List", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCcv - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthCcv - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthCcv - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.List = append(m.List, ValidatorSetChangePacketData{}) - if err := m.List[len(m.List)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipCcv(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthCcv + return ErrInvalidLengthWire } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF @@ -1611,7 +1334,7 @@ func (m *VSCMaturedPacketData) Unmarshal(dAtA []byte) error { var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCcv + return ErrIntOverflowWire } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -1639,7 +1362,7 @@ func (m *VSCMaturedPacketData) Unmarshal(dAtA []byte) error { m.ValsetUpdateId = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCcv + return ErrIntOverflowWire } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -1653,12 +1376,12 @@ func (m *VSCMaturedPacketData) Unmarshal(dAtA []byte) error { } default: iNdEx = preIndex - skippy, err := skipCcv(dAtA[iNdEx:]) + skippy, err := skipWire(dAtA[iNdEx:]) if err != nil { return err } if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthCcv + return ErrInvalidLengthWire } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF @@ -1680,7 +1403,7 @@ func (m *SlashPacketData) Unmarshal(dAtA []byte) error { var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCcv + return ErrIntOverflowWire } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -1708,7 +1431,7 @@ func (m *SlashPacketData) Unmarshal(dAtA []byte) error { var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCcv + return ErrIntOverflowWire } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -1721,11 +1444,11 @@ func (m *SlashPacketData) Unmarshal(dAtA []byte) error { } } if msglen < 0 { - return ErrInvalidLengthCcv + return ErrInvalidLengthWire } postIndex := iNdEx + msglen if postIndex < 0 { - return ErrInvalidLengthCcv + return ErrInvalidLengthWire } if postIndex > l { return io.ErrUnexpectedEOF @@ -1741,7 +1464,7 @@ func (m *SlashPacketData) Unmarshal(dAtA []byte) error { m.ValsetUpdateId = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCcv + return ErrIntOverflowWire } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -1760,7 +1483,7 @@ func (m *SlashPacketData) Unmarshal(dAtA []byte) error { m.Infraction = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCcv + return ErrIntOverflowWire } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -1774,138 +1497,12 @@ func (m *SlashPacketData) Unmarshal(dAtA []byte) error { } default: iNdEx = preIndex - skippy, err := skipCcv(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthCcv - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MaturedUnbondingOps) 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 ErrIntOverflowCcv - } - 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: MaturedUnbondingOps: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MaturedUnbondingOps: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType == 0 { - var v uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCcv - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.Ids = append(m.Ids, v) - } else if wireType == 2 { - var packedLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCcv - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - packedLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if packedLen < 0 { - return ErrInvalidLengthCcv - } - postIndex := iNdEx + packedLen - if postIndex < 0 { - return ErrInvalidLengthCcv - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - var elementCount int - var count int - for _, integer := range dAtA[iNdEx:postIndex] { - if integer < 128 { - count++ - } - } - elementCount = count - if elementCount != 0 && len(m.Ids) == 0 { - m.Ids = make([]uint64, 0, elementCount) - } - for iNdEx < postIndex { - var v uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCcv - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.Ids = append(m.Ids, v) - } - } else { - return fmt.Errorf("proto: wrong wireType = %d for field Ids", wireType) - } - default: - iNdEx = preIndex - skippy, err := skipCcv(dAtA[iNdEx:]) + skippy, err := skipWire(dAtA[iNdEx:]) if err != nil { return err } if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthCcv + return ErrInvalidLengthWire } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF @@ -1927,7 +1524,7 @@ func (m *ConsumerPacketData) Unmarshal(dAtA []byte) error { var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCcv + return ErrIntOverflowWire } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -1955,7 +1552,7 @@ func (m *ConsumerPacketData) Unmarshal(dAtA []byte) error { m.Type = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCcv + return ErrIntOverflowWire } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -1974,7 +1571,7 @@ func (m *ConsumerPacketData) Unmarshal(dAtA []byte) error { var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCcv + return ErrIntOverflowWire } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -1987,11 +1584,11 @@ func (m *ConsumerPacketData) Unmarshal(dAtA []byte) error { } } if msglen < 0 { - return ErrInvalidLengthCcv + return ErrInvalidLengthWire } postIndex := iNdEx + msglen if postIndex < 0 { - return ErrInvalidLengthCcv + return ErrInvalidLengthWire } if postIndex > l { return io.ErrUnexpectedEOF @@ -2009,7 +1606,7 @@ func (m *ConsumerPacketData) Unmarshal(dAtA []byte) error { var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCcv + return ErrIntOverflowWire } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2022,11 +1619,11 @@ func (m *ConsumerPacketData) Unmarshal(dAtA []byte) error { } } if msglen < 0 { - return ErrInvalidLengthCcv + return ErrInvalidLengthWire } postIndex := iNdEx + msglen if postIndex < 0 { - return ErrInvalidLengthCcv + return ErrInvalidLengthWire } if postIndex > l { return io.ErrUnexpectedEOF @@ -2039,12 +1636,12 @@ func (m *ConsumerPacketData) Unmarshal(dAtA []byte) error { iNdEx = postIndex default: iNdEx = preIndex - skippy, err := skipCcv(dAtA[iNdEx:]) + skippy, err := skipWire(dAtA[iNdEx:]) if err != nil { return err } if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthCcv + return ErrInvalidLengthWire } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF @@ -2058,7 +1655,7 @@ func (m *ConsumerPacketData) Unmarshal(dAtA []byte) error { } return nil } -func (m *ConsumerPacketDataList) Unmarshal(dAtA []byte) error { +func (m *HandshakeMetadata) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -2066,7 +1663,7 @@ func (m *ConsumerPacketDataList) Unmarshal(dAtA []byte) error { var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCcv + return ErrIntOverflowWire } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2081,54 +1678,84 @@ func (m *ConsumerPacketDataList) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: ConsumerPacketDataList: wiretype end group for non-group") + return fmt.Errorf("proto: HandshakeMetadata: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: ConsumerPacketDataList: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: HandshakeMetadata: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field List", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ProviderFeePoolAddr", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCcv + return ErrIntOverflowWire } if iNdEx >= l { return io.ErrUnexpectedEOF } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { - return ErrInvalidLengthCcv + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthWire } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { - return ErrInvalidLengthCcv + return ErrInvalidLengthWire } if postIndex > l { return io.ErrUnexpectedEOF } - m.List = append(m.List, ConsumerPacketData{}) - if err := m.List[len(m.List)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err + m.ProviderFeePoolAddr = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowWire + } + 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 ErrInvalidLengthWire + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthWire + } + if postIndex > l { + return io.ErrUnexpectedEOF } + m.Version = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex - skippy, err := skipCcv(dAtA[iNdEx:]) + skippy, err := skipWire(dAtA[iNdEx:]) if err != nil { return err } if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthCcv + return ErrInvalidLengthWire } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF @@ -2150,7 +1777,7 @@ func (m *ConsumerPacketDataV1) Unmarshal(dAtA []byte) error { var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCcv + return ErrIntOverflowWire } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2178,7 +1805,7 @@ func (m *ConsumerPacketDataV1) Unmarshal(dAtA []byte) error { m.Type = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCcv + return ErrIntOverflowWire } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2197,7 +1824,7 @@ func (m *ConsumerPacketDataV1) Unmarshal(dAtA []byte) error { var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCcv + return ErrIntOverflowWire } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2210,11 +1837,11 @@ func (m *ConsumerPacketDataV1) Unmarshal(dAtA []byte) error { } } if msglen < 0 { - return ErrInvalidLengthCcv + return ErrInvalidLengthWire } postIndex := iNdEx + msglen if postIndex < 0 { - return ErrInvalidLengthCcv + return ErrInvalidLengthWire } if postIndex > l { return io.ErrUnexpectedEOF @@ -2232,7 +1859,7 @@ func (m *ConsumerPacketDataV1) Unmarshal(dAtA []byte) error { var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCcv + return ErrIntOverflowWire } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2245,11 +1872,11 @@ func (m *ConsumerPacketDataV1) Unmarshal(dAtA []byte) error { } } if msglen < 0 { - return ErrInvalidLengthCcv + return ErrInvalidLengthWire } postIndex := iNdEx + msglen if postIndex < 0 { - return ErrInvalidLengthCcv + return ErrInvalidLengthWire } if postIndex > l { return io.ErrUnexpectedEOF @@ -2262,12 +1889,12 @@ func (m *ConsumerPacketDataV1) Unmarshal(dAtA []byte) error { iNdEx = postIndex default: iNdEx = preIndex - skippy, err := skipCcv(dAtA[iNdEx:]) + skippy, err := skipWire(dAtA[iNdEx:]) if err != nil { return err } if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthCcv + return ErrInvalidLengthWire } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF @@ -2289,7 +1916,7 @@ func (m *SlashPacketDataV1) Unmarshal(dAtA []byte) error { var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCcv + return ErrIntOverflowWire } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2317,7 +1944,7 @@ func (m *SlashPacketDataV1) Unmarshal(dAtA []byte) error { var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCcv + return ErrIntOverflowWire } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2330,11 +1957,11 @@ func (m *SlashPacketDataV1) Unmarshal(dAtA []byte) error { } } if msglen < 0 { - return ErrInvalidLengthCcv + return ErrInvalidLengthWire } postIndex := iNdEx + msglen if postIndex < 0 { - return ErrInvalidLengthCcv + return ErrInvalidLengthWire } if postIndex > l { return io.ErrUnexpectedEOF @@ -2350,7 +1977,7 @@ func (m *SlashPacketDataV1) Unmarshal(dAtA []byte) error { m.ValsetUpdateId = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCcv + return ErrIntOverflowWire } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2369,7 +1996,7 @@ func (m *SlashPacketDataV1) Unmarshal(dAtA []byte) error { m.Infraction = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowCcv + return ErrIntOverflowWire } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -2383,12 +2010,12 @@ func (m *SlashPacketDataV1) Unmarshal(dAtA []byte) error { } default: iNdEx = preIndex - skippy, err := skipCcv(dAtA[iNdEx:]) + skippy, err := skipWire(dAtA[iNdEx:]) if err != nil { return err } if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthCcv + return ErrInvalidLengthWire } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF @@ -2402,7 +2029,7 @@ func (m *SlashPacketDataV1) Unmarshal(dAtA []byte) error { } return nil } -func skipCcv(dAtA []byte) (n int, err error) { +func skipWire(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 depth := 0 @@ -2410,7 +2037,7 @@ func skipCcv(dAtA []byte) (n int, err error) { var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return 0, ErrIntOverflowCcv + return 0, ErrIntOverflowWire } if iNdEx >= l { return 0, io.ErrUnexpectedEOF @@ -2427,7 +2054,7 @@ func skipCcv(dAtA []byte) (n int, err error) { case 0: for shift := uint(0); ; shift += 7 { if shift >= 64 { - return 0, ErrIntOverflowCcv + return 0, ErrIntOverflowWire } if iNdEx >= l { return 0, io.ErrUnexpectedEOF @@ -2443,7 +2070,7 @@ func skipCcv(dAtA []byte) (n int, err error) { var length int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return 0, ErrIntOverflowCcv + return 0, ErrIntOverflowWire } if iNdEx >= l { return 0, io.ErrUnexpectedEOF @@ -2456,14 +2083,14 @@ func skipCcv(dAtA []byte) (n int, err error) { } } if length < 0 { - return 0, ErrInvalidLengthCcv + return 0, ErrInvalidLengthWire } iNdEx += length case 3: depth++ case 4: if depth == 0 { - return 0, ErrUnexpectedEndOfGroupCcv + return 0, ErrUnexpectedEndOfGroupWire } depth-- case 5: @@ -2472,7 +2099,7 @@ func skipCcv(dAtA []byte) (n int, err error) { return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } if iNdEx < 0 { - return 0, ErrInvalidLengthCcv + return 0, ErrInvalidLengthWire } if depth == 0 { return iNdEx, nil @@ -2482,7 +2109,7 @@ func skipCcv(dAtA []byte) (n int, err error) { } var ( - ErrInvalidLengthCcv = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowCcv = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupCcv = fmt.Errorf("proto: unexpected end of group") + ErrInvalidLengthWire = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowWire = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupWire = fmt.Errorf("proto: unexpected end of group") ) diff --git a/x/ccv/types/ccv_test.go b/x/ccv/types/wire_test.go similarity index 100% rename from x/ccv/types/ccv_test.go rename to x/ccv/types/wire_test.go From b18a317c9a4c7ca85939a0313543673d50de68a7 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Date: Fri, 25 Aug 2023 14:37:47 +0200 Subject: [PATCH 096/134] Add waitBlocks for *both* chains on relayPackets (#1236) --- tests/e2e/actions.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index d7fba4a358..fccc27a957 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -1309,6 +1309,7 @@ func (tr TestRun) relayPacketsGorelayer( } tr.waitBlocks(action.chainA, 1, 30*time.Second) + tr.waitBlocks(action.chainB, 1, 30*time.Second) } func (tr TestRun) relayPacketsHermes( @@ -1332,6 +1333,7 @@ func (tr TestRun) relayPacketsHermes( } tr.waitBlocks(action.chainA, 1, 30*time.Second) + tr.waitBlocks(action.chainB, 1, 30*time.Second) } type relayRewardPacketsToProviderAction struct { From d137d39f01a2e2c85f90e7ea0bc0d1738affb4b1 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Date: Fri, 25 Aug 2023 14:58:57 +0200 Subject: [PATCH 097/134] chore: improve logging in getValPower (#1211) * Add more waits * Add debug setup for CometMock * Add extra output for errors in getValPower * Revert changes to actions.go * Remove utility script for making tests fail * Remove unnecessary log after curlJsonRPCRequest * Remove extra output after waitBlocks * Revert extraneous change to waitBlocks * Revert change to verbosity level of curlJsonRPC * Fix linter * Add pretty-printed chainstate and set log message to only execute when verbose * Add pretty printed valset to error message * Pretty-print the validator set in more error messages --- tests/e2e/state.go | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/tests/e2e/state.go b/tests/e2e/state.go index 5464b291ac..8cc343ef00 100644 --- a/tests/e2e/state.go +++ b/tests/e2e/state.go @@ -9,6 +9,7 @@ import ( "time" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + "github.com/kylelemons/godebug/pretty" "github.com/tidwall/gjson" "gopkg.in/yaml.v2" ) @@ -111,6 +112,7 @@ type Param struct { func (tr TestRun) getState(modelState State) State { systemState := State{} for k, modelState := range modelState { + log.Println("Getting model state for chain: ", k) systemState[k] = tr.getChainState(k, modelState) } @@ -184,6 +186,10 @@ func (tr TestRun) getChainState(chain chainID, modelState ChainState) ChainState chainState.RegisteredConsumerRewardDenoms = ®isteredConsumerRewardDenoms } + if *verbose { + log.Println("Done getting chain state:\n" + pretty.Sprint(chainState)) + } + return chainState } @@ -492,32 +498,36 @@ type ValPubKey struct { } func (tr TestRun) getValPower(chain chainID, validator validatorID) uint { + if *verbose { + log.Println("getting validator power for chain: ", chain, " validator: ", validator) + } //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - bz, err := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[chain].binaryName, + command := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[chain].binaryName, "query", "tendermint-validator-set", `--node`, tr.getQueryNode(chain), - ).CombinedOutput() + ) + bz, err := command.CombinedOutput() if err != nil { - log.Fatalf("error: %v", err) + log.Fatalf("encountered an error when executing command '%s': %v, output: %s", command.String(), err, string(bz)) } valset := TmValidatorSetYaml{} err = yaml.Unmarshal(bz, &valset) if err != nil { - log.Fatalf("error: %v", err) + log.Fatalf("yaml.Unmarshal returned an error while unmarshalling validator set: %v, input: %s", err, string(bz)) } total, err := strconv.Atoi(valset.Total) if err != nil { - log.Fatalf("error: %v", err) + log.Fatalf("strconv.Atoi returned an error while coonverting total for validator set: %v, input: %s, validator set: %s", err, valset.Total, pretty.Sprint(valset)) } if total != len(valset.Validators) { - log.Fatalf("Total number of validators %v does not match number of validators in list %v. Probably a query pagination issue.", - valset.Total, uint(len(valset.Validators))) + log.Fatalf("Total number of validators %v does not match number of validators in list %v. Probably a query pagination issue. Validator set: %v", + valset.Total, uint(len(valset.Validators)), pretty.Sprint(valset)) } for _, val := range valset.Validators { @@ -526,7 +536,7 @@ func (tr TestRun) getValPower(chain chainID, validator validatorID) uint { votingPower, err := strconv.Atoi(val.VotingPower) if err != nil { - log.Fatalf("error: %v", err) + log.Fatalf("strconv.Atoi returned an error while convering validator voting power: %v, voting power string: %s, validator set: %s", err, val.VotingPower, pretty.Sprint(valset)) } return uint(votingPower) From f91cb70e8f21312115bb9cb09a00b1bf323c3b89 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Sep 2023 10:15:48 +0200 Subject: [PATCH 098/134] build(deps): bump actions/checkout from 3 to 4 (#1257) Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/automated-tests.yml | 6 +++--- .github/workflows/build.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/deploy-docs.yml | 2 +- .github/workflows/golangci-lint.yml | 2 +- .github/workflows/gosec.yml | 2 +- .github/workflows/linkchecker.yml | 2 +- .github/workflows/manual-e2e.yml | 12 ++++++------ .github/workflows/nightly-e2e.yml | 12 ++++++------ .github/workflows/proto-registry.yml | 2 +- .github/workflows/proto.yml | 2 +- 11 files changed, 23 insertions(+), 23 deletions(-) diff --git a/.github/workflows/automated-tests.yml b/.github/workflows/automated-tests.yml index a9b594f53d..ad53314e76 100644 --- a/.github/workflows/automated-tests.yml +++ b/.github/workflows/automated-tests.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: lfs: true - name: Checkout LFS objects @@ -31,7 +31,7 @@ jobs: E2E_Tests: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: lfs: true - name: Checkout LFS objects @@ -45,7 +45,7 @@ jobs: Cometmock_Tests: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: lfs: true - name: Checkout LFS objects diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ec188dd429..a812b9fcf2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,7 +12,7 @@ jobs: name: SonarCloud runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis lfs: true diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 09a848478a..c6fb56c2a6 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -41,7 +41,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index 0c7dff60c5..7fbd30cad7 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout 🛎️ - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false fetch-depth: 0 diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 56166af86a..33a2f62c07 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -20,7 +20,7 @@ jobs: - uses: actions/setup-go@v4 with: go-version: '1.20' - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: golangci-lint uses: golangci/golangci-lint-action@v3 with: diff --git a/.github/workflows/gosec.yml b/.github/workflows/gosec.yml index ddcf2d3594..80dc4a3689 100644 --- a/.github/workflows/gosec.yml +++ b/.github/workflows/gosec.yml @@ -15,7 +15,7 @@ jobs: GO111MODULE: on steps: - name: Checkout Source - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Run Gosec Security Scanner uses: securego/gosec@master with: diff --git a/.github/workflows/linkchecker.yml b/.github/workflows/linkchecker.yml index 91242e5992..a1afa643cf 100644 --- a/.github/workflows/linkchecker.yml +++ b/.github/workflows/linkchecker.yml @@ -5,7 +5,7 @@ jobs: runs-on: ubuntu-latest steps: # Check out the latest version of the code - - uses: actions/checkout@v3.5.2 + - uses: actions/checkout@v4 # Checks the status of hyperlinks in *.md files in docs/ - uses: gaurav-nelson/github-action-markdown-link-check@1.0.15 diff --git a/.github/workflows/manual-e2e.yml b/.github/workflows/manual-e2e.yml index 388a19f0f5..2bb74bb52d 100644 --- a/.github/workflows/manual-e2e.yml +++ b/.github/workflows/manual-e2e.yml @@ -12,7 +12,7 @@ jobs: - uses: actions/setup-go@v4 with: go-version: "1.20" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Checkout LFS objects run: git lfs checkout - name: Setup Go @@ -28,7 +28,7 @@ jobs: - uses: actions/setup-go@v4 with: go-version: "1.20" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Checkout LFS objects run: git lfs checkout - name: Setup Go @@ -44,7 +44,7 @@ jobs: - uses: actions/setup-go@v4 with: go-version: "1.20" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Checkout LFS objects run: git lfs checkout - name: Setup Go @@ -60,7 +60,7 @@ jobs: - uses: actions/setup-go@v4 with: go-version: "1.20" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Checkout LFS objects run: git lfs checkout - name: Setup Go @@ -76,7 +76,7 @@ jobs: - uses: actions/setup-go@v4 with: go-version: "1.20" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Checkout LFS objects run: git lfs checkout - name: Setup Go @@ -92,7 +92,7 @@ jobs: - uses: actions/setup-go@v4 with: go-version: "1.20" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Checkout LFS objects run: git lfs checkout - name: Setup Go diff --git a/.github/workflows/nightly-e2e.yml b/.github/workflows/nightly-e2e.yml index cd7f155e12..4ab03527fd 100644 --- a/.github/workflows/nightly-e2e.yml +++ b/.github/workflows/nightly-e2e.yml @@ -25,7 +25,7 @@ jobs: - uses: actions/setup-go@v4 with: go-version: "1.20" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Checkout LFS objects run: git lfs checkout - name: Setup Go @@ -41,7 +41,7 @@ jobs: - uses: actions/setup-go@v4 with: go-version: "1.20" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Checkout LFS objects run: git lfs checkout - name: Setup Go @@ -57,7 +57,7 @@ jobs: - uses: actions/setup-go@v4 with: go-version: "1.20" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Checkout LFS objects run: git lfs checkout - name: Setup Go @@ -73,7 +73,7 @@ jobs: - uses: actions/setup-go@v4 with: go-version: "1.20" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Checkout LFS objects run: git lfs checkout - name: Setup Go @@ -89,7 +89,7 @@ jobs: - uses: actions/setup-go@v4 with: go-version: "1.20" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Checkout LFS objects run: git lfs checkout - name: Setup Go @@ -105,7 +105,7 @@ jobs: - uses: actions/setup-go@v4 with: go-version: "1.20" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Checkout LFS objects run: git lfs checkout - name: Setup Go diff --git a/.github/workflows/proto-registry.yml b/.github/workflows/proto-registry.yml index 5e4c7cb9ad..025c45b618 100644 --- a/.github/workflows/proto-registry.yml +++ b/.github/workflows/proto-registry.yml @@ -12,7 +12,7 @@ jobs: push: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: bufbuild/buf-setup-action@v1.26.1 - uses: bufbuild/buf-push-action@v1 with: diff --git a/.github/workflows/proto.yml b/.github/workflows/proto.yml index 1b0846a842..ce525c5a8a 100644 --- a/.github/workflows/proto.yml +++ b/.github/workflows/proto.yml @@ -13,7 +13,7 @@ jobs: break-check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: bufbuild/buf-setup-action@v1.26.1 - uses: bufbuild/buf-breaking-action@v1 with: From aca836260ebbfb6854b6de39fe06aa5a8b9efde9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Sep 2023 10:17:45 +0200 Subject: [PATCH 099/134] build(deps)!: bump github.com/cosmos/ibc-go/v7 from 7.2.0 to 7.3.0 (#1258) * build(deps): bump github.com/cosmos/ibc-go/v7 from 7.2.0 to 7.3.0 Bumps [github.com/cosmos/ibc-go/v7](https://github.com/cosmos/ibc-go) from 7.2.0 to 7.3.0. - [Release notes](https://github.com/cosmos/ibc-go/releases) - [Changelog](https://github.com/cosmos/ibc-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/cosmos/ibc-go/compare/v7.2.0...v7.3.0) --- updated-dependencies: - dependency-name: github.com/cosmos/ibc-go/v7 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * add changelog entries --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: mpoke --- CHANGELOG.md | 2 ++ go.mod | 32 ++++++++++++------------- go.sum | 67 ++++++++++++++++++++++++++-------------------------- 3 files changed, 51 insertions(+), 50 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c019b885c..3d94fa9887 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ Add an entry to the unreleased section whenever merging a PR to main that is not targeted at a specific release. These entries will eventually be included in a release. +* (deps!) [#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). +* (deps) [#1258](https://github.com/cosmos/interchain-security/pull/1258) Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to [v0.47.4](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.4). * (deps!) [#1196](https://github.com/cosmos/interchain-security/pull/1196) Bump [ibc-go](https://github.com/cosmos/ibc-go) to [v7.2.0](https://github.com/cosmos/ibc-go/releases/tag/v7.2.0). * `[x/ccv/provider]` (fix) [#1076](https://github.com/cosmos/interchain-security/pull/1076) Add `InitTimeoutTimestamps` and `ExportedVscSendTimestamps` to exported genesis. * (feat!) [#1024](https://github.com/cosmos/interchain-security/pull/1024) throttle with retries, consumer changes diff --git a/go.mod b/go.mod index b7d1eb9afe..28e8b8dbe2 100644 --- a/go.mod +++ b/go.mod @@ -7,9 +7,9 @@ require ( cosmossdk.io/math v1.1.2 github.com/cometbft/cometbft v0.37.2 github.com/cometbft/cometbft-db v0.8.0 - github.com/cosmos/cosmos-sdk v0.47.3 + github.com/cosmos/cosmos-sdk v0.47.4 github.com/cosmos/gogoproto v1.4.10 - github.com/cosmos/ibc-go/v7 v7.2.0 + github.com/cosmos/ibc-go/v7 v7.3.0 github.com/cosmos/ics23/go v0.10.0 github.com/golang/mock v1.6.0 github.com/golang/protobuf v1.5.3 @@ -26,18 +26,18 @@ require ( golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc golang.org/x/net v0.12.0 // indirect golang.org/x/sys v0.10.0 // indirect - google.golang.org/genproto v0.0.0-20230629202037-9506855d4529 // indirect + google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 // indirect google.golang.org/grpc v1.57.0 google.golang.org/protobuf v1.31.0 gopkg.in/yaml.v2 v2.4.0 ) require ( - cloud.google.com/go v0.110.0 // indirect - cloud.google.com/go/compute v1.19.1 // indirect + cloud.google.com/go v0.110.4 // indirect + cloud.google.com/go/compute v1.20.1 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/iam v0.13.0 // indirect - cloud.google.com/go/storage v1.29.0 // indirect + cloud.google.com/go/iam v1.1.0 // indirect + cloud.google.com/go/storage v1.30.1 // indirect cosmossdk.io/api v0.3.1 cosmossdk.io/core v0.5.1 // indirect cosmossdk.io/depinject v1.0.0-alpha.3 // indirect @@ -92,7 +92,7 @@ require ( github.com/google/orderedcode v0.0.1 // indirect github.com/google/uuid v1.3.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect - github.com/googleapis/gax-go/v2 v2.8.0 // indirect + github.com/googleapis/gax-go/v2 v2.11.0 // indirect github.com/gorilla/handlers v1.5.1 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect @@ -119,7 +119,7 @@ require ( github.com/linxGnu/grocksdb v1.7.16 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/manifoldco/promptui v0.9.0 // indirect - github.com/mattn/go-isatty v0.0.18 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect github.com/minio/highwayhash v1.0.2 // indirect @@ -152,11 +152,11 @@ require ( github.com/zondax/ledger-go v0.14.1 // indirect go.etcd.io/bbolt v1.3.7 // indirect go.opencensus.io v0.24.0 // indirect - golang.org/x/oauth2 v0.7.0 // indirect + golang.org/x/oauth2 v0.8.0 // indirect golang.org/x/term v0.10.0 // indirect golang.org/x/text v0.11.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect - google.golang.org/api v0.122.0 // indirect + google.golang.org/api v0.126.0 // indirect google.golang.org/appengine v1.6.7 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect @@ -167,17 +167,17 @@ require ( require ( github.com/spf13/viper v1.16.0 - google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e + google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529 ) require ( - cosmossdk.io/log v1.1.0 // indirect + cosmossdk.io/log v1.1.1-0.20230704160919-88f2c830b0ca // indirect github.com/go-playground/locales v0.14.0 // indirect - github.com/google/s2a-go v0.1.3 // indirect + github.com/google/s2a-go v0.1.4 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/rs/zerolog v1.29.1 // indirect - golang.org/x/sync v0.1.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130 // indirect + golang.org/x/sync v0.2.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect ) // following versions might cause unexpected behavior diff --git a/go.sum b/go.sum index a008e343c5..5592fb5810 100644 --- a/go.sum +++ b/go.sum @@ -34,8 +34,8 @@ cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w9 cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= -cloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys= -cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go v0.110.4 h1:1JYyxKMN9hd5dR2MYTPWkGUgcoxVVhg0LKNKEo0qvmk= +cloud.google.com/go v0.110.4/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= @@ -73,8 +73,8 @@ cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= -cloud.google.com/go/compute v1.19.1 h1:am86mquDUgjGNWxiGn+5PGLbmgiWXlE/yNWpIpNvuXY= -cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE= +cloud.google.com/go/compute v1.20.1 h1:6aKEtlUiwEpJzM001l0yFkpXmUVXaN8W+fbkb2AZNbg= +cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= @@ -114,13 +114,12 @@ cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y97 cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= -cloud.google.com/go/iam v0.13.0 h1:+CmB+K0J/33d0zSQ9SlFWUeCCEn5XJA0ZMZ3pHE9u8k= -cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= +cloud.google.com/go/iam v1.1.0 h1:67gSqaPukx7O8WLLHMa0PNs3EBGd2eE4d+psbO/CO94= +cloud.google.com/go/iam v1.1.0/go.mod h1:nxdHjaKfCr7fNYx/HJMM8LgiMugmveWlkatear5gVyk= cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= -cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM= cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= @@ -178,8 +177,8 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= -cloud.google.com/go/storage v1.29.0 h1:6weCgzRvMg7lzuUurI4697AqIRPU1SvzHhynwpW31jI= -cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= +cloud.google.com/go/storage v1.30.1 h1:uOdMxAs8HExqBlnLtnQyP0YkvbiDpdGShGKtx6U/oNM= +cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E= cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= @@ -200,8 +199,8 @@ cosmossdk.io/depinject v1.0.0-alpha.3 h1:6evFIgj//Y3w09bqOUOzEpFj5tsxBqdc5CfkO7z cosmossdk.io/depinject v1.0.0-alpha.3/go.mod h1:eRbcdQ7MRpIPEM5YUJh8k97nxHpYbc3sMUnEtt8HPWU= cosmossdk.io/errors v1.0.0 h1:nxF07lmlBbB8NKQhtJ+sJm6ef5uV1XkvPXG2bUntb04= cosmossdk.io/errors v1.0.0/go.mod h1:+hJZLuhdDE0pYN8HkOrVNwrIOYvUGnn6+4fjnJs/oV0= -cosmossdk.io/log v1.1.0 h1:v0ogPHYeTzPcBTcPR1A3j1hkei4pZama8kz8LKlCMv0= -cosmossdk.io/log v1.1.0/go.mod h1:6zjroETlcDs+mm62gd8Ig7mZ+N+fVOZS91V17H+M4N4= +cosmossdk.io/log v1.1.1-0.20230704160919-88f2c830b0ca h1:msenprh2BLLRwNT7zN56TbBHOGk/7ARQckXHxXyvjoQ= +cosmossdk.io/log v1.1.1-0.20230704160919-88f2c830b0ca/go.mod h1:PkIAKXZvaxrTRc++z53XMRvFk8AcGGWYHcMIPzVYX9c= cosmossdk.io/math v1.1.2 h1:ORZetZCTyWkI5GlZ6CZS28fMHi83ZYf+A2vVnHNzZBM= cosmossdk.io/math v1.1.2/go.mod h1:l2Gnda87F0su8a/7FEKJfFdJrM0JZRXQaohlgJeyQh0= cosmossdk.io/tools/rosetta v0.2.1 h1:ddOMatOH+pbxWbrGJKRAawdBkPYLfKXutK9IETnjYxw= @@ -381,8 +380,8 @@ github.com/cosmos/btcutil v1.0.5 h1:t+ZFcX77LpKtDBhjucvnOH8C2l2ioGsBNEQ3jef8xFk= github.com/cosmos/btcutil v1.0.5/go.mod h1:IyB7iuqZMJlthe2tkIFL33xPyzbFYP0XVdS8P5lUPis= github.com/cosmos/cosmos-proto v1.0.0-beta.2 h1:X3OKvWgK9Gsejo0F1qs5l8Qn6xJV/AzgIWR2wZ8Nua8= github.com/cosmos/cosmos-proto v1.0.0-beta.2/go.mod h1:+XRCLJ14pr5HFEHIUcn51IKXD1Fy3rkEQqt4WqmN4V0= -github.com/cosmos/cosmos-sdk v0.47.3 h1:r0hGmZoAzP2D+MaPaFGHwAaTdFQq3pNpHaUp1BsffbM= -github.com/cosmos/cosmos-sdk v0.47.3/go.mod h1:c4OfLdAykA9zsj1CqrxBRqXzVz48I++JSvIMPSPcEmk= +github.com/cosmos/cosmos-sdk v0.47.4 h1:FVUpEprm58nMmBX4xkRdMDaIG5Nr4yy92HZAfGAw9bg= +github.com/cosmos/cosmos-sdk v0.47.4/go.mod h1:R5n+uM7vguVPFap4pgkdvQCT1nVo/OtPwrlAU40rvok= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= @@ -393,8 +392,8 @@ github.com/cosmos/gogoproto v1.4.10 h1:QH/yT8X+c0F4ZDacDv3z+xE3WU1P1Z3wQoLMBRJoK github.com/cosmos/gogoproto v1.4.10/go.mod h1:3aAZzeRWpAwr+SS/LLkICX2/kDFyaYVzckBDzygIxek= github.com/cosmos/iavl v0.20.0 h1:fTVznVlepH0KK8NyKq8w+U7c2L6jofa27aFX6YGlm38= github.com/cosmos/iavl v0.20.0/go.mod h1:WO7FyvaZJoH65+HFOsDir7xU9FWk2w9cHXNW1XHcl7A= -github.com/cosmos/ibc-go/v7 v7.2.0 h1:dx0DLUl7rxdyZ8NiT6UsrbzKOJx/w7s+BOaewFRH6cg= -github.com/cosmos/ibc-go/v7 v7.2.0/go.mod h1:OOcjKIRku/j1Xs1RgKK0yvKRrJ5iFuZYMetR1n3yMlc= +github.com/cosmos/ibc-go/v7 v7.3.0 h1:QtGeVMi/3JeLWuvEuC60sBHpAF40Oenx/y+bP8+wRRw= +github.com/cosmos/ibc-go/v7 v7.3.0/go.mod h1:mUmaHFXpXrEdcxfdXyau+utZf14pGKVUiXwYftRZZfQ= github.com/cosmos/ics23/go v0.10.0 h1:iXqLLgp2Lp+EdpIuwXTYIQU+AiHj9mOC2X9ab++bZDM= github.com/cosmos/ics23/go v0.10.0/go.mod h1:ZfJSmng/TBNTBkFemHHHj5YY7VAU/MBU980F4VU1NG0= github.com/cosmos/ledger-cosmos-go v0.12.2 h1:/XYaBlE2BJxtvpkHiBm97gFGSGmYGKunKyF3nNqAXZA= @@ -645,8 +644,8 @@ github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/s2a-go v0.1.3 h1:FAgZmpLl/SXurPEZyCMPBIiiYeTbqfjlbdnCNTAkbGE= -github.com/google/s2a-go v0.1.3/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= +github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= +github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -667,8 +666,8 @@ github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99 github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= -github.com/googleapis/gax-go/v2 v2.8.0 h1:UBtEZqx1bjXtOQ5BVTkuYghXrr3N4V123VKJK67vJZc= -github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= +github.com/googleapis/gax-go/v2 v2.11.0 h1:9V9PWXEsWnPpQhu/PeQIkS4eGzMlTLGgt80cUUI8Ki4= +github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -867,8 +866,8 @@ github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2y github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= -github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= @@ -1350,8 +1349,8 @@ golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= -golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= -golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= +golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= +golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1366,8 +1365,8 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= +golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1633,8 +1632,8 @@ google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= -google.golang.org/api v0.122.0 h1:zDobeejm3E7pEG1mNHvdxvjs5XJoCMzyNH+CmwL94Es= -google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms= +google.golang.org/api v0.126.0 h1:q4GJq+cAdMAC7XP7njvQ4tvohGLiSlytuL4BQxbIZ+o= +google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1754,12 +1753,12 @@ google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqw google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20230629202037-9506855d4529 h1:9JucMWR7sPvCxUFd6UsOUNmA5kCcWOfORaT3tpAsKQs= -google.golang.org/genproto v0.0.0-20230629202037-9506855d4529/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= -google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e h1:AZX1ra8YbFMSb7+1pI8S9v4rrgRR7jU1FmuFSSjTVcQ= -google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130 h1:2FZP5XuJY9zQyGM5N0rtovnoXjiMUEIUMvw0m9wlpLc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:8mL13HKkDa+IuJ8yruA3ci0q+0vsUz4m//+ottjwS5o= +google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 h1:Au6te5hbKUV8pIYWHqOUZ1pva5qK/rwbIhoXEUB9Lu8= +google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:O9kGHb51iE/nOGvQaDUuadVYqovW56s5emA88lQnj6Y= +google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529 h1:s5YSX+ZH5b5vS9rnpGymvIyMpLRJizowqDlOuyjXnTk= +google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= @@ -1858,7 +1857,7 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= -gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= +gotest.tools/v3 v3.5.0 h1:Ljk6PdHdOhAb5aDMWXjDLMMhph+BpztA4v1QdqEW2eY= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From 66adc8a36b96f6f3f09150c09188b086395c87d6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Sep 2023 10:34:06 +0200 Subject: [PATCH 100/134] build(deps): bump github.com/cosmos/cosmos-sdk from 0.47.4 to 0.47.5 (#1259) * build(deps): bump github.com/cosmos/cosmos-sdk from 0.47.3 to 0.47.5 Bumps [github.com/cosmos/cosmos-sdk](https://github.com/cosmos/cosmos-sdk) from 0.47.3 to 0.47.5. - [Release notes](https://github.com/cosmos/cosmos-sdk/releases) - [Changelog](https://github.com/cosmos/cosmos-sdk/blob/main/CHANGELOG.md) - [Commits](https://github.com/cosmos/cosmos-sdk/compare/v0.47.3...v0.47.5) --- updated-dependencies: - dependency-name: github.com/cosmos/cosmos-sdk dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * add changelog entries --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: mpoke --- CHANGELOG.md | 1 + go.mod | 22 ++++++++++++------- go.sum | 60 +++++++++++++++++++++++++++++----------------------- 3 files changed, 49 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d94fa9887..0debde491e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Add an entry to the unreleased section whenever merging a PR to main that is not targeted at a specific release. These entries will eventually be included in a release. +* (deps) [#1259](https://github.com/cosmos/interchain-security/pull/1259) Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to [v0.47.5](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.5). * (deps!) [#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). * (deps) [#1258](https://github.com/cosmos/interchain-security/pull/1258) Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to [v0.47.4](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.4). * (deps!) [#1196](https://github.com/cosmos/interchain-security/pull/1196) Bump [ibc-go](https://github.com/cosmos/ibc-go) to [v7.2.0](https://github.com/cosmos/ibc-go/releases/tag/v7.2.0). diff --git a/go.mod b/go.mod index 28e8b8dbe2..6cc988a794 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( cosmossdk.io/math v1.1.2 github.com/cometbft/cometbft v0.37.2 github.com/cometbft/cometbft-db v0.8.0 - github.com/cosmos/cosmos-sdk v0.47.4 + github.com/cosmos/cosmos-sdk v0.47.5 github.com/cosmos/gogoproto v1.4.10 github.com/cosmos/ibc-go/v7 v7.3.0 github.com/cosmos/ics23/go v0.10.0 @@ -23,9 +23,9 @@ require ( github.com/stretchr/testify v1.8.4 github.com/tidwall/gjson v1.16.0 golang.org/x/crypto v0.11.0 // indirect - golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc + golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb golang.org/x/net v0.12.0 // indirect - golang.org/x/sys v0.10.0 // indirect + golang.org/x/sys v0.11.0 // indirect google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 // indirect google.golang.org/grpc v1.57.0 google.golang.org/protobuf v1.31.0 @@ -40,7 +40,7 @@ require ( cloud.google.com/go/storage v1.30.1 // indirect cosmossdk.io/api v0.3.1 cosmossdk.io/core v0.5.1 // indirect - cosmossdk.io/depinject v1.0.0-alpha.3 // indirect + cosmossdk.io/depinject v1.0.0-alpha.4 // indirect cosmossdk.io/tools/rosetta v0.2.1 filippo.io/edwards25519 v1.0.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect @@ -154,7 +154,7 @@ require ( go.opencensus.io v0.24.0 // indirect golang.org/x/oauth2 v0.8.0 // indirect golang.org/x/term v0.10.0 // indirect - golang.org/x/text v0.11.0 // indirect + golang.org/x/text v0.12.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/api v0.126.0 // indirect google.golang.org/appengine v1.6.7 // indirect @@ -171,11 +171,17 @@ require ( ) require ( - cosmossdk.io/log v1.1.1-0.20230704160919-88f2c830b0ca // indirect - github.com/go-playground/locales v0.14.0 // indirect + cosmossdk.io/log v1.2.1 // indirect + github.com/cockroachdb/errors v1.10.0 // indirect + github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect + github.com/cockroachdb/redact v1.1.5 // indirect + github.com/getsentry/sentry-go v0.23.0 // indirect github.com/google/s2a-go v0.1.4 // indirect + github.com/kr/pretty v0.3.1 // indirect + github.com/kr/text v0.2.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/rs/zerolog v1.29.1 // indirect + github.com/rogpeppe/go-internal v1.11.0 // indirect + github.com/rs/zerolog v1.30.0 // indirect golang.org/x/sync v0.2.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect ) diff --git a/go.sum b/go.sum index 5592fb5810..03e76f9812 100644 --- a/go.sum +++ b/go.sum @@ -195,12 +195,12 @@ cosmossdk.io/api v0.3.1 h1:NNiOclKRR0AOlO4KIqeaG6PS6kswOMhHD0ir0SscNXE= cosmossdk.io/api v0.3.1/go.mod h1:DfHfMkiNA2Uhy8fj0JJlOCYOBp4eWUUJ1te5zBGNyIw= cosmossdk.io/core v0.5.1 h1:vQVtFrIYOQJDV3f7rw4pjjVqc1id4+mE0L9hHP66pyI= cosmossdk.io/core v0.5.1/go.mod h1:KZtwHCLjcFuo0nmDc24Xy6CRNEL9Vl/MeimQ2aC7NLE= -cosmossdk.io/depinject v1.0.0-alpha.3 h1:6evFIgj//Y3w09bqOUOzEpFj5tsxBqdc5CfkO7z+zfw= -cosmossdk.io/depinject v1.0.0-alpha.3/go.mod h1:eRbcdQ7MRpIPEM5YUJh8k97nxHpYbc3sMUnEtt8HPWU= +cosmossdk.io/depinject v1.0.0-alpha.4 h1:PLNp8ZYAMPTUKyG9IK2hsbciDWqna2z1Wsl98okJopc= +cosmossdk.io/depinject v1.0.0-alpha.4/go.mod h1:HeDk7IkR5ckZ3lMGs/o91AVUc7E596vMaOmslGFM3yU= cosmossdk.io/errors v1.0.0 h1:nxF07lmlBbB8NKQhtJ+sJm6ef5uV1XkvPXG2bUntb04= cosmossdk.io/errors v1.0.0/go.mod h1:+hJZLuhdDE0pYN8HkOrVNwrIOYvUGnn6+4fjnJs/oV0= -cosmossdk.io/log v1.1.1-0.20230704160919-88f2c830b0ca h1:msenprh2BLLRwNT7zN56TbBHOGk/7ARQckXHxXyvjoQ= -cosmossdk.io/log v1.1.1-0.20230704160919-88f2c830b0ca/go.mod h1:PkIAKXZvaxrTRc++z53XMRvFk8AcGGWYHcMIPzVYX9c= +cosmossdk.io/log v1.2.1 h1:Xc1GgTCicniwmMiKwDxUjO4eLhPxoVdI9vtMW8Ti/uk= +cosmossdk.io/log v1.2.1/go.mod h1:GNSCc/6+DhFIj1aLn/j7Id7PaO8DzNylUZoOYBL9+I4= cosmossdk.io/math v1.1.2 h1:ORZetZCTyWkI5GlZ6CZS28fMHi83ZYf+A2vVnHNzZBM= cosmossdk.io/math v1.1.2/go.mod h1:l2Gnda87F0su8a/7FEKJfFdJrM0JZRXQaohlgJeyQh0= cosmossdk.io/tools/rosetta v0.2.1 h1:ddOMatOH+pbxWbrGJKRAawdBkPYLfKXutK9IETnjYxw= @@ -242,7 +242,6 @@ github.com/adlio/schema v1.3.3 h1:oBJn8I02PyTB466pZO1UZEn1TV5XLlifBSyMrmHl/1I= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= -github.com/alecthomas/participle/v2 v2.0.0-alpha7 h1:cK4vjj0VSgb3lN1nuKA5F7dw+1s1pWBe5bx7nNCnN+c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -353,8 +352,13 @@ github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b8034E= github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw= -github.com/cockroachdb/apd/v3 v3.1.0 h1:MK3Ow7LH0W8zkd5GMKA1PvS9qG3bWFI95WaVNfyZJ/w= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/cockroachdb/errors v1.10.0 h1:lfxS8zZz1+OjtV4MtNWgboi/W5tyLEB6VQZBXN+0VUU= +github.com/cockroachdb/errors v1.10.0/go.mod h1:lknhIsEVQ9Ss/qKDBQS/UqFSvPQjOwNq2qyKAxtHRqE= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= +github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= +github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/coinbase/kryptology v1.8.0/go.mod h1:RYXOAPdzOGUe3qlSFkMGn58i3xUA8hmxYHksuq+8ciI= github.com/coinbase/rosetta-sdk-go v0.7.9 h1:lqllBjMnazTjIqYrOGv8h8jxjg9+hJazIGZr9ZvoCcA= @@ -380,8 +384,8 @@ github.com/cosmos/btcutil v1.0.5 h1:t+ZFcX77LpKtDBhjucvnOH8C2l2ioGsBNEQ3jef8xFk= github.com/cosmos/btcutil v1.0.5/go.mod h1:IyB7iuqZMJlthe2tkIFL33xPyzbFYP0XVdS8P5lUPis= github.com/cosmos/cosmos-proto v1.0.0-beta.2 h1:X3OKvWgK9Gsejo0F1qs5l8Qn6xJV/AzgIWR2wZ8Nua8= github.com/cosmos/cosmos-proto v1.0.0-beta.2/go.mod h1:+XRCLJ14pr5HFEHIUcn51IKXD1Fy3rkEQqt4WqmN4V0= -github.com/cosmos/cosmos-sdk v0.47.4 h1:FVUpEprm58nMmBX4xkRdMDaIG5Nr4yy92HZAfGAw9bg= -github.com/cosmos/cosmos-sdk v0.47.4/go.mod h1:R5n+uM7vguVPFap4pgkdvQCT1nVo/OtPwrlAU40rvok= +github.com/cosmos/cosmos-sdk v0.47.5 h1:n1+WjP/VM/gAEOx3TqU2/Ny734rj/MX1kpUnn7zVJP8= +github.com/cosmos/cosmos-sdk v0.47.5/go.mod h1:EHwCeN9IXonsjKcjpS12MqeStdZvIdxt3VYXhus3G3c= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= @@ -407,8 +411,6 @@ github.com/creachadair/taskgroup v0.4.2 h1:jsBLdAJE42asreGss2xZGZ8fJra7WtwnHWeJF github.com/creachadair/taskgroup v0.4.2/go.mod h1:qiXUOSrbwAY3u0JPGTzObbE3yf9hcXHDKBZ2ZjpCbgM= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cucumber/common/gherkin/go/v22 v22.0.0 h1:4K8NqptbvdOrjL9DEea6HFjSpbdT9+Q5kgLpmmsHYl0= -github.com/cucumber/common/messages/go/v17 v17.1.1 h1:RNqopvIFyLWnKv0LfATh34SWBhXeoFTJnSrgm9cT/Ts= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= @@ -489,14 +491,17 @@ github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbS github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= +github.com/getsentry/sentry-go v0.23.0 h1:dn+QRCeJv4pPt9OjVXiMcGIBIefaTJPw/h0bZWO05nE= +github.com/getsentry/sentry-go v0.23.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= +github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8= github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -518,11 +523,10 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= -github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= -github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= @@ -533,11 +537,11 @@ github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gofrs/uuid v4.3.0+incompatible h1:CaSVZxm5B+7o45rtab4jC2G37WGYX1zQfuU2i6DSvnc= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/googleapis v1.4.1-0.20201022092350-68b0159b7869/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0= @@ -821,6 +825,7 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -975,6 +980,8 @@ github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08/go.mod h1:pxMtw7c github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -1025,19 +1032,20 @@ github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Ung github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/regen-network/gocuke v0.6.2 h1:pHviZ0kKAq2U2hN2q3smKNxct6hS0mGByFMHGnWA97M= github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.8.3 h1:O+qNyWn7Z+F9M0ILBHgMVPuB1xTOucVd5gtaYyXBpRo= github.com/rs/cors v1.8.3/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= -github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc= -github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.30.0 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c= +github.com/rs/zerolog v1.30.0/go.mod h1:/tk+P47gFdPXq4QYjvCmT5/Gsug2nagsFWBWhAiSi1w= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -1226,8 +1234,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= -golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc h1:mCRnTeVUjcrhlRmO0VK8a6k6Rrf6TF9htwo2pJVSjIU= -golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= +golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb h1:xIApU0ow1zwMa2uL1VDNeQlNVFTWMQxZUZCMDy0Q4Us= +golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -1255,7 +1263,7 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= +golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1475,8 +1483,8 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1494,8 +1502,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= From cc9064d014cccaef6c88e2832e3aa9bb95dbc141 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Tue, 5 Sep 2023 01:37:46 -0700 Subject: [PATCH 101/134] chore: Separate semver (#1217) separate semver --- .github/PULL_REQUEST_TEMPLATE/production.md | 1 + CHANGELOG.md | 12 +++++++++--- CONTRIBUTING.md | 6 +++--- RELEASE_NOTES.md | 13 ++++++++----- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE/production.md b/.github/PULL_REQUEST_TEMPLATE/production.md index 885d852cf0..7fe79eceb9 100644 --- a/.github/PULL_REQUEST_TEMPLATE/production.md +++ b/.github/PULL_REQUEST_TEMPLATE/production.md @@ -30,6 +30,7 @@ I have... * [ ] Updated the relevant documentation or specification * [ ] Reviewed "Files changed" and left comments if necessary * [ ] Confirmed all CI checks have passed +* [ ] If this PR is library API breaking, bump the go.mod version string of the repo, and follow through on a new major release for both the consumer and provider ### Reviewers Checklist diff --git a/CHANGELOG.md b/CHANGELOG.md index 0debde491e..b247082a1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,19 +1,25 @@ # CHANGELOG -## [Unreleased] +## [Unreleased for Provider] -Add an entry to the unreleased section whenever merging a PR to main that is not targeted at a specific release. These entries will eventually be included in a release. +Add an entry to the unreleased provider section whenever merging a PR to main that is not targeted at a specific release. These entries will eventually be included in a provider release. * (deps) [#1259](https://github.com/cosmos/interchain-security/pull/1259) Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to [v0.47.5](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.5). * (deps!) [#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). * (deps) [#1258](https://github.com/cosmos/interchain-security/pull/1258) Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to [v0.47.4](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.4). * (deps!) [#1196](https://github.com/cosmos/interchain-security/pull/1196) Bump [ibc-go](https://github.com/cosmos/ibc-go) to [v7.2.0](https://github.com/cosmos/ibc-go/releases/tag/v7.2.0). * `[x/ccv/provider]` (fix) [#1076](https://github.com/cosmos/interchain-security/pull/1076) Add `InitTimeoutTimestamps` and `ExportedVscSendTimestamps` to exported genesis. + +## [Unreleased for Consumer] + +Add an entry to the unreleased consumer section whenever merging a PR to main that is not targeted at a specific release. These entries will eventually be included in a consumer release. + +* (deps!) [#1196](https://github.com/cosmos/interchain-security/pull/1196) Bump [ibc-go](https://github.com/cosmos/ibc-go) to [v7.2.0](https://github.com/cosmos/ibc-go/releases/tag/v7.2.0). * (feat!) [#1024](https://github.com/cosmos/interchain-security/pull/1024) throttle with retries, consumer changes * (fix!) revert consumer packet data changes from #1037 [#1150](https://github.com/cosmos/interchain-security/pull/1150) * (fix!) proper deletion of pending packets [#1146](https://github.com/cosmos/interchain-security/pull/1146) * (feat!) optimize pending packets storage on consumer, with migration! [#1037](https://github.com/cosmos/interchain-security/pull/1037) -* (feat) 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. +* (feat) 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). ## v3.1.0 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8975d37269..c376c3b824 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -247,9 +247,9 @@ ICS adheres to the [trunk based development branching model](https://trunkbasedd ICS follows [semantic versioning](https://semver.org), but with the following deviations (similar to [IBC-Go](https://github.com/cosmos/ibc-go/blob/main/RELEASES.md)): -- A library API breaking change will result in an increase of the MAJOR version number (X.y.z | x > 0). -- A state breaking change (change requiring coordinated upgrade and/or state migration for the consumer, the provider, or both) will result in an increase of the MINOR version number (x.Y.z | x > 0). -- Any other changes (including node API breaking changes) will result in an increase of the PATCH version number (x.y.Z | x > 0). +- A library API breaking change to EITHER the provider or consumer module will result in an increase of the MAJOR version number for BOTH modules (X.y.z-provider AND X.y.z-consumer). +- A state breaking change (change requiring coordinated upgrade and/or state migration) will result in an increase of the MINOR version number for the AFFECTED module(s) (x.Y.z-provider AND/OR x.Y.z-consumer). +- Any other changes (including node API breaking changes) will result in an increase of the PATCH version number for the AFFECTED module(s) (x.y.Z-provider AND/OR x.y.Z-consumer). ### Backwards Compatibility diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 62704ea9c6..f1a6edb066 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,12 +1,15 @@ -# Replicated Security Release Notes +# Replicated Security - Release Notes + + +## Note this release is ONLY relevant to ## 📝 Changelog From 6da7fef077dd4a591d803780e8dbe7796887d5a7 Mon Sep 17 00:00:00 2001 From: Marius Poke Date: Tue, 5 Sep 2023 11:58:45 +0200 Subject: [PATCH 102/134] docs: cleanup changelog (#1260) fix changelog --- CHANGELOG.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b247082a1b..b145ff740e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,12 +14,15 @@ Add an entry to the unreleased provider section whenever merging a PR to main th Add an entry to the unreleased consumer section whenever merging a PR to main that is not targeted at a specific release. These entries will eventually be included in a consumer release. +* (deps) [#1259](https://github.com/cosmos/interchain-security/pull/1259) Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to [v0.47.5](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.5). +* (deps!) [#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). +* (deps) [#1258](https://github.com/cosmos/interchain-security/pull/1258) Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to [v0.47.4](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.4). * (deps!) [#1196](https://github.com/cosmos/interchain-security/pull/1196) Bump [ibc-go](https://github.com/cosmos/ibc-go) to [v7.2.0](https://github.com/cosmos/ibc-go/releases/tag/v7.2.0). -* (feat!) [#1024](https://github.com/cosmos/interchain-security/pull/1024) throttle with retries, consumer changes -* (fix!) revert consumer packet data changes from #1037 [#1150](https://github.com/cosmos/interchain-security/pull/1150) -* (fix!) proper deletion of pending packets [#1146](https://github.com/cosmos/interchain-security/pull/1146) -* (feat!) optimize pending packets storage on consumer, with migration! [#1037](https://github.com/cosmos/interchain-security/pull/1037) -* (feat) 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). +* (feat!) [#1024](https://github.com/cosmos/interchain-security/pull/1024) Throttle with retries, consumer changes. +* (fix!) [#1150](https://github.com/cosmos/interchain-security/pull/1150) Revert consumer packet data changes from #1037. +* (fix!) [#1146](https://github.com/cosmos/interchain-security/pull/1146) Proper deletion of pending packets. +* (feat!) [#1037](https://github.com/cosmos/interchain-security/pull/1037) Optimize pending packets storage on consumer, with migration. +* (feat) [#1164](https://github.com/cosmos/interchain-security/pull/1164) 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. ## v3.1.0 From 840d290d2b9b30169a59153a120a8ea74dd1accd Mon Sep 17 00:00:00 2001 From: Marius Poke Date: Tue, 5 Sep 2023 15:05:56 +0200 Subject: [PATCH 103/134] fix!: validate MsgTransfer before calling Transfer() (#1244) * validate MsgTransfer * add TestSendRewardsToProvider * update DefaultConsumerUnbondingPeriod to 14 days * update changelog * fix linter * fix test * apply review suggestions * update changelog --- CHANGELOG.md | 3 + tests/integration/distribution.go | 147 +++++++++++++++++++++++++- testutil/integration/debug_test.go | 4 + x/ccv/consumer/keeper/distribution.go | 116 +++++++++++--------- x/ccv/types/params.go | 4 +- 5 files changed, 219 insertions(+), 55 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b145ff740e..353d7226f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Add an entry to the unreleased provider section whenever merging a PR to main that is not targeted at a specific release. These entries will eventually be included in a provider release. +* (feature!) [#1244](https://github.com/cosmos/interchain-security/pull/1244) Update the default consumer unbonding period to 2 weeks. * (deps) [#1259](https://github.com/cosmos/interchain-security/pull/1259) Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to [v0.47.5](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.5). * (deps!) [#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). * (deps) [#1258](https://github.com/cosmos/interchain-security/pull/1258) Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to [v0.47.4](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.4). @@ -14,6 +15,8 @@ Add an entry to the unreleased provider section whenever merging a PR to main th Add an entry to the unreleased consumer section whenever merging a PR to main that is not targeted at a specific release. These entries will eventually be included in a consumer release. +* (feature!) [#1244](https://github.com/cosmos/interchain-security/pull/1244) Update the default consumer unbonding period to 2 weeks. +* (fix!) [#1244](https://github.com/cosmos/interchain-security/pull/1244) Validate token transfer messages before calling `Transfer()`. * (deps) [#1259](https://github.com/cosmos/interchain-security/pull/1259) Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to [v0.47.5](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.5). * (deps!) [#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). * (deps) [#1258](https://github.com/cosmos/interchain-security/pull/1258) Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to [v0.47.4](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.4). diff --git a/tests/integration/distribution.go b/tests/integration/distribution.go index 5d5c50220a..65b82eecd6 100644 --- a/tests/integration/distribution.go +++ b/tests/integration/distribution.go @@ -9,6 +9,8 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + icstestingutils "github.com/cosmos/interchain-security/v3/testutil/integration" + consumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" @@ -338,8 +340,151 @@ func (s *CCVTestSuite) TestEndBlockRD() { } } +// TestSendRewardsToProvider is effectively a unit test for SendRewardsToProvider(), +// but is written as an integration test to avoid excessive mocking. +func (s *CCVTestSuite) TestSendRewardsToProvider() { + testCases := []struct { + name string + setup func(sdk.Context, *consumerkeeper.Keeper, icstestingutils.TestBankKeeper) + expError bool + tokenTransfers int + }{ + { + name: "successful token transfer", + setup: func(ctx sdk.Context, keeper *consumerkeeper.Keeper, bankKeeper icstestingutils.TestBankKeeper) { + s.SetupTransferChannel() + + // register a consumer reward denom + params := keeper.GetConsumerParams(ctx) + params.RewardDenoms = []string{sdk.DefaultBondDenom} + keeper.SetParams(ctx, params) + + // send coins to the pool which is used for collect reward distributions to be sent to the provider + err := bankKeeper.SendCoinsFromAccountToModule( + ctx, + s.consumerChain.SenderAccount.GetAddress(), + consumertypes.ConsumerToSendToProviderName, + sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))), + ) + s.Require().NoError(err) + }, + expError: false, + tokenTransfers: 1, + }, + { + name: "no transfer channel", + setup: func(ctx sdk.Context, keeper *consumerkeeper.Keeper, bankKeeper icstestingutils.TestBankKeeper) { + }, + expError: false, + tokenTransfers: 0, + }, + { + name: "no reward denom", + setup: func(ctx sdk.Context, keeper *consumerkeeper.Keeper, bankKeeper icstestingutils.TestBankKeeper) { + s.SetupTransferChannel() + }, + expError: false, + tokenTransfers: 0, + }, + { + name: "reward balance is zero", + setup: func(ctx sdk.Context, keeper *consumerkeeper.Keeper, bankKeeper icstestingutils.TestBankKeeper) { + s.SetupTransferChannel() + + // register a consumer reward denom + params := keeper.GetConsumerParams(ctx) + params.RewardDenoms = []string{"uatom"} + keeper.SetParams(ctx, params) + + denoms := keeper.AllowedRewardDenoms(ctx) + s.Require().Len(denoms, 1) + }, + expError: false, + tokenTransfers: 0, + }, + { + name: "no distribution transmission channel", + setup: func(ctx sdk.Context, keeper *consumerkeeper.Keeper, bankKeeper icstestingutils.TestBankKeeper) { + s.SetupTransferChannel() + + // register a consumer reward denom + params := keeper.GetConsumerParams(ctx) + params.RewardDenoms = []string{sdk.DefaultBondDenom} + params.DistributionTransmissionChannel = "" + keeper.SetParams(ctx, params) + + // send coins to the pool which is used for collect reward distributions to be sent to the provider + err := bankKeeper.SendCoinsFromAccountToModule( + ctx, + s.consumerChain.SenderAccount.GetAddress(), + consumertypes.ConsumerToSendToProviderName, + sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))), + ) + s.Require().NoError(err) + }, + expError: false, + tokenTransfers: 0, + }, + { + name: "no recipient address", + setup: func(ctx sdk.Context, keeper *consumerkeeper.Keeper, bankKeeper icstestingutils.TestBankKeeper) { + s.SetupTransferChannel() + + // register a consumer reward denom + params := keeper.GetConsumerParams(ctx) + params.RewardDenoms = []string{sdk.DefaultBondDenom} + params.ProviderFeePoolAddrStr = "" + keeper.SetParams(ctx, params) + + // send coins to the pool which is used for collect reward distributions to be sent to the provider + err := bankKeeper.SendCoinsFromAccountToModule( + ctx, + s.consumerChain.SenderAccount.GetAddress(), + consumertypes.ConsumerToSendToProviderName, + sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))), + ) + s.Require().NoError(err) + }, + expError: true, + tokenTransfers: 0, + }, + } + + for _, tc := range testCases { + s.SetupTest() + + // ccv channels setup + s.SetupCCVChannel(s.path) + bondAmt := sdk.NewInt(10000000) + delAddr := s.providerChain.SenderAccount.GetAddress() + delegate(s, delAddr, bondAmt) + s.providerChain.NextBlock() + + // customized setup + consumerCtx := s.consumerCtx() + consumerKeeper := s.consumerApp.GetConsumerKeeper() + tc.setup(consumerCtx, &consumerKeeper, s.consumerApp.GetTestBankKeeper()) + + // call SendRewardsToProvider + err := s.consumerApp.GetConsumerKeeper().SendRewardsToProvider(consumerCtx) + if tc.expError { + s.Require().Error(err) + } else { + s.Require().NoError(err) + } + + // check whether the amount of token transfers is as expected + commitments := s.consumerApp.GetIBCKeeper().ChannelKeeper.GetAllPacketCommitmentsAtChannel( + consumerCtx, + transfertypes.PortID, + s.consumerApp.GetConsumerKeeper().GetDistributionTransmissionChannel(consumerCtx), + ) + s.Require().Len(commitments, tc.tokenTransfers, "unexpected amount of token transfers; test: %s", tc.name) + } +} + // getEscrowBalance gets the current balances in the escrow account holding the transferred tokens to the provider -func (s CCVTestSuite) getEscrowBalance() sdk.Coins { //nolint:govet // we copy locks for this test +func (s *CCVTestSuite) getEscrowBalance() sdk.Coins { consumerBankKeeper := s.consumerApp.GetTestBankKeeper() transChanID := s.consumerApp.GetConsumerKeeper().GetDistributionTransmissionChannel(s.consumerCtx()) escAddr := transfertypes.GetEscrowAddress(transfertypes.PortID, transChanID) diff --git a/testutil/integration/debug_test.go b/testutil/integration/debug_test.go index 828c9b6810..6b9415440e 100644 --- a/testutil/integration/debug_test.go +++ b/testutil/integration/debug_test.go @@ -85,6 +85,10 @@ func TestEndBlockRD(t *testing.T) { runCCVTestByName(t, "TestEndBlockRD") } +func TestSendRewardsToProvider(t *testing.T) { + runCCVTestByName(t, "TestSendRewardsToProvider") +} + // // Expired client tests // diff --git a/x/ccv/consumer/keeper/distribution.go b/x/ccv/consumer/keeper/distribution.go index 5fe416ea2b..a2c19b495d 100644 --- a/x/ccv/consumer/keeper/distribution.go +++ b/x/ccv/consumer/keeper/distribution.go @@ -103,62 +103,74 @@ func (k Keeper) shouldSendRewardsToProvider(ctx sdk.Context) bool { // all the block rewards allocated for the provider func (k Keeper) SendRewardsToProvider(ctx sdk.Context) error { // empty out the toSendToProviderTokens address - ch := k.GetDistributionTransmissionChannel(ctx) - transferChannel, found := k.channelKeeper.GetChannel(ctx, transfertypes.PortID, ch) - if found && transferChannel.State == channeltypes.OPEN { - tstProviderAddr := k.authKeeper.GetModuleAccount(ctx, - types.ConsumerToSendToProviderName).GetAddress() - providerAddr := k.GetProviderFeePoolAddrStr(ctx) - timeoutHeight := clienttypes.ZeroHeight() - transferTimeoutPeriod := k.GetTransferTimeoutPeriod(ctx) - timeoutTimestamp := uint64(ctx.BlockTime().Add(transferTimeoutPeriod).UnixNano()) - - sentCoins := sdk.NewCoins() - var allBalances sdk.Coins - // iterate over all whitelisted reward denoms - for _, denom := range k.AllowedRewardDenoms(ctx) { - // get the balance of the denom in the toSendToProviderTokens address - balance := k.bankKeeper.GetBalance(ctx, tstProviderAddr, denom) - allBalances = allBalances.Add(balance) - - // if the balance is not zero, - if !balance.IsZero() { - packetTransfer := &transfertypes.MsgTransfer{ - SourcePort: transfertypes.PortID, - SourceChannel: ch, - Token: balance, - Sender: tstProviderAddr.String(), // consumer address to send from - Receiver: providerAddr, // provider fee pool address to send to - TimeoutHeight: timeoutHeight, // timeout height disabled - TimeoutTimestamp: timeoutTimestamp, - Memo: "consumer chain rewards distribution", - } - _, err := k.ibcTransferKeeper.Transfer(ctx, packetTransfer) - if err != nil { - return err - } - sentCoins = sentCoins.Add(balance) + sourceChannelID := k.GetDistributionTransmissionChannel(ctx) + transferChannel, found := k.channelKeeper.GetChannel(ctx, transfertypes.PortID, sourceChannelID) + if !found || transferChannel.State != channeltypes.OPEN { + k.Logger(ctx).Info("WARNING: cannot send rewards to provider;", + "transmission channel not in OPEN state", "channelID", sourceChannelID) + return nil + } + + // get params for sending rewards + toSendToProviderAddr := k.authKeeper.GetModuleAccount(ctx, + types.ConsumerToSendToProviderName).GetAddress() // sender address + providerAddr := k.GetProviderFeePoolAddrStr(ctx) // recipient address + timeoutHeight := clienttypes.ZeroHeight() + timeoutTimestamp := uint64(ctx.BlockTime().Add(k.GetTransferTimeoutPeriod(ctx)).UnixNano()) + + sentCoins := sdk.NewCoins() + var allBalances sdk.Coins + // iterate over all whitelisted reward denoms + for _, denom := range k.AllowedRewardDenoms(ctx) { + // get the balance of the denom in the toSendToProviderTokens address + balance := k.bankKeeper.GetBalance(ctx, toSendToProviderAddr, denom) + allBalances = allBalances.Add(balance) + + // if the balance is not zero, + if !balance.IsZero() { + packetTransfer := &transfertypes.MsgTransfer{ + SourcePort: transfertypes.PortID, + SourceChannel: sourceChannelID, + Token: balance, + Sender: toSendToProviderAddr.String(), // consumer address to send from + Receiver: providerAddr, // provider fee pool address to send to + TimeoutHeight: timeoutHeight, // timeout height disabled + TimeoutTimestamp: timeoutTimestamp, + Memo: "consumer chain rewards distribution", } - } - k.Logger(ctx).Info("sent block rewards to provider", - "total fee pool", allBalances.String(), - "sent", sentCoins.String(), - ) - currentHeight := ctx.BlockHeight() - ctx.EventManager().EmitEvent( - sdk.NewEvent( - ccv.EventTypeFeeDistribution, - sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), - sdk.NewAttribute(ccv.AttributeDistributionCurrentHeight, strconv.Itoa(int(currentHeight))), - sdk.NewAttribute(ccv.AttributeDistributionNextHeight, strconv.Itoa(int(currentHeight+k.GetBlocksPerDistributionTransmission(ctx)))), - sdk.NewAttribute(ccv.AttributeDistributionFraction, (k.GetConsumerRedistributionFrac(ctx))), - sdk.NewAttribute(ccv.AttributeDistributionTotal, allBalances.String()), - sdk.NewAttribute(ccv.AttributeDistributionToProvider, sentCoins.String()), - ), - ) + // validate MsgTransfer before calling Transfer() + err := packetTransfer.ValidateBasic() + if err != nil { + return err + } + + _, err = k.ibcTransferKeeper.Transfer(ctx, packetTransfer) + if err != nil { + return err + } + + sentCoins = sentCoins.Add(balance) + } } + k.Logger(ctx).Info("sent block rewards to provider", + "total fee pool", allBalances.String(), + "sent", sentCoins.String(), + ) + currentHeight := ctx.BlockHeight() + ctx.EventManager().EmitEvent( + sdk.NewEvent( + ccv.EventTypeFeeDistribution, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(ccv.AttributeDistributionCurrentHeight, strconv.Itoa(int(currentHeight))), + sdk.NewAttribute(ccv.AttributeDistributionNextHeight, strconv.Itoa(int(currentHeight+k.GetBlocksPerDistributionTransmission(ctx)))), + sdk.NewAttribute(ccv.AttributeDistributionFraction, (k.GetConsumerRedistributionFrac(ctx))), + sdk.NewAttribute(ccv.AttributeDistributionTotal, allBalances.String()), + sdk.NewAttribute(ccv.AttributeDistributionToProvider, sentCoins.String()), + ), + ) + return nil } diff --git a/x/ccv/types/params.go b/x/ccv/types/params.go index e8ea0a8765..2b553e8366 100644 --- a/x/ccv/types/params.go +++ b/x/ccv/types/params.go @@ -32,10 +32,10 @@ const ( // (and for consistency with other protobuf schemas defined for ccv). DefaultHistoricalEntries = int64(stakingtypes.DefaultHistoricalEntries) - // In general, the default unbonding period on the consumer is one day less + // In general, the default unbonding period on the consumer is one week less // than the default unbonding period on the provider, where the provider uses // the staking module default. - DefaultConsumerUnbondingPeriod = stakingtypes.DefaultUnbondingTime - 24*time.Hour + DefaultConsumerUnbondingPeriod = stakingtypes.DefaultUnbondingTime - 7*24*time.Hour // By default, the bottom 5% of the validator set can opt out of validating consumer chains DefaultSoftOptOutThreshold = "0.05" From 8ec7bc55067e92091f951851584350ff988676d7 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Tue, 5 Sep 2023 09:59:36 -0700 Subject: [PATCH 104/134] docs: Create adr-012-separate-releasing.md (#1229) * Create adr-011-separate-releasing.md * Update docs/docs/adrs/adr-011-separate-releasing.md Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * adr 12 not 11 * correct that we use postfix not prefix * explanation on example release flow --------- Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> --- docs/docs/adrs/adr-012-separate-releasing.md | 76 ++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 docs/docs/adrs/adr-012-separate-releasing.md diff --git a/docs/docs/adrs/adr-012-separate-releasing.md b/docs/docs/adrs/adr-012-separate-releasing.md new file mode 100644 index 0000000000..386c8add29 --- /dev/null +++ b/docs/docs/adrs/adr-012-separate-releasing.md @@ -0,0 +1,76 @@ +--- +sidebar_position: 13 +title: Separate Releasing +--- +# ADR 012: Separate Releasing + +## Changelog + +* {8/18/22}: Initial draft of idea in [#801](https://github.com/cosmos/interchain-security/issues/801) +* {8/22/22}: Put idea in this ADR + +## Status + +Accepted + +## Context + +### Spike results + +I explored the idea of [#801](https://github.com/cosmos/interchain-security/issues/801) with this [spike branch](https://github.com/cosmos/interchain-security/tree/shawn%2Fgo-mod-split-aug-spike). Here's my conclusions: + +Splitting this repo to have multiple go.mods is possible. However there are various intricacies involved in decoupling the package hierarchy to have `x/ccv/types` as the lowest level dep, with `x/ccv/consumer` and `x/ccv/provider` being one dep layer above, with high-level tests depending on all three of the mentioned packages. I'd estimate this decoupling would take 2-5 workdays to finish, and require significant review effort. + +### Why go.mod split is not the way to go + +Let's take a step back and remember the issue we're trying to solve - **We need a clean way to decouple semver/releasing for the consumer and provider modules**. After more consideration, splitting up go.mods gives us little benefit in achieving this. Reasons: + +* The `go.mod` dependency system is tied to git tags for the entire repo (ex: `require github.com/cometbft/cometbft v0.37.2` refers to a historical tag for the entire cometbft repo). +* It'd be an odd dev experience to allow modules to reference past releases of other modules in the same repo. When would we ever want the consumer module to reference a past release of the types module for example? +* If we allow for `go.mod` replace statements to build from local source code, why split up the package deps at all? +* Splitting go.mods adds a bunch of complexity with `go.work` files and all that shiz. VSCode does not play well with multiple module repos either. + +### Why separate repos is cool but also not the way to go + +All this considered, the cleanest solution to decoupling semver/releasing for the consumer and provider modules would be to have multiple repos, each with their own go.mod (3-4 repos total including high level tests). With this scheme we could separately tag each repo as changes are merged, they could share some code from `types` being an external dep, etc. + +I don't think any of us want to split up the monorepo, that's a lot of work and seems like bikeshedding. There's another solution that's very simple.. + +## Decision + +Slightly adapting [the current semver ruleset](https://github.com/cosmos/interchain-security/blob/cca008d856e3ffc60ec1a486871d0faa702abe26/CONTRIBUTING.md#semantic-versioning): + +* A library API breaking change to EITHER the provider or consumer module will result in an increase of the MAJOR version number for BOTH modules (X.y.z-provider AND X.y.z-consumer). +* A state breaking change (change requiring coordinated upgrade and/or state migration) will result in an increase of the MINOR version number for the AFFECTED module(s) (x.Y.z-provider AND/OR x.Y.z-consumer). +* Any other changes (including node API breaking changes) will result in an increase of the PATCH version number for the AFFECTED module(s) (x.y.Z-provider AND/OR x.y.Z-consumer). + +### Example release flow + +We upgrade `main` to use a new version of SDK. This is a major version bump, triggering a new release for both the provider and consumer modules, `v5.0.0-provider` and `v5.0.0-consumer`. + +* A state breaking change is merged to `main` for the provider module. We release only a `v5.1.0-provider` off main. +* Another state breaking change is merged to `main` for the provider module. We release only a `v5.2.0-provider` off main. +* At this point, the latest consumer version is still `v5.0.0-consumer`. We now merge a state breaking change for the consumer module to `main`, and consequently release `v5.1.0-consumer`. Note that `v5.1.0-consumer` is tagged off a LATER commit from main than `v5.2.0-provider`. This is fine, as the consumer module should not be affected by the provider module's state breaking changes. +* Once either module sees a library API breaking change, we bump the major version for both modules. For example, we merge a library API breaking change to `main` for the provider module. We release `v6.0.0-provider` and `v6.0.0-consumer` off main. Note that most often, a library API breaking change will affect both modules simultaneously (example being bumping sdk version). + +## Consequences + +### Positive + +* Consumer repos have clear communication of what tagged versions are relevant to them. Consumer devs should know to never reference an ICS version that starts with `provider`, even if it'd technically build. +* Consumer and provider modules do not deviate as long as we continually release off a shared main branch. Backporting remains relatively unchanged besides being explicit about what module(s) your changes should affect. +* No code changes, just changes in process. Very simple. + +### Negative + +* Slightly more complexity. +* This solution does not allow having provider and consumer on separate versions of e.g. the Cosmos SDK + +### Neutral + +## References + +> Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here! + +* [#801](https://github.com/cosmos/interchain-security/issues/801) +* [#801 comment](https://github.com/cosmos/interchain-security/issues/801#issuecomment-1683349298) From b152c03f98704a07a6e2241acb03c0fe3a5c8aa1 Mon Sep 17 00:00:00 2001 From: Dmitry Kolupaev Date: Wed, 6 Sep 2023 16:00:35 +0400 Subject: [PATCH 105/134] fix: remove addr validation for provider fee pool addr param (#1262) * fix: remove validation for provider chain address since we cannot validate it properly on consumer * add changelog entry --- CHANGELOG.md | 1 + x/ccv/consumer/types/params_test.go | 4 ---- x/ccv/types/params.go | 4 ++-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 353d7226f1..792e83a7a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ Add an entry to the unreleased consumer section whenever merging a PR to main th * (fix!) [#1146](https://github.com/cosmos/interchain-security/pull/1146) Proper deletion of pending packets. * (feat!) [#1037](https://github.com/cosmos/interchain-security/pull/1037) Optimize pending packets storage on consumer, with migration. * (feat) [#1164](https://github.com/cosmos/interchain-security/pull/1164) 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. +* (fix!) [#1262](https://github.com/cosmos/interchain-security/pull/1262) Remove incorrect address validation on `ProviderFeePoolAddrStr` param ## v3.1.0 diff --git a/x/ccv/consumer/types/params_test.go b/x/ccv/consumer/types/params_test.go index 1690fc9f81..ff5d0f325f 100644 --- a/x/ccv/consumer/types/params_test.go +++ b/x/ccv/consumer/types/params_test.go @@ -29,10 +29,6 @@ func TestValidateParams(t *testing.T) { "custom invalid params, dist transmission channel", ccvtypes.NewParams(true, 5, "badchannel/", "", 5, 1005, "0.5", 1000, 24*21*time.Hour, "0.05", []string{"untrn"}, []string{"uatom"}), false, }, - { - "custom invalid params, provider fee pool addr string", - ccvtypes.NewParams(true, 5, "", "imabadaddress", 5, 1005, "0.5", 1000, 24*21*time.Hour, "0.05", []string{"untrn"}, []string{"uatom"}), false, - }, { "custom invalid params, ccv timeout", ccvtypes.NewParams(true, 5, "", "", -5, 1005, "0.5", 1000, 24*21*time.Hour, "0.05", []string{"untrn"}, []string{"uatom"}), false, diff --git a/x/ccv/types/params.go b/x/ccv/types/params.go index 2b553e8366..6a903c0d8f 100644 --- a/x/ccv/types/params.go +++ b/x/ccv/types/params.go @@ -179,8 +179,8 @@ func ValidateProviderFeePoolAddrStr(i interface{}) error { if i == "" { return nil } - // Otherwise validate as usual for a bech32 address - return ValidateBech32(i) + // Cannot validate provider chain address on the consumer chain + return nil } func ValidateSoftOptOutThreshold(i interface{}) error { From 27e73685604c932bca7a4f7553d1ba9ee782052b Mon Sep 17 00:00:00 2001 From: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Thu, 7 Sep 2023 01:11:31 -0700 Subject: [PATCH 106/134] docs: update CHANGELOG.md for `v3.2.0-consumer` release (#1268) * Update CHANGELOG.md * Update CHANGELOG.md --- CHANGELOG.md | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 792e83a7a9..ce07a8e132 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,20 @@ Add an entry to the unreleased provider section whenever merging a PR to main th Add an entry to the unreleased consumer section whenever merging a PR to main that is not targeted at a specific release. These entries will eventually be included in a consumer release. +## v3.2.0-consumer + +Date September 6th, 2023 + +A minor version upgrade to the CONSUMER CCV module. This release includes various changes involving throttling v2 functionality, validation, and bumps to deps like cosmos-sdk and ibc-go. + +Note: + +* This release is ONLY RELEVANT TO CONSUMERS. The most recent provider release is v3.1.0, and will eventually be a release postfixed with `-provider`. +* this is the first upgrade to the consumer module with a separate semver cycle from the provider module. See [contributing.md](./CONTRIBUTING.md#semantic-versioning) and [associated ADR](docs/docs/adrs/adr-012-separate-releasing.md) for more info. + +Changes: + +* (fix!) [#1262](https://github.com/cosmos/interchain-security/pull/1262) Remove incorrect address validation on `ProviderFeePoolAddrStr` param. * (feature!) [#1244](https://github.com/cosmos/interchain-security/pull/1244) Update the default consumer unbonding period to 2 weeks. * (fix!) [#1244](https://github.com/cosmos/interchain-security/pull/1244) Validate token transfer messages before calling `Transfer()`. * (deps) [#1259](https://github.com/cosmos/interchain-security/pull/1259) Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to [v0.47.5](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.5). @@ -22,11 +36,10 @@ Add an entry to the unreleased consumer section whenever merging a PR to main th * (deps) [#1258](https://github.com/cosmos/interchain-security/pull/1258) Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to [v0.47.4](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.4). * (deps!) [#1196](https://github.com/cosmos/interchain-security/pull/1196) Bump [ibc-go](https://github.com/cosmos/ibc-go) to [v7.2.0](https://github.com/cosmos/ibc-go/releases/tag/v7.2.0). * (feat!) [#1024](https://github.com/cosmos/interchain-security/pull/1024) Throttle with retries, consumer changes. -* (fix!) [#1150](https://github.com/cosmos/interchain-security/pull/1150) Revert consumer packet data changes from #1037. +* (fix!) [#1150](https://github.com/cosmos/interchain-security/pull/1150) Revert consumer packet data changes from #1037. * (fix!) [#1146](https://github.com/cosmos/interchain-security/pull/1146) Proper deletion of pending packets. -* (feat!) [#1037](https://github.com/cosmos/interchain-security/pull/1037) Optimize pending packets storage on consumer, with migration. +* (feat!) [#1037](https://github.com/cosmos/interchain-security/pull/1037) Optimize pending packets storage on consumer, with migration. * (feat) [#1164](https://github.com/cosmos/interchain-security/pull/1164) 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. -* (fix!) [#1262](https://github.com/cosmos/interchain-security/pull/1262) Remove incorrect address validation on `ProviderFeePoolAddrStr` param ## v3.1.0 From 4f9d35aa019dc256f3692fbc9e80f45a4012570b Mon Sep 17 00:00:00 2001 From: Thomas Bruyelle Date: Thu, 7 Sep 2023 16:38:46 +0200 Subject: [PATCH 107/134] chore: remove legacy_ibc_testing (rebased on main) (#1185) * chore: remove legacy_ibc_testing * fix import * introduce provider.UnmarshalConsumerPacketData * use patched ibc-go * fix annoying import order * test: ignore key ordering Seems like ibctesting.GenerateKeys can returns keys in different orders when test cover is enabled. * fix after rebase * replace allinbits/ibc-go with patched cosmos/ibc-go Also fix panic in TestRedelegationNoConsumer * fix lint * use released ibc-go 7.3.0 * add newPacketFromConsumer/Provider helper funcs * constructPacket method return ccv type instead of []byte --- app/consumer-democracy/app.go | 6 +- .../proposals_whitelisting_test.go | 8 +- app/consumer/app.go | 6 +- app/provider/app.go | 6 +- app/sovereign/app.go | 6 +- legacy_ibc_testing/README.md | 13 - legacy_ibc_testing/core/events.go | 48 -- legacy_ibc_testing/core/expected_keepers.go | 20 - .../simapp/helpers/test_helpers.go | 85 --- legacy_ibc_testing/simapp/test_helpers.go | 158 ----- legacy_ibc_testing/testing/app.go | 175 ----- legacy_ibc_testing/testing/chain.go | 655 ------------------ legacy_ibc_testing/testing/config.go | 72 -- legacy_ibc_testing/testing/coordinator.go | 253 ------- legacy_ibc_testing/testing/endpoint.go | 581 ---------------- legacy_ibc_testing/testing/events.go | 79 --- legacy_ibc_testing/testing/path.go | 99 --- legacy_ibc_testing/testing/utils.go | 32 - legacy_ibc_testing/testing/values.go | 53 -- tests/difference/core/driver/core_test.go | 15 +- tests/difference/core/driver/setup.go | 8 +- tests/integration/common.go | 80 +-- tests/integration/democracy.go | 17 +- tests/integration/expired_client.go | 2 +- tests/integration/setup.go | 80 ++- tests/integration/slashing.go | 27 +- tests/integration/throttle.go | 202 ++++-- tests/integration/throttle_retry.go | 12 +- tests/integration/unbonding.go | 4 + tests/integration/valset_update.go | 4 +- testutil/ibc_testing/generic_setup.go | 48 +- testutil/ibc_testing/specific_setup.go | 62 +- testutil/integration/interfaces.go | 3 +- testutil/integration/validators.go | 50 ++ testutil/simibc/chain_util.go | 39 +- testutil/simibc/relay_util.go | 5 +- testutil/simibc/relayed_path.go | 3 +- x/ccv/provider/ibc_module.go | 8 +- x/ccv/provider/keeper/keeper_test.go | 4 +- x/ccv/provider/keeper/relay_test.go | 4 +- x/ccv/types/utils_test.go | 6 +- 41 files changed, 490 insertions(+), 2548 deletions(-) delete mode 100644 legacy_ibc_testing/README.md delete mode 100644 legacy_ibc_testing/core/events.go delete mode 100644 legacy_ibc_testing/core/expected_keepers.go delete mode 100644 legacy_ibc_testing/simapp/helpers/test_helpers.go delete mode 100644 legacy_ibc_testing/simapp/test_helpers.go delete mode 100644 legacy_ibc_testing/testing/app.go delete mode 100644 legacy_ibc_testing/testing/chain.go delete mode 100644 legacy_ibc_testing/testing/config.go delete mode 100644 legacy_ibc_testing/testing/coordinator.go delete mode 100644 legacy_ibc_testing/testing/endpoint.go delete mode 100644 legacy_ibc_testing/testing/events.go delete mode 100644 legacy_ibc_testing/testing/path.go delete mode 100644 legacy_ibc_testing/testing/utils.go delete mode 100644 legacy_ibc_testing/testing/values.go create mode 100644 testutil/integration/validators.go diff --git a/app/consumer-democracy/app.go b/app/consumer-democracy/app.go index fee730d752..1a35a89a8a 100644 --- a/app/consumer-democracy/app.go +++ b/app/consumer-democracy/app.go @@ -16,6 +16,8 @@ import ( ibchost "github.com/cosmos/ibc-go/v7/modules/core/exported" ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" tendermint "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + ibctesting "github.com/cosmos/ibc-go/v7/testing" + ibctestingtypes "github.com/cosmos/ibc-go/v7/testing/types" "github.com/spf13/cast" autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" @@ -103,8 +105,6 @@ import ( tmos "github.com/cometbft/cometbft/libs/os" appparams "github.com/cosmos/interchain-security/v3/app/params" - ibctestingcore "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/core" - ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" testutil "github.com/cosmos/interchain-security/v3/testutil/integration" consumer "github.com/cosmos/interchain-security/v3/x/ccv/consumer" consumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" @@ -916,7 +916,7 @@ func (app *App) GetBaseApp() *baseapp.BaseApp { } // GetStakingKeeper implements the TestingApp interface. -func (app *App) GetStakingKeeper() ibctestingcore.StakingKeeper { +func (app *App) GetStakingKeeper() ibctestingtypes.StakingKeeper { return app.ConsumerKeeper } diff --git a/app/consumer-democracy/proposals_whitelisting_test.go b/app/consumer-democracy/proposals_whitelisting_test.go index 127ec82ec5..d0e5a7742d 100644 --- a/app/consumer-democracy/proposals_whitelisting_test.go +++ b/app/consumer-democracy/proposals_whitelisting_test.go @@ -3,16 +3,18 @@ package app_test import ( "testing" + ibctesting "github.com/cosmos/ibc-go/v7/testing" "github.com/stretchr/testify/require" appConsumer "github.com/cosmos/interchain-security/v3/app/consumer-democracy" - ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" icstestingutils "github.com/cosmos/interchain-security/v3/testutil/ibc_testing" + testutil "github.com/cosmos/interchain-security/v3/testutil/integration" ) func TestDemocracyGovernanceWhitelistingKeys(t *testing.T) { - chain := ibctesting.NewTestChain(t, ibctesting.NewCoordinator(t, 0), - icstestingutils.DemocracyConsumerAppIniter, "test") + _, valUpdates, _ := testutil.CreateValidators(t, 4) + ibctesting.DefaultTestingAppInit = icstestingutils.DemocracyConsumerAppIniter(valUpdates) + chain := ibctesting.NewTestChain(t, ibctesting.NewCoordinator(t, 0), "test") paramKeeper := chain.App.(*appConsumer.App).ParamsKeeper for paramKey := range appConsumer.LegacyWhitelistedParams { ss, ok := paramKeeper.GetSubspace(paramKey.Subspace) diff --git a/app/consumer/app.go b/app/consumer/app.go index c65447e244..0c94ed8d75 100644 --- a/app/consumer/app.go +++ b/app/consumer/app.go @@ -16,6 +16,8 @@ import ( ibchost "github.com/cosmos/ibc-go/v7/modules/core/exported" ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" tendermint "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + ibctesting "github.com/cosmos/ibc-go/v7/testing" + ibctestingtypes "github.com/cosmos/ibc-go/v7/testing/types" "github.com/spf13/cast" autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" @@ -86,8 +88,6 @@ import ( tmos "github.com/cometbft/cometbft/libs/os" appparams "github.com/cosmos/interchain-security/v3/app/params" - ibctestingcore "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/core" - ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" testutil "github.com/cosmos/interchain-security/v3/testutil/integration" ibcconsumer "github.com/cosmos/interchain-security/v3/x/ccv/consumer" ibcconsumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" @@ -732,7 +732,7 @@ func (app *App) GetBaseApp() *baseapp.BaseApp { } // GetStakingKeeper implements the TestingApp interface. -func (app *App) GetStakingKeeper() ibctestingcore.StakingKeeper { +func (app *App) GetStakingKeeper() ibctestingtypes.StakingKeeper { return app.ConsumerKeeper } diff --git a/app/provider/app.go b/app/provider/app.go index c054f4a00b..ef3f6508f7 100644 --- a/app/provider/app.go +++ b/app/provider/app.go @@ -19,6 +19,8 @@ import ( ibchost "github.com/cosmos/ibc-go/v7/modules/core/exported" ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" tendermint "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + ibctesting "github.com/cosmos/ibc-go/v7/testing" + ibctestingtypes "github.com/cosmos/ibc-go/v7/testing/types" "github.com/spf13/cast" autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" @@ -99,8 +101,6 @@ import ( tmos "github.com/cometbft/cometbft/libs/os" appparams "github.com/cosmos/interchain-security/v3/app/params" - ibctestingcore "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/core" - ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" testutil "github.com/cosmos/interchain-security/v3/testutil/integration" ibcprovider "github.com/cosmos/interchain-security/v3/x/ccv/provider" ibcproviderclient "github.com/cosmos/interchain-security/v3/x/ccv/provider/client" @@ -817,7 +817,7 @@ func (app *App) GetBaseApp() *baseapp.BaseApp { } // GetStakingKeeper implements the TestingApp interface. -func (app *App) GetStakingKeeper() ibctestingcore.StakingKeeper { +func (app *App) GetStakingKeeper() ibctestingtypes.StakingKeeper { return app.StakingKeeper } diff --git a/app/sovereign/app.go b/app/sovereign/app.go index 1693cb1b60..b5629bfc22 100644 --- a/app/sovereign/app.go +++ b/app/sovereign/app.go @@ -16,6 +16,8 @@ import ( ibchost "github.com/cosmos/ibc-go/v7/modules/core/exported" ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" tendermint "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + ibctesting "github.com/cosmos/ibc-go/v7/testing" + ibctestingtypes "github.com/cosmos/ibc-go/v7/testing/types" "github.com/spf13/cast" autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" @@ -104,8 +106,6 @@ import ( tmos "github.com/cometbft/cometbft/libs/os" appparams "github.com/cosmos/interchain-security/v3/app/params" - ibctestingcore "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/core" - ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" testutil "github.com/cosmos/interchain-security/v3/testutil/integration" ) @@ -770,7 +770,7 @@ func (app *App) GetBaseApp() *baseapp.BaseApp { } // GetStakingKeeper implements the TestingApp interface. -func (app *App) GetStakingKeeper() ibctestingcore.StakingKeeper { +func (app *App) GetStakingKeeper() ibctestingtypes.StakingKeeper { return app.StakingKeeper } diff --git a/legacy_ibc_testing/README.md b/legacy_ibc_testing/README.md deleted file mode 100644 index 1337ec1412..0000000000 --- a/legacy_ibc_testing/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Legacy IBC Testing - -### `legacy_ibc_testing` is imported from [Informal Systems fork of ibc-go](https://github.com/informalsystems/ibc-go). It contains modifications to canonical ibc-go `v3.4.0` for testing purposes only. - -Crucially, Informal's fork contained changes to the [StakingKeeper interface](https://github.com/informalsystems/ibc-go/blob/interchain-security-v3.4.0/modules/core/02-client/types/expected_keepers.go#L12) that both consumer and providers would be expected to return from the testing method `GetStakingKeeper`. For consumer apps, this method would return and IBCKeeper type. This change could not be back-ported to `v3.4.0` of ibc-go as it would be api breaking. Instead, the relevant changes made to ibc-go were consolidated and copied directly into `interchain-security`. Once ICS upgrades ibc-go to a version that supports this change, `v5` at the earliest, this test helper directory can be removed. - -**Directory** -- Core - - Contains changes made in ibc-go `core/`, but do not contain any logic requiring they live in that directory. Includes an interface definition and a testing helper method. -- Simapp - - Includes test helper substitutions for ibc-go's `simapp/` used in the Diff tests. -- Testing - - Replaces ibc-go's `testing/` directory to facilitate ibc's `TestApp`'s implementation of `GetStakingKeeper` returning the relevant `StakingKeeper` interface enhanced in Informal's ibc-go fork. \ No newline at end of file diff --git a/legacy_ibc_testing/core/events.go b/legacy_ibc_testing/core/events.go deleted file mode 100644 index a01c14c685..0000000000 --- a/legacy_ibc_testing/core/events.go +++ /dev/null @@ -1,48 +0,0 @@ -package core - -import ( - "strconv" - - clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" - - abci "github.com/cometbft/cometbft/abci/types" -) - -/* -TODO: Remove after upgrading to ibc-go v5 -legacy_ibc_testing is temporarily copied into the interchain-security repository for the purpose of testing only. -The integration test suites rely on modifications to ibc-go's test framework that cannot be back-ported to the canonical version that ics will rely on. -These files will be deprecated once ICS is able to upgrade to ibc-go v5. -*/ - -// ReconstructPacketFromEvent recreates a packet from an appropriate provided event -func ReconstructPacketFromEvent(event abci.Event) (packet types.Packet, err error) { - attrMap := make(map[string][]byte) - for _, attr := range event.Attributes { - attrMap[attr.Key] = []byte(attr.Value) - } - - sequence, err := strconv.Atoi(string(attrMap[string(types.AttributeKeySequence)])) - if err != nil { - return packet, err - } - timeoutTimestamp, err := strconv.Atoi(string(attrMap[string(types.AttributeKeyTimeoutTimestamp)])) - if err != nil { - return packet, err - } - timeoutHeight, err := clienttypes.ParseHeight(string(attrMap[string(types.AttributeKeyTimeoutHeight)])) - if err != nil { - return packet, err - } - return types.NewPacket( - attrMap[string(types.AttributeKeyData)], //nolint:staticcheck // data - uint64(sequence), - string(attrMap[string(types.AttributeKeySrcPort)]), // sourcePort, - string(attrMap[string(types.AttributeKeySrcChannel)]), // sourceChannel, - string(attrMap[string(types.AttributeKeyDstPort)]), // destinationPort, - string(attrMap[string(types.AttributeKeyDstChannel)]), // destinationChannel string, - timeoutHeight, - uint64(timeoutTimestamp), - ), nil -} diff --git a/legacy_ibc_testing/core/expected_keepers.go b/legacy_ibc_testing/core/expected_keepers.go deleted file mode 100644 index 90a9d40f3c..0000000000 --- a/legacy_ibc_testing/core/expected_keepers.go +++ /dev/null @@ -1,20 +0,0 @@ -package core - -import ( - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" -) - -/* -TODO: Remove after upgrading to ibc-go v5 -legacy_ibc_testing is temporarily copied into the interchain-security repository for the purpose of testing only. -The integration test suites rely on modifications to ibc-go's test framework that cannot be back-ported to the canonical version that ics will rely on. -These files will be deprecated once ICS is able to upgrade to ibc-go v5. -*/ - -type StakingKeeper interface { - GetHistoricalInfo(ctx sdk.Context, height int64) (stakingtypes.HistoricalInfo, bool) - UnbondingTime(ctx sdk.Context) time.Duration -} diff --git a/legacy_ibc_testing/simapp/helpers/test_helpers.go b/legacy_ibc_testing/simapp/helpers/test_helpers.go deleted file mode 100644 index b3e5c80d5e..0000000000 --- a/legacy_ibc_testing/simapp/helpers/test_helpers.go +++ /dev/null @@ -1,85 +0,0 @@ -package helpers - -import ( - "math/rand" - - "github.com/cosmos/cosmos-sdk/client" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/cosmos/cosmos-sdk/types/tx/signing" - authsign "github.com/cosmos/cosmos-sdk/x/auth/signing" -) - -/* -TODO: Remove after upgrading to ibc-go v5 -legacy_ibc_testing is temporarily copied into the interchain-security repository for the purpose of testing only. -The integration test suites rely on modifications to ibc-go's test framework that cannot be back-ported to the canonical version that ics will rely on. -These files will be deprecated once ICS is able to upgrade to ibc-go v5. -*/ - -// SimAppChainID hardcoded chainID for simulation -const ( - DefaultGenTxGas = 1000000 -) - -// GenTx generates a signed mock transaction. -func GenTx(gen client.TxConfig, msgs []sdk.Msg, feeAmt sdk.Coins, gas uint64, chainID string, accNums, accSeqs []uint64, priv ...cryptotypes.PrivKey) (sdk.Tx, error) { - sigs := make([]signing.SignatureV2, len(priv)) - - // create a random length memo - r := rand.New(rand.NewSource(rand.Int63())) - - memo := simulation.RandStringOfLength(r, simulation.RandIntBetween(r, 0, 100)) - - signMode := gen.SignModeHandler().DefaultMode() - - // 1st round: set SignatureV2 with empty signatures, to set correct - // signer infos. - for i, p := range priv { - sigs[i] = signing.SignatureV2{ - PubKey: p.PubKey(), - Data: &signing.SingleSignatureData{ - SignMode: signMode, - }, - Sequence: accSeqs[i], - } - } - - tx := gen.NewTxBuilder() - err := tx.SetMsgs(msgs...) - if err != nil { - return nil, err - } - err = tx.SetSignatures(sigs...) - if err != nil { - return nil, err - } - tx.SetMemo(memo) - tx.SetFeeAmount(feeAmt) - tx.SetGasLimit(gas) - - // 2nd round: once all signer infos are set, every signer can sign. - for i, p := range priv { - signerData := authsign.SignerData{ - ChainID: chainID, - AccountNumber: accNums[i], - Sequence: accSeqs[i], - } - signBytes, err := gen.SignModeHandler().GetSignBytes(signMode, signerData, tx.GetTx()) - if err != nil { - panic(err) - } - sig, err := p.Sign(signBytes) - if err != nil { - panic(err) - } - sigs[i].Data.(*signing.SingleSignatureData).Signature = sig - err = tx.SetSignatures(sigs...) - if err != nil { - panic(err) - } - } - - return tx.GetTx(), nil -} diff --git a/legacy_ibc_testing/simapp/test_helpers.go b/legacy_ibc_testing/simapp/test_helpers.go deleted file mode 100644 index efdc359499..0000000000 --- a/legacy_ibc_testing/simapp/test_helpers.go +++ /dev/null @@ -1,158 +0,0 @@ -package simapp - -import ( - "bytes" - "encoding/hex" - "fmt" - "strconv" - "testing" - "time" - - "github.com/stretchr/testify/require" - - errorsmod "cosmossdk.io/errors" - - bam "github.com/cosmos/cosmos-sdk/baseapp" - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/errors" - - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - tmtypes "github.com/cometbft/cometbft/types" - - "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/simapp/helpers" -) - -/* -TODO: Remove after upgrading to ibc-go v5 -legacy_ibc_testing is temporarily copied into the interchain-security repository for the purpose of testing only. -The integration test suites rely on modifications to ibc-go's test framework that cannot be back-ported to the canonical version that ics will rely on. -These files will be deprecated once ICS is able to upgrade to ibc-go v5. -*/ - -// DefaultConsensusParams defines the default Tendermint consensus params used in -// SimApp testing. -var DefaultConsensusParams = &tmproto.ConsensusParams{ - Block: &tmproto.BlockParams{ - MaxBytes: 200000, - MaxGas: 2000000, - }, - Evidence: &tmproto.EvidenceParams{ - MaxAgeNumBlocks: 302400, - MaxAgeDuration: 504 * time.Hour, // 3 weeks is the max duration - MaxBytes: 10000, - }, - Validator: &tmproto.ValidatorParams{ - PubKeyTypes: []string{ - tmtypes.ABCIPubKeyTypeEd25519, - }, - }, -} - -type GenerateAccountStrategy func(int) []sdk.AccAddress - -// ConvertAddrsToValAddrs converts the provided addresses to ValAddress. -func ConvertAddrsToValAddrs(addrs []sdk.AccAddress) []sdk.ValAddress { - valAddrs := make([]sdk.ValAddress, len(addrs)) - - for i, addr := range addrs { - valAddrs[i] = sdk.ValAddress(addr) - } - - return valAddrs -} - -func TestAddr(addr, bech string) (sdk.AccAddress, error) { - res, err := sdk.AccAddressFromHexUnsafe(addr) - if err != nil { - return nil, err - } - bechexpected := res.String() - if bech != bechexpected { - return nil, fmt.Errorf("bech encoding doesn't match reference") - } - - bechres, err := sdk.AccAddressFromBech32(bech) - if err != nil { - return nil, err - } - if !bytes.Equal(bechres, res) { - return nil, err - } - - return res, nil -} - -// SignAndDeliver signs and delivers a transaction. No simulation occurs as the -// ibc testing package causes checkState and deliverState to diverge in block time. -// -// CONTRACT: BeginBlock must be called before this function. -func SignAndDeliver( - t *testing.T, txCfg client.TxConfig, app *bam.BaseApp, header tmproto.Header, msgs []sdk.Msg, - chainID string, accNums, accSeqs []uint64, expSimPass, expPass bool, priv ...cryptotypes.PrivKey, -) (sdk.GasInfo, *sdk.Result, error) { - t.Helper() - tx, err := helpers.GenTx( - txCfg, - msgs, - sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 0)}, - helpers.DefaultGenTxGas, - chainID, - accNums, - accSeqs, - priv..., - ) - require.NoError(t, err) - - // Simulate a sending a transaction - gInfo, res, err := app.SimDeliver(txCfg.TxEncoder(), tx) - - if expPass { - require.NoError(t, err) - require.NotNil(t, res) - } else { - require.Error(t, err) - require.Nil(t, res) - } - - return gInfo, res, err -} - -// CreateTestPubKeys returns a total of numPubKeys public keys in ascending order. -func CreateTestPubKeys(numPubKeys int) []cryptotypes.PubKey { - var publicKeys []cryptotypes.PubKey - var buffer bytes.Buffer - - // start at 10 to avoid changing 1 to 01, 2 to 02, etc - for i := 100; i < (numPubKeys + 100); i++ { - numString := strconv.Itoa(i) - buffer.WriteString("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AF") // base pubkey string - buffer.WriteString(numString) // adding on final two digits to make pubkeys unique - publicKeys = append(publicKeys, NewPubKeyFromHex(buffer.String())) - buffer.Reset() - } - - return publicKeys -} - -// NewPubKeyFromHex returns a PubKey from a hex string. -func NewPubKeyFromHex(pk string) (res cryptotypes.PubKey) { - pkBytes, err := hex.DecodeString(pk) - if err != nil { - panic(err) - } - if len(pkBytes) != ed25519.PubKeySize { - panic(errorsmod.Wrap(errors.ErrInvalidPubKey, "invalid pubkey size")) - } - return &ed25519.PubKey{Key: pkBytes} -} - -// EmptyAppOptions is a stub implementing AppOptions -type EmptyAppOptions struct{} - -// Get implements AppOptions -func (ao EmptyAppOptions) Get(o string) interface{} { - return nil -} diff --git a/legacy_ibc_testing/testing/app.go b/legacy_ibc_testing/testing/app.go deleted file mode 100644 index ff3c146a4a..0000000000 --- a/legacy_ibc_testing/testing/app.go +++ /dev/null @@ -1,175 +0,0 @@ -package testing - -import ( - "encoding/json" - "testing" - "time" - - "github.com/cosmos/ibc-go/v7/modules/core/keeper" - "github.com/stretchr/testify/require" - - "cosmossdk.io/math" - - "github.com/cosmos/cosmos-sdk/baseapp" - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/codec" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" - storetypes "github.com/cosmos/cosmos-sdk/store/types" - 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" - capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - - abci "github.com/cometbft/cometbft/abci/types" - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - tmtypes "github.com/cometbft/cometbft/types" - - "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/core" - "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/simapp" - consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" - ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" -) - -/* -TODO: Remove after upgrading to ibc-go v5 -legacy_ibc_testing is temporarily copied into the interchain-security repository for the purpose of testing only. -The integration test suites rely on modifications to ibc-go's test framework that cannot be back-ported to the canonical version that ics will rely on. -These files will be deprecated once ICS is able to upgrade to ibc-go v5. -*/ - -type AppIniter func() (TestingApp, map[string]json.RawMessage) - -var DefaultTestingAppInit AppIniter - -type TestingApp interface { - abci.Application - - // ibc-go additions - GetBaseApp() *baseapp.BaseApp - GetStakingKeeper() core.StakingKeeper - GetIBCKeeper() *keeper.Keeper - GetScopedIBCKeeper() capabilitykeeper.ScopedKeeper - GetTxConfig() client.TxConfig - - // Implemented by SimApp - AppCodec() codec.Codec - - // Implemented by BaseApp - LastCommitID() storetypes.CommitID - LastBlockHeight() int64 -} - -// SetupWithGenesisValSet initializes a new SimApp with a validator set and genesis accounts -// that also act as delegators. For simplicity, each validator is bonded with a delegation -// of one consensus engine unit (10^6) in the default token of the simapp from first genesis -// account. A Nop logger is set in SimApp. -func SetupWithGenesisValSet(t *testing.T, appIniter AppIniter, valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount, chainID string, powerReduction math.Int, balances ...banktypes.Balance) TestingApp { - t.Helper() - app, genesisState := appIniter() - baseapp.SetChainID(chainID)(app.GetBaseApp()) - - // set genesis accounts - authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs) - genesisState[authtypes.ModuleName] = app.AppCodec().MustMarshalJSON(authGenesis) - - validators := make([]stakingtypes.Validator, 0, len(valSet.Validators)) - delegations := make([]stakingtypes.Delegation, 0, len(valSet.Validators)) - - bondAmt := sdk.TokensFromConsensusPower(1, powerReduction) - - initValPowers := []abci.ValidatorUpdate{} - for _, val := range valSet.Validators { - pk, err := cryptocodec.FromTmPubKeyInterface(val.PubKey) - require.NoError(t, err) - pkAny, err := codectypes.NewAnyWithValue(pk) - require.NoError(t, err) - validator := stakingtypes.Validator{ - OperatorAddress: sdk.ValAddress(val.Address).String(), - ConsensusPubkey: pkAny, - Jailed: false, - Status: stakingtypes.Bonded, - Tokens: bondAmt, - DelegatorShares: sdk.OneDec(), - Description: stakingtypes.Description{}, - UnbondingHeight: int64(0), - UnbondingTime: time.Unix(0, 0).UTC(), - Commission: stakingtypes.NewCommission(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()), - MinSelfDelegation: sdk.ZeroInt(), - } - - validators = append(validators, validator) - delegations = append(delegations, stakingtypes.NewDelegation(genAccs[0].GetAddress(), val.Address.Bytes(), sdk.OneDec())) - - pub, _ := val.ToProto() - initValPowers = append(initValPowers, abci.ValidatorUpdate{ - Power: val.VotingPower, - PubKey: pub.PubKey, - }) - } - - // set validators and delegations - var ( - stakingGenesis stakingtypes.GenesisState - consumerGenesis ccvtypes.GenesisState - bondDenom string - ) - if genesisState[stakingtypes.ModuleName] != nil { - app.AppCodec().MustUnmarshalJSON(genesisState[stakingtypes.ModuleName], &stakingGenesis) - bondDenom = stakingGenesis.Params.BondDenom - } else { - bondDenom = sdk.DefaultBondDenom - } - - // add bonded amount to bonded pool module account - balances = append(balances, banktypes.Balance{ - Address: authtypes.NewModuleAddress(stakingtypes.BondedPoolName).String(), - Coins: sdk.Coins{sdk.NewCoin(bondDenom, bondAmt.Mul(sdk.NewInt(int64(len(valSet.Validators)))))}, - }) - - // set validators and delegations - stakingGenesis = *stakingtypes.NewGenesisState(stakingGenesis.Params, validators, delegations) - genesisState[stakingtypes.ModuleName] = app.AppCodec().MustMarshalJSON(&stakingGenesis) - - // update total supply - bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, sdk.NewCoins(), []banktypes.Metadata{}, []banktypes.SendEnabled{}) - genesisState[banktypes.ModuleName] = app.AppCodec().MustMarshalJSON(bankGenesis) - - if genesisState[consumertypes.ModuleName] != nil { - app.AppCodec().MustUnmarshalJSON(genesisState[consumertypes.ModuleName], &consumerGenesis) - consumerGenesis.InitialValSet = initValPowers - consumerGenesis.Params.Enabled = true - genesisState[consumertypes.ModuleName] = app.AppCodec().MustMarshalJSON(&consumerGenesis) - } - - stateBytes, err := json.MarshalIndent(genesisState, "", " ") - require.NoError(t, err) - - // init chain will set the validator set and initialize the genesis accounts - app.InitChain( - abci.RequestInitChain{ - ChainId: chainID, - Validators: []abci.ValidatorUpdate{}, - ConsensusParams: simapp.DefaultConsensusParams, - AppStateBytes: stateBytes, - }, - ) - - // commit genesis changes - app.Commit() - - app.BeginBlock( - abci.RequestBeginBlock{ - Header: tmproto.Header{ - ChainID: chainID, - Height: app.LastBlockHeight() + 1, - AppHash: app.LastCommitID().Hash, - ValidatorsHash: valSet.Hash(), - NextValidatorsHash: valSet.Hash(), - }, - }, - ) - - return app -} diff --git a/legacy_ibc_testing/testing/chain.go b/legacy_ibc_testing/testing/chain.go deleted file mode 100644 index 14177679b7..0000000000 --- a/legacy_ibc_testing/testing/chain.go +++ /dev/null @@ -1,655 +0,0 @@ -package testing - -import ( - "bytes" - "fmt" - "testing" - "time" - - clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" - commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v7/modules/core/24-host" - "github.com/cosmos/ibc-go/v7/modules/core/exported" - "github.com/cosmos/ibc-go/v7/modules/core/types" - ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - "github.com/cosmos/ibc-go/v7/testing/mock" - "github.com/stretchr/testify/require" - - errorsmod "cosmossdk.io/errors" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - 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" - capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" - capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - teststaking "github.com/cosmos/cosmos-sdk/x/staking/testutil" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - - abci "github.com/cometbft/cometbft/abci/types" - "github.com/cometbft/cometbft/crypto/tmhash" - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - tmprotoversion "github.com/cometbft/cometbft/proto/tendermint/version" - tmtypes "github.com/cometbft/cometbft/types" - tmversion "github.com/cometbft/cometbft/version" - - ibctestingcore "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/core" - "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/simapp" -) - -/* -TODO: Remove after upgrading to ibc-go v5 -legacy_ibc_testing is temporarily copied into the interchain-security repository for the purpose of testing only. -The integration test suites rely on modifications to ibc-go's test framework that cannot be back-ported to the canonical version that ics will rely on. -These files will be deprecated once ICS is able to upgrade to ibc-go v5. -*/ - -var MaxAccounts = 10 - -type SenderAccount struct { - SenderPrivKey cryptotypes.PrivKey - SenderAccount authtypes.AccountI -} - -// TestChain is a testing struct that wraps a simapp with the last TM Header, the current ABCI -// header and the validators of the TestChain. It also contains a field called ChainID. This -// is the clientID that *other* chains use to refer to this TestChain. The SenderAccount -// is used for delivering transactions through the application state. -// NOTE: the actual application uses an empty chain-id for ease of testing. -type TestChain struct { - *testing.T - - Coordinator *Coordinator - App TestingApp - ChainID string - LastHeader *ibctmtypes.Header // header for last block height committed - CurrentHeader tmproto.Header // header for current block height - QueryServer types.QueryServer - TxConfig client.TxConfig - Codec codec.BinaryCodec - - Vals *tmtypes.ValidatorSet - NextVals *tmtypes.ValidatorSet - - // Signers is a map from validator address to the PrivValidator - // The map is converted into an array that is the same order as the validators right before signing commit - // This ensures that signers will always be in correct order even as validator powers change. - // If a test adds a new validator after chain creation, then the signer map must be updated to include - // the new PrivValidator entry. - Signers map[string]tmtypes.PrivValidator - - // SentPackets is a map from packet sequences to sent packets, - // reconstructed from emitted events of type SendPacketEvent - SentPackets map[string]channeltypes.Packet - - // autogenerated sender private key - SenderPrivKey cryptotypes.PrivKey - SenderAccount authtypes.AccountI - - SenderAccounts []SenderAccount -} - -// NewTestChainWithValSet initializes a new TestChain instance with the given validator set -// and signer array. It also initializes 10 Sender accounts with a balance of 10000000000000000000 coins of -// bond denom to use for tests. -// -// The first block height is committed to state in order to allow for client creations on -// counterparty chains. The TestChain will return with a block height starting at 2. -// -// Time management is handled by the Coordinator in order to ensure synchrony between chains. -// Each update of any chain increments the block header time for all chains by 5 seconds. -// -// NOTE: to use a custom sender privkey and account for testing purposes, replace and modify this -// constructor function. -// -// CONTRACT: Validator array must be provided in the order expected by Tendermint. -// i.e. sorted first by power and then lexicographically by address. -func NewTestChainWithValSet(t *testing.T, coord *Coordinator, appIniter AppIniter, chainID string, valSet *tmtypes.ValidatorSet, signers map[string]tmtypes.PrivValidator) *TestChain { - t.Helper() - genAccs := []authtypes.GenesisAccount{} - genBals := []banktypes.Balance{} - senderAccs := []SenderAccount{} - - // generate genesis accounts - for i := 0; i < MaxAccounts; i++ { - senderPrivKey := secp256k1.GenPrivKey() - acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), uint64(i), 0) - amount, ok := sdk.NewIntFromString("10000000000000000000") - require.True(t, ok) - - balance := banktypes.Balance{ - Address: acc.GetAddress().String(), - Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, amount)), - } - - genAccs = append(genAccs, acc) - genBals = append(genBals, balance) - - senderAcc := SenderAccount{ - SenderAccount: acc, - SenderPrivKey: senderPrivKey, - } - - senderAccs = append(senderAccs, senderAcc) - } - - app := SetupWithGenesisValSet(t, appIniter, valSet, genAccs, chainID, sdk.DefaultPowerReduction, genBals...) - - // create current header and call begin block - header := tmproto.Header{ - ChainID: chainID, - Height: 1, - Time: coord.CurrentTime.UTC(), - } - - txConfig := app.GetTxConfig() - - // create an account to send transactions from - chain := &TestChain{ - T: t, - Coordinator: coord, - ChainID: chainID, - App: app, - CurrentHeader: header, - QueryServer: app.GetIBCKeeper(), - TxConfig: txConfig, - Codec: app.AppCodec(), - Vals: valSet, - NextVals: valSet, - Signers: signers, - SentPackets: make(map[string]channeltypes.Packet), - SenderPrivKey: senderAccs[0].SenderPrivKey, - SenderAccount: senderAccs[0].SenderAccount, - SenderAccounts: senderAccs, - } - - coord.CommitBlock(chain) - - return chain -} - -// NewTestChain initializes a new test chain with a default of 4 validators -// Use this function if the tests do not need custom control over the validator set -func NewTestChain(t *testing.T, coord *Coordinator, appIniter AppIniter, chainID string) *TestChain { - t.Helper() - // generate validators private/public key - var ( - validatorsPerChain = 4 - validators []*tmtypes.Validator - signersByAddress = make(map[string]tmtypes.PrivValidator, validatorsPerChain) - ) - - for i := 0; i < validatorsPerChain; i++ { - privVal := mock.NewPV() - pubKey, err := privVal.GetPubKey() - require.NoError(t, err) - validators = append(validators, tmtypes.NewValidator(pubKey, 1)) - signersByAddress[pubKey.Address().String()] = privVal - } - - // construct validator set; - // Note that the validators are sorted by voting power - // or, if equal, by address lexical order - valSet := tmtypes.NewValidatorSet(validators) - - return NewTestChainWithValSet(t, coord, appIniter, chainID, valSet, signersByAddress) -} - -// GetContext returns the current context for the application. -func (chain *TestChain) GetContext() sdk.Context { - return chain.App.GetBaseApp().NewContext(false, chain.CurrentHeader) -} - -// QueryProof performs an abci query with the given key and returns the proto encoded merkle proof -// for the query and the height at which the proof will succeed on a tendermint verifier. -func (chain *TestChain) QueryProof(key []byte) ([]byte, clienttypes.Height) { - return chain.QueryProofAtHeight(key, chain.App.LastBlockHeight()) -} - -// QueryProof performs an abci query with the given key and returns the proto encoded merkle proof -// for the query and the height at which the proof will succeed on a tendermint verifier. -func (chain *TestChain) QueryProofAtHeight(key []byte, height int64) ([]byte, clienttypes.Height) { - res := chain.App.Query(abci.RequestQuery{ - Path: fmt.Sprintf("store/%s/key", exported.StoreKey), - Height: height - 1, - Data: key, - Prove: true, - }) - - merkleProof, err := commitmenttypes.ConvertProofs(res.ProofOps) - require.NoError(chain.T, err) - - proof, err := chain.App.AppCodec().Marshal(&merkleProof) - require.NoError(chain.T, err) - - revision := clienttypes.ParseChainID(chain.ChainID) - - // proof height + 1 is returned as the proof created corresponds to the height the proof - // was created in the IAVL tree. Tendermint and subsequently the clients that rely on it - // have heights 1 above the IAVL tree. Thus we return proof height + 1 - return proof, clienttypes.NewHeight(revision, uint64(res.Height)+1) -} - -// QueryUpgradeProof performs an abci query with the given key and returns the proto encoded merkle proof -// for the query and the height at which the proof will succeed on a tendermint verifier. -func (chain *TestChain) QueryUpgradeProof(key []byte, height uint64) ([]byte, clienttypes.Height) { - res := chain.App.Query(abci.RequestQuery{ - Path: "store/upgrade/key", - Height: int64(height - 1), - Data: key, - Prove: true, - }) - - merkleProof, err := commitmenttypes.ConvertProofs(res.ProofOps) - require.NoError(chain.T, err) - - proof, err := chain.App.AppCodec().Marshal(&merkleProof) - require.NoError(chain.T, err) - - revision := clienttypes.ParseChainID(chain.ChainID) - - // proof height + 1 is returned as the proof created corresponds to the height the proof - // was created in the IAVL tree. Tendermint and subsequently the clients that rely on it - // have heights 1 above the IAVL tree. Thus we return proof height + 1 - return proof, clienttypes.NewHeight(revision, uint64(res.Height+1)) -} - -// QueryConsensusStateProof performs an abci query for a consensus state -// stored on the given clientID. The proof and consensusHeight are returned. -func (chain *TestChain) QueryConsensusStateProof(clientID string) ([]byte, clienttypes.Height) { - clientState := chain.GetClientState(clientID) - - consensusHeight := clientState.GetLatestHeight().(clienttypes.Height) - consensusKey := host.FullConsensusStateKey(clientID, consensusHeight) - proofConsensus, _ := chain.QueryProof(consensusKey) - - return proofConsensus, consensusHeight -} - -// GetSentPacketKey returns a key for accessing a sent packet, -// given an ibc sequence number and the channel ID for the source endpoint. -func GetSentPacketKey(sequence uint64, channelID string) string { - return fmt.Sprintf("%s-%d", channelID, sequence) -} - -// GetSentPacket returns the sent packet with `sequence` (if any), -// reconstructed from emitted events of type SendPacketEvent -func (chain *TestChain) GetSentPacket(sequence uint64, channelID string) (packet channeltypes.Packet, found bool) { - sentPacketKey := GetSentPacketKey(sequence, channelID) - packet, found = chain.SentPackets[sentPacketKey] - return -} - -// setSentPacketsFromEvents stores the sent packet reconstructed -// from emitted events of type SendPacketEvent -func (chain *TestChain) setSentPacketsFromEvents(events []abci.Event) { - for _, event := range events { - if event.Type == channeltypes.EventTypeSendPacket { - packet, err := ibctestingcore.ReconstructPacketFromEvent(event) - require.NoError(chain.T, err) - sentPacketKey := GetSentPacketKey(packet.GetSequence(), packet.GetSourceChannel()) - chain.SentPackets[sentPacketKey] = packet - } - } -} - -// NextBlock sets the last header to the current header and increments the current header to be -// at the next block height. It does not update the time as that is handled by the Coordinator. -// It will call Endblock and Commit and apply the validator set changes to the next validators -// of the next block being created. This follows the Tendermint protocol of applying valset changes -// returned on block `n` to the validators of block `n+2`. -// It calls BeginBlock with the new block created before returning. -func (chain *TestChain) NextBlock() (abci.ResponseEndBlock, abci.ResponseCommit, abci.ResponseBeginBlock) { - ebRes := chain.App.EndBlock(abci.RequestEndBlock{Height: chain.CurrentHeader.Height}) - // store packets sent during EndBlock - chain.setSentPacketsFromEvents(ebRes.Events) - - cRes := chain.App.Commit() - - // val set changes returned from previous block get applied to the next validators - // of this block. See tendermint spec for details. - chain.Vals = chain.NextVals - chain.NextVals = ApplyValSetChanges(chain.T, chain.Vals, ebRes.ValidatorUpdates) - - // set the last header to the current header - // use nil trusted fields - chain.LastHeader = chain.CurrentTMClientHeader() - - // increment the current header - chain.CurrentHeader = tmproto.Header{ - ChainID: chain.ChainID, - Height: chain.App.LastBlockHeight() + 1, - AppHash: chain.App.LastCommitID().Hash, - // NOTE: the time is increased by the coordinator to maintain time synchrony amongst - // chains. - Time: chain.CurrentHeader.Time, - ValidatorsHash: chain.Vals.Hash(), - NextValidatorsHash: chain.NextVals.Hash(), - } - - bbRes := chain.App.BeginBlock(abci.RequestBeginBlock{Header: chain.CurrentHeader}) - // store packets sent during BeginBlock - chain.setSentPacketsFromEvents(bbRes.Events) - - return ebRes, cRes, bbRes -} - -// sendMsgs delivers a transaction through the application without returning the result. -func (chain *TestChain) sendMsgs(msgs ...sdk.Msg) error { - _, err := chain.SendMsgs(msgs...) - return err -} - -// SendMsgs delivers a transaction through the application. It updates the senders sequence -// number and updates the TestChain's headers. It returns the result and error if one -// occurred. -func (chain *TestChain) SendMsgs(msgs ...sdk.Msg) (*sdk.Result, error) { - // ensure the chain has the latest time - chain.Coordinator.UpdateTimeForChain(chain) - - _, r, err := simapp.SignAndDeliver( - chain.T, - chain.TxConfig, - chain.App.GetBaseApp(), - chain.GetContext().BlockHeader(), - msgs, - chain.ChainID, - []uint64{chain.SenderAccount.GetAccountNumber()}, - []uint64{chain.SenderAccount.GetSequence()}, - true, true, chain.SenderPrivKey, - ) - if err != nil { - return nil, err - } - // store packets sent during the execution of this transaction - chain.setSentPacketsFromEvents(r.Events) - - // NextBlock calls app.Commit() - chain.NextBlock() - - // increment sequence for successful transaction execution - err = chain.SenderAccount.SetSequence(chain.SenderAccount.GetSequence() + 1) - if err != nil { - return nil, err - } - - chain.Coordinator.IncrementTime() - - return r, nil -} - -// GetClientState retrieves the client state for the provided clientID. The client is -// expected to exist otherwise testing will fail. -func (chain *TestChain) GetClientState(clientID string) exported.ClientState { - clientState, found := chain.App.GetIBCKeeper().ClientKeeper.GetClientState(chain.GetContext(), clientID) - require.True(chain.T, found) - - return clientState -} - -// GetConsensusState retrieves the consensus state for the provided clientID and height. -// It will return a success boolean depending on if consensus state exists or not. -func (chain *TestChain) GetConsensusState(clientID string, height exported.Height) (exported.ConsensusState, bool) { - return chain.App.GetIBCKeeper().ClientKeeper.GetClientConsensusState(chain.GetContext(), clientID, height) -} - -// GetValsAtHeight will return the validator set of the chain at a given height. It will return -// a success boolean depending on if the validator set exists or not at that height. -func (chain *TestChain) GetValsAtHeight(height int64) (*tmtypes.ValidatorSet, bool) { - histInfo, ok := chain.App.GetStakingKeeper().GetHistoricalInfo(chain.GetContext(), height) - if !ok { - return nil, false - } - - valSet := stakingtypes.Validators(histInfo.Valset) - - tmValidators, err := teststaking.ToTmValidators(valSet, sdk.DefaultPowerReduction) - if err != nil { - panic(err) - } - return tmtypes.NewValidatorSet(tmValidators), true -} - -// GetAcknowledgement retrieves an acknowledgement for the provided packet. If the -// acknowledgement does not exist then testing will fail. -func (chain *TestChain) GetAcknowledgement(packet exported.PacketI) []byte { - ack, found := chain.App.GetIBCKeeper().ChannelKeeper.GetPacketAcknowledgement(chain.GetContext(), packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) - require.True(chain.T, found) - - return ack -} - -// GetPrefix returns the prefix for used by a chain in connection creation -func (chain *TestChain) GetPrefix() commitmenttypes.MerklePrefix { - return commitmenttypes.NewMerklePrefix(chain.App.GetIBCKeeper().ConnectionKeeper.GetCommitmentPrefix().Bytes()) -} - -// ConstructUpdateTMClientHeader will construct a valid 07-tendermint Header to update the -// light client on the source chain. -func (chain *TestChain) ConstructUpdateTMClientHeader(counterparty *TestChain, clientID string) (*ibctmtypes.Header, error) { - return chain.ConstructUpdateTMClientHeaderWithTrustedHeight(counterparty, clientID, clienttypes.ZeroHeight()) -} - -// ConstructUpdateTMClientHeader will construct a valid 07-tendermint Header to update the -// light client on the source chain. -func (chain *TestChain) ConstructUpdateTMClientHeaderWithTrustedHeight(counterparty *TestChain, clientID string, trustedHeight clienttypes.Height) (*ibctmtypes.Header, error) { - header := counterparty.LastHeader - // Relayer must query for LatestHeight on client to get TrustedHeight if the trusted height is not set - if trustedHeight.IsZero() { - trustedHeight = chain.GetClientState(clientID).GetLatestHeight().(clienttypes.Height) - } - var ( - tmTrustedVals *tmtypes.ValidatorSet - ok bool - ) - // Once we get TrustedHeight from client, we must query the validators from the counterparty chain - // If the LatestHeight == LastHeader.Height, then TrustedValidators are current validators - // If LatestHeight < LastHeader.Height, we can query the historical validator set from HistoricalInfo - if trustedHeight == counterparty.LastHeader.GetHeight() { - tmTrustedVals = counterparty.Vals - } else { - // NOTE: We need to get validators from counterparty at height: trustedHeight+1 - // since the last trusted validators for a header at height h - // is the NextValidators at h+1 committed to in header h by - // NextValidatorsHash - tmTrustedVals, ok = counterparty.GetValsAtHeight(int64(trustedHeight.RevisionHeight + 1)) - if !ok { - return nil, errorsmod.Wrapf(ibctmtypes.ErrInvalidHeaderHeight, "could not retrieve trusted validators at trustedHeight: %d", trustedHeight) - } - } - // inject trusted fields into last header - // for now assume revision number is 0 - header.TrustedHeight = trustedHeight - - trustedVals, err := tmTrustedVals.ToProto() - if err != nil { - return nil, err - } - header.TrustedValidators = trustedVals - - return header, nil -} - -// ExpireClient fast forwards the chain's block time by the provided amount of time which will -// expire any clients with a trusting period less than or equal to this amount of time. -func (chain *TestChain) ExpireClient(amount time.Duration) { - chain.Coordinator.IncrementTimeBy(amount) -} - -// CurrentTMClientHeader creates a TM header using the current header parameters -// on the chain. The trusted fields in the header are set to nil. -func (chain *TestChain) CurrentTMClientHeader() *ibctmtypes.Header { - return chain.CreateTMClientHeader(chain.ChainID, chain.CurrentHeader.Height, clienttypes.Height{}, chain.CurrentHeader.Time, chain.Vals, chain.NextVals, nil, chain.Signers) -} - -// CreateTMClientHeader creates a TM header to update the TM client. Args are passed in to allow -// caller flexibility to use params that differ from the chain. -func (chain *TestChain) CreateTMClientHeader(chainID string, blockHeight int64, trustedHeight clienttypes.Height, timestamp time.Time, tmValSet, nextVals, tmTrustedVals *tmtypes.ValidatorSet, signers map[string]tmtypes.PrivValidator) *ibctmtypes.Header { - var ( - valSet *tmproto.ValidatorSet - trustedVals *tmproto.ValidatorSet - ) - - if tmValSet == nil { - panic("tmValSet cannot be nil") - } - - vsetHash := tmValSet.Hash() - nextValHash := nextVals.Hash() - - tmHeader := tmtypes.Header{ - Version: tmprotoversion.Consensus{Block: tmversion.BlockProtocol, App: 2}, - ChainID: chainID, - Height: blockHeight, - Time: timestamp, - LastBlockID: MakeBlockID(make([]byte, tmhash.Size), 10000, make([]byte, tmhash.Size)), - LastCommitHash: chain.App.LastCommitID().Hash, - DataHash: tmhash.Sum([]byte("data_hash")), - ValidatorsHash: vsetHash, - NextValidatorsHash: nextValHash, - ConsensusHash: tmhash.Sum([]byte("consensus_hash")), - AppHash: chain.CurrentHeader.AppHash, - LastResultsHash: tmhash.Sum([]byte("last_results_hash")), - EvidenceHash: tmhash.Sum([]byte("evidence_hash")), - ProposerAddress: tmValSet.Proposer.Address, - } - - hhash := tmHeader.Hash() - blockID := MakeBlockID(hhash, 3, tmhash.Sum([]byte("part_set"))) - voteSet := tmtypes.NewVoteSet(chainID, blockHeight, 1, tmproto.PrecommitType, tmValSet) - - // MakeCommit expects a signer array in the same order as the validator array. - // Thus we iterate over the ordered validator set and construct a signer array - // from the signer map in the same order. - var signerArr []tmtypes.PrivValidator - - for _, v := range tmValSet.Validators { - if v == nil { - panic("validator in tmValSet cannot be nil") - } - signerArr = append(signerArr, signers[v.Address.String()]) - } - - commit, err := tmtypes.MakeCommit(blockID, blockHeight, 1, voteSet, signerArr, timestamp) - require.NoError(chain.T, err) - - signedHeader := &tmproto.SignedHeader{ - Header: tmHeader.ToProto(), - Commit: commit.ToProto(), - } - - if tmValSet != nil { - valSet, err = tmValSet.ToProto() - require.NoError(chain.T, err) - } - - if tmTrustedVals != nil { - trustedVals, err = tmTrustedVals.ToProto() - require.NoError(chain.T, err) - } - - // The trusted fields may be nil. They may be filled before relaying messages to a client. - // The relayer is responsible for querying client and injecting appropriate trusted fields. - return &ibctmtypes.Header{ - SignedHeader: signedHeader, - ValidatorSet: valSet, - TrustedHeight: trustedHeight, - TrustedValidators: trustedVals, - } -} - -// MakeBlockID copied unimported test functions from tmtypes to use them here -func MakeBlockID(hash []byte, partSetSize uint32, partSetHash []byte) tmtypes.BlockID { - return tmtypes.BlockID{ - Hash: hash, - PartSetHeader: tmtypes.PartSetHeader{ - Total: partSetSize, - Hash: partSetHash, - }, - } -} - -// CreateSortedSignerArray takes two PrivValidators, and the corresponding Validator structs -// (including voting power). It returns a signer array of PrivValidators that matches the -// sorting of ValidatorSet. -// The sorting is first by .VotingPower (descending), with secondary index of .Address (ascending). -func CreateSortedSignerArray(altPrivVal, suitePrivVal tmtypes.PrivValidator, - altVal, suiteVal *tmtypes.Validator, -) []tmtypes.PrivValidator { - switch { - case altVal.VotingPower > suiteVal.VotingPower: - return []tmtypes.PrivValidator{altPrivVal, suitePrivVal} - case altVal.VotingPower < suiteVal.VotingPower: - return []tmtypes.PrivValidator{suitePrivVal, altPrivVal} - default: - if bytes.Compare(altVal.Address, suiteVal.Address) == -1 { - return []tmtypes.PrivValidator{altPrivVal, suitePrivVal} - } - return []tmtypes.PrivValidator{suitePrivVal, altPrivVal} - } -} - -// CreatePortCapability binds and claims a capability for the given portID if it does not -// already exist. This function will fail testing on any resulting error. -// NOTE: only creation of a capability for a transfer or mock port is supported -// Other applications must bind to the port in InitGenesis or modify this code. -func (chain *TestChain) CreatePortCapability(scopedKeeper capabilitykeeper.ScopedKeeper, portID string) { - // check if the portId is already binded, if not bind it - _, ok := chain.App.GetScopedIBCKeeper().GetCapability(chain.GetContext(), host.PortPath(portID)) - if !ok { - // create capability using the IBC capability keeper - cap, err := chain.App.GetScopedIBCKeeper().NewCapability(chain.GetContext(), host.PortPath(portID)) - require.NoError(chain.T, err) - - // claim capability using the scopedKeeper - err = scopedKeeper.ClaimCapability(chain.GetContext(), cap, host.PortPath(portID)) - require.NoError(chain.T, err) - } - - chain.NextBlock() -} - -// GetPortCapability returns the port capability for the given portID. The capability must -// exist, otherwise testing will fail. -func (chain *TestChain) GetPortCapability(portID string) *capabilitytypes.Capability { - cap, ok := chain.App.GetScopedIBCKeeper().GetCapability(chain.GetContext(), host.PortPath(portID)) - require.True(chain.T, ok) - - return cap -} - -// CreateChannelCapability binds and claims a capability for the given portID and channelID -// if it does not already exist. This function will fail testing on any resulting error. The -// scoped keeper passed in will claim the new capability. -func (chain *TestChain) CreateChannelCapability(scopedKeeper capabilitykeeper.ScopedKeeper, portID, channelID string) { - capName := host.ChannelCapabilityPath(portID, channelID) - // check if the portId is already binded, if not bind it - _, ok := chain.App.GetScopedIBCKeeper().GetCapability(chain.GetContext(), capName) - if !ok { - cap, err := chain.App.GetScopedIBCKeeper().NewCapability(chain.GetContext(), capName) - require.NoError(chain.T, err) - err = scopedKeeper.ClaimCapability(chain.GetContext(), cap, capName) - require.NoError(chain.T, err) - } - - chain.NextBlock() -} - -// GetChannelCapability returns the channel capability for the given portID and channelID. -// The capability must exist, otherwise testing will fail. -func (chain *TestChain) GetChannelCapability(portID, channelID string) *capabilitytypes.Capability { - cap, ok := chain.App.GetScopedIBCKeeper().GetCapability(chain.GetContext(), host.ChannelCapabilityPath(portID, channelID)) - require.True(chain.T, ok) - - return cap -} - -// GetTimeoutHeight is a convenience function which returns a IBC packet timeout height -// to be used for testing. It returns the current IBC height + 100 blocks -func (chain *TestChain) GetTimeoutHeight() clienttypes.Height { - return clienttypes.NewHeight(clienttypes.ParseChainID(chain.ChainID), uint64(chain.GetContext().BlockHeight())+100) -} diff --git a/legacy_ibc_testing/testing/config.go b/legacy_ibc_testing/testing/config.go deleted file mode 100644 index dffe01053f..0000000000 --- a/legacy_ibc_testing/testing/config.go +++ /dev/null @@ -1,72 +0,0 @@ -package testing - -import ( - "time" - - connectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" - "github.com/cosmos/ibc-go/v7/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - "github.com/cosmos/ibc-go/v7/testing/mock" -) - -/* -TODO: Remove after upgrading to ibc-go v5 -legacy_ibc_testing is temporarily copied into the interchain-security repository for the purpose of testing only. -The integration test suites rely on modifications to ibc-go's test framework that cannot be back-ported to the canonical version that ics will rely on. -These files will be deprecated once ICS is able to upgrade to ibc-go v5. -*/ - -type ClientConfig interface { - GetClientType() string -} - -type TendermintConfig struct { - TrustLevel ibctmtypes.Fraction - TrustingPeriod time.Duration - UnbondingPeriod time.Duration - MaxClockDrift time.Duration - AllowUpdateAfterExpiry bool - AllowUpdateAfterMisbehaviour bool -} - -func NewTendermintConfig() *TendermintConfig { - return &TendermintConfig{ - TrustLevel: DefaultTrustLevel, - TrustingPeriod: TrustingPeriod, - UnbondingPeriod: UnbondingPeriod, - MaxClockDrift: MaxClockDrift, - AllowUpdateAfterExpiry: false, - AllowUpdateAfterMisbehaviour: false, - } -} - -func (tmcfg *TendermintConfig) GetClientType() string { - return exported.Tendermint -} - -type ConnectionConfig struct { - DelayPeriod uint64 - Version *connectiontypes.Version -} - -func NewConnectionConfig() *ConnectionConfig { - return &ConnectionConfig{ - DelayPeriod: DefaultDelayPeriod, - Version: ConnectionVersion, - } -} - -type ChannelConfig struct { - PortID string - Version string - Order channeltypes.Order -} - -func NewChannelConfig() *ChannelConfig { - return &ChannelConfig{ - PortID: mock.PortID, - Version: DefaultChannelVersion, - Order: channeltypes.UNORDERED, - } -} diff --git a/legacy_ibc_testing/testing/coordinator.go b/legacy_ibc_testing/testing/coordinator.go deleted file mode 100644 index 13f5ac1bec..0000000000 --- a/legacy_ibc_testing/testing/coordinator.go +++ /dev/null @@ -1,253 +0,0 @@ -package testing - -import ( - "fmt" - "strconv" - "testing" - "time" - - "github.com/stretchr/testify/require" - - abci "github.com/cometbft/cometbft/abci/types" -) - -/* -TODO: Remove after upgrading to ibc-go v5 -legacy_ibc_testing is temporarily copied into the interchain-security repository for the purpose of testing only. -The integration test suites rely on modifications to ibc-go's test framework that cannot be back-ported to the canonical version that ics will rely on. -These files will be deprecated once ICS is able to upgrade to ibc-go v5. -*/ - -var ( - ChainIDPrefix = "testchain" - GlobalStartTime = time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC) - TimeIncrement = time.Second * 5 -) - -// Coordinator is a testing struct which contains N TestChain's. It handles keeping all chains -// in sync with regards to time. -type Coordinator struct { - *testing.T - - CurrentTime time.Time - Chains map[string]*TestChain -} - -// NewCoordinator initializes Coordinator with N TestChain's -func NewCoordinator(t *testing.T, n int) *Coordinator { - t.Helper() - chains := make(map[string]*TestChain) - coord := &Coordinator{ - T: t, - CurrentTime: GlobalStartTime, - } - - for i := 1; i <= n; i++ { - chainID := GetChainID(i) - chains[chainID] = NewTestChain(t, coord, DefaultTestingAppInit, chainID) - } - coord.Chains = chains - - return coord -} - -// IncrementTime iterates through all the TestChain's and increments their current header time -// by 5 seconds. -// -// CONTRACT: this function must be called after every Commit on any TestChain. -func (coord *Coordinator) IncrementTime() { - coord.IncrementTimeBy(TimeIncrement) -} - -// IncrementTimeBy iterates through all the TestChain's and increments their current header time -// by specified time. -func (coord *Coordinator) IncrementTimeBy(increment time.Duration) { - coord.CurrentTime = coord.CurrentTime.Add(increment).UTC() - coord.UpdateTime() -} - -// UpdateTime updates all clocks for the TestChains to the current global time. -func (coord *Coordinator) UpdateTime() { - for _, chain := range coord.Chains { - coord.UpdateTimeForChain(chain) - } -} - -// UpdateTimeForChain updates the clock for a specific chain. -func (coord *Coordinator) UpdateTimeForChain(chain *TestChain) { - chain.CurrentHeader.Time = coord.CurrentTime.UTC() - chain.App.BeginBlock(abci.RequestBeginBlock{Header: chain.CurrentHeader}) -} - -// Setup constructs a TM client, connection, and channel on both chains provided. It will -// fail if any error occurs. The clientID's, TestConnections, and TestChannels are returned -// for both chains. The channels created are connected to the ibc-transfer application. -func (coord *Coordinator) Setup(path *Path) { - coord.SetupConnections(path) - - // channels can also be referenced through the returned connections - coord.CreateChannels(path) -} - -// SetupClients is a helper function to create clients on both chains. It assumes the -// caller does not anticipate any errors. -func (coord *Coordinator) SetupClients(path *Path) { - err := path.EndpointA.CreateClient() - require.NoError(coord.T, err) - - err = path.EndpointB.CreateClient() - require.NoError(coord.T, err) -} - -// SetupClientConnections is a helper function to create clients and the appropriate -// connections on both the source and counterparty chain. It assumes the caller does not -// anticipate any errors. -func (coord *Coordinator) SetupConnections(path *Path) { - coord.SetupClients(path) - - coord.CreateConnections(path) -} - -// CreateConnection constructs and executes connection handshake messages in order to create -// OPEN channels on chainA and chainB. The connection information of for chainA and chainB -// are returned within a TestConnection struct. The function expects the connections to be -// successfully opened otherwise testing will fail. -func (coord *Coordinator) CreateConnections(path *Path) { - err := path.EndpointA.ConnOpenInit() - require.NoError(coord.T, err) - - err = path.EndpointB.ConnOpenTry() - require.NoError(coord.T, err) - - err = path.EndpointA.ConnOpenAck() - require.NoError(coord.T, err) - - err = path.EndpointB.ConnOpenConfirm() - require.NoError(coord.T, err) - - // ensure counterparty is up to date - err = path.EndpointA.UpdateClient() - require.NoError(coord.T, err) -} - -// CreateMockChannels constructs and executes channel handshake messages to create OPEN -// channels that use a mock application module that returns nil on all callbacks. This -// function is expects the channels to be successfully opened otherwise testing will -// fail. -func (coord *Coordinator) CreateMockChannels(path *Path) { - path.EndpointA.ChannelConfig.PortID = MockPort - path.EndpointB.ChannelConfig.PortID = MockPort - - coord.CreateChannels(path) -} - -// CreateTransferChannels constructs and executes channel handshake messages to create OPEN -// ibc-transfer channels on chainA and chainB. The function expects the channels to be -// successfully opened otherwise testing will fail. -func (coord *Coordinator) CreateTransferChannels(path *Path) { - path.EndpointA.ChannelConfig.PortID = TransferPort - path.EndpointB.ChannelConfig.PortID = TransferPort - - coord.CreateChannels(path) -} - -// CreateChannel constructs and executes channel handshake messages in order to create -// OPEN channels on chainA and chainB. The function expects the channels to be successfully -// opened otherwise testing will fail. -func (coord *Coordinator) CreateChannels(path *Path) { - err := path.EndpointA.ChanOpenInit() - require.NoError(coord.T, err) - - err = path.EndpointB.ChanOpenTry() - require.NoError(coord.T, err) - - err = path.EndpointA.ChanOpenAck() - require.NoError(coord.T, err) - - err = path.EndpointB.ChanOpenConfirm() - require.NoError(coord.T, err) - - // ensure counterparty is up to date - err = path.EndpointA.UpdateClient() - require.NoError(coord.T, err) -} - -// GetChain returns the TestChain using the given chainID and returns an error if it does -// not exist. -func (coord *Coordinator) GetChain(chainID string) *TestChain { - chain, found := coord.Chains[chainID] - require.True(coord.T, found, fmt.Sprintf("%s chain does not exist", chainID)) - return chain -} - -// GetChainID returns the chainID used for the provided index. -func GetChainID(index int) string { - return ChainIDPrefix + strconv.Itoa(index) -} - -// CommitBlock commits a block on the provided indexes and then increments the global time. -// -// CONTRACT: the passed in list of indexes must not contain duplicates -func (coord *Coordinator) CommitBlock(chains ...*TestChain) { - for _, chain := range chains { - // NextBlock calls app.Commit() - chain.NextBlock() - } - coord.IncrementTime() -} - -// CommitNBlocks commits n blocks to state and updates the block height by 1 for each commit. -func (coord *Coordinator) CommitNBlocks(chain *TestChain, n uint64) { - for i := uint64(0); i < n; i++ { - chain.NextBlock() - coord.IncrementTime() - } -} - -// CommitBlockGetResponses commits a block and provides abci responses -func (coord *Coordinator) CommitBlockGetResponses(chain *TestChain) ( - abci.ResponseEndBlock, abci.ResponseCommit, abci.ResponseBeginBlock, -) { - ebRes, cRes, bbResp := chain.NextBlock() - coord.IncrementTime() - return ebRes, cRes, bbResp -} - -// ConnOpenInitOnBothChains initializes a connection on both endpoints with the state INIT -// using the OpenInit handshake call. -func (coord *Coordinator) ConnOpenInitOnBothChains(path *Path) error { - if err := path.EndpointA.ConnOpenInit(); err != nil { - return err - } - - if err := path.EndpointB.ConnOpenInit(); err != nil { - return err - } - - if err := path.EndpointA.UpdateClient(); err != nil { - return err - } - - return path.EndpointB.UpdateClient() -} - -// ChanOpenInitOnBothChains initializes a channel on the source chain and counterparty chain -// with the state INIT using the OpenInit handshake call. -func (coord *Coordinator) ChanOpenInitOnBothChains(path *Path) error { - // NOTE: only creation of a capability for a transfer or mock port is supported - // Other applications must bind to the port in InitGenesis or modify this code. - - if err := path.EndpointA.ChanOpenInit(); err != nil { - return err - } - - if err := path.EndpointB.ChanOpenInit(); err != nil { - return err - } - - if err := path.EndpointA.UpdateClient(); err != nil { - return err - } - - return path.EndpointB.UpdateClient() -} diff --git a/legacy_ibc_testing/testing/endpoint.go b/legacy_ibc_testing/testing/endpoint.go deleted file mode 100644 index ef9213d222..0000000000 --- a/legacy_ibc_testing/testing/endpoint.go +++ /dev/null @@ -1,581 +0,0 @@ -package testing - -import ( - "fmt" - - clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" - commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v7/modules/core/24-host" - "github.com/cosmos/ibc-go/v7/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - "github.com/stretchr/testify/require" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -/* -TODO: Remove after upgrading to ibc-go v5 -legacy_ibc_testing is temporarily copied into the interchain-security repository for the purpose of testing only. -The integration test suites rely on modifications to ibc-go's test framework that cannot be back-ported to the canonical version that ics will rely on. -These files will be deprecated once ICS is able to upgrade to ibc-go v5. -*/ - -// Endpoint is a which represents a channel endpoint and its associated -// client and connections. It contains client, connection, and channel -// configuration parameters. Endpoint functions will utilize the parameters -// set in the configuration structs when executing IBC messages. -type Endpoint struct { - Chain *TestChain - Counterparty *Endpoint - ClientID string - ConnectionID string - ChannelID string - - ClientConfig ClientConfig - ConnectionConfig *ConnectionConfig - ChannelConfig *ChannelConfig -} - -// NewDefaultEndpoint constructs a new endpoint using default values. -// CONTRACT: the counterparty endpoitn must be set by the caller. -func NewDefaultEndpoint(chain *TestChain) *Endpoint { - return &Endpoint{ - Chain: chain, - ClientConfig: NewTendermintConfig(), - ConnectionConfig: NewConnectionConfig(), - ChannelConfig: NewChannelConfig(), - } -} - -// QueryProof queries proof associated with this endpoint using the lastest client state -// height on the counterparty chain. -func (endpoint *Endpoint) QueryProof(key []byte) ([]byte, clienttypes.Height) { - // obtain the counterparty client representing the chain associated with the endpoint - clientState := endpoint.Counterparty.Chain.GetClientState(endpoint.Counterparty.ClientID) - - // query proof on the counterparty using the latest height of the IBC client - return endpoint.QueryProofAtHeight(key, clientState.GetLatestHeight().GetRevisionHeight()) -} - -// QueryProofAtHeight queries proof associated with this endpoint using the proof height -// provided -func (endpoint *Endpoint) QueryProofAtHeight(key []byte, height uint64) ([]byte, clienttypes.Height) { - // query proof on the counterparty using the latest height of the IBC client - return endpoint.Chain.QueryProofAtHeight(key, int64(height)) -} - -// CreateClient creates an IBC client on the endpoint. It will update the -// clientID for the endpoint if the message is successfully executed. -// NOTE: a solo machine client will be created with an empty diversifier. -func (endpoint *Endpoint) CreateClient() (err error) { - // ensure counterparty has committed state - endpoint.Chain.Coordinator.CommitBlock(endpoint.Counterparty.Chain) - - var ( - clientState exported.ClientState - consensusState exported.ConsensusState - ) - - switch endpoint.ClientConfig.GetClientType() { - case exported.Tendermint: - tmConfig, ok := endpoint.ClientConfig.(*TendermintConfig) - require.True(endpoint.Chain.T, ok) - - height := endpoint.Counterparty.Chain.LastHeader.GetHeight().(clienttypes.Height) - clientState = ibctmtypes.NewClientState( - endpoint.Counterparty.Chain.ChainID, tmConfig.TrustLevel, tmConfig.TrustingPeriod, tmConfig.UnbondingPeriod, tmConfig.MaxClockDrift, - height, commitmenttypes.GetSDKSpecs(), UpgradePath, - ) - consensusState = endpoint.Counterparty.Chain.LastHeader.ConsensusState() - case exported.Solomachine: - // TODO - // solo := NewSolomachine(endpoint.Chain.T, endpoint.Chain.Codec, clientID, "", 1) - // clientState = solo.ClientState() - // consensusState = solo.ConsensusState() - - default: - err = fmt.Errorf("client type %s is not supported", endpoint.ClientConfig.GetClientType()) - } - - if err != nil { - return err - } - - msg, err := clienttypes.NewMsgCreateClient( - clientState, consensusState, endpoint.Chain.SenderAccount.GetAddress().String(), - ) - require.NoError(endpoint.Chain.T, err) - - res, err := endpoint.Chain.SendMsgs(msg) - if err != nil { - return err - } - - endpoint.ClientID, err = ParseClientIDFromEvents(res.GetEvents()) - require.NoError(endpoint.Chain.T, err) - - return nil -} - -// UpdateClient updates the IBC client associated with the endpoint. -func (endpoint *Endpoint) UpdateClient() (err error) { - // ensure counterparty has committed state - endpoint.Chain.Coordinator.CommitBlock(endpoint.Counterparty.Chain) - - var header *ibctmtypes.Header - - switch endpoint.ClientConfig.GetClientType() { - case exported.Tendermint: - header, err = endpoint.Chain.ConstructUpdateTMClientHeader(endpoint.Counterparty.Chain, endpoint.ClientID) - - default: - err = fmt.Errorf("client type %s is not supported", endpoint.ClientConfig.GetClientType()) - } - - if err != nil { - return err - } - - msg, err := clienttypes.NewMsgUpdateClient( - endpoint.ClientID, header, - endpoint.Chain.SenderAccount.GetAddress().String(), - ) - require.NoError(endpoint.Chain.T, err) - - return endpoint.Chain.sendMsgs(msg) -} - -// ConnOpenInit will construct and execute a MsgConnectionOpenInit on the associated endpoint. -func (endpoint *Endpoint) ConnOpenInit() error { - msg := connectiontypes.NewMsgConnectionOpenInit( - endpoint.ClientID, - endpoint.Counterparty.ClientID, - endpoint.Counterparty.Chain.GetPrefix(), DefaultOpenInitVersion, endpoint.ConnectionConfig.DelayPeriod, - endpoint.Chain.SenderAccount.GetAddress().String(), - ) - res, err := endpoint.Chain.SendMsgs(msg) - if err != nil { - return err - } - - endpoint.ConnectionID, err = ParseConnectionIDFromEvents(res.GetEvents()) - require.NoError(endpoint.Chain.T, err) - - return nil -} - -// ConnOpenTry will construct and execute a MsgConnectionOpenTry on the associated endpoint. -func (endpoint *Endpoint) ConnOpenTry() error { - err := endpoint.UpdateClient() - require.NoError(endpoint.Chain.T, err) - - counterpartyClient, proofClient, proofConsensus, consensusHeight, proofInit, proofHeight := endpoint.QueryConnectionHandshakeProof() - - msg := connectiontypes.NewMsgConnectionOpenTry( - endpoint.ClientID, // does not support handshake continuation - endpoint.Counterparty.ConnectionID, - endpoint.Counterparty.ClientID, - counterpartyClient, - endpoint.Counterparty.Chain.GetPrefix(), - []*connectiontypes.Version{ConnectionVersion}, - endpoint.ConnectionConfig.DelayPeriod, - proofInit, proofClient, proofConsensus, - proofHeight, consensusHeight, - endpoint.Chain.SenderAccount.GetAddress().String(), - ) - res, err := endpoint.Chain.SendMsgs(msg) - if err != nil { - return err - } - - if endpoint.ConnectionID == "" { - endpoint.ConnectionID, err = ParseConnectionIDFromEvents(res.GetEvents()) - require.NoError(endpoint.Chain.T, err) - } - - return nil -} - -// ConnOpenAck will construct and execute a MsgConnectionOpenAck on the associated endpoint. -func (endpoint *Endpoint) ConnOpenAck() error { - err := endpoint.UpdateClient() - require.NoError(endpoint.Chain.T, err) - - counterpartyClient, proofClient, proofConsensus, consensusHeight, proofTry, proofHeight := endpoint.QueryConnectionHandshakeProof() - - msg := connectiontypes.NewMsgConnectionOpenAck( - endpoint.ConnectionID, endpoint.Counterparty.ConnectionID, counterpartyClient, // testing doesn't use flexible selection - proofTry, proofClient, proofConsensus, - proofHeight, consensusHeight, - ConnectionVersion, - endpoint.Chain.SenderAccount.GetAddress().String(), - ) - return endpoint.Chain.sendMsgs(msg) -} - -// ConnOpenConfirm will construct and execute a MsgConnectionOpenConfirm on the associated endpoint. -func (endpoint *Endpoint) ConnOpenConfirm() error { - err := endpoint.UpdateClient() - require.NoError(endpoint.Chain.T, err) - - connectionKey := host.ConnectionKey(endpoint.Counterparty.ConnectionID) - proof, height := endpoint.Counterparty.Chain.QueryProof(connectionKey) - - msg := connectiontypes.NewMsgConnectionOpenConfirm( - endpoint.ConnectionID, - proof, height, - endpoint.Chain.SenderAccount.GetAddress().String(), - ) - return endpoint.Chain.sendMsgs(msg) -} - -// QueryConnectionHandshakeProof returns all the proofs necessary to execute OpenTry or Open Ack of -// the connection handshakes. It returns the counterparty client state, proof of the counterparty -// client state, proof of the counterparty consensus state, the consensus state height, proof of -// the counterparty connection, and the proof height for all the proofs returned. -func (endpoint *Endpoint) QueryConnectionHandshakeProof() ( - clientState exported.ClientState, proofClient, - proofConsensus []byte, consensusHeight clienttypes.Height, - proofConnection []byte, proofHeight clienttypes.Height, -) { - // obtain the client state on the counterparty chain - clientState = endpoint.Counterparty.Chain.GetClientState(endpoint.Counterparty.ClientID) - - // query proof for the client state on the counterparty - clientKey := host.FullClientStateKey(endpoint.Counterparty.ClientID) - proofClient, proofHeight = endpoint.Counterparty.QueryProof(clientKey) - - consensusHeight = clientState.GetLatestHeight().(clienttypes.Height) - - // query proof for the consensus state on the counterparty - consensusKey := host.FullConsensusStateKey(endpoint.Counterparty.ClientID, consensusHeight) - proofConsensus, _ = endpoint.Counterparty.QueryProofAtHeight(consensusKey, proofHeight.GetRevisionHeight()) - - // query proof for the connection on the counterparty - connectionKey := host.ConnectionKey(endpoint.Counterparty.ConnectionID) - proofConnection, _ = endpoint.Counterparty.QueryProofAtHeight(connectionKey, proofHeight.GetRevisionHeight()) - - return -} - -// ChanOpenInit will construct and execute a MsgChannelOpenInit on the associated endpoint. -func (endpoint *Endpoint) ChanOpenInit() error { - msg := channeltypes.NewMsgChannelOpenInit( - endpoint.ChannelConfig.PortID, - endpoint.ChannelConfig.Version, endpoint.ChannelConfig.Order, []string{endpoint.ConnectionID}, - endpoint.Counterparty.ChannelConfig.PortID, - endpoint.Chain.SenderAccount.GetAddress().String(), - ) - res, err := endpoint.Chain.SendMsgs(msg) - if err != nil { - return err - } - - endpoint.ChannelID, err = ParseChannelIDFromEvents(res.GetEvents()) - require.NoError(endpoint.Chain.T, err) - - return nil -} - -// ChanOpenTry will construct and execute a MsgChannelOpenTry on the associated endpoint. -func (endpoint *Endpoint) ChanOpenTry() error { - err := endpoint.UpdateClient() - require.NoError(endpoint.Chain.T, err) - - channelKey := host.ChannelKey(endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID) - proof, height := endpoint.Counterparty.Chain.QueryProof(channelKey) - - msg := channeltypes.NewMsgChannelOpenTry( - endpoint.ChannelConfig.PortID, // does not support handshake continuation - endpoint.ChannelConfig.Version, - endpoint.ChannelConfig.Order, - []string{endpoint.ConnectionID}, - endpoint.Counterparty.ChannelConfig.PortID, - endpoint.Counterparty.ChannelID, - endpoint.Counterparty.ChannelConfig.Version, - proof, height, - endpoint.Chain.SenderAccount.GetAddress().String(), - ) - res, err := endpoint.Chain.SendMsgs(msg) - if err != nil { - return err - } - - if endpoint.ChannelID == "" { - endpoint.ChannelID, err = ParseChannelIDFromEvents(res.GetEvents()) - require.NoError(endpoint.Chain.T, err) - } - - // update version to selected app version - // NOTE: this update must be performed after the endpoint channelID is set - endpoint.ChannelConfig.Version = endpoint.GetChannel().Version - - return nil -} - -// ChanOpenAck will construct and execute a MsgChannelOpenAck on the associated endpoint. -func (endpoint *Endpoint) ChanOpenAck() error { - err := endpoint.UpdateClient() - require.NoError(endpoint.Chain.T, err) - - channelKey := host.ChannelKey(endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID) - proof, height := endpoint.Counterparty.Chain.QueryProof(channelKey) - - msg := channeltypes.NewMsgChannelOpenAck( - endpoint.ChannelConfig.PortID, endpoint.ChannelID, - endpoint.Counterparty.ChannelID, endpoint.Counterparty.ChannelConfig.Version, // testing doesn't use flexible selection - proof, height, - endpoint.Chain.SenderAccount.GetAddress().String(), - ) - return endpoint.Chain.sendMsgs(msg) -} - -// ChanOpenConfirm will construct and execute a MsgChannelOpenConfirm on the associated endpoint. -func (endpoint *Endpoint) ChanOpenConfirm() error { - err := endpoint.UpdateClient() - require.NoError(endpoint.Chain.T, err) - - channelKey := host.ChannelKey(endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID) - proof, height := endpoint.Counterparty.Chain.QueryProof(channelKey) - - msg := channeltypes.NewMsgChannelOpenConfirm( - endpoint.ChannelConfig.PortID, endpoint.ChannelID, - proof, height, - endpoint.Chain.SenderAccount.GetAddress().String(), - ) - return endpoint.Chain.sendMsgs(msg) -} - -// ChanCloseInit will construct and execute a MsgChannelCloseInit on the associated endpoint. -// -// NOTE: does not work with ibc-transfer module -func (endpoint *Endpoint) ChanCloseInit() error { - msg := channeltypes.NewMsgChannelCloseInit( - endpoint.ChannelConfig.PortID, endpoint.ChannelID, - endpoint.Chain.SenderAccount.GetAddress().String(), - ) - return endpoint.Chain.sendMsgs(msg) -} - -// SendPacket sends a packet through the channel keeper using the associated endpoint -// The counterparty client is updated so proofs can be sent to the counterparty chain. -func (endpoint *Endpoint) SendPacket(packet exported.PacketI) error { - channelCap := endpoint.Chain.GetChannelCapability(packet.GetSourcePort(), packet.GetSourceChannel()) - - timeoutHeight := clienttypes.Height{ - RevisionNumber: packet.GetTimeoutHeight().GetRevisionNumber(), - RevisionHeight: packet.GetTimeoutHeight().GetRevisionHeight(), - } - - // no need to send message, acting as a module - _, err := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.SendPacket(endpoint.Chain.GetContext(), - channelCap, packet.GetSourcePort(), - packet.GetSourceChannel(), - timeoutHeight, - packet.GetTimeoutTimestamp(), - packet.GetData()) - if err != nil { - return err - } - - // commit changes since no message was sent - endpoint.Chain.Coordinator.CommitBlock(endpoint.Chain) - - return endpoint.Counterparty.UpdateClient() -} - -// RecvPacket receives a packet on the associated endpoint. -// The counterparty client is updated. -func (endpoint *Endpoint) RecvPacket(packet channeltypes.Packet) error { - _, err := endpoint.RecvPacketWithResult(packet) - if err != nil { - return err - } - - return nil -} - -// RecvPacketWithResult receives a packet on the associated endpoint and the result -// of the transaction is returned. The counterparty client is updated. -func (endpoint *Endpoint) RecvPacketWithResult(packet channeltypes.Packet) (*sdk.Result, error) { - // get proof of packet commitment on source - packetKey := host.PacketCommitmentKey(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) - proof, proofHeight := endpoint.Counterparty.Chain.QueryProof(packetKey) - - recvMsg := channeltypes.NewMsgRecvPacket(packet, proof, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String()) - - // receive on counterparty and update source client - res, err := endpoint.Chain.SendMsgs(recvMsg) - if err != nil { - return nil, err - } - - if err := endpoint.Counterparty.UpdateClient(); err != nil { - return nil, err - } - - return res, nil -} - -// WriteAcknowledgement writes an acknowledgement on the channel associated with the endpoint. -// The counterparty client is updated. -func (endpoint *Endpoint) WriteAcknowledgement(ack exported.Acknowledgement, packet exported.PacketI) error { - channelCap := endpoint.Chain.GetChannelCapability(packet.GetDestPort(), packet.GetDestChannel()) - - // no need to send message, acting as a handler - err := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.WriteAcknowledgement(endpoint.Chain.GetContext(), channelCap, packet, ack) - if err != nil { - return err - } - - // commit changes since no message was sent - endpoint.Chain.Coordinator.CommitBlock(endpoint.Chain) - - return endpoint.Counterparty.UpdateClient() -} - -// AcknowledgePacket sends a MsgAcknowledgement to the channel associated with the endpoint. -func (endpoint *Endpoint) AcknowledgePacket(packet channeltypes.Packet, ack []byte) error { - // get proof of acknowledgement on counterparty - packetKey := host.PacketAcknowledgementKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) - proof, proofHeight := endpoint.Counterparty.QueryProof(packetKey) - - ackMsg := channeltypes.NewMsgAcknowledgement(packet, ack, proof, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String()) - - return endpoint.Chain.sendMsgs(ackMsg) -} - -// TimeoutPacket sends a MsgTimeout to the channel associated with the endpoint. -func (endpoint *Endpoint) TimeoutPacket(packet channeltypes.Packet) error { - // get proof for timeout based on channel order - var packetKey []byte - - switch endpoint.ChannelConfig.Order { - case channeltypes.ORDERED: - packetKey = host.NextSequenceRecvKey(packet.GetDestPort(), packet.GetDestChannel()) - case channeltypes.UNORDERED: - packetKey = host.PacketReceiptKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) - default: - return fmt.Errorf("unsupported order type %s", endpoint.ChannelConfig.Order) - } - - proof, proofHeight := endpoint.Counterparty.QueryProof(packetKey) - nextSeqRecv, found := endpoint.Counterparty.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextSequenceRecv(endpoint.Counterparty.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID) - require.True(endpoint.Chain.T, found) - - timeoutMsg := channeltypes.NewMsgTimeout( - packet, nextSeqRecv, - proof, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String(), - ) - - return endpoint.Chain.sendMsgs(timeoutMsg) -} - -// TimeoutOnClose sends a MsgTimeoutOnClose to the channel associated with the endpoint. -func (endpoint *Endpoint) TimeoutOnClose(packet channeltypes.Packet) error { - // get proof for timeout based on channel order - var packetKey []byte - - switch endpoint.ChannelConfig.Order { - case channeltypes.ORDERED: - packetKey = host.NextSequenceRecvKey(packet.GetDestPort(), packet.GetDestChannel()) - case channeltypes.UNORDERED: - packetKey = host.PacketReceiptKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) - default: - return fmt.Errorf("unsupported order type %s", endpoint.ChannelConfig.Order) - } - - proof, proofHeight := endpoint.Counterparty.QueryProof(packetKey) - - channelKey := host.ChannelKey(packet.GetDestPort(), packet.GetDestChannel()) - proofClosed, _ := endpoint.Counterparty.QueryProof(channelKey) - - nextSeqRecv, found := endpoint.Counterparty.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextSequenceRecv(endpoint.Counterparty.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID) - require.True(endpoint.Chain.T, found) - - timeoutOnCloseMsg := channeltypes.NewMsgTimeoutOnClose( - packet, nextSeqRecv, - proof, proofClosed, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String(), - ) - - return endpoint.Chain.sendMsgs(timeoutOnCloseMsg) -} - -// SetChannelClosed sets a channel state to CLOSED. -func (endpoint *Endpoint) SetChannelClosed() error { - channel := endpoint.GetChannel() - - channel.State = channeltypes.CLOSED - endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.SetChannel(endpoint.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID, channel) - - endpoint.Chain.Coordinator.CommitBlock(endpoint.Chain) - - return endpoint.Counterparty.UpdateClient() -} - -// GetClientState retrieves the Client State for this endpoint. The -// client state is expected to exist otherwise testing will fail. -func (endpoint *Endpoint) GetClientState() exported.ClientState { - return endpoint.Chain.GetClientState(endpoint.ClientID) -} - -// SetClientState sets the client state for this endpoint. -func (endpoint *Endpoint) SetClientState(clientState exported.ClientState) { - endpoint.Chain.App.GetIBCKeeper().ClientKeeper.SetClientState(endpoint.Chain.GetContext(), endpoint.ClientID, clientState) -} - -// GetConsensusState retrieves the Consensus State for this endpoint at the provided height. -// The consensus state is expected to exist otherwise testing will fail. -func (endpoint *Endpoint) GetConsensusState(height exported.Height) exported.ConsensusState { - consensusState, found := endpoint.Chain.GetConsensusState(endpoint.ClientID, height) - require.True(endpoint.Chain.T, found) - - return consensusState -} - -// SetConsensusState sets the consensus state for this endpoint. -func (endpoint *Endpoint) SetConsensusState(consensusState exported.ConsensusState, height exported.Height) { - endpoint.Chain.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(endpoint.Chain.GetContext(), endpoint.ClientID, height, consensusState) -} - -// GetConnection retrieves an IBC Connection for the endpoint. The -// connection is expected to exist otherwise testing will fail. -func (endpoint *Endpoint) GetConnection() connectiontypes.ConnectionEnd { - connection, found := endpoint.Chain.App.GetIBCKeeper().ConnectionKeeper.GetConnection(endpoint.Chain.GetContext(), endpoint.ConnectionID) - require.True(endpoint.Chain.T, found) - - return connection -} - -// SetConnection sets the connection for this endpoint. -func (endpoint *Endpoint) SetConnection(connection connectiontypes.ConnectionEnd) { - endpoint.Chain.App.GetIBCKeeper().ConnectionKeeper.SetConnection(endpoint.Chain.GetContext(), endpoint.ConnectionID, connection) -} - -// GetChannel retrieves an IBC Channel for the endpoint. The channel -// is expected to exist otherwise testing will fail. -func (endpoint *Endpoint) GetChannel() channeltypes.Channel { - channel, found := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetChannel(endpoint.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID) - require.True(endpoint.Chain.T, found) - - return channel -} - -// SetChannel sets the channel for this endpoint. -func (endpoint *Endpoint) SetChannel(channel channeltypes.Channel) { - endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.SetChannel(endpoint.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID, channel) -} - -// QueryClientStateProof performs and abci query for a client stat associated -// with this endpoint and returns the ClientState along with the proof. -func (endpoint *Endpoint) QueryClientStateProof() (exported.ClientState, []byte) { - // retrieve client state to provide proof for - clientState := endpoint.GetClientState() - - clientKey := host.FullClientStateKey(endpoint.ClientID) - proofClient, _ := endpoint.QueryProof(clientKey) - - return clientState, proofClient -} diff --git a/legacy_ibc_testing/testing/events.go b/legacy_ibc_testing/testing/events.go deleted file mode 100644 index 4bab444cbb..0000000000 --- a/legacy_ibc_testing/testing/events.go +++ /dev/null @@ -1,79 +0,0 @@ -package testing - -import ( - "fmt" - - clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -/* -TODO: Remove after upgrading to ibc-go v5 -legacy_ibc_testing is temporarily copied into the interchain-security repository for the purpose of testing only. -The integration test suites rely on modifications to ibc-go's test framework that cannot be back-ported to the canonical version that ics will rely on. -These files will be deprecated once ICS is able to upgrade to ibc-go v5. -*/ - -// ParseClientIDFromEvents parses events emitted from a MsgCreateClient and returns the -// client identifier. -func ParseClientIDFromEvents(events sdk.Events) (string, error) { - for _, ev := range events { - if ev.Type == clienttypes.EventTypeCreateClient { - for _, attr := range ev.Attributes { - if attr.Key == clienttypes.AttributeKeyClientID { - return attr.Value, nil - } - } - } - } - return "", fmt.Errorf("client identifier event attribute not found") -} - -// ParseConnectionIDFromEvents parses events emitted from a MsgConnectionOpenInit or -// MsgConnectionOpenTry and returns the connection identifier. -func ParseConnectionIDFromEvents(events sdk.Events) (string, error) { - for _, ev := range events { - if ev.Type == connectiontypes.EventTypeConnectionOpenInit || - ev.Type == connectiontypes.EventTypeConnectionOpenTry { - for _, attr := range ev.Attributes { - if attr.Key == connectiontypes.AttributeKeyConnectionID { - return attr.Value, nil - } - } - } - } - return "", fmt.Errorf("connection identifier event attribute not found") -} - -// ParseChannelIDFromEvents parses events emitted from a MsgChannelOpenInit or -// MsgChannelOpenTry and returns the channel identifier. -func ParseChannelIDFromEvents(events sdk.Events) (string, error) { - for _, ev := range events { - if ev.Type == channeltypes.EventTypeChannelOpenInit || ev.Type == channeltypes.EventTypeChannelOpenTry { - for _, attr := range ev.Attributes { - if attr.Key == channeltypes.AttributeKeyChannelID { - return attr.Value, nil - } - } - } - } - return "", fmt.Errorf("channel identifier event attribute not found") -} - -// ParseAckFromEvents parses events emitted from a MsgRecvPacket and returns the -// acknowledgement. -func ParseAckFromEvents(events sdk.Events) ([]byte, error) { - for _, ev := range events { - if ev.Type == channeltypes.EventTypeWriteAck { - for _, attr := range ev.Attributes { - if attr.Key == channeltypes.AttributeKeyAck { //nolint:staticcheck // data - return []byte(attr.Value), nil - } - } - } - } - return nil, fmt.Errorf("acknowledgement event attribute not found") -} diff --git a/legacy_ibc_testing/testing/path.go b/legacy_ibc_testing/testing/path.go deleted file mode 100644 index 31efe8215d..0000000000 --- a/legacy_ibc_testing/testing/path.go +++ /dev/null @@ -1,99 +0,0 @@ -package testing - -import ( - "bytes" - "fmt" - - channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" -) - -/* -TODO: Remove after upgrading to ibc-go v5 -legacy_ibc_testing is temporarily copied into the interchain-security repository for the purpose of testing only. -The integration test suites rely on modifications to ibc-go's test framework that cannot be back-ported to the canonical version that ics will rely on. -These files will be deprecated once ICS is able to upgrade to ibc-go v5. -*/ - -// Path contains two endpoints representing two chains connected over IBC -type Path struct { - EndpointA *Endpoint - EndpointB *Endpoint -} - -// NewPath constructs an endpoint for each chain using the default values -// for the endpoints. Each endpoint is updated to have a pointer to the -// counterparty endpoint. -func NewPath(chainA, chainB *TestChain) *Path { - endpointA := NewDefaultEndpoint(chainA) - endpointB := NewDefaultEndpoint(chainB) - - endpointA.Counterparty = endpointB - endpointB.Counterparty = endpointA - - return &Path{ - EndpointA: endpointA, - EndpointB: endpointB, - } -} - -// SetChannelOrdered sets the channel order for both endpoints to ORDERED. -func (path *Path) SetChannelOrdered() { - path.EndpointA.ChannelConfig.Order = channeltypes.ORDERED - path.EndpointB.ChannelConfig.Order = channeltypes.ORDERED -} - -// RelayPacket attempts to relay the packet first on EndpointA and then on EndpointB -// if EndpointA does not contain a packet commitment for that packet. An error is returned -// if a relay step fails or the packet commitment does not exist on either endpoint. -func (path *Path) RelayPacket(packet channeltypes.Packet) error { - pc := path.EndpointA.Chain.App.GetIBCKeeper().ChannelKeeper.GetPacketCommitment(path.EndpointA.Chain.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) - if bytes.Equal(pc, channeltypes.CommitPacket(path.EndpointA.Chain.App.AppCodec(), packet)) { - - // packet found, relay from A to B - if err := path.EndpointB.UpdateClient(); err != nil { - return err - } - - res, err := path.EndpointB.RecvPacketWithResult(packet) - if err != nil { - return err - } - - ack, err := ParseAckFromEvents(res.GetEvents()) - if err != nil { - return err - } - - if err := path.EndpointA.AcknowledgePacket(packet, ack); err != nil { - return err - } - - return nil - } - - pc = path.EndpointB.Chain.App.GetIBCKeeper().ChannelKeeper.GetPacketCommitment(path.EndpointB.Chain.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) - if bytes.Equal(pc, channeltypes.CommitPacket(path.EndpointB.Chain.App.AppCodec(), packet)) { - - // packet found, relay B to A - if err := path.EndpointA.UpdateClient(); err != nil { - return err - } - - res, err := path.EndpointA.RecvPacketWithResult(packet) - if err != nil { - return err - } - - ack, err := ParseAckFromEvents(res.GetEvents()) - if err != nil { - return err - } - - if err := path.EndpointB.AcknowledgePacket(packet, ack); err != nil { - return err - } - return nil - } - - return fmt.Errorf("packet commitment does not exist on either endpoint for provided packet") -} diff --git a/legacy_ibc_testing/testing/utils.go b/legacy_ibc_testing/testing/utils.go deleted file mode 100644 index 047793f455..0000000000 --- a/legacy_ibc_testing/testing/utils.go +++ /dev/null @@ -1,32 +0,0 @@ -package testing - -import ( - "testing" - - "github.com/stretchr/testify/require" - - abci "github.com/cometbft/cometbft/abci/types" - tmtypes "github.com/cometbft/cometbft/types" -) - -/* -TODO: Remove after upgrading to ibc-go v5 -legacy_ibc_testing is temporarily copied into the interchain-security repository for the purpose of testing only. -The integration test suites rely on modifications to ibc-go's test framework that cannot be back-ported to the canonical version that ics will rely on. -These files will be deprecated once ICS is able to upgrade to ibc-go v5. -*/ - -// ApplyValSetChanges takes in tmtypes.ValidatorSet and []abci.ValidatorUpdate and will return a new tmtypes.ValidatorSet which has the -// provided validator updates applied to the provided validator set. -func ApplyValSetChanges(t *testing.T, valSet *tmtypes.ValidatorSet, valUpdates []abci.ValidatorUpdate) *tmtypes.ValidatorSet { - t.Helper() - updates, err := tmtypes.PB2TM.ValidatorUpdates(valUpdates) - require.NoError(t, err) - - // must copy since validator set will mutate with UpdateWithChangeSet - newVals := valSet.Copy() - err = newVals.UpdateWithChangeSet(updates) - require.NoError(t, err) - - return newVals -} diff --git a/legacy_ibc_testing/testing/values.go b/legacy_ibc_testing/testing/values.go deleted file mode 100644 index 579d00cea4..0000000000 --- a/legacy_ibc_testing/testing/values.go +++ /dev/null @@ -1,53 +0,0 @@ -package testing - -import ( - "time" - - ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" - connectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" - ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - "github.com/cosmos/ibc-go/v7/testing/mock" -) - -/* -TODO: Remove after upgrading to ibc-go v5 -legacy_ibc_testing is temporarily copied into the interchain-security repository for the purpose of testing only. -The integration test suites rely on modifications to ibc-go's test framework that cannot be back-ported to the canonical version that ics will rely on. -These files will be deprecated once ICS is able to upgrade to ibc-go v5. -*/ - -const ( - FirstChannelID = "channel-0" - FirstConnectionID = "connection-0" - - // Default params constants used to create a TM client - TrustingPeriod time.Duration = time.Hour * 24 * 7 * 2 - UnbondingPeriod time.Duration = time.Hour * 24 * 7 * 3 - MaxClockDrift time.Duration = time.Second * 10 - DefaultDelayPeriod uint64 = 0 - - DefaultChannelVersion = mock.Version - InvalidID = "IDisInvalid" - - // Application Ports - TransferPort = ibctransfertypes.ModuleName - MockPort = mock.ModuleName - - // used for testing proposals - Title = "title" - Description = "description" -) - -var ( - DefaultOpenInitVersion *connectiontypes.Version - - // Default params variables used to create a TM client - DefaultTrustLevel ibctmtypes.Fraction = ibctmtypes.DefaultTrustLevel - - UpgradePath = []string{"upgrade", "upgradedIBCState"} - - ConnectionVersion = connectiontypes.ExportedVersionsToProto(connectiontypes.GetCompatibleVersions())[0] - - MockAcknowledgement = mock.MockAcknowledgement.Acknowledgement() - MockPacketData = mock.MockPacketData -) diff --git a/tests/difference/core/driver/core_test.go b/tests/difference/core/driver/core_test.go index ec97fbf9c1..2d42e65dba 100644 --- a/tests/difference/core/driver/core_test.go +++ b/tests/difference/core/driver/core_test.go @@ -4,7 +4,7 @@ import ( "fmt" "time" - channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v7/testing" "github.com/stretchr/testify/suite" sdk "github.com/cosmos/cosmos-sdk/types" @@ -14,8 +14,6 @@ import ( appConsumer "github.com/cosmos/interchain-security/v3/app/consumer" appProvider "github.com/cosmos/interchain-security/v3/app/provider" - ibctestingcore "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/core" - ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" simibc "github.com/cosmos/interchain-security/v3/testutil/simibc" consumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" ) @@ -184,13 +182,10 @@ func (s *CoreSuite) consumerSlash(val sdk.ConsAddress, h int64, isDowntime bool) before := len(ctx.EventManager().Events()) s.consumerKeeper().SlashWithInfractionReason(ctx, val, h, 0, sdk.Dec{}, kind) // consumer module emits packets on slash, so these must be collected. - evts := ctx.EventManager().ABCIEvents() - for _, e := range evts[before:] { - if e.Type == channeltypes.EventTypeSendPacket { - packet, err := ibctestingcore.ReconstructPacketFromEvent(e) - s.Require().NoError(err) - s.simibc.Outboxes.AddPacket(s.chainID(C), packet) - } + evts := ctx.EventManager().Events() + packets := simibc.ParsePacketsFromEvents(evts[before:]) + if len(packets) > 0 { + s.simibc.Outboxes.AddPacket(s.chainID(C), packets[0]) } } diff --git a/tests/difference/core/driver/setup.go b/tests/difference/core/driver/setup.go index 9ca6d00b9f..2a4b17eddf 100644 --- a/tests/difference/core/driver/setup.go +++ b/tests/difference/core/driver/setup.go @@ -10,6 +10,7 @@ import ( channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + ibctesting "github.com/cosmos/ibc-go/v7/testing" "github.com/cosmos/ibc-go/v7/testing/mock" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" @@ -33,8 +34,8 @@ import ( appConsumer "github.com/cosmos/interchain-security/v3/app/consumer" appProvider "github.com/cosmos/interchain-security/v3/app/provider" - ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" icstestingutils "github.com/cosmos/interchain-security/v3/testutil/ibc_testing" + testutil "github.com/cosmos/interchain-security/v3/testutil/integration" simibc "github.com/cosmos/interchain-security/v3/testutil/simibc" consumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" @@ -252,7 +253,7 @@ func (b *Builder) getAppBytesAndSenders( func (b *Builder) newChain( coord *ibctesting.Coordinator, - appInit ibctesting.AppIniter, + appInit icstestingutils.AppIniter, chainID string, validators *tmtypes.ValidatorSet, signers map[string]tmtypes.PrivValidator, @@ -349,7 +350,8 @@ func (b *Builder) createProviderAndConsumer() { // Create provider coordinator.Chains[ibctesting.GetChainID(0)] = b.newChain(coordinator, icstestingutils.ProviderAppIniter, ibctesting.GetChainID(0), validators, signers) // Create consumer, using the same validators. - coordinator.Chains[ibctesting.GetChainID(1)] = b.newChain(coordinator, icstestingutils.ConsumerAppIniter, ibctesting.GetChainID(1), validators, signers) + valUpdates := testutil.ToValidatorUpdates(b.suite.T(), validators) + coordinator.Chains[ibctesting.GetChainID(1)] = b.newChain(coordinator, icstestingutils.ConsumerAppIniter(valUpdates), ibctesting.GetChainID(1), validators, signers) b.coordinator = coordinator b.valAddresses = addresses diff --git a/tests/integration/common.go b/tests/integration/common.go index 7d5175d5d7..a638c73fc2 100644 --- a/tests/integration/common.go +++ b/tests/integration/common.go @@ -9,6 +9,7 @@ import ( commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" "github.com/cosmos/ibc-go/v7/modules/core/exported" ibctm "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + ibctesting "github.com/cosmos/ibc-go/v7/testing" "github.com/stretchr/testify/require" "cosmossdk.io/math" @@ -21,7 +22,6 @@ import ( abci "github.com/cometbft/cometbft/abci/types" tmtypes "github.com/cometbft/cometbft/types" - ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" icstestingutils "github.com/cosmos/interchain-security/v3/testutil/ibc_testing" testutil "github.com/cosmos/interchain-security/v3/testutil/integration" providertypes "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" @@ -215,20 +215,42 @@ func redelegate(s *CCVTestSuite, delAddr sdk.AccAddress, valSrcAddr sdk.ValAddre } } +func (s *CCVTestSuite) newPacketFromProvider(data []byte, sequence uint64, path *ibctesting.Path, timeoutHeight clienttypes.Height, timeoutTimestamp uint64) channeltypes.Packet { + return channeltypes.NewPacket(data, sequence, + path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, + path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, + timeoutHeight, timeoutTimestamp) +} + +func (s *CCVTestSuite) newPacketFromConsumer(data []byte, sequence uint64, path *ibctesting.Path, timeoutHeight clienttypes.Height, timeoutTimestamp uint64) channeltypes.Packet { + return channeltypes.NewPacket(data, sequence, + path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, + path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, + timeoutHeight, timeoutTimestamp) +} + // sendOnProviderRecvOnConsumer sends a packet from the provider chain and receives it on the consumer chain -func sendOnProviderRecvOnConsumer(s *CCVTestSuite, path *ibctesting.Path, packet channeltypes.Packet) { - err := path.EndpointB.SendPacket(packet) +func sendOnProviderRecvOnConsumer(s *CCVTestSuite, path *ibctesting.Path, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, data []byte) channeltypes.Packet { + sequence, err := path.EndpointB.SendPacket(timeoutHeight, timeoutTimestamp, data) s.Require().NoError(err) + + packet := s.newPacketFromProvider(data, sequence, path, timeoutHeight, timeoutTimestamp) + err = path.EndpointA.RecvPacket(packet) s.Require().NoError(err) + return packet } // sendOnConsumerRecvOnProvider sends a packet from the consumer chain and receives it on the provider chain -func sendOnConsumerRecvOnProvider(s *CCVTestSuite, path *ibctesting.Path, packet channeltypes.Packet) { - err := path.EndpointA.SendPacket(packet) +func sendOnConsumerRecvOnProvider(s *CCVTestSuite, path *ibctesting.Path, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, data []byte) channeltypes.Packet { + sequence, err := path.EndpointA.SendPacket(timeoutHeight, timeoutTimestamp, data) s.Require().NoError(err) + + packet := s.newPacketFromConsumer(data, sequence, path, timeoutHeight, timeoutTimestamp) + err = path.EndpointB.RecvPacket(packet) s.Require().NoError(err) + return packet } // relayAllCommittedPackets relays all committed packets from `srcChain` on `path` @@ -256,7 +278,7 @@ func relayAllCommittedPackets( // relay all packets from srcChain to counterparty for _, commitment := range commitments { // - get packets - packet, found := srcChain.GetSentPacket(commitment.Sequence, srcChannelID) + packet, found := s.getSentPacket(srcChain, commitment.Sequence, srcChannelID) s.Require().True( found, fmt.Sprintf("did not find sent packet; %s", msgAndArgs...), @@ -278,7 +300,7 @@ func relayAllCommittedPackets( // to be one day larger than the consumer unbonding period. func incrementTimeByUnbondingPeriod(s *CCVTestSuite, chainType ChainType) { // Get unboding periods - providerUnbondingPeriod := s.providerApp.GetStakingKeeper().UnbondingTime(s.providerCtx()) + providerUnbondingPeriod := s.providerApp.GetTestStakingKeeper().UnbondingTime(s.providerCtx()) consumerUnbondingPeriod := s.consumerApp.GetConsumerKeeper().GetUnbondingPeriod(s.consumerCtx()) var jumpPeriod time.Duration if chainType == Provider { @@ -374,14 +396,7 @@ func (suite *CCVTestSuite) SendEmptyVSCPacket() { nil, ) - seq, ok := suite.providerApp.GetIBCKeeper().ChannelKeeper.GetNextSequenceSend( - suite.providerChain.GetContext(), ccv.ProviderPortID, suite.path.EndpointB.ChannelID) - suite.Require().True(ok) - - packet := channeltypes.NewPacket(pd.GetBytes(), seq, ccv.ProviderPortID, suite.path.EndpointB.ChannelID, - ccv.ConsumerPortID, suite.path.EndpointA.ChannelID, clienttypes.Height{}, timeout) - - sendOnProviderRecvOnConsumer(suite, suite.getFirstBundle().Path, packet) + sendOnProviderRecvOnConsumer(suite, suite.getFirstBundle().Path, clienttypes.Height{}, timeout, pd.GetBytes()) } // commitSlashPacket returns a commit hash for the given slash packet data @@ -403,8 +418,7 @@ func (suite *CCVTestSuite) commitConsumerPacket(ctx sdk.Context, packetData ccv. oldBlockTime := ctx.BlockTime() timeout := uint64(oldBlockTime.Add(ccv.DefaultCCVTimeoutPeriod).UnixNano()) - packet := channeltypes.NewPacket(packetData.GetBytes(), 1, ccv.ConsumerPortID, suite.path.EndpointA.ChannelID, - ccv.ProviderPortID, suite.path.EndpointB.ChannelID, clienttypes.Height{}, timeout) + packet := suite.newPacketFromConsumer(packetData.GetBytes(), 1, suite.path, clienttypes.Height{}, timeout) return channeltypes.CommitPacket(suite.consumerChain.App.AppCodec(), packet) } @@ -412,12 +426,12 @@ func (suite *CCVTestSuite) commitConsumerPacket(ctx sdk.Context, packetData ccv. // constructSlashPacketFromConsumer constructs an IBC packet embedding // slash packet data to be sent from consumer to provider func (s *CCVTestSuite) constructSlashPacketFromConsumer(bundle icstestingutils.ConsumerBundle, - tmVal tmtypes.Validator, infractionType stakingtypes.Infraction, ibcSeqNum uint64, -) channeltypes.Packet { + tmVal tmtypes.Validator, infractionType stakingtypes.Infraction, +) ccv.ConsumerPacketData { valsetUpdateId := bundle.GetKeeper().GetHeightValsetUpdateID( bundle.GetCtx(), uint64(bundle.GetCtx().BlockHeight())) - data := ccv.ConsumerPacketData{ + return ccv.ConsumerPacketData{ Type: ccv.SlashPacket, Data: &ccv.ConsumerPacketData_SlashPacketData{ SlashPacketData: &ccv.SlashPacketData{ @@ -430,42 +444,20 @@ func (s *CCVTestSuite) constructSlashPacketFromConsumer(bundle icstestingutils.C }, }, } - - return channeltypes.NewPacket(data.GetBytes(), - ibcSeqNum, - ccv.ConsumerPortID, // Src port - bundle.Path.EndpointA.ChannelID, // Src channel - ccv.ProviderPortID, // Dst port - bundle.Path.EndpointB.ChannelID, // Dst channel - clienttypes.Height{}, - uint64(bundle.GetCtx().BlockTime().Add(ccv.DefaultCCVTimeoutPeriod).UnixNano()), - ) } // constructVSCMaturedPacketFromConsumer constructs an IBC packet embedding // VSC Matured packet data to be sent from consumer to provider -func (s *CCVTestSuite) constructVSCMaturedPacketFromConsumer(bundle icstestingutils.ConsumerBundle, - ibcSeqNum uint64, -) channeltypes.Packet { +func (s *CCVTestSuite) constructVSCMaturedPacketFromConsumer(bundle icstestingutils.ConsumerBundle) ccv.ConsumerPacketData { valsetUpdateId := bundle.GetKeeper().GetHeightValsetUpdateID( bundle.GetCtx(), uint64(bundle.GetCtx().BlockHeight())) - data := ccv.ConsumerPacketData{ + return ccv.ConsumerPacketData{ Type: ccv.VscMaturedPacket, Data: &ccv.ConsumerPacketData_VscMaturedPacketData{ VscMaturedPacketData: &ccv.VSCMaturedPacketData{ValsetUpdateId: valsetUpdateId}, }, } - - return channeltypes.NewPacket(data.GetBytes(), - ibcSeqNum, - ccv.ConsumerPortID, // Src port - bundle.Path.EndpointA.ChannelID, // Src channel - ccv.ProviderPortID, // Dst port - bundle.Path.EndpointB.ChannelID, // Dst channel - clienttypes.Height{}, - uint64(bundle.GetCtx().BlockTime().Add(ccv.DefaultCCVTimeoutPeriod).UnixNano()), - ) } // incrementTime increments the overall time by jumpPeriod diff --git a/tests/integration/democracy.go b/tests/integration/democracy.go index 461cfec3b3..56cfcea02c 100644 --- a/tests/integration/democracy.go +++ b/tests/integration/democracy.go @@ -1,9 +1,9 @@ package integration import ( - "testing" "time" + ibctesting "github.com/cosmos/ibc-go/v7/testing" "github.com/stretchr/testify/suite" "cosmossdk.io/math" @@ -14,7 +14,6 @@ import ( govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" - ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" icstestingutils "github.com/cosmos/interchain-security/v3/testutil/ibc_testing" testutil "github.com/cosmos/interchain-security/v3/testutil/integration" consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" @@ -31,22 +30,22 @@ type ConsumerDemocracyTestSuite struct { // NewCCVTestSuite returns a new instance of ConsumerDemocracyTestSuite, // ready to be tested against using suite.Run(). func NewConsumerDemocracyTestSuite[T testutil.DemocConsumerApp]( - democConsumerAppIniter ibctesting.AppIniter, + democConsumerAppIniter icstestingutils.ValSetAppIniter, ) *ConsumerDemocracyTestSuite { democSuite := new(ConsumerDemocracyTestSuite) - democSuite.setupCallback = func(t *testing.T) ( + democSuite.setupCallback = func(s *suite.Suite) ( *ibctesting.Coordinator, *ibctesting.TestChain, testutil.DemocConsumerApp, ) { - t.Helper() + s.T().Helper() // Instantiate the test coordinator - coordinator := ibctesting.NewCoordinator(t, 0) + coordinator := ibctesting.NewCoordinator(s.T(), 0) // Add single democracy consumer to coordinator, store returned test chain and app. democConsumer, democConsumerApp := icstestingutils.AddDemocracyConsumer[T]( - t, coordinator, democConsumerAppIniter) + coordinator, s, democConsumerAppIniter) // Pass variables to suite. return coordinator, democConsumer, democConsumerApp @@ -56,7 +55,7 @@ func NewConsumerDemocracyTestSuite[T testutil.DemocConsumerApp]( // Callback for instantiating a new coordinator, consumer test chain, and consumer app // before every test defined on the suite. -type DemocSetupCallback func(t *testing.T) ( +type DemocSetupCallback func(s *suite.Suite) ( coord *ibctesting.Coordinator, consumerChain *ibctesting.TestChain, consumerApp testutil.DemocConsumerApp, @@ -66,7 +65,7 @@ type DemocSetupCallback func(t *testing.T) ( func (suite *ConsumerDemocracyTestSuite) SetupTest() { // Instantiate new test utils using callback suite.coordinator, suite.consumerChain, - suite.consumerApp = suite.setupCallback(suite.T()) + suite.consumerApp = suite.setupCallback(&suite.Suite) } func (s *ConsumerDemocracyTestSuite) TestDemocracyRewardsDistribution() { diff --git a/tests/integration/expired_client.go b/tests/integration/expired_client.go index 2a8babacfa..f196f16ce1 100644 --- a/tests/integration/expired_client.go +++ b/tests/integration/expired_client.go @@ -6,6 +6,7 @@ import ( clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" ibctm "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + ibctesting "github.com/cosmos/ibc-go/v7/testing" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" sdk "github.com/cosmos/cosmos-sdk/types" @@ -13,7 +14,6 @@ import ( abci "github.com/cometbft/cometbft/abci/types" - ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) diff --git a/tests/integration/setup.go b/tests/integration/setup.go index 61cb8a96c9..76f6311dab 100644 --- a/tests/integration/setup.go +++ b/tests/integration/setup.go @@ -1,21 +1,28 @@ package integration import ( + "context" + "fmt" + "sync" "testing" transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/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" + ibctesting "github.com/cosmos/ibc-go/v7/testing" "github.com/cosmos/ibc-go/v7/testing/mock" "github.com/stretchr/testify/suite" + "github.com/cosmos/cosmos-sdk/baseapp" + store "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" + abci "github.com/cometbft/cometbft/abci/types" tmencoding "github.com/cometbft/cometbft/crypto/encoding" - ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" icstestingutils "github.com/cosmos/interchain-security/v3/testutil/ibc_testing" testutil "github.com/cosmos/interchain-security/v3/testutil/integration" + "github.com/cosmos/interchain-security/v3/testutil/simibc" ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" ) @@ -58,11 +65,16 @@ type CCVTestSuite struct { // The preferred way to access chains, apps, and paths when designing tests around multiple consumers. consumerBundles map[string]*icstestingutils.ConsumerBundle skippedTests map[string]bool + + // packetSniffers maps a chain and a packetSniffer + packetSniffers map[*ibctesting.TestChain]*packetSniffer } // NewCCVTestSuite returns a new instance of CCVTestSuite, ready to be tested against using suite.Run(). func NewCCVTestSuite[Tp testutil.ProviderApp, Tc testutil.ConsumerApp]( - providerAppIniter, consumerAppIniter ibctesting.AppIniter, skippedTests []string, + providerAppIniter icstestingutils.AppIniter, + consumerAppIniter icstestingutils.ValSetAppIniter, + skippedTests []string, ) *CCVTestSuite { ccvSuite := new(CCVTestSuite) @@ -107,9 +119,12 @@ func (suite *CCVTestSuite) BeforeTest(suiteName, testName string) { // SetupTest sets up in-mem state before every test func (suite *CCVTestSuite) SetupTest() { + suite.packetSniffers = make(map[*ibctesting.TestChain]*packetSniffer) + // Instantiate new coordinator and provider chain using callback suite.coordinator, suite.providerChain, suite.providerApp = suite.setupProviderCallback(suite.T()) + suite.registerPacketSniffer(suite.providerChain) providerKeeper := suite.providerApp.GetProviderKeeper() // re-assign all validator keys for the first consumer chain @@ -121,6 +136,7 @@ func (suite *CCVTestSuite) SetupTest() { for i := 0; i < numConsumers; i++ { bundle := suite.setupConsumerCallback(&suite.Suite, suite.coordinator, i) suite.consumerBundles[bundle.Chain.ChainID] = bundle + suite.registerPacketSniffer(bundle.Chain) } // initialize each consumer chain with it's corresponding genesis state @@ -147,6 +163,21 @@ func (suite *CCVTestSuite) SetupTest() { } } +func (s *CCVTestSuite) registerPacketSniffer(chain *ibctesting.TestChain) { + if s.packetSniffers == nil { + s.packetSniffers = make(map[*ibctesting.TestChain]*packetSniffer) + } + p := newPacketSniffer() + chain.App.GetBaseApp().SetStreamingService(p) + s.packetSniffers[chain] = p +} + +func (s *CCVTestSuite) getSentPacket(chain *ibctesting.TestChain, sequence uint64, channelID string) (packet channeltypes.Packet, found bool) { + key := getSentPacketKey(sequence, channelID) + packet, found = s.packetSniffers[chain].packets[key] + return +} + // initConsumerChain initializes a consumer chain given a genesis state func initConsumerChain( s *CCVTestSuite, @@ -292,7 +323,7 @@ func (suite *CCVTestSuite) SetupTransferChannel() { func (s CCVTestSuite) validateEndpointsClientConfig(consumerBundle icstestingutils.ConsumerBundle) { //nolint:govet // this is a test so we can copy locks consumerKeeper := consumerBundle.GetKeeper() - providerStakingKeeper := s.providerApp.GetStakingKeeper() + providerStakingKeeper := s.providerApp.GetTestStakingKeeper() consumerUnbondingPeriod := consumerKeeper.GetUnbondingPeriod(consumerBundle.GetCtx()) cs, ok := s.providerApp.GetIBCKeeper().ClientKeeper.GetClientState(s.providerCtx(), @@ -342,3 +373,46 @@ func preProposalKeyAssignment(s *CCVTestSuite, chainID string) { s.Require().NoError(err) } } + +// packetSniffer implements the StreamingService interface. +// Implements ListenEndBlock to record packets from events. +type packetSniffer struct { + packets map[string]channeltypes.Packet +} + +var _ baseapp.StreamingService = &packetSniffer{} + +func newPacketSniffer() *packetSniffer { + return &packetSniffer{ + packets: make(map[string]channeltypes.Packet), + } +} + +func (ps *packetSniffer) ListenEndBlock(ctx context.Context, req abci.RequestEndBlock, res abci.ResponseEndBlock) error { + packets := simibc.ParsePacketsFromEvents(simibc.ABCIToSDKEvents(res.GetEvents())) + for _, packet := range packets { + ps.packets[getSentPacketKey(packet.Sequence, packet.SourceChannel)] = packet + } + return nil +} + +// getSentPacketKey returns a key for accessing a sent packet, +// given an ibc sequence number and the channel ID for the source endpoint. +func getSentPacketKey(sequence uint64, channelID string) string { + return fmt.Sprintf("%s-%d", channelID, sequence) +} + +func (*packetSniffer) ListenBeginBlock(ctx context.Context, req abci.RequestBeginBlock, res abci.ResponseBeginBlock) error { + return nil +} + +func (*packetSniffer) ListenCommit(ctx context.Context, res abci.ResponseCommit) error { + return nil +} + +func (*packetSniffer) ListenDeliverTx(ctx context.Context, req abci.RequestDeliverTx, res abci.ResponseDeliverTx) error { + return nil +} +func (*packetSniffer) Close() error { return nil } +func (*packetSniffer) Listeners() map[store.StoreKey][]store.WriteListener { return nil } +func (*packetSniffer) Stream(wg *sync.WaitGroup) error { return nil } diff --git a/tests/integration/slashing.go b/tests/integration/slashing.go index 1ce7d11db8..f1be51d33c 100644 --- a/tests/integration/slashing.go +++ b/tests/integration/slashing.go @@ -68,8 +68,12 @@ func (s *CCVTestSuite) TestRelayAndApplyDowntimePacket() { s.setDefaultValSigningInfo(*tmtypes.NewValidator(tmPk, stakingVal.ConsensusPower(sdk.DefaultPowerReduction))) // Send slash packet from the first consumer chain - packet := s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmVal, stakingtypes.Infraction_INFRACTION_DOWNTIME, 1) - err = s.getFirstBundle().Path.EndpointA.SendPacket(packet) + var ( + timeoutHeight = clienttypes.Height{} + timeoutTimestamp = uint64(s.getFirstBundle().GetCtx().BlockTime().Add(ccv.DefaultCCVTimeoutPeriod).UnixNano()) + ) + slashPacket := s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmVal, stakingtypes.Infraction_INFRACTION_DOWNTIME) + sequence, err := s.getFirstBundle().Path.EndpointA.SendPacket(timeoutHeight, timeoutTimestamp, slashPacket.GetBytes()) s.Require().NoError(err) // Set outstanding slashing flag for first consumer, it's important to use the consumer's cons addr here @@ -86,6 +90,7 @@ func (s *CCVTestSuite) TestRelayAndApplyDowntimePacket() { valsetUpdateIdN := providerKeeper.GetValidatorSetUpdateId(s.providerCtx()) // receive the slash packet on the provider chain. RecvPacket() calls the provider endblocker twice + packet := s.newPacketFromConsumer(slashPacket.GetBytes(), sequence, s.getFirstBundle().Path, timeoutHeight, timeoutTimestamp) err = s.path.EndpointB.RecvPacket(packet) s.Require().NoError(err) @@ -196,13 +201,12 @@ func (s *CCVTestSuite) TestRelayAndApplyDoubleSignPacket() { s.setDefaultValSigningInfo(*tmtypes.NewValidator(tmPk, stakingVal.ConsensusPower(sdk.DefaultPowerReduction))) // Send slash packet from the first consumer chain - packet := s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmVal, stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN, 1) - err = s.getFirstBundle().Path.EndpointA.SendPacket(packet) - s.Require().NoError(err) - - // receive the slash packet on the provider chain. RecvPacket() advances two blocks - err = s.path.EndpointB.RecvPacket(packet) - s.Require().NoError(err) + var ( + timeoutHeight = clienttypes.Height{} + timeoutTimestamp = uint64(s.getFirstBundle().GetCtx().BlockTime().Add(ccv.DefaultCCVTimeoutPeriod).UnixNano()) + ) + slashPacket := s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmVal, stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN) + packet := sendOnConsumerRecvOnProvider(s, s.getFirstBundle().Path, timeoutHeight, timeoutTimestamp, slashPacket.GetBytes()) // Advance a few more blocks to make sure any voting power changes would be reflected s.providerChain.NextBlock() @@ -259,9 +263,8 @@ func (s *CCVTestSuite) TestSlashPacketAcknowledgement() { SlashPacketData: &spd, }, ) - packet := channeltypes.NewPacket(cpd.GetBytes(), // Consumer always sends v1 packet data - 1, ccv.ConsumerPortID, s.path.EndpointA.ChannelID, - ccv.ProviderPortID, s.path.EndpointB.ChannelID, clienttypes.Height{}, 0) + packet := s.newPacketFromConsumer(cpd.GetBytes(), // Consumer always sends v1 packet data + 1, s.path, clienttypes.Height{}, 0) // Map infraction height on provider so validation passes and provider returns valid ack result providerKeeper.SetValsetUpdateBlockHeight(s.providerCtx(), spd.ValsetUpdateId, 47923) diff --git a/tests/integration/throttle.go b/tests/integration/throttle.go index 0505d6257a..7c83529262 100644 --- a/tests/integration/throttle.go +++ b/tests/integration/throttle.go @@ -3,7 +3,7 @@ package integration import ( "time" - channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" @@ -59,12 +59,16 @@ func (s *CCVTestSuite) TestBasicSlashPacketThrottling() { for _, val := range vals { s.Require().False(val.IsJailed()) } + var ( + timeoutHeight = clienttypes.Height{} + timeoutTimestamp = uint64(s.getFirstBundle().GetCtx().BlockTime().Add(ccvtypes.DefaultCCVTimeoutPeriod).UnixNano()) + ) // Send a slash packet from consumer to provider s.setDefaultValSigningInfo(*s.providerChain.Vals.Validators[0]) tmVal := s.providerChain.Vals.Validators[0] - packet := s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmVal, stakingtypes.Infraction_INFRACTION_DOWNTIME, 1) - sendOnConsumerRecvOnProvider(s, s.getFirstBundle().Path, packet) + slashPacket := s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmVal, stakingtypes.Infraction_INFRACTION_DOWNTIME) + sendOnConsumerRecvOnProvider(s, s.getFirstBundle().Path, timeoutHeight, timeoutTimestamp, slashPacket.GetBytes()) // Assert validator 0 is jailed and has no power vals = providerStakingKeeper.GetAllValidators(s.providerCtx()) @@ -82,8 +86,8 @@ func (s *CCVTestSuite) TestBasicSlashPacketThrottling() { // Now send a second slash packet from consumer to provider for a different validator. s.setDefaultValSigningInfo(*s.providerChain.Vals.Validators[2]) tmVal = s.providerChain.Vals.Validators[2] - packet = s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmVal, stakingtypes.Infraction_INFRACTION_DOWNTIME, 2) - sendOnConsumerRecvOnProvider(s, s.getFirstBundle().Path, packet) + slashPacket = s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmVal, stakingtypes.Infraction_INFRACTION_DOWNTIME) + sendOnConsumerRecvOnProvider(s, s.getFirstBundle().Path, timeoutHeight, timeoutTimestamp, slashPacket.GetBytes()) // Require that slash packet has not been handled vals = providerStakingKeeper.GetAllValidators(s.providerCtx()) @@ -163,11 +167,15 @@ func (s *CCVTestSuite) TestMultiConsumerSlashPacketThrottling() { // when no slash packets are sent. // Send 2 VSC matured packets from every consumer to provider + var ( + timeoutHeight = clienttypes.Height{} + timeoutTimestamp = uint64(s.getFirstBundle().GetCtx().BlockTime().Add(ccvtypes.DefaultCCVTimeoutPeriod).UnixNano()) + ) for consumerChainID, bundle := range s.consumerBundles { - packet := s.constructVSCMaturedPacketFromConsumer(*bundle, 1) // use sequence 1 - sendOnConsumerRecvOnProvider(s, bundle.Path, packet) - packet = s.constructVSCMaturedPacketFromConsumer(*bundle, 2) // use sequence 2 - sendOnConsumerRecvOnProvider(s, bundle.Path, packet) + slashPacket := s.constructVSCMaturedPacketFromConsumer(*bundle) + sendOnConsumerRecvOnProvider(s, bundle.Path, timeoutHeight, timeoutTimestamp, slashPacket.GetBytes()) + slashPacket = s.constructVSCMaturedPacketFromConsumer(*bundle) + sendOnConsumerRecvOnProvider(s, bundle.Path, timeoutHeight, timeoutTimestamp, slashPacket.GetBytes()) // Confirm packets were not queued on provider for this consumer s.Require().Equal(uint64(0), providerKeeper.GetThrottledPacketDataSize(s.providerCtx(), consumerChainID)) @@ -196,19 +204,18 @@ func (s *CCVTestSuite) TestMultiConsumerSlashPacketThrottling() { // Send downtime slash packet from consumer to provider tmVal := s.providerChain.Vals.Validators[idx] valsToSlash = append(valsToSlash, *tmVal) - packet := s.constructSlashPacketFromConsumer( + slashPacket := s.constructSlashPacketFromConsumer( *bundle, *tmVal, stakingtypes.Infraction_INFRACTION_DOWNTIME, - 3, // use sequence 3, 1 and 2 are used above. ) - sendOnConsumerRecvOnProvider(s, bundle.Path, packet) + sendOnConsumerRecvOnProvider(s, bundle.Path, timeoutHeight, timeoutTimestamp, slashPacket.GetBytes()) // Send two trailing VSC matured packets from consumer to provider - packet = s.constructVSCMaturedPacketFromConsumer(*bundle, 4) // use sequence 4 - sendOnConsumerRecvOnProvider(s, bundle.Path, packet) - packet = s.constructVSCMaturedPacketFromConsumer(*bundle, 5) // use sequence 5 - sendOnConsumerRecvOnProvider(s, bundle.Path, packet) + slashPacket = s.constructVSCMaturedPacketFromConsumer(*bundle) + sendOnConsumerRecvOnProvider(s, bundle.Path, timeoutHeight, timeoutTimestamp, slashPacket.GetBytes()) + slashPacket = s.constructVSCMaturedPacketFromConsumer(*bundle) + sendOnConsumerRecvOnProvider(s, bundle.Path, timeoutHeight, timeoutTimestamp, slashPacket.GetBytes()) idx++ } @@ -287,8 +294,8 @@ func (s *CCVTestSuite) TestPacketSpam() { providerKeeper.SetParams(s.providerCtx(), params) providerKeeper.InitializeSlashMeter(s.providerCtx()) - // The packets to be recv in a single block, ordered as they will be recv. - packets := []channeltypes.Packet{} + // The packets data to be recv in a single block, ordered as they will be recv. + var packetsData [][]byte firstBundle := s.getFirstBundle() @@ -312,13 +319,19 @@ func (s *CCVTestSuite) TestPacketSpam() { infractionType = stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN } valToJail := s.providerChain.Vals.Validators[ibcSeqNum%3] - packets = append(packets, s.constructSlashPacketFromConsumer(firstBundle, *valToJail, infractionType, ibcSeqNum)) + slashPacket := s.constructSlashPacketFromConsumer(firstBundle, *valToJail, infractionType) + packetsData = append(packetsData, slashPacket.GetBytes()) } // Recv 500 packets from consumer to provider in same block - for _, packet := range packets { - consumerPacketData, err := provider.UnmarshalConsumerPacket(packet) // Same func used by provider's OnRecvPacket + var ( + timeoutHeight = clienttypes.Height{} + timeoutTimestamp = uint64(firstBundle.GetCtx().BlockTime().Add(ccvtypes.DefaultCCVTimeoutPeriod).UnixNano()) + ) + for sequence, data := range packetsData { + consumerPacketData, err := provider.UnmarshalConsumerPacketData(data) // Same func used by provider's OnRecvPacket s.Require().NoError(err) + packet := s.newPacketFromConsumer(data, uint64(sequence), firstBundle.Path, timeoutHeight, timeoutTimestamp) providerKeeper.OnRecvSlashPacket(s.providerCtx(), packet, *consumerPacketData.GetSlashPacketData()) } @@ -349,8 +362,8 @@ func (s *CCVTestSuite) TestDoubleSignDoesNotAffectThrottling() { providerKeeper.SetParams(s.providerCtx(), params) providerKeeper.InitializeSlashMeter(s.providerCtx()) - // The packets to be recv in a single block, ordered as they will be recv. - packets := []channeltypes.Packet{} + // The packetsData to be recv in a single block, ordered as they will be recv. + var packetsData [][]byte firstBundle := s.getFirstBundle() @@ -366,13 +379,19 @@ func (s *CCVTestSuite) TestDoubleSignDoesNotAffectThrottling() { // Increment ibc seq num for each packet (starting at 1) ibcSeqNum++ valToJail := s.providerChain.Vals.Validators[ibcSeqNum%3] - packets = append(packets, s.constructSlashPacketFromConsumer(firstBundle, *valToJail, stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN, ibcSeqNum)) + slashPacket := s.constructSlashPacketFromConsumer(firstBundle, *valToJail, stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN) + packetsData = append(packetsData, slashPacket.GetBytes()) } // Recv 500 packets from consumer to provider in same block - for _, packet := range packets { - consumerPacketData, err := provider.UnmarshalConsumerPacket(packet) // Same func used by provider's OnRecvPacket + var ( + timeoutHeight = clienttypes.Height{} + timeoutTimestamp = uint64(firstBundle.GetCtx().BlockTime().Add(ccvtypes.DefaultCCVTimeoutPeriod).UnixNano()) + ) + for sequence, data := range packetsData { + consumerPacketData, err := provider.UnmarshalConsumerPacketData(data) // Same func used by provider's OnRecvPacket s.Require().NoError(err) + packet := s.newPacketFromConsumer(data, uint64(sequence), firstBundle.Path, timeoutHeight, timeoutTimestamp) providerKeeper.OnRecvSlashPacket(s.providerCtx(), packet, *consumerPacketData.GetSlashPacketData()) } @@ -438,7 +457,7 @@ func (s *CCVTestSuite) TestQueueOrdering() { providerKeeper.InitializeSlashMeter(s.providerCtx()) // The packets to be recv in a single block, ordered as they will be recv. - packets := []channeltypes.Packet{} + var packetsData [][]byte firstBundle := s.getFirstBundle() @@ -448,29 +467,36 @@ func (s *CCVTestSuite) TestQueueOrdering() { s.setDefaultValSigningInfo(*s.providerChain.Vals.Validators[2]) // Track and increment ibc seq num for each packet, since these need to be unique. - ibcSeqNum := uint64(4) + var ( + ibcSeqNum = uint64(4) + ibcSeqs []uint64 + ) for ibcSeqNum < 504 { // Increment ibc seq num for each packet (starting at 5) ibcSeqNum++ + ibcSeqs = append(ibcSeqs, ibcSeqNum) // Instantiate a vsc matured packet every 10th packet if ibcSeqNum%10 == 0 { - packets = append(packets, s.constructVSCMaturedPacketFromConsumer(firstBundle, ibcSeqNum)) + packetsData = append(packetsData, s.constructVSCMaturedPacketFromConsumer(firstBundle).GetBytes()) continue } // Else instantiate a slash packet valToJail := s.providerChain.Vals.Validators[ibcSeqNum%3] - packets = append(packets, s.constructSlashPacketFromConsumer(firstBundle, *valToJail, stakingtypes.Infraction_INFRACTION_DOWNTIME, ibcSeqNum)) + packetsData = append(packetsData, s.constructSlashPacketFromConsumer(firstBundle, *valToJail, stakingtypes.Infraction_INFRACTION_DOWNTIME).GetBytes()) } // Recv 500 packets from consumer to provider in same block - for i, packet := range packets { - - consumerPacketData, err := provider.UnmarshalConsumerPacket(packet) // Same func used by provider's OnRecvPacket + var ( + timeoutHeight = clienttypes.Height{} + timeoutTimestamp = uint64(firstBundle.GetCtx().BlockTime().Add(ccvtypes.DefaultCCVTimeoutPeriod).UnixNano()) + ) + for i, data := range packetsData { + consumerPacketData, err := provider.UnmarshalConsumerPacketData(data) // Same func used by provider's OnRecvPacket s.Require().NoError(err) - + packet := s.newPacketFromConsumer(data, ibcSeqs[i], firstBundle.Path, timeoutHeight, timeoutTimestamp) // Type depends on index packets were appended from above if (i+5)%10 == 0 { vscMaturedPacketData := consumerPacketData.GetVscMaturedPacketData() @@ -595,15 +621,19 @@ func (s *CCVTestSuite) TestSlashingSmallValidators() { s.setDefaultValSigningInfo(*s.providerChain.Vals.Validators[3]) // Send slash packets from consumer to provider for small validators. + var ( + timeoutHeight = clienttypes.Height{} + timeoutTimestamp = uint64(s.getFirstBundle().GetCtx().BlockTime().Add(ccvtypes.DefaultCCVTimeoutPeriod).UnixNano()) + ) tmval1 := s.providerChain.Vals.Validators[1] tmval2 := s.providerChain.Vals.Validators[2] tmval3 := s.providerChain.Vals.Validators[3] - packet1 := s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval1, stakingtypes.Infraction_INFRACTION_DOWNTIME, 1) - packet2 := s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval2, stakingtypes.Infraction_INFRACTION_DOWNTIME, 2) - packet3 := s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval3, stakingtypes.Infraction_INFRACTION_DOWNTIME, 3) - sendOnConsumerRecvOnProvider(s, s.getFirstBundle().Path, packet1) - sendOnConsumerRecvOnProvider(s, s.getFirstBundle().Path, packet2) - sendOnConsumerRecvOnProvider(s, s.getFirstBundle().Path, packet3) + slashPacket1 := s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval1, stakingtypes.Infraction_INFRACTION_DOWNTIME) + slashPacket2 := s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval2, stakingtypes.Infraction_INFRACTION_DOWNTIME) + slashPacket3 := s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval3, stakingtypes.Infraction_INFRACTION_DOWNTIME) + sendOnConsumerRecvOnProvider(s, s.getFirstBundle().Path, timeoutHeight, timeoutTimestamp, slashPacket1.GetBytes()) + sendOnConsumerRecvOnProvider(s, s.getFirstBundle().Path, timeoutHeight, timeoutTimestamp, slashPacket2.GetBytes()) + sendOnConsumerRecvOnProvider(s, s.getFirstBundle().Path, timeoutHeight, timeoutTimestamp, slashPacket3.GetBytes()) // Default slash meter replenish fraction is 0.05, so all sent packets should be handled immediately. vals = providerStakingKeeper.GetAllValidators(s.providerCtx()) @@ -672,19 +702,24 @@ func (s *CCVTestSuite) TestSlashSameValidator() { s.setDefaultValSigningInfo(*tmval2) s.setDefaultValSigningInfo(*tmval3) - packets := []channeltypes.Packet{ - s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval1, stakingtypes.Infraction_INFRACTION_DOWNTIME, 1), - s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval2, stakingtypes.Infraction_INFRACTION_DOWNTIME, 2), - s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval3, stakingtypes.Infraction_INFRACTION_DOWNTIME, 3), - s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval1, stakingtypes.Infraction_INFRACTION_DOWNTIME, 4), - s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval2, stakingtypes.Infraction_INFRACTION_DOWNTIME, 5), - s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval3, stakingtypes.Infraction_INFRACTION_DOWNTIME, 6), + packetsData := [][]byte{ + s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval1, stakingtypes.Infraction_INFRACTION_DOWNTIME).GetBytes(), + s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval2, stakingtypes.Infraction_INFRACTION_DOWNTIME).GetBytes(), + s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval3, stakingtypes.Infraction_INFRACTION_DOWNTIME).GetBytes(), + s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval1, stakingtypes.Infraction_INFRACTION_DOWNTIME).GetBytes(), + s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval2, stakingtypes.Infraction_INFRACTION_DOWNTIME).GetBytes(), + s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval3, stakingtypes.Infraction_INFRACTION_DOWNTIME).GetBytes(), } // Recv and queue all slash packets. - for _, packet := range packets { - consumerPacketData, err := provider.UnmarshalConsumerPacket(packet) // Same func used by provider's OnRecvPacket + var ( + timeoutHeight = clienttypes.Height{} + timeoutTimestamp = uint64(s.getFirstBundle().GetCtx().BlockTime().Add(ccvtypes.DefaultCCVTimeoutPeriod).UnixNano()) + ) + for i, data := range packetsData { + consumerPacketData, err := provider.UnmarshalConsumerPacketData(data) // Same func used by provider's OnRecvPacket s.Require().NoError(err) + packet := s.newPacketFromConsumer(data, uint64(i), s.getFirstBundle().Path, timeoutHeight, timeoutTimestamp) providerKeeper.OnRecvSlashPacket(s.providerCtx(), packet, *consumerPacketData.GetSlashPacketData()) } @@ -719,33 +754,34 @@ func (s CCVTestSuite) TestSlashAllValidators() { //nolint:govet // this is a tes providerKeeper.InitializeSlashMeter(s.providerCtx()) // The packets to be recv in a single block, ordered as they will be recv. - packets := []channeltypes.Packet{} - - // Track and increment ibc seq num for each packet, since these need to be unique. - ibcSeqNum := uint64(1) + var packetsData [][]byte // Instantiate a slash packet for each validator, // these first 4 packets should jail 100% of the total power. for _, val := range s.providerChain.Vals.Validators { s.setDefaultValSigningInfo(*val) - packets = append(packets, s.constructSlashPacketFromConsumer( - s.getFirstBundle(), *val, stakingtypes.Infraction_INFRACTION_DOWNTIME, ibcSeqNum)) - ibcSeqNum++ + packetsData = append(packetsData, s.constructSlashPacketFromConsumer( + s.getFirstBundle(), *val, stakingtypes.Infraction_INFRACTION_DOWNTIME).GetBytes()) } // add 5 more slash packets for each validator, that will be handled in the same block. for _, val := range s.providerChain.Vals.Validators { for i := 0; i < 5; i++ { - packets = append(packets, s.constructSlashPacketFromConsumer( - s.getFirstBundle(), *val, stakingtypes.Infraction_INFRACTION_DOWNTIME, ibcSeqNum)) - ibcSeqNum++ + packetsData = append(packetsData, s.constructSlashPacketFromConsumer( + s.getFirstBundle(), *val, stakingtypes.Infraction_INFRACTION_DOWNTIME).GetBytes()) } } // Recv and queue all slash packets. - for _, packet := range packets { - consumerPacketData, err := provider.UnmarshalConsumerPacket(packet) // Same func used by provider's OnRecvPacket + var ( + timeoutHeight = clienttypes.Height{} + timeoutTimestamp = uint64(s.getFirstBundle().GetCtx().BlockTime().Add(ccvtypes.DefaultCCVTimeoutPeriod).UnixNano()) + ) + for i, data := range packetsData { + ibcSeqNum := uint64(i) + consumerPacketData, err := provider.UnmarshalConsumerPacketData(data) // Same func used by provider's OnRecvPacket s.Require().NoError(err) + packet := s.newPacketFromConsumer(data, ibcSeqNum, s.getFirstBundle().Path, timeoutHeight, timeoutTimestamp) providerKeeper.OnRecvSlashPacket(s.providerCtx(), packet, *consumerPacketData.GetSlashPacketData()) } @@ -774,12 +810,17 @@ func (s *CCVTestSuite) TestLeadingVSCMaturedAreDequeued() { providerKeeper := s.providerApp.GetProviderKeeper() // Queue up 50 vsc matured packets for each consumer + var ( + timeoutHeight = clienttypes.Height{} + timeoutTimestamp = uint64(s.getFirstBundle().GetCtx().BlockTime().Add(ccvtypes.DefaultCCVTimeoutPeriod).UnixNano()) + ) for _, bundle := range s.consumerBundles { for i := 0; i < 50; i++ { ibcSeqNum := uint64(i) - packet := s.constructVSCMaturedPacketFromConsumer(*bundle, ibcSeqNum) - packetData := ccvtypes.ConsumerPacketData{} - ccvtypes.ModuleCdc.MustUnmarshalJSON(packet.GetData(), &packetData) + data := s.constructVSCMaturedPacketFromConsumer(*bundle).GetBytes() + packetData, err := provider.UnmarshalConsumerPacketData(data) // Same func used by provider's OnRecvPacket + s.Require().NoError(err) + packet := s.newPacketFromConsumer(data, ibcSeqNum, bundle.Path, timeoutHeight, timeoutTimestamp) providerKeeper.OnRecvVSCMaturedPacket(s.providerCtx(), packet, *packetData.GetVscMaturedPacketData()) } @@ -789,11 +830,13 @@ func (s *CCVTestSuite) TestLeadingVSCMaturedAreDequeued() { for _, bundle := range s.consumerBundles { for i := 50; i < 100; i++ { ibcSeqNum := uint64(i) - packet := s.constructSlashPacketFromConsumer(*bundle, - *s.providerChain.Vals.Validators[0], stakingtypes.Infraction_INFRACTION_DOWNTIME, ibcSeqNum) - consumerPacketData, err := provider.UnmarshalConsumerPacket(packet) // Same func used by provider's OnRecvPacket + data := s.constructSlashPacketFromConsumer(*bundle, + *s.providerChain.Vals.Validators[0], stakingtypes.Infraction_INFRACTION_DOWNTIME).GetBytes() + packetData, err := provider.UnmarshalConsumerPacketData(data) // Same func used by provider's OnRecvPacket s.Require().NoError(err) - providerKeeper.OnRecvSlashPacket(s.providerCtx(), packet, *consumerPacketData.GetSlashPacketData()) + packet := s.newPacketFromConsumer(data, ibcSeqNum, bundle.Path, timeoutHeight, timeoutTimestamp) + providerKeeper.OnRecvSlashPacket(s.providerCtx(), + packet, *packetData.GetSlashPacketData()) } } @@ -801,9 +844,10 @@ func (s *CCVTestSuite) TestLeadingVSCMaturedAreDequeued() { for _, bundle := range s.consumerBundles { for i := 100; i < 150; i++ { ibcSeqNum := uint64(i) - packet := s.constructVSCMaturedPacketFromConsumer(*bundle, ibcSeqNum) + data := s.constructVSCMaturedPacketFromConsumer(*bundle).GetBytes() packetData := ccvtypes.ConsumerPacketData{} - ccvtypes.ModuleCdc.MustUnmarshalJSON(packet.GetData(), &packetData) + ccvtypes.ModuleCdc.MustUnmarshalJSON(data, &packetData) + packet := s.newPacketFromConsumer(data, ibcSeqNum, bundle.Path, timeoutHeight, timeoutTimestamp) providerKeeper.OnRecvVSCMaturedPacket(s.providerCtx(), packet, *packetData.GetVscMaturedPacketData()) } @@ -864,12 +908,17 @@ func (s *CCVTestSuite) TestVscMaturedHandledPerBlockLimit() { providerKeeper.InitializeSlashMeter(s.providerCtx()) // Queue up 100 vsc matured packets for each consumer + var ( + timeoutHeight = clienttypes.Height{} + timeoutTimestamp = uint64(s.getFirstBundle().GetCtx().BlockTime().Add(ccvtypes.DefaultCCVTimeoutPeriod).UnixNano()) + ) for _, bundle := range s.consumerBundles { for i := 0; i < 100; i++ { ibcSeqNum := uint64(i) - packet := s.constructVSCMaturedPacketFromConsumer(*bundle, ibcSeqNum) + data := s.constructVSCMaturedPacketFromConsumer(*bundle).GetBytes() packetData := ccvtypes.ConsumerPacketData{} - ccvtypes.ModuleCdc.MustUnmarshalJSON(packet.GetData(), &packetData) + ccvtypes.ModuleCdc.MustUnmarshalJSON(data, &packetData) + packet := s.newPacketFromConsumer(data, ibcSeqNum, bundle.Path, timeoutHeight, timeoutTimestamp) providerKeeper.OnRecvVSCMaturedPacket(s.providerCtx(), packet, *packetData.GetVscMaturedPacketData()) } @@ -879,11 +928,12 @@ func (s *CCVTestSuite) TestVscMaturedHandledPerBlockLimit() { for _, bundle := range s.consumerBundles { for i := 100; i < 150; i++ { ibcSeqNum := uint64(i) - packet := s.constructSlashPacketFromConsumer(*bundle, - *s.providerChain.Vals.Validators[0], stakingtypes.Infraction_INFRACTION_DOWNTIME, ibcSeqNum) - consumerPacketData, err := provider.UnmarshalConsumerPacket(packet) // Same func used by provider's OnRecvPacket + data := s.constructSlashPacketFromConsumer(*bundle, + *s.providerChain.Vals.Validators[0], stakingtypes.Infraction_INFRACTION_DOWNTIME).GetBytes() + consumderPacketData, err := provider.UnmarshalConsumerPacketData(data) // Same func used by provider's OnRecvPacket s.Require().NoError(err) - providerKeeper.OnRecvSlashPacket(s.providerCtx(), packet, *consumerPacketData.GetSlashPacketData()) + packet := s.newPacketFromConsumer(data, ibcSeqNum, bundle.Path, timeoutHeight, timeoutTimestamp) + providerKeeper.OnRecvSlashPacket(s.providerCtx(), packet, *consumderPacketData.GetSlashPacketData()) } } diff --git a/tests/integration/throttle_retry.go b/tests/integration/throttle_retry.go index ae15aac977..4d46b310cf 100644 --- a/tests/integration/throttle_retry.go +++ b/tests/integration/throttle_retry.go @@ -1,6 +1,7 @@ package integration 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" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" @@ -52,8 +53,12 @@ func (s *CCVTestSuite) TestSlashRetries() { // Construct a mock slash packet from consumer tmval1 := s.providerChain.Vals.Validators[1] - packet1 := s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval1, stakingtypes.Infraction_INFRACTION_DOWNTIME, 1) - + packetData1 := s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval1, stakingtypes.Infraction_INFRACTION_DOWNTIME).GetBytes() + var ( + timeoutHeight = clienttypes.Height{} + timeoutTimestamp = uint64(s.getFirstBundle().GetCtx().BlockTime().Add(ccvtypes.DefaultCCVTimeoutPeriod).UnixNano()) + ) + packet1 := s.newPacketFromConsumer(packetData1, 1, s.getFirstBundle().Path, timeoutHeight, timeoutTimestamp) // Mock the sending of the packet on consumer consumerKeeper.AppendPendingPacket(s.consumerCtx(), ccvtypes.SlashPacket, &ccvtypes.ConsumerPacketData_SlashPacketData{ @@ -105,7 +110,8 @@ func (s *CCVTestSuite) TestSlashRetries() { // Construct and mock the sending of a second packet on consumer tmval2 := s.providerChain.Vals.Validators[2] - packet2 := s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval2, stakingtypes.Infraction_INFRACTION_DOWNTIME, 1) + packetData2 := s.constructSlashPacketFromConsumer(s.getFirstBundle(), *tmval2, stakingtypes.Infraction_INFRACTION_DOWNTIME).GetBytes() + packet2 := s.newPacketFromConsumer(packetData2, 1, s.getFirstBundle().Path, timeoutHeight, timeoutTimestamp) consumerKeeper.AppendPendingPacket(s.consumerCtx(), ccvtypes.SlashPacket, &ccvtypes.ConsumerPacketData_SlashPacketData{ diff --git a/tests/integration/unbonding.go b/tests/integration/unbonding.go index 7693c782e5..35d1cfbae1 100644 --- a/tests/integration/unbonding.go +++ b/tests/integration/unbonding.go @@ -370,6 +370,10 @@ func (s *CCVTestSuite) TestRedelegationNoConsumer() { s.providerCtx().BlockTime().Add(stakingKeeper.UnbondingTime(s.providerCtx())), ) + // required before call to incrementTimeByUnbondingPeriod or else a panic + // occurs in ibc-go because trusted validators don't match last trusted. + s.providerChain.NextBlock() + // Increment time so that the unbonding period passes on the provider incrementTimeByUnbondingPeriod(s, Provider) diff --git a/tests/integration/valset_update.go b/tests/integration/valset_update.go index 955261aa79..b12066afa8 100644 --- a/tests/integration/valset_update.go +++ b/tests/integration/valset_update.go @@ -4,7 +4,6 @@ import ( "time" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" sdk "github.com/cosmos/cosmos-sdk/types" @@ -71,8 +70,7 @@ func (suite *CCVTestSuite) TestQueueAndSendVSCMaturedPackets() { ) // send first packet - packet := channeltypes.NewPacket(pd.GetBytes(), 1, ccv.ProviderPortID, suite.path.EndpointB.ChannelID, ccv.ConsumerPortID, suite.path.EndpointA.ChannelID, - clienttypes.NewHeight(1, 0), 0) + packet := suite.newPacketFromProvider(pd.GetBytes(), 1, suite.path, clienttypes.NewHeight(1, 0), 0) ack := consumerKeeper.OnRecvVSCPacket(suite.consumerChain.GetContext(), packet, pd) suite.Require().NotNil(ack, "OnRecvVSCPacket did not return ack") suite.Require().True(ack.Success(), "OnRecvVSCPacket did not return a Success Acknowledgment") diff --git a/testutil/ibc_testing/generic_setup.go b/testutil/ibc_testing/generic_setup.go index 25c483fca5..e9d959b665 100644 --- a/testutil/ibc_testing/generic_setup.go +++ b/testutil/ibc_testing/generic_setup.go @@ -1,32 +1,47 @@ package ibc_testing import ( + "encoding/json" "fmt" "testing" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + ibctesting "github.com/cosmos/ibc-go/v7/testing" "github.com/stretchr/testify/suite" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cometbft/cometbft/abci/types" tmencoding "github.com/cometbft/cometbft/crypto/encoding" tmtypes "github.com/cometbft/cometbft/types" - ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" testutil "github.com/cosmos/interchain-security/v3/testutil/integration" testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" consumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" ) +type ( + AppIniter func() (ibctesting.TestingApp, map[string]json.RawMessage) + ValSetAppIniter func([]types.ValidatorUpdate) AppIniter +) + // Contains generic setup code for running integration tests against a provider, consumer, // 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! var ( + FirstConsumerChainID string + provChainID string + democConsumerChainID string +) + +func init() { + // Disable revision format + ibctesting.ChainIDSuffix = "" FirstConsumerChainID = ibctesting.GetChainID(2) - provChainID = ibctesting.GetChainID(1) + provChainID = ibctesting.GetChainID(1) democConsumerChainID = ibctesting.GetChainID(5000) -) +} // ConsumerBundle serves as a way to store useful in-mem consumer app chain state // and relevant IBC paths in the context of CCV integration testing. @@ -48,11 +63,12 @@ func (cb ConsumerBundle) GetKeeper() consumerkeeper.Keeper { } // AddProvider adds a new provider chain to the coordinator and returns the test chain and app type -func AddProvider[T testutil.ProviderApp](t *testing.T, coordinator *ibctesting.Coordinator, appIniter ibctesting.AppIniter) ( +func AddProvider[T testutil.ProviderApp](t *testing.T, coordinator *ibctesting.Coordinator, appIniter AppIniter) ( *ibctesting.TestChain, T, ) { t.Helper() - provider := ibctesting.NewTestChain(t, coordinator, appIniter, provChainID) + ibctesting.DefaultTestingAppInit = appIniter + provider := ibctesting.NewTestChain(t, coordinator, provChainID) coordinator.Chains[provChainID] = provider providerToReturn, ok := provider.App.(T) @@ -64,11 +80,18 @@ func AddProvider[T testutil.ProviderApp](t *testing.T, coordinator *ibctesting.C } // AddDemocracyConsumer adds a new democ consumer chain to the coordinator and returns the test chain and app type -func AddDemocracyConsumer[T testutil.DemocConsumerApp](t *testing.T, coordinator *ibctesting.Coordinator, - appIniter ibctesting.AppIniter, +func AddDemocracyConsumer[T testutil.DemocConsumerApp]( + coordinator *ibctesting.Coordinator, + s *suite.Suite, + appIniter ValSetAppIniter, ) (*ibctesting.TestChain, T) { - t.Helper() - democConsumer := ibctesting.NewTestChain(t, coordinator, appIniter, democConsumerChainID) + s.T().Helper() + + // generate validators private/public key + valSet, valUpdates, signers := testutil.CreateValidators(s.T(), 4) + + ibctesting.DefaultTestingAppInit = appIniter(valUpdates) + democConsumer := ibctesting.NewTestChainWithValSet(s.T(), coordinator, democConsumerChainID, valSet, signers) coordinator.Chains[democConsumerChainID] = democConsumer democConsumerToReturn, ok := democConsumer.App.(T) @@ -89,7 +112,7 @@ func AddConsumer[Tp testutil.ProviderApp, Tc testutil.ConsumerApp]( coordinator *ibctesting.Coordinator, s *suite.Suite, index int, - appIniter ibctesting.AppIniter, + appIniter ValSetAppIniter, ) *ConsumerBundle { // consumer chain ID chainID := ibctesting.GetChainID(index + 2) @@ -135,8 +158,9 @@ func AddConsumer[Tp testutil.ProviderApp, Tc testutil.ConsumerApp]( } // create and instantiate consumer chain - testChain := ibctesting.NewTestChainWithValSet(s.T(), coordinator, - appIniter, chainID, tmtypes.NewValidatorSet(valz), providerChain.Signers) + ibctesting.DefaultTestingAppInit = appIniter(consumerGenesisState.InitialValSet) + testChain := ibctesting.NewTestChainWithValSet(s.T(), coordinator, chainID, + tmtypes.NewValidatorSet(valz), providerChain.Signers) coordinator.Chains[chainID] = testChain consumerToReturn, ok := testChain.App.(Tc) diff --git a/testutil/ibc_testing/specific_setup.go b/testutil/ibc_testing/specific_setup.go index 948007d212..8ac559d740 100644 --- a/testutil/ibc_testing/specific_setup.go +++ b/testutil/ibc_testing/specific_setup.go @@ -7,15 +7,27 @@ package ibc_testing import ( "encoding/json" + ibctesting "github.com/cosmos/ibc-go/v7/testing" + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" + sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" tmdb "github.com/cometbft/cometbft-db" + "github.com/cometbft/cometbft/abci/types" "github.com/cometbft/cometbft/libs/log" appConsumer "github.com/cosmos/interchain-security/v3/app/consumer" appConsumerDemocracy "github.com/cosmos/interchain-security/v3/app/consumer-democracy" appProvider "github.com/cosmos/interchain-security/v3/app/provider" - ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" +) + +var ( + _ AppIniter = ProviderAppIniter + _ ValSetAppIniter = ConsumerAppIniter + _ ValSetAppIniter = DemocracyConsumerAppIniter ) // ProviderAppIniter implements ibctesting.AppIniter for a provider app @@ -25,16 +37,44 @@ func ProviderAppIniter() (ibctesting.TestingApp, map[string]json.RawMessage) { return testApp, appProvider.NewDefaultGenesisState(encoding.Codec) } -// ConsumerAppIniter implements ibctesting.AppIniter for a consumer app -func ConsumerAppIniter() (ibctesting.TestingApp, map[string]json.RawMessage) { - encoding := appConsumer.MakeTestEncodingConfig() - testApp := appConsumer.New(log.NewNopLogger(), tmdb.NewMemDB(), nil, true, simtestutil.EmptyAppOptions{}) - return testApp, appConsumer.NewDefaultGenesisState(encoding.Codec) +// ConsumerAppIniter returns a ibctesting.ValSetAppIniter for a consumer app +func ConsumerAppIniter(initValPowers []types.ValidatorUpdate) AppIniter { + return func() (ibctesting.TestingApp, map[string]json.RawMessage) { + encoding := appConsumer.MakeTestEncodingConfig() + testApp := appConsumer.New(log.NewNopLogger(), tmdb.NewMemDB(), nil, true, simtestutil.EmptyAppOptions{}) + genesisState := appConsumer.NewDefaultGenesisState(encoding.Codec) + // NOTE ibc-go/v7/testing.SetupWithGenesisValSet requires a staking module + // genesisState or it panics. Feed a minimum one. + genesisState[stakingtypes.ModuleName] = encoding.Codec.MustMarshalJSON( + &stakingtypes.GenesisState{ + Params: stakingtypes.Params{BondDenom: sdk.DefaultBondDenom}, + }, + ) + // Feed consumer genesis with provider validators + var consumerGenesis ccvtypes.GenesisState + encoding.Codec.MustUnmarshalJSON(genesisState[consumertypes.ModuleName], &consumerGenesis) + consumerGenesis.InitialValSet = initValPowers + consumerGenesis.Params.Enabled = true + genesisState[consumertypes.ModuleName] = encoding.Codec.MustMarshalJSON(&consumerGenesis) + + return testApp, genesisState + } } -// DemocracyConsumerAppIniter implements ibctesting.AppIniter for a democracy consumer app -func DemocracyConsumerAppIniter() (ibctesting.TestingApp, map[string]json.RawMessage) { - encoding := appConsumerDemocracy.MakeTestEncodingConfig() - testApp := appConsumerDemocracy.New(log.NewNopLogger(), tmdb.NewMemDB(), nil, true, simtestutil.EmptyAppOptions{}) - return testApp, appConsumerDemocracy.NewDefaultGenesisState(encoding.Codec) +// DemocracyConsumerAppIniter implements ibctesting.ValSetAppIniter for a democracy consumer app +func DemocracyConsumerAppIniter(initValPowers []types.ValidatorUpdate) AppIniter { + return func() (ibctesting.TestingApp, map[string]json.RawMessage) { + encoding := appConsumerDemocracy.MakeTestEncodingConfig() + testApp := appConsumerDemocracy.New(log.NewNopLogger(), tmdb.NewMemDB(), nil, true, simtestutil.EmptyAppOptions{}) + genesisState := appConsumerDemocracy.NewDefaultGenesisState(encoding.Codec) + // Feed consumer genesis with provider validators + // TODO See if useful for democracy + var consumerGenesis ccvtypes.GenesisState + encoding.Codec.MustUnmarshalJSON(genesisState[consumertypes.ModuleName], &consumerGenesis) + consumerGenesis.InitialValSet = initValPowers + consumerGenesis.Params.Enabled = true + genesisState[consumertypes.ModuleName] = encoding.Codec.MustMarshalJSON(&consumerGenesis) + + return testApp, genesisState + } } diff --git a/testutil/integration/interfaces.go b/testutil/integration/interfaces.go index b677d46789..f084129ec0 100644 --- a/testutil/integration/interfaces.go +++ b/testutil/integration/interfaces.go @@ -3,6 +3,8 @@ package integration import ( "time" + ibctesting "github.com/cosmos/ibc-go/v7/testing" + "cosmossdk.io/math" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" @@ -18,7 +20,6 @@ import ( abci "github.com/cometbft/cometbft/abci/types" - ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" consumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" providerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" diff --git a/testutil/integration/validators.go b/testutil/integration/validators.go new file mode 100644 index 0000000000..c8d2decadc --- /dev/null +++ b/testutil/integration/validators.go @@ -0,0 +1,50 @@ +package integration + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/testutil/mock" + + "github.com/cometbft/cometbft/abci/types" + tmencoding "github.com/cometbft/cometbft/crypto/encoding" + tmtypes "github.com/cometbft/cometbft/types" +) + +func CreateValidators(t *testing.T, n int) ( + *tmtypes.ValidatorSet, []types.ValidatorUpdate, map[string]tmtypes.PrivValidator, +) { + t.Helper() + // generate validators private/public key + var ( + validators []*tmtypes.Validator + signersByAddress = make(map[string]tmtypes.PrivValidator, n) + ) + for i := 0; i < n; i++ { + privVal := mock.NewPV() + pubKey, err := privVal.GetPubKey() + require.NoError(t, err) + val := tmtypes.NewValidator(pubKey, 1) + validators = append(validators, val) + signersByAddress[pubKey.Address().String()] = privVal + } + // construct validator set; + // Note that the validators are sorted by voting power + // or, if equal, by address lexical order + valSet := tmtypes.NewValidatorSet(validators) + return valSet, ToValidatorUpdates(t, valSet), signersByAddress +} + +func ToValidatorUpdates(t *testing.T, valSet *tmtypes.ValidatorSet) (valUpdates []types.ValidatorUpdate) { + t.Helper() + for _, val := range valSet.Validators { + protoPubKey, err := tmencoding.PubKeyToProto(val.PubKey) + require.NoError(t, err) + valUpdates = append(valUpdates, types.ValidatorUpdate{ + PubKey: protoPubKey, + Power: val.VotingPower, + }) + } + return +} diff --git a/testutil/simibc/chain_util.go b/testutil/simibc/chain_util.go index 98622695d3..1c00c928c5 100644 --- a/testutil/simibc/chain_util.go +++ b/testutil/simibc/chain_util.go @@ -5,12 +5,12 @@ import ( channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + ibctesting "github.com/cosmos/ibc-go/v7/testing" + + sdk "github.com/cosmos/cosmos-sdk/types" abci "github.com/cometbft/cometbft/abci/types" tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - - ibctestingcore "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/core" - ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" ) // BeginBlock updates the current header and calls the app.BeginBlock method. @@ -56,14 +56,37 @@ func EndBlock(c *ibctesting.TestChain, preCommitCallback func()) (*ibctmtypes.He c.LastHeader = c.CurrentTMClientHeader() - packets := []channeltypes.Packet{} + sdkEvts := ABCIToSDKEvents(ebRes.Events) + packets := ParsePacketsFromEvents(sdkEvts) + + return c.LastHeader, packets +} - for _, e := range ebRes.Events { - if e.Type == channeltypes.EventTypeSendPacket { - packet, _ := ibctestingcore.ReconstructPacketFromEvent(e) +// ParsePacketsFromEvents returns all packets found in events. +func ParsePacketsFromEvents(events []sdk.Event) (packets []channeltypes.Packet) { + for i, ev := range events { + if ev.Type == channeltypes.EventTypeSendPacket { + packet, err := ibctesting.ParsePacketFromEvents(events[i:]) + if err != nil { + panic(err) + } packets = append(packets, packet) } } + return +} - return c.LastHeader, packets +// ABCIToSDKEvents converts a list of ABCI events to Cosmos SDK events. +func ABCIToSDKEvents(abciEvents []abci.Event) sdk.Events { + var events sdk.Events + for _, evt := range abciEvents { + var attributes []sdk.Attribute + for _, attr := range evt.GetAttributes() { + attributes = append(attributes, sdk.NewAttribute(attr.Key, attr.Value)) + } + + events = events.AppendEvent(sdk.NewEvent(evt.GetType(), attributes...)) + } + + return events } diff --git a/testutil/simibc/relay_util.go b/testutil/simibc/relay_util.go index 97bcabf57c..9fd5213d5b 100644 --- a/testutil/simibc/relay_util.go +++ b/testutil/simibc/relay_util.go @@ -5,6 +5,8 @@ import ( channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v7/modules/core/24-host" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + ibctesting "github.com/cosmos/ibc-go/v7/testing" + simapp "github.com/cosmos/ibc-go/v7/testing/simapp" "github.com/stretchr/testify/require" errorsmod "cosmossdk.io/errors" @@ -12,9 +14,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" tmtypes "github.com/cometbft/cometbft/types" - - simapp "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/simapp" - ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" ) // UpdateReceiverClient DELIVERs a header to the receiving endpoint diff --git a/testutil/simibc/relayed_path.go b/testutil/simibc/relayed_path.go index 7ef97c4bee..daf32f0c84 100644 --- a/testutil/simibc/relayed_path.go +++ b/testutil/simibc/relayed_path.go @@ -5,8 +5,7 @@ import ( "time" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - - ibctesting "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/testing" + ibctesting "github.com/cosmos/ibc-go/v7/testing" ) // RelayedPath is a wrapper around ibctesting.Path gives fine-grained diff --git a/x/ccv/provider/ibc_module.go b/x/ccv/provider/ibc_module.go index a19fd7e5bb..75da9588d6 100644 --- a/x/ccv/provider/ibc_module.go +++ b/x/ccv/provider/ibc_module.go @@ -209,11 +209,15 @@ func (am AppModule) OnRecvPacket( } func UnmarshalConsumerPacket(packet channeltypes.Packet) (consumerPacket ccv.ConsumerPacketData, err error) { + return UnmarshalConsumerPacketData(packet.GetData()) +} + +func UnmarshalConsumerPacketData(packetData []byte) (consumerPacket ccv.ConsumerPacketData, err error) { // First try unmarshaling into ccv.ConsumerPacketData type - if err := ccv.ModuleCdc.UnmarshalJSON(packet.GetData(), &consumerPacket); err != nil { + if err := ccv.ModuleCdc.UnmarshalJSON(packetData, &consumerPacket); err != nil { // If failed, packet should be a v1 slash packet, retry for ConsumerPacketDataV1 packet type var v1Packet ccv.ConsumerPacketDataV1 - errV1 := ccv.ModuleCdc.UnmarshalJSON(packet.GetData(), &v1Packet) + errV1 := ccv.ModuleCdc.UnmarshalJSON(packetData, &v1Packet) if errV1 != nil { // If neither worked, return error return ccv.ConsumerPacketData{}, errV1 diff --git a/x/ccv/provider/keeper/keeper_test.go b/x/ccv/provider/keeper/keeper_test.go index 364aac5669..be3ef4001c 100644 --- a/x/ccv/provider/keeper/keeper_test.go +++ b/x/ccv/provider/keeper/keeper_test.go @@ -6,6 +6,7 @@ import ( "testing" "time" + ibctesting "github.com/cosmos/ibc-go/v7/testing" "github.com/stretchr/testify/require" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" @@ -13,7 +14,6 @@ import ( abci "github.com/cometbft/cometbft/abci/types" tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" - ibcsimapp "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/simapp" cryptotestutil "github.com/cosmos/interchain-security/v3/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" @@ -156,7 +156,7 @@ func TestPendingVSCs(t *testing.T) { pending := providerKeeper.GetPendingVSCPackets(ctx, chainID) require.Len(t, pending, 0) - pks := ibcsimapp.CreateTestPubKeys(4) + _, pks, _ := ibctesting.GenerateKeys(t, 4) var ppks [4]tmprotocrypto.PublicKey for i, pk := range pks { ppks[i], _ = cryptocodec.ToTmProtoPublicKey(pk) diff --git a/x/ccv/provider/keeper/relay_test.go b/x/ccv/provider/keeper/relay_test.go index 590286261c..d3fdcaa21e 100644 --- a/x/ccv/provider/keeper/relay_test.go +++ b/x/ccv/provider/keeper/relay_test.go @@ -8,6 +8,7 @@ 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" exported "github.com/cosmos/ibc-go/v7/modules/core/exported" + ibctesting "github.com/cosmos/ibc-go/v7/testing" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" @@ -17,7 +18,6 @@ import ( abci "github.com/cometbft/cometbft/abci/types" - ibcsimapp "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/simapp" cryptotestutil "github.com/cosmos/interchain-security/v3/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" @@ -27,7 +27,7 @@ import ( // TestQueueVSCPackets tests queueing validator set updates. func TestQueueVSCPackets(t *testing.T) { - key := ibcsimapp.CreateTestPubKeys(1)[0] + _, _, key := ibctesting.GenerateKeys(t, 1) tmPubKey, _ := cryptocodec.ToTmProtoPublicKey(key) testCases := []struct { diff --git a/x/ccv/types/utils_test.go b/x/ccv/types/utils_test.go index f43e5449f1..18ed01f7dc 100644 --- a/x/ccv/types/utils_test.go +++ b/x/ccv/types/utils_test.go @@ -3,18 +3,18 @@ package types_test import ( "testing" + ibctesting "github.com/cosmos/ibc-go/v7/testing" "github.com/stretchr/testify/require" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" abci "github.com/cometbft/cometbft/abci/types" - ibcsimapp "github.com/cosmos/interchain-security/v3/legacy_ibc_testing/simapp" "github.com/cosmos/interchain-security/v3/x/ccv/types" ) func TestAccumulateChanges(t *testing.T) { - testKeys := ibcsimapp.CreateTestPubKeys(2) + _, testKeys, _ := ibctesting.GenerateKeys(t, 2) tmPubKey, _ := cryptocodec.ToTmProtoPublicKey(testKeys[0]) tmPubKey2, _ := cryptocodec.ToTmProtoPublicKey(testKeys[1]) @@ -84,7 +84,7 @@ func TestAccumulateChanges(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { changes := types.AccumulateChanges(tc.changes1, tc.changes2) - require.Equal(t, tc.expected, changes) + require.ElementsMatch(t, tc.expected, changes) }) } } From 24b89edb9e528ad4ae177d58e5d2a96bcbbe82ac Mon Sep 17 00:00:00 2001 From: MSalopek Date: Fri, 8 Sep 2023 09:44:16 +0200 Subject: [PATCH 108/134] tests: increase timeout in nightly e2e for multiconsumer (#1272) --- .github/workflows/manual-e2e.yml | 2 +- .github/workflows/nightly-e2e.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/manual-e2e.yml b/.github/workflows/manual-e2e.yml index 2bb74bb52d..3893d009df 100644 --- a/.github/workflows/manual-e2e.yml +++ b/.github/workflows/manual-e2e.yml @@ -87,7 +87,7 @@ jobs: run: go run ./tests/e2e/... --tc slash-throttle multiconsumer-test: runs-on: ubuntu-latest - timeout-minutes: 20 + timeout-minutes: 40 steps: - uses: actions/setup-go@v4 with: diff --git a/.github/workflows/nightly-e2e.yml b/.github/workflows/nightly-e2e.yml index 4ab03527fd..913f7e0bbe 100644 --- a/.github/workflows/nightly-e2e.yml +++ b/.github/workflows/nightly-e2e.yml @@ -100,7 +100,7 @@ jobs: run: go run ./tests/e2e/... --tc slash-throttle multiconsumer-test: runs-on: ubuntu-latest - timeout-minutes: 20 + timeout-minutes: 40 steps: - uses: actions/setup-go@v4 with: From 57b96ca8d82052b34f49ec57d1160cffe54cb667 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Date: Fri, 8 Sep 2023 14:01:29 +0200 Subject: [PATCH 109/134] test: Add light client attack to e2e tests (#1249) * Add light client attack to e2e tests * Add details about the attack types * Rename validatorAddress to validatorPrivateKeyAddress * Add URL to CometMock to flag * Improve wording for light client attack run * Add submitting equivocation proposals and change consu->consumerName --- tests/e2e/actions.go | 93 ++++++++++++++++-- tests/e2e/main.go | 14 ++- tests/e2e/steps.go | 19 +++- tests/e2e/steps_light_client_attack.go | 130 +++++++++++++++++++++++++ 4 files changed, 244 insertions(+), 12 deletions(-) create mode 100644 tests/e2e/steps_light_client_attack.go diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index fccc27a957..c05b21bfef 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -1606,10 +1606,10 @@ func (tr TestRun) setValidatorDowntime(chain chainID, validator validatorID, dow if tr.useCometmock { // send set_signing_status either to down or up for validator - validatorAddress := tr.GetValidatorAddress(chain, validator) + validatorPrivateKeyAddress := tr.GetValidatorPrivateKeyAddress(chain, validator) method := "set_signing_status" - params := fmt.Sprintf(`{"private_key_address":"%s","status":"%s"}`, validatorAddress, lastArg) + params := fmt.Sprintf(`{"private_key_address":"%s","status":"%s"}`, validatorPrivateKeyAddress, lastArg) address := tr.getQueryNodeRPCAddress(chain) tr.curlJsonRPCRequest(method, params, address) @@ -1639,10 +1639,10 @@ func (tr TestRun) setValidatorDowntime(chain chainID, validator validatorID, dow } } -func (tr TestRun) GetValidatorAddress(chain chainID, validator validatorID) string { - var validatorAddress string +func (tr TestRun) GetValidatorPrivateKeyAddress(chain chainID, validator validatorID) string { + var validatorPrivateKeyAddress string if chain == chainID("provi") { - validatorAddress = tr.getValidatorKeyAddressFromString(tr.validatorConfigs[validator].privValidatorKey) + validatorPrivateKeyAddress = tr.getValidatorKeyAddressFromString(tr.validatorConfigs[validator].privValidatorKey) } else { var valAddressString string if tr.validatorConfigs[validator].useConsumerKey { @@ -1650,9 +1650,9 @@ func (tr TestRun) GetValidatorAddress(chain chainID, validator validatorID) stri } else { valAddressString = tr.validatorConfigs[validator].privValidatorKey } - validatorAddress = tr.getValidatorKeyAddressFromString(valAddressString) + validatorPrivateKeyAddress = tr.getValidatorKeyAddressFromString(valAddressString) } - return validatorAddress + return validatorPrivateKeyAddress } type unjailValidatorAction struct { @@ -1813,10 +1813,10 @@ func (tr TestRun) invokeDoublesignSlash( } tr.waitBlocks("provi", 10, 2*time.Minute) } else { // tr.useCometMock - validatorAddress := tr.GetValidatorAddress(action.chain, action.validator) + validatorPrivateKeyAddress := tr.GetValidatorPrivateKeyAddress(action.chain, action.validator) method := "cause_double_sign" - params := fmt.Sprintf(`{"private_key_address":"%s"}`, validatorAddress) + params := fmt.Sprintf(`{"private_key_address":"%s"}`, validatorPrivateKeyAddress) address := tr.getQueryNodeRPCAddress(action.chain) @@ -1826,6 +1826,81 @@ func (tr TestRun) invokeDoublesignSlash( } } +// Cause light client attack evidence for a certain validator to appear on the given chain. +// The evidence will look like the validator equivocated to a light client. +// See https://github.com/cometbft/cometbft/tree/main/spec/light-client/accountability +// for more information about light client attacks. +type lightClientEquivocationAttackAction struct { + validator validatorID + chain chainID +} + +func (tr TestRun) lightClientEquivocationAttack( + action lightClientEquivocationAttackAction, + verbose bool, +) { + tr.lightClientAttack(action.validator, action.chain, LightClientEquivocationAttack) +} + +// Cause light client attack evidence for a certain validator to appear on the given chain. +// The evidence will look like the validator tried to perform an amnesia attack. +// See https://github.com/cometbft/cometbft/tree/main/spec/light-client/accountability +// for more information about light client attacks. +type lightClientAmnesiaAttackAction struct { + validator validatorID + chain chainID +} + +func (tr TestRun) lightClientAmnesiaAttack( + action lightClientAmnesiaAttackAction, + verbose bool, +) { + tr.lightClientAttack(action.validator, action.chain, LightClientAmnesiaAttack) +} + +// Cause light client attack evidence for a certain validator to appear on the given chain. +// The evidence will look like the validator tried to perform a lunatic attack. +// See https://github.com/cometbft/cometbft/tree/main/spec/light-client/accountability +// for more information about light client attacks. +type lightClientLunaticAttackAction struct { + validator validatorID + chain chainID +} + +func (tr TestRun) lightClientLunaticAttack( + action lightClientLunaticAttackAction, + verbose bool, +) { + tr.lightClientAttack(action.validator, action.chain, LightClientLunaticAttack) +} + +type LightClientAttackType string + +const ( + LightClientEquivocationAttack LightClientAttackType = "Equivocation" + LightClientAmnesiaAttack LightClientAttackType = "Amnesia" + LightClientLunaticAttack LightClientAttackType = "Lunatic" +) + +func (tr TestRun) lightClientAttack( + validator validatorID, + chain chainID, + attackType LightClientAttackType, +) { + if !tr.useCometmock { + log.Fatal("light client attack is only supported with CometMock") + } + validatorPrivateKeyAddress := tr.GetValidatorPrivateKeyAddress(chain, validator) + + method := "cause_light_client_attack" + params := fmt.Sprintf(`{"private_key_address":"%s", "misbehaviour_type": "%s"}`, validatorPrivateKeyAddress, attackType) + + address := tr.getQueryNodeRPCAddress(chain) + + tr.curlJsonRPCRequest(method, params, address) + tr.waitBlocks(chain, 1, 10*time.Second) +} + type assignConsumerPubKeyAction struct { chain chainID validator validatorID diff --git a/tests/e2e/main.go b/tests/e2e/main.go index e9336422ae..1998e95a2e 100644 --- a/tests/e2e/main.go +++ b/tests/e2e/main.go @@ -39,7 +39,7 @@ var ( parallel = flag.Bool("parallel", false, "run all tests in parallel") localSdkPath = flag.String("local-sdk-path", "", "path of a local sdk version to build and reference in integration tests") - useCometmock = flag.Bool("use-cometmock", false, "use cometmock instead of CometBFT") + useCometmock = flag.Bool("use-cometmock", false, "use cometmock instead of CometBFT. see https://github.com/informalsystems/CometMock") useGorelayer = flag.Bool("use-gorelayer", false, "use go relayer instead of Hermes") ) @@ -56,6 +56,12 @@ var ( description: `This is like the happy path, but skips steps that involve starting or stopping nodes for the same chain outside of the chain setup or teardown. This is suited for CometMock+Gorelayer testing`, + }, + "light-client-attack": { + testRun: DefaultTestRun(), steps: lightClientAttackSteps, + description: `This is like the short happy path, but will slash validators for LightClientAttackEvidence instead of DuplicateVoteEvidence. +This is suited for CometMock+Gorelayer testing, but currently does not work with CometBFT, +since causing light client attacks is not implemented.`, }, "happy-path": {testRun: DefaultTestRun(), steps: happyPathSteps, description: "happy path tests"}, "changeover": {testRun: ChangeoverTestRun(), steps: changeoverSteps, description: "changeover tests"}, @@ -238,6 +244,12 @@ func (tr *TestRun) runStep(step Step, verbose bool) { tr.unjailValidator(action, verbose) case doublesignSlashAction: tr.invokeDoublesignSlash(action, verbose) + case lightClientAmnesiaAttackAction: + tr.lightClientAmnesiaAttack(action, verbose) + case lightClientEquivocationAttackAction: + tr.lightClientEquivocationAttack(action, verbose) + case lightClientLunaticAttackAction: + tr.lightClientLunaticAttack(action, verbose) case registerRepresentativeAction: tr.registerRepresentative(action, verbose) case assignConsumerPubKeyAction: diff --git a/tests/e2e/steps.go b/tests/e2e/steps.go index b33d19783a..6fb284c07a 100644 --- a/tests/e2e/steps.go +++ b/tests/e2e/steps.go @@ -39,9 +39,24 @@ var shortHappyPathSteps = concatSteps( stepsDowntime("consu"), stepsRejectEquivocationProposal("consu", 2), // prop to tombstone bob is rejected stepsDoubleSignOnProviderAndConsumer("consu"), // carol double signs on provider, bob double signs on consumer + stepsSubmitEquivocationProposal("consu", 2), // now prop to tombstone bob is submitted and accepted stepsStartRelayer(), - stepsConsumerRemovalPropNotPassing("consu", 2), // submit removal prop but vote no on it - chain should stay - stepsStopChain("consu", 3), // stop chain + stepsConsumerRemovalPropNotPassing("consu", 3), // submit removal prop but vote no on it - chain should stay + stepsStopChain("consu", 4), // stop chain +) + +var lightClientAttackSteps = concatSteps( + stepsStartChains([]string{"consu"}, false), + stepsDelegate("consu"), + stepsUnbond("consu"), + stepsRedelegateShort("consu"), + stepsDowntime("consu"), + stepsRejectEquivocationProposal("consu", 2), // prop to tombstone bob is rejected + stepsLightClientAttackOnProviderAndConsumer("consu"), // carol double signs on provider, bob double signs on consumer + stepsSubmitEquivocationProposal("consu", 2), // now prop to tombstone bob is submitted and accepted + stepsStartRelayer(), + stepsConsumerRemovalPropNotPassing("consu", 3), // submit removal prop but vote no on it - chain should stay + stepsStopChain("consu", 4), // stop chain ) var slashThrottleSteps = concatSteps( diff --git a/tests/e2e/steps_light_client_attack.go b/tests/e2e/steps_light_client_attack.go new file mode 100644 index 0000000000..f00d5f5bd6 --- /dev/null +++ b/tests/e2e/steps_light_client_attack.go @@ -0,0 +1,130 @@ +package main + +// Steps that make carol double sign on the provider, and bob double sign on a single consumer +func stepsLightClientAttackOnProviderAndConsumer(consumerName string) []Step { + return []Step{ + { + // provider double sign + action: lightClientEquivocationAttackAction{ + chain: chainID("provi"), + validator: validatorID("carol"), + }, + state: State{ + // slash on provider + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 500, + validatorID("carol"): 0, // from 500 to 0 + }, + }, + chainID(consumerName): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 500, + validatorID("carol"): 495, // not tombstoned on consumerName yet + }, + }, + }, + }, + { + // relay power change to consumerName + action: relayPacketsAction{ + chainA: chainID("provi"), + chainB: chainID(consumerName), + port: "provider", + channel: 0, // consumerName channel + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 500, + validatorID("carol"): 0, + }, + }, + chainID(consumerName): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 500, + validatorID("carol"): 0, // tombstoning visible on consumerName + }, + }, + }, + }, + { + // consumer double sign + // provider will only log the double sign slash + // stepsSubmitEquivocationProposal will cause the double sign slash to be executed + action: lightClientEquivocationAttackAction{ + chain: chainID(consumerName), + validator: validatorID("bob"), + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 500, + validatorID("carol"): 0, + }, + }, + chainID(consumerName): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 500, + validatorID("carol"): 0, + }, + }, + }, + }, + { + action: relayPacketsAction{ + chainA: chainID("provi"), + chainB: chainID(consumerName), + port: "provider", + channel: 0, + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 500, // not tombstoned + validatorID("carol"): 0, + }, + }, + chainID(consumerName): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 500, // not tombstoned + validatorID("carol"): 0, + }, + }, + }, + }, + { + // consumer learns about the double sign + action: relayPacketsAction{ + chainA: chainID("provi"), + chainB: chainID(consumerName), + port: "provider", + channel: 0, + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 500, + validatorID("carol"): 0, + }, + }, + chainID(consumerName): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 500, // not tombstoned + validatorID("carol"): 0, + }, + }, + }, + }, + } +} From d0dda4bd06c0429d22b7324e3f561e379531fa36 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Sep 2023 09:48:07 +0200 Subject: [PATCH 110/134] build(deps): bump google.golang.org/grpc from 1.57.0 to 1.58.0 (#1284) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.57.0 to 1.58.0. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.57.0...v1.58.0) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 14 +++++++------- go.sum | 28 ++++++++++++++-------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/go.mod b/go.mod index 6cc988a794..7b54164770 100644 --- a/go.mod +++ b/go.mod @@ -26,17 +26,17 @@ require ( golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb golang.org/x/net v0.12.0 // indirect golang.org/x/sys v0.11.0 // indirect - google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 // indirect - google.golang.org/grpc v1.57.0 + google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 // indirect + google.golang.org/grpc v1.58.0 google.golang.org/protobuf v1.31.0 gopkg.in/yaml.v2 v2.4.0 ) require ( cloud.google.com/go v0.110.4 // indirect - cloud.google.com/go/compute v1.20.1 // indirect + cloud.google.com/go/compute v1.21.0 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/iam v1.1.0 // indirect + cloud.google.com/go/iam v1.1.1 // indirect cloud.google.com/go/storage v1.30.1 // indirect cosmossdk.io/api v0.3.1 cosmossdk.io/core v0.5.1 // indirect @@ -152,7 +152,7 @@ require ( github.com/zondax/ledger-go v0.14.1 // indirect go.etcd.io/bbolt v1.3.7 // indirect go.opencensus.io v0.24.0 // indirect - golang.org/x/oauth2 v0.8.0 // indirect + golang.org/x/oauth2 v0.10.0 // indirect golang.org/x/term v0.10.0 // indirect golang.org/x/text v0.12.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect @@ -167,7 +167,7 @@ require ( require ( github.com/spf13/viper v1.16.0 - google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529 + google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 ) require ( @@ -182,7 +182,7 @@ require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/rs/zerolog v1.30.0 // indirect - golang.org/x/sync v0.2.0 // indirect + golang.org/x/sync v0.3.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect ) diff --git a/go.sum b/go.sum index 03e76f9812..045c45ef25 100644 --- a/go.sum +++ b/go.sum @@ -73,8 +73,8 @@ cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= -cloud.google.com/go/compute v1.20.1 h1:6aKEtlUiwEpJzM001l0yFkpXmUVXaN8W+fbkb2AZNbg= -cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute v1.21.0 h1:JNBsyXVoOoNJtTQcnEY5uYpZIbeCTYIeDe0Xh1bySMk= +cloud.google.com/go/compute v1.21.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= @@ -114,8 +114,8 @@ cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y97 cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= -cloud.google.com/go/iam v1.1.0 h1:67gSqaPukx7O8WLLHMa0PNs3EBGd2eE4d+psbO/CO94= -cloud.google.com/go/iam v1.1.0/go.mod h1:nxdHjaKfCr7fNYx/HJMM8LgiMugmveWlkatear5gVyk= +cloud.google.com/go/iam v1.1.1 h1:lW7fzj15aVIXYHREOqjRBV9PsH0Z6u8Y46a1YGvQP4Y= +cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= @@ -1357,8 +1357,8 @@ golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= -golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= -golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= +golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= +golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1373,8 +1373,8 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= -golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1761,10 +1761,10 @@ google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqw google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 h1:Au6te5hbKUV8pIYWHqOUZ1pva5qK/rwbIhoXEUB9Lu8= -google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:O9kGHb51iE/nOGvQaDUuadVYqovW56s5emA88lQnj6Y= -google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529 h1:s5YSX+ZH5b5vS9rnpGymvIyMpLRJizowqDlOuyjXnTk= -google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= +google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 h1:Z0hjGZePRE0ZBWotvtrwxFNrNE9CUAGtplaDK5NNI/g= +google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0= +google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 h1:FmF5cCW94Ij59cfpoLiwTgodWmm60eEV0CjlsVg2fuw= +google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U= google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= @@ -1808,8 +1808,8 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= -google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= +google.golang.org/grpc v1.58.0 h1:32JY8YpPMSR45K+c3o6b8VL73V+rR8k+DeMIr4vRH8o= +google.golang.org/grpc v1.58.0/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= From 67bb558fcb841b17a4f54fd2dbd191210ecd444f Mon Sep 17 00:00:00 2001 From: Marius Poke Date: Tue, 12 Sep 2023 13:00:28 +0200 Subject: [PATCH 111/134] ci: update mergify and dependabot for v2.x-lsm (#1281) update mergify and dependabot for v2.x-lsm --- .github/dependabot.yml | 20 ++++++++++++++++++++ .mergify.yml | 16 ++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 647408015a..404825428c 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -28,6 +28,26 @@ updates: labels: - dependencies + - package-ecosystem: gomod + directory: "/" + schedule: + interval: daily + target-branch: "release/v2.0.x-lsm" + # Only allow automated security-related dependency updates on release branches. + open-pull-requests-limit: 0 + labels: + - dependencies + + - package-ecosystem: gomod + directory: "/" + schedule: + interval: daily + target-branch: "release/v2.1.x-lsm" + # Only allow automated security-related dependency updates on release branches. + open-pull-requests-limit: 0 + labels: + - dependencies + - package-ecosystem: gomod directory: "/" schedule: diff --git a/.mergify.yml b/.mergify.yml index e08625bf28..226075ed45 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -18,6 +18,22 @@ pull_request_rules: backport: branches: - release/v2.0.x + - name: Backport patches to the release/v2.0.x-lsm branch + conditions: + - base=main + - label=A:backport/v2.0.x-lsm + actions: + backport: + branches: + - release/v2.0.x-lsm + - name: Backport patches to the release/v2.1.x-lsm branch + conditions: + - base=main + - label=A:backport/v2.1.x-lsm + actions: + backport: + branches: + - release/v2.1.x-lsm - name: Backport patches to the release/v3.0.x branch conditions: - base=main From d842bca21ad73d16a4e94e0214227ff1077d42d2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Sep 2023 17:12:21 +0200 Subject: [PATCH 112/134] build(deps): bump github.com/oxyno-zeta/gomock-extra-matcher from 1.1.0 to 1.2.0 (#1286) build(deps): bump github.com/oxyno-zeta/gomock-extra-matcher Bumps [github.com/oxyno-zeta/gomock-extra-matcher](https://github.com/oxyno-zeta/gomock-extra-matcher) from 1.1.0 to 1.2.0. - [Release notes](https://github.com/oxyno-zeta/gomock-extra-matcher/releases) - [Changelog](https://github.com/oxyno-zeta/gomock-extra-matcher/blob/master/release.config.js) - [Commits](https://github.com/oxyno-zeta/gomock-extra-matcher/compare/v1.1.0...v1.2.0) --- updated-dependencies: - dependency-name: github.com/oxyno-zeta/gomock-extra-matcher dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 3 ++- go.sum | 9 +++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 7b54164770..3fc1b177b7 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/gorilla/mux v1.8.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/kylelemons/godebug v1.1.0 - github.com/oxyno-zeta/gomock-extra-matcher v1.1.0 + github.com/oxyno-zeta/gomock-extra-matcher v1.2.0 github.com/rakyll/statik v0.1.7 // indirect github.com/spf13/cast v1.5.1 github.com/spf13/cobra v1.7.0 @@ -182,6 +182,7 @@ require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/rs/zerolog v1.30.0 // indirect + go.uber.org/mock v0.2.0 // indirect golang.org/x/sync v0.3.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect ) diff --git a/go.sum b/go.sum index 045c45ef25..033aa8adf2 100644 --- a/go.sum +++ b/go.sum @@ -960,8 +960,8 @@ github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJ github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= -github.com/oxyno-zeta/gomock-extra-matcher v1.1.0 h1:Yyk5ov0ZPKBXtVEeIWtc4J2XVrHuNoIK+0F2BUJgtsc= -github.com/oxyno-zeta/gomock-extra-matcher v1.1.0/go.mod h1:UMGTHYEmJ1dRq8LDZ7VTAYO4nqM3GD1UGC3RJEUxEz0= +github.com/oxyno-zeta/gomock-extra-matcher v1.2.0 h1:WPEclU0y0PMwUzdDcaKZvld4aXpa3fkzjiUMQdcBEHg= +github.com/oxyno-zeta/gomock-extra-matcher v1.2.0/go.mod h1:S0r7HmKeCGsHmvIVFMjKWwswb4+30nCNWbXRMBVPkaU= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= @@ -1164,6 +1164,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zondax/hid v0.9.1 h1:gQe66rtmyZ8VeGFcOpbuH3r7erYtNEAezCAYu8LdkJo= github.com/zondax/hid v0.9.1/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= @@ -1188,6 +1189,8 @@ go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqe go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/mock v0.2.0 h1:TaP3xedm7JaAgScZO7tlvlKrqT0p7I6OsdGB5YNSMDU= +go.uber.org/mock v0.2.0/go.mod h1:J0y0rp9L3xiff1+ZBfKxlC1fz2+aO16tw0tsDOixfuM= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= @@ -1262,6 +1265,7 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1574,6 +1578,7 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From 48a21869e9a56cafff53b5c51077a96d1e3c4926 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Tue, 12 Sep 2023 09:42:40 -0700 Subject: [PATCH 113/134] feat!: provider proposal for changing reward denoms (#1280) * new provider prop type * add methods and tests for new prop, update docs * remove old tx, fix tests * e2e handling * fix command type * boilerplate * fix e2e tests * Update CHANGELOG.md * lint * validate denoms * Update proposal.go * rm msg string * fix tests * rm chain in change denom action * lint * test for invalid denom * events for both add and remove * Update proposal_test.go --- CHANGELOG.md | 1 + app/provider/app.go | 1 + docs/docs/features/proposals.md | 17 + .../ccv/provider/v1/provider.proto | 13 + .../ccv/provider/v1/tx.proto | 17 - tests/e2e/actions.go | 58 +- tests/e2e/main.go | 4 +- tests/e2e/steps_democracy.go | 26 +- tests/e2e/steps_reward_denom.go | 26 +- tests/integration/distribution.go | 33 +- x/ccv/provider/client/cli/tx.go | 37 -- x/ccv/provider/client/proposal_handler.go | 97 ++- x/ccv/provider/handler.go | 3 - x/ccv/provider/keeper/distribution.go | 25 +- x/ccv/provider/keeper/distribution_test.go | 50 -- x/ccv/provider/keeper/msg_server.go | 21 - x/ccv/provider/keeper/proposal.go | 28 + x/ccv/provider/proposal_handler.go | 2 + x/ccv/provider/proposal_handler_test.go | 24 +- x/ccv/provider/types/codec.go | 6 +- x/ccv/provider/types/msg.go | 48 +- x/ccv/provider/types/proposal.go | 64 +- x/ccv/provider/types/proposal_test.go | 49 ++ x/ccv/provider/types/provider.pb.go | 588 ++++++++++++++---- x/ccv/provider/types/tx.pb.go | 424 +------------ x/ccv/types/events.go | 18 +- 26 files changed, 872 insertions(+), 808 deletions(-) delete mode 100644 x/ccv/provider/keeper/distribution_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index ce07a8e132..032927214a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Add an entry to the unreleased provider section whenever merging a PR to main that is not targeted at a specific release. These entries will eventually be included in a provider release. +* (feature!) [#1280](https://github.com/cosmos/interchain-security/pull/1280) provider proposal for changing reward denoms * (feature!) [#1244](https://github.com/cosmos/interchain-security/pull/1244) Update the default consumer unbonding period to 2 weeks. * (deps) [#1259](https://github.com/cosmos/interchain-security/pull/1259) Bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to [v0.47.5](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.47.5). * (deps!) [#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). diff --git a/app/provider/app.go b/app/provider/app.go index ef3f6508f7..4550ec77d2 100644 --- a/app/provider/app.go +++ b/app/provider/app.go @@ -141,6 +141,7 @@ var ( ibcproviderclient.ConsumerAdditionProposalHandler, ibcproviderclient.ConsumerRemovalProposalHandler, ibcproviderclient.EquivocationProposalHandler, + ibcproviderclient.ChangeRewardDenomsProposalHandler, }, ), params.AppModuleBasic{}, diff --git a/docs/docs/features/proposals.md b/docs/docs/features/proposals.md index 25664bfc1e..de4f2dc421 100644 --- a/docs/docs/features/proposals.md +++ b/docs/docs/features/proposals.md @@ -105,6 +105,23 @@ Minimal example: } ``` +## ChangeRewardDenomProposal +:::tip +`ChangeRewardDenomProposal` will only be accepted on the provider chain if at least one of the denomsToAdd or denomsToRemove fields is populated with at least one denom. Also, a denom cannot be repeated in both sets. +::: + +Proposal type used to mutate the set of denoms accepted by the provider as rewards. + +Minimal example: +```js +{ + "title": "Add untrn as a reward denom", + "description": "Here is more information about the proposal", + "denomsToAdd": ["untrn"], + "denomsToRemove": [] +} +``` + ### Notes When submitting equivocation evidence through an `EquivocationProposal` please take note that you need to use the consensus address (`valcons`) of the offending validator on the **provider chain**. Besides that, the `height` and the `time` fields should be mapped to the **provider chain** to avoid your evidence being rejected. diff --git a/proto/interchain_security/ccv/provider/v1/provider.proto b/proto/interchain_security/ccv/provider/v1/provider.proto index 9423e1f924..b0de16097b 100644 --- a/proto/interchain_security/ccv/provider/v1/provider.proto +++ b/proto/interchain_security/ccv/provider/v1/provider.proto @@ -116,6 +116,19 @@ message EquivocationProposal { repeated cosmos.evidence.v1beta1.Equivocation equivocations = 3; } +// ChangeRewardDenomsProposal is a governance proposal on the provider chain to +// mutate the set of denoms accepted by the provider as rewards. +message ChangeRewardDenomsProposal { + // the title of the proposal + string title = 1; + // the description of the proposal + string description = 2; + // the list of consumer reward denoms to add + repeated string denoms_to_add = 3; + // the list of consumer reward denoms to remove + repeated string denoms_to_remove = 4; +} + // A persisted queue entry indicating that a slash packet data instance needs to // be handled. This type belongs in the "global" queue, to coordinate slash // packet handling times between consumers. diff --git a/proto/interchain_security/ccv/provider/v1/tx.proto b/proto/interchain_security/ccv/provider/v1/tx.proto index 952ba31c09..7d4cce685e 100644 --- a/proto/interchain_security/ccv/provider/v1/tx.proto +++ b/proto/interchain_security/ccv/provider/v1/tx.proto @@ -12,8 +12,6 @@ import "google/protobuf/any.proto"; service Msg { rpc AssignConsumerKey(MsgAssignConsumerKey) returns (MsgAssignConsumerKeyResponse); - rpc RegisterConsumerRewardDenom(MsgRegisterConsumerRewardDenom) - returns (MsgRegisterConsumerRewardDenomResponse); } message MsgAssignConsumerKey { @@ -30,18 +28,3 @@ message MsgAssignConsumerKey { } message MsgAssignConsumerKeyResponse {} - -// MsgRegisterConsumerRewardDenom allows an account to register -// a consumer reward denom, i.e., add it to the list of denoms -// accepted by the provider as rewards. -message MsgRegisterConsumerRewardDenom { - option (gogoproto.equal) = false; - option (gogoproto.goproto_getters) = false; - - string denom = 1; - string depositor = 2; -} - -// MsgRegisterConsumerRewardDenomResponse defines the -// Msg/RegisterConsumerRewardDenom response type. -message MsgRegisterConsumerRewardDenomResponse {} diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index c05b21bfef..2256156958 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -1751,35 +1751,63 @@ func (tr TestRun) registerRepresentative( wg.Wait() } -type registerConsumerRewardDenomAction struct { - chain chainID - from validatorID - denom string +type submitChangeRewardDenomsProposalAction struct { + denom string + deposit uint + from validatorID } -func (tr TestRun) registerConsumerRewardDenom(action registerConsumerRewardDenomAction, verbose bool) { +func (tr TestRun) submitChangeRewardDenomsProposal(action submitChangeRewardDenomsProposalAction, verbose bool) { + providerChain := tr.chainConfigs[chainID("provi")] + + prop := client.ChangeRewardDenomsProposalJSON{ + Summary: "Change reward denoms", + ChangeRewardDenomsProposal: types.ChangeRewardDenomsProposal{ + Title: "Change reward denoms", + Description: "Change reward denoms", + DenomsToAdd: []string{action.denom}, + DenomsToRemove: []string{"stake"}, + }, + Deposit: fmt.Sprint(action.deposit) + `stake`, + } + + bz, err := json.Marshal(prop) + if err != nil { + log.Fatal(err) + } + + jsonStr := string(bz) + if strings.Contains(jsonStr, "'") { + log.Fatal("prop json contains single quote") + } + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - bz, err := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[action.chain].binaryName, - "tx", "provider", "register-consumer-reward-denom", action.denom, + bz, err = exec.Command("docker", "exec", tr.containerConfig.instanceName, + "/bin/bash", "-c", fmt.Sprintf(`echo '%s' > %s`, jsonStr, "/change-reward-denoms-proposal.json")).CombinedOutput() + if err != nil { + log.Fatal(err, "\n", string(bz)) + } + + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + // CHANGE REWARDS DENOM PROPOSAL + bz, err = exec.Command("docker", "exec", tr.containerConfig.instanceName, providerChain.binaryName, + "tx", "gov", "submit-legacy-proposal", "change-reward-denoms", "/change-reward-denoms-proposal.json", `--from`, `validator`+fmt.Sprint(action.from), - `--chain-id`, string(action.chain), - `--home`, tr.getValidatorHome(action.chain, action.from), - `--node`, tr.getValidatorNode(action.chain, action.from), + `--chain-id`, string(providerChain.chainId), + `--home`, tr.getValidatorHome(providerChain.chainId, action.from), + `--node`, tr.getValidatorNode(providerChain.chainId, action.from), `--gas`, "9000000", `--keyring-backend`, `test`, `-y`, ).CombinedOutput() - if verbose { - fmt.Println("redelegate cmd:", string(bz)) - } - if err != nil { log.Fatal(err, "\n", string(bz)) } - tr.waitBlocks(action.chain, 2, 10*time.Second) + // wait for inclusion in a block -> '--broadcast-mode block' is deprecated + tr.waitBlocks(chainID("provi"), 2, 30*time.Second) } // Creates an additional node on selected chain diff --git a/tests/e2e/main.go b/tests/e2e/main.go index 1998e95a2e..baf2db05da 100644 --- a/tests/e2e/main.go +++ b/tests/e2e/main.go @@ -258,8 +258,8 @@ func (tr *TestRun) runStep(step Step, verbose bool) { tr.waitForSlashThrottleDequeue(action, verbose) case startRelayerAction: tr.startRelayer(action, verbose) - case registerConsumerRewardDenomAction: - tr.registerConsumerRewardDenom(action, verbose) + case submitChangeRewardDenomsProposalAction: + tr.submitChangeRewardDenomsProposal(action, verbose) default: log.Fatalf("unknown action in testRun %s: %#v", tr.name, action) } diff --git a/tests/e2e/steps_democracy.go b/tests/e2e/steps_democracy.go index 7264c44341..85e9e8cbd7 100644 --- a/tests/e2e/steps_democracy.go +++ b/tests/e2e/steps_democracy.go @@ -133,19 +133,29 @@ func stepsDemocracy(consumerName string) []Step { }, }, { - action: registerConsumerRewardDenomAction{ - chain: chainID("provi"), - from: validatorID("bob"), - denom: consumerRewardDenom, + action: submitChangeRewardDenomsProposalAction{ + denom: consumerRewardDenom, + deposit: 10000001, + from: validatorID("bob"), + }, + state: State{ + chainID("provi"): ChainState{ + // Denom not yet registered, gov prop needs to pass first + RegisteredConsumerRewardDenoms: &[]string{}, + }, + }, + }, + { + action: voteGovProposalAction{ + chain: chainID("provi"), + from: []validatorID{validatorID("alice"), validatorID("bob"), validatorID("carol")}, + vote: []string{"yes", "yes", "yes"}, + propNumber: 2, }, state: State{ chainID("provi"): ChainState{ // Check that the denom is registered on provider chain RegisteredConsumerRewardDenoms: &[]string{consumerRewardDenom}, - ValBalances: &map[validatorID]uint{ - // make sure that bob's account was debited - validatorID("bob"): 9490000000, - }, }, }, }, diff --git a/tests/e2e/steps_reward_denom.go b/tests/e2e/steps_reward_denom.go index 9aad8ec7a8..cc9934f3f8 100644 --- a/tests/e2e/steps_reward_denom.go +++ b/tests/e2e/steps_reward_denom.go @@ -131,19 +131,29 @@ func stepsRewardDenomConsumer(consumerName string) []Step { }, }, { - action: registerConsumerRewardDenomAction{ - chain: chainID("provi"), - from: validatorID("bob"), - denom: "ibc/3C3D7B3BE4ECC85A0E5B52A3AEC3B7DFC2AA9CA47C37821E57020D6807043BE9", + action: submitChangeRewardDenomsProposalAction{ + denom: "ibc/3C3D7B3BE4ECC85A0E5B52A3AEC3B7DFC2AA9CA47C37821E57020D6807043BE9", + deposit: 10000001, + from: validatorID("bob"), + }, + state: State{ + chainID("provi"): ChainState{ + // Denom not yet registered, gov prop needs to pass first + RegisteredConsumerRewardDenoms: &[]string{}, + }, + }, + }, + { + action: voteGovProposalAction{ + chain: chainID("provi"), + from: []validatorID{validatorID("alice"), validatorID("bob"), validatorID("carol")}, + vote: []string{"yes", "yes", "yes"}, + propNumber: 2, }, state: State{ chainID("provi"): ChainState{ // Check that the denom is registered on provider chain RegisteredConsumerRewardDenoms: &[]string{"ibc/3C3D7B3BE4ECC85A0E5B52A3AEC3B7DFC2AA9CA47C37821E57020D6807043BE9"}, - ValBalances: &map[validatorID]uint{ - // make sure that bob's account was debited - validatorID("bob"): 9490000000, - }, }, }, }, diff --git a/tests/integration/distribution.go b/tests/integration/distribution.go index 65b82eecd6..668cf8cc7e 100644 --- a/tests/integration/distribution.go +++ b/tests/integration/distribution.go @@ -7,7 +7,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" icstestingutils "github.com/cosmos/interchain-security/v3/testutil/integration" consumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" @@ -96,41 +95,13 @@ func (s *CCVTestSuite) TestRewardsDistribution() { // Check that the coins got into the ConsumerRewardsPool s.Require().True(rewardCoins[ibcCoinIndex].Amount.Equal(providerExpectedRewards[0].Amount)) - // Attempt to register the consumer reward denom, but fail because the account has no coins - - // Get the balance of delAddr to send it out - senderCoins := providerBankKeeper.GetAllBalances(s.providerCtx(), delAddr) - - // Send the coins to the governance module just to have a place to send them - err = providerBankKeeper.SendCoinsFromAccountToModule(s.providerCtx(), delAddr, govtypes.ModuleName, senderCoins) - s.Require().NoError(err) - - // Attempt to register the consumer reward denom, but fail because the account has no coins - err = s.providerApp.GetProviderKeeper().RegisterConsumerRewardDenom(s.providerCtx(), rewardCoins[ibcCoinIndex].Denom, delAddr) - s.Require().Error(err) - // 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)) - // Successfully register the consumer reward denom this time - - // Send the coins back to the delAddr - err = providerBankKeeper.SendCoinsFromModuleToAccount(s.providerCtx(), govtypes.ModuleName, delAddr, senderCoins) - s.Require().NoError(err) - - // log the sender's coins - senderCoins1 := providerBankKeeper.GetAllBalances(s.providerCtx(), delAddr) - - // Register the consumer reward denom - err = s.providerApp.GetProviderKeeper().RegisterConsumerRewardDenom(s.providerCtx(), rewardCoins[ibcCoinIndex].Denom, delAddr) - s.Require().NoError(err) - - // Check that the delAddr has the right amount less money in it after paying the fee - senderCoins2 := providerBankKeeper.GetAllBalances(s.providerCtx(), delAddr) - consumerRewardDenomRegistrationFee := s.providerApp.GetProviderKeeper().GetConsumerRewardDenomRegistrationFee(s.providerCtx()) - s.Require().Equal(senderCoins1.Sub(senderCoins2...), sdk.NewCoins(consumerRewardDenomRegistrationFee)) + // 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() diff --git a/x/ccv/provider/client/cli/tx.go b/x/ccv/provider/client/cli/tx.go index 7e0609d74c..0d37ef52a9 100644 --- a/x/ccv/provider/client/cli/tx.go +++ b/x/ccv/provider/client/cli/tx.go @@ -2,7 +2,6 @@ package cli import ( "fmt" - "strings" "github.com/spf13/cobra" @@ -10,7 +9,6 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/tx" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ) @@ -26,7 +24,6 @@ func GetTxCmd() *cobra.Command { } cmd.AddCommand(NewAssignConsumerKeyCmd()) - cmd.AddCommand(NewRegisterConsumerRewardDenomCmd()) return cmd } @@ -68,37 +65,3 @@ func NewAssignConsumerKeyCmd() *cobra.Command { return cmd } - -func NewRegisterConsumerRewardDenomCmd() *cobra.Command { - cmd := &cobra.Command{ - Use: "register-consumer-reward-denom [denom]", - Args: cobra.ExactArgs(1), - Short: "Registers a denom that can be sent from consumer chains to all validators and delegators as a reward", - Long: strings.TrimSpace( - fmt.Sprintf(`Registers a denom that can be sent from consumer chains to all validators and delegators as a reward. - -Costs a fee, which is specified in genesis.json under the "consumer_reward_denom_fee" key. Will fail if the sending account has an insufficient balance. - -Example: -$ %s tx provider register-consumer-reward-denom untrn --from mykey -`, - version.AppName, - ), - ), - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - depositorAddr := clientCtx.GetFromAddress() - - msg := types.NewMsgRegisterConsumerRewardDenom(args[0], depositorAddr) - - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) - }, - } - - flags.AddTxFlagsToCmd(cmd) - - return cmd -} diff --git a/x/ccv/provider/client/proposal_handler.go b/x/ccv/provider/client/proposal_handler.go index 8ec6e89bfd..2b28c63466 100644 --- a/x/ccv/provider/client/proposal_handler.go +++ b/x/ccv/provider/client/proposal_handler.go @@ -24,9 +24,10 @@ import ( ) var ( - ConsumerAdditionProposalHandler = govclient.NewProposalHandler(SubmitConsumerAdditionPropTxCmd) - ConsumerRemovalProposalHandler = govclient.NewProposalHandler(SubmitConsumerRemovalProposalTxCmd) - EquivocationProposalHandler = govclient.NewProposalHandler(SubmitEquivocationProposalTxCmd) + ConsumerAdditionProposalHandler = govclient.NewProposalHandler(SubmitConsumerAdditionPropTxCmd) + ConsumerRemovalProposalHandler = govclient.NewProposalHandler(SubmitConsumerRemovalProposalTxCmd) + EquivocationProposalHandler = govclient.NewProposalHandler(SubmitEquivocationProposalTxCmd) + ChangeRewardDenomsProposalHandler = govclient.NewProposalHandler(SubmitChangeRewardDenomsProposalTxCmd) ) // SubmitConsumerAdditionPropTxCmd returns a CLI command handler for submitting @@ -229,6 +230,63 @@ Where proposal.json contains: } } +// SubmitChangeRewardDenomsProposalTxCmd returns a CLI command handler for submitting +// a change reward denoms proposal via a transaction. +func SubmitChangeRewardDenomsProposalTxCmd() *cobra.Command { + return &cobra.Command{ + Use: "change-reward-denoms [proposal-file]", + Args: cobra.ExactArgs(1), + Short: "Submit a change reward denoms proposal", + Long: `Submit an change reward denoms proposal with an initial deposit. + The proposal details must be supplied via a JSON file. + + Example: + $ tx gov submit-legacy-proposal change-reward-denoms --from= + + Where proposal.json contains: + { + "title": "Change reward denoms", + "summary": "Change reward denoms", + "denoms_to_add": ["untrn"], + "denoms_to_remove": ["stake"], + "deposit": "10000stake" + } + `, + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + proposal, err := ParseChangeRewardDenomsProposalJSON(args[0]) + if err != nil { + return err + } + + content := types.NewChangeRewardDenomsProposal(proposal.Title, proposal.Summary, proposal.DenomsToAdd, proposal.DenomsToRemove) + + from := clientCtx.GetFromAddress() + + msgContent, err := govv1.NewLegacyContent(content, authtypes.NewModuleAddress(govtypes.ModuleName).String()) + if err != nil { + return err + } + + deposit, err := sdk.ParseCoinsNormalized(proposal.Deposit) + if err != nil { + return err + } + + msg, err := govv1.NewMsgSubmitProposal([]sdk.Msg{msgContent}, deposit, from.String(), "", content.GetTitle(), proposal.Summary) + if err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } +} + type ConsumerAdditionProposalJSON struct { Title string `json:"title"` Summary string `json:"summary"` @@ -305,6 +363,21 @@ type ConsumerRemovalProposalReq struct { Deposit sdk.Coins `json:"deposit"` } +func ParseConsumerRemovalProposalJSON(proposalFile string) (ConsumerRemovalProposalJSON, error) { + proposal := ConsumerRemovalProposalJSON{} + + contents, err := os.ReadFile(filepath.Clean(proposalFile)) + if err != nil { + return proposal, err + } + + if err := json.Unmarshal(contents, &proposal); err != nil { + return proposal, err + } + + return proposal, nil +} + type EquivocationProposalJSON struct { // evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" Summary string `json:"summary"` @@ -337,18 +410,28 @@ func ParseEquivocationProposalJSON(proposalFile string) (EquivocationProposalJSO return proposal, nil } -func ParseConsumerRemovalProposalJSON(proposalFile string) (ConsumerRemovalProposalJSON, error) { - proposal := ConsumerRemovalProposalJSON{} +type ChangeRewardDenomsProposalJSON struct { + Summary string `json:"summary"` + types.ChangeRewardDenomsProposal + Deposit string `json:"deposit"` +} + +type ChangeRewardDenomsProposalReq struct { + Proposer sdk.AccAddress `json:"proposer"` + types.ChangeRewardDenomsProposal + Deposit sdk.Coins `json:"deposit"` +} + +func ParseChangeRewardDenomsProposalJSON(proposalFile string) (ChangeRewardDenomsProposalJSON, error) { + proposal := ChangeRewardDenomsProposalJSON{} contents, err := os.ReadFile(filepath.Clean(proposalFile)) if err != nil { return proposal, err } - if err := json.Unmarshal(contents, &proposal); err != nil { return proposal, err } - return proposal, nil } diff --git a/x/ccv/provider/handler.go b/x/ccv/provider/handler.go index 71da622fce..067d896cda 100644 --- a/x/ccv/provider/handler.go +++ b/x/ccv/provider/handler.go @@ -20,9 +20,6 @@ func NewHandler(k *keeper.Keeper) sdk.Handler { case *types.MsgAssignConsumerKey: res, err := msgServer.AssignConsumerKey(sdk.WrapSDKContext(ctx), msg) return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgRegisterConsumerRewardDenom: - res, err := msgServer.RegisterConsumerRewardDenom(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/keeper/distribution.go b/x/ccv/provider/keeper/distribution.go index a1dff6faf4..1b3336aefa 100644 --- a/x/ccv/provider/keeper/distribution.go +++ b/x/ccv/provider/keeper/distribution.go @@ -3,7 +3,6 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" - consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ) @@ -15,22 +14,6 @@ func (k Keeper) EndBlockRD(ctx sdk.Context) { k.TransferRewardsToFeeCollector(ctx) } -func (k Keeper) RegisterConsumerRewardDenom(ctx sdk.Context, denom string, sender sdk.AccAddress) error { - // Check if the denom is already registered - if k.ConsumerRewardDenomExists(ctx, denom) { - return consumertypes.ErrConsumerRewardDenomAlreadyRegistered - } - - // Send the consumer reward denom registration fee to the community pool - err := k.distributionKeeper.FundCommunityPool(ctx, sdk.NewCoins(k.GetConsumerRewardDenomRegistrationFee(ctx)), sender) - if err != nil { - return err - } - k.SetConsumerRewardDenom(ctx, denom) - k.Logger(ctx).Info("new consumer reward denom registered:", "denom", denom, "sender", sender.String()) - return nil -} - func (k Keeper) GetConsumerRewardsPoolAddressStr(ctx sdk.Context) string { return k.accountKeeper.GetModuleAccount( ctx, types.ConsumerRewardsPool).GetAddress().String() @@ -53,6 +36,14 @@ func (k Keeper) ConsumerRewardDenomExists( return bz != nil } +func (k Keeper) DeleteConsumerRewardDenom( + ctx sdk.Context, + denom string, +) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.ConsumerRewardDenomsKey(denom)) +} + func (k Keeper) GetAllConsumerRewardDenoms(ctx sdk.Context) (consumerRewardDenoms []string) { store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, []byte{types.ConsumerRewardDenomsBytePrefix}) diff --git a/x/ccv/provider/keeper/distribution_test.go b/x/ccv/provider/keeper/distribution_test.go deleted file mode 100644 index a470feea74..0000000000 --- a/x/ccv/provider/keeper/distribution_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package keeper_test - -import ( - "testing" - - "github.com/golang/mock/gomock" - "github.com/stretchr/testify/require" - - sdk "github.com/cosmos/cosmos-sdk/types" - - testutil "github.com/cosmos/interchain-security/v3/testutil/keeper" - consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" - "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" -) - -// TestRegisterConsumerRewardDenom tests the RegisterConsumerRewardDenom method. -func TestRegisterConsumerRewardDenom(t *testing.T) { - // Setup - providerKeeper, ctx, ctrl, mocks := testutil.GetProviderKeeperAndCtx(t, testutil.NewInMemKeeperParams(t)) - defer ctrl.Finish() - defaultParams := types.DefaultParams() - providerKeeper.SetParams(ctx, defaultParams) - accAddr := sdk.AccAddress([]byte("addr1")) - gomock.InOrder( - mocks.MockDistributionKeeper.EXPECT().FundCommunityPool(ctx, - sdk.NewCoins(defaultParams.ConsumerRewardDenomRegistrationFee), accAddr).Return(nil).Times(2), - ) - - // Register a consumer reward denom, confirm it's persisted as expected - err := providerKeeper.RegisterConsumerRewardDenom(ctx, "denom1", accAddr) - require.NoError(t, err) - require.True(t, providerKeeper.ConsumerRewardDenomExists(ctx, "denom1")) - allDenoms := providerKeeper.GetAllConsumerRewardDenoms(ctx) - require.Len(t, allDenoms, 1) - require.Equal(t, "denom1", allDenoms[0]) - - // Register another consumer reward denom, confirm both denoms are persisted as expected - err = providerKeeper.RegisterConsumerRewardDenom(ctx, "denom2", accAddr) - require.NoError(t, err) - require.True(t, providerKeeper.ConsumerRewardDenomExists(ctx, "denom2")) - allDenoms = providerKeeper.GetAllConsumerRewardDenoms(ctx) - require.Len(t, allDenoms, 2) - require.Equal(t, "denom1", allDenoms[0]) - require.Equal(t, "denom2", allDenoms[1]) - - // Try to register first consumer reward denom again, confirm it fails - err = providerKeeper.RegisterConsumerRewardDenom(ctx, "denom1", accAddr) - require.Error(t, err) - require.Equal(t, consumertypes.ErrConsumerRewardDenomAlreadyRegistered, err) -} diff --git a/x/ccv/provider/keeper/msg_server.go b/x/ccv/provider/keeper/msg_server.go index 195e2a7215..2aa0fed46c 100644 --- a/x/ccv/provider/keeper/msg_server.go +++ b/x/ccv/provider/keeper/msg_server.go @@ -108,24 +108,3 @@ func (k msgServer) AssignConsumerKey(goCtx context.Context, msg *types.MsgAssign return &types.MsgAssignConsumerKeyResponse{}, nil } - -func (k msgServer) RegisterConsumerRewardDenom(goCtx context.Context, msg *types.MsgRegisterConsumerRewardDenom) (*types.MsgRegisterConsumerRewardDenomResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) - - depositer, err := sdk.AccAddressFromBech32(msg.Depositor) - if err != nil { - return nil, err - } - - if err := k.Keeper.RegisterConsumerRewardDenom(ctx, msg.Denom, depositer); err != nil { - return nil, err - } - - ctx.EventManager().EmitEvent(sdk.NewEvent( - ccvtypes.EventTypeRegisterConsumerRewardDenom, - sdk.NewAttribute(ccvtypes.AttributeConsumerRewardDenom, msg.Denom), - sdk.NewAttribute(ccvtypes.AttributeConsumerRewardDepositor, msg.Depositor), - )) - - return &types.MsgRegisterConsumerRewardDenomResponse{}, nil -} diff --git a/x/ccv/provider/keeper/proposal.go b/x/ccv/provider/keeper/proposal.go index 7e4eb557f7..53c5f4396f 100644 --- a/x/ccv/provider/keeper/proposal.go +++ b/x/ccv/provider/keeper/proposal.go @@ -616,3 +616,31 @@ func (k Keeper) HandleEquivocationProposal(ctx sdk.Context, p *types.Equivocatio } return nil } + +func (k Keeper) HandleConsumerRewardDenomProposal(ctx sdk.Context, p *types.ChangeRewardDenomsProposal) error { + for _, denomToAdd := range p.DenomsToAdd { + // Log error and move on if one of the denoms is already registered + if k.ConsumerRewardDenomExists(ctx, denomToAdd) { + ctx.Logger().Error("denom %s already registered", denomToAdd) + continue + } + k.SetConsumerRewardDenom(ctx, denomToAdd) + ctx.EventManager().EmitEvent(sdk.NewEvent( + ccv.EventTypeAddConsumerRewardDenom, + sdk.NewAttribute(ccv.AttributeConsumerRewardDenom, denomToAdd), + )) + } + for _, denomToRemove := range p.DenomsToRemove { + // Log error and move on if one of the denoms is not registered + if !k.ConsumerRewardDenomExists(ctx, denomToRemove) { + ctx.Logger().Error("denom %s not registered", denomToRemove) + continue + } + k.DeleteConsumerRewardDenom(ctx, denomToRemove) + ctx.EventManager().EmitEvent(sdk.NewEvent( + ccv.EventTypeRemoveConsumerRewardDenom, + sdk.NewAttribute(ccv.AttributeConsumerRewardDenom, denomToRemove), + )) + } + return nil +} diff --git a/x/ccv/provider/proposal_handler.go b/x/ccv/provider/proposal_handler.go index 137cbecec7..7af7ec4e5f 100644 --- a/x/ccv/provider/proposal_handler.go +++ b/x/ccv/provider/proposal_handler.go @@ -23,6 +23,8 @@ func NewProviderProposalHandler(k keeper.Keeper) govv1beta1.Handler { return k.HandleConsumerRemovalProposal(ctx, c) case *types.EquivocationProposal: return k.HandleEquivocationProposal(ctx, c) + case *types.ChangeRewardDenomsProposal: + return k.HandleConsumerRewardDenomProposal(ctx, c) default: return errorsmod.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized ccv proposal content type: %T", c) } diff --git a/x/ccv/provider/proposal_handler_test.go b/x/ccv/provider/proposal_handler_test.go index e8963421d2..8f1322b3d2 100644 --- a/x/ccv/provider/proposal_handler_test.go +++ b/x/ccv/provider/proposal_handler_test.go @@ -27,12 +27,13 @@ func TestProviderProposalHandler(t *testing.T) { equivocation := &evidencetypes.Equivocation{Height: 42} testCases := []struct { - name string - content govv1beta1.Content - blockTime time.Time - expValidConsumerAddition bool - expValidConsumerRemoval bool - expValidEquivocation bool + name string + content govv1beta1.Content + blockTime time.Time + expValidConsumerAddition bool + expValidConsumerRemoval bool + expValidEquivocation bool + expValidChangeRewardDenom bool }{ { name: "valid consumer addition proposal", @@ -72,6 +73,13 @@ func TestProviderProposalHandler(t *testing.T) { blockTime: hourFromNow, expValidEquivocation: true, }, + { + name: "valid change reward denoms proposal", + content: providertypes.NewChangeRewardDenomsProposal( + "title", "description", []string{"denom1"}, []string{"denom2"}), + blockTime: hourFromNow, + expValidChangeRewardDenom: true, + }, { name: "nil proposal", content: nil, @@ -114,6 +122,8 @@ func TestProviderProposalHandler(t *testing.T) { case tc.expValidEquivocation: providerKeeper.SetSlashLog(ctx, providertypes.NewProviderConsAddress(equivocation.GetConsensusAddress())) mocks.MockEvidenceKeeper.EXPECT().HandleEquivocationEvidence(ctx, equivocation) + case tc.expValidChangeRewardDenom: + // Nothing to mock } // Execution @@ -121,7 +131,7 @@ func TestProviderProposalHandler(t *testing.T) { err := proposalHandler(ctx, tc.content) if tc.expValidConsumerAddition || tc.expValidConsumerRemoval || - tc.expValidEquivocation { + tc.expValidEquivocation || tc.expValidChangeRewardDenom { require.NoError(t, err) } else { require.Error(t, err) diff --git a/x/ccv/provider/types/codec.go b/x/ccv/provider/types/codec.go index 54c29442ae..ceed3bf789 100644 --- a/x/ccv/provider/types/codec.go +++ b/x/ccv/provider/types/codec.go @@ -28,12 +28,12 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { &MsgAssignConsumerKey{}, ) registry.RegisterImplementations( - (*sdk.Msg)(nil), - &MsgRegisterConsumerRewardDenom{}, + (*govv1beta1.Content)(nil), + &EquivocationProposal{}, ) registry.RegisterImplementations( (*govv1beta1.Content)(nil), - &EquivocationProposal{}, + &ChangeRewardDenomsProposal{}, ) msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) diff --git a/x/ccv/provider/types/msg.go b/x/ccv/provider/types/msg.go index 67ad99d10c..901aa03600 100644 --- a/x/ccv/provider/types/msg.go +++ b/x/ccv/provider/types/msg.go @@ -9,8 +9,7 @@ import ( // provider message types const ( - TypeMsgAssignConsumerKey = "assign_consumer_key" - TypeMsgRegisterConsumerRewardDenom = "register_consumer_reward_denom" + TypeMsgAssignConsumerKey = "assign_consumer_key" ) var _ sdk.Msg = &MsgAssignConsumerKey{} @@ -94,48 +93,3 @@ func ParseConsumerKeyFromJson(jsonStr string) (pkType, key string, err error) { } return pubKey.Type, pubKey.Key, nil } - -// NewMsgRegisterConsumerRewardDenom returns a new MsgRegisterConsumerRewardDenom with a sender and -// a funding amount. -func NewMsgRegisterConsumerRewardDenom(denom string, depositor sdk.AccAddress) *MsgRegisterConsumerRewardDenom { - return &MsgRegisterConsumerRewardDenom{ - Denom: denom, - Depositor: depositor.String(), - } -} - -// Route returns the MsgRegisterConsumerRewardDenom message route. -func (msg MsgRegisterConsumerRewardDenom) Route() string { return ModuleName } - -// Type returns the MsgRegisterConsumerRewardDenom message type. -func (msg MsgRegisterConsumerRewardDenom) Type() string { return TypeMsgRegisterConsumerRewardDenom } - -// GetSigners returns the signer addresses that are expected to sign the result -// of GetSignBytes. -func (msg MsgRegisterConsumerRewardDenom) GetSigners() []sdk.AccAddress { - depoAddr, err := sdk.AccAddressFromBech32(msg.Depositor) - if err != nil { - panic(err) - } - return []sdk.AccAddress{depoAddr} -} - -// GetSignBytes returns the raw bytes for a MsgRegisterConsumerRewardDenom message that -// the expected signer needs to sign. -func (msg MsgRegisterConsumerRewardDenom) GetSignBytes() []byte { - bz := ModuleCdc.MustMarshalJSON(&msg) - return sdk.MustSortJSON(bz) -} - -// ValidateBasic performs basic MsgRegisterConsumerRewardDenom message validation. -func (msg MsgRegisterConsumerRewardDenom) ValidateBasic() error { - if !sdk.NewCoin(msg.Denom, sdk.NewInt(0)).IsValid() { - return ErrInvalidConsumerRewardDenom - } - _, err := sdk.AccAddressFromBech32(msg.Depositor) - if err != nil { - return ErrInvalidDepositorAddress - } - - return nil -} diff --git a/x/ccv/provider/types/proposal.go b/x/ccv/provider/types/proposal.go index c369ec95f1..b2286d4adf 100644 --- a/x/ccv/provider/types/proposal.go +++ b/x/ccv/provider/types/proposal.go @@ -10,6 +10,7 @@ import ( errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" @@ -17,21 +18,24 @@ import ( ) const ( - ProposalTypeConsumerAddition = "ConsumerAddition" - ProposalTypeConsumerRemoval = "ConsumerRemoval" - ProposalTypeEquivocation = "Equivocation" + ProposalTypeConsumerAddition = "ConsumerAddition" + ProposalTypeConsumerRemoval = "ConsumerRemoval" + ProposalTypeEquivocation = "Equivocation" + ProposalTypeChangeRewardDenoms = "ChangeRewardDenoms" ) var ( _ govv1beta1.Content = &ConsumerAdditionProposal{} _ govv1beta1.Content = &ConsumerRemovalProposal{} _ govv1beta1.Content = &EquivocationProposal{} + _ govv1beta1.Content = &ChangeRewardDenomsProposal{} ) func init() { govv1beta1.RegisterProposalType(ProposalTypeConsumerAddition) govv1beta1.RegisterProposalType(ProposalTypeConsumerRemoval) govv1beta1.RegisterProposalType(ProposalTypeEquivocation) + govv1beta1.RegisterProposalType(ProposalTypeChangeRewardDenoms) } // NewConsumerAdditionProposal creates a new consumer addition proposal. @@ -231,3 +235,57 @@ func (sp *EquivocationProposal) ValidateBasic() error { } return nil } + +func NewChangeRewardDenomsProposal(title, description string, + denomsToAdd, denomsToRemove []string, +) govv1beta1.Content { + return &ChangeRewardDenomsProposal{ + Title: title, + Description: description, + DenomsToAdd: denomsToAdd, + DenomsToRemove: denomsToRemove, + } +} + +// ProposalRoute returns the routing key of a change reward denoms proposal. +func (crdp *ChangeRewardDenomsProposal) ProposalRoute() string { return RouterKey } + +// ProposalType returns the type of a change reward denoms proposal. +func (crdp *ChangeRewardDenomsProposal) ProposalType() string { + return ProposalTypeChangeRewardDenoms +} + +// ValidateBasic runs basic stateless validity checks on a ChangeRewardDenomsProposal. +func (crdp *ChangeRewardDenomsProposal) ValidateBasic() error { + emptyDenomsToAdd := len(crdp.DenomsToAdd) == 0 + emptyDenomsToRemove := len(crdp.DenomsToRemove) == 0 + // Return error if both sets are empty or nil + if emptyDenomsToAdd && emptyDenomsToRemove { + return fmt.Errorf( + "invalid change reward denoms proposal: both denoms to add and denoms to remove are empty") + } + + // Return error if a denom is in both sets + for _, denomToAdd := range crdp.DenomsToAdd { + for _, denomToRemove := range crdp.DenomsToRemove { + if denomToAdd == denomToRemove { + return fmt.Errorf( + "invalid change reward denoms proposal: %s cannot be both added and removed", denomToAdd) + } + } + } + + // Return error if any denom is "invalid" + for _, denom := range crdp.DenomsToAdd { + if !sdk.NewCoin(denom, sdk.NewInt(1)).IsValid() { + return fmt.Errorf("invalid change reward denoms proposal: %s is not a valid denom", denom) + } + } + for _, denom := range crdp.DenomsToRemove { + if !sdk.NewCoin(denom, sdk.NewInt(1)).IsValid() { + return fmt.Errorf("invalid change reward denoms proposal: %s is not a valid denom", denom) + } + } + + return nil +} diff --git a/x/ccv/provider/types/proposal_test.go b/x/ccv/provider/types/proposal_test.go index fac4c7fc4b..357c555d0e 100644 --- a/x/ccv/provider/types/proposal_test.go +++ b/x/ccv/provider/types/proposal_test.go @@ -362,3 +362,52 @@ func TestEquivocationProposalValidateBasic(t *testing.T) { }) } } + +func TestChangeRewardDenomsProposalValidateBasic(t *testing.T) { + tcs := []struct { + name string + proposal govv1beta1.Content + expectError bool + expectPanic bool + }{ + { + name: "invalid change reward denoms proposal, none to add or remove", + proposal: types.NewChangeRewardDenomsProposal( + "title", "description", []string{}, []string{}), + expectError: true, + }, + { + name: "invalid change reward denoms proposal, same denom in both sets", + proposal: types.NewChangeRewardDenomsProposal( + "title", "description", []string{"denom1"}, []string{"denom1"}), + expectError: true, + }, + { + name: "valid change reward denoms proposal", + proposal: types.NewChangeRewardDenomsProposal( + "title", "description", []string{"denom1"}, []string{"denom2"}), + expectError: false, + }, + { + name: "invalid prop, invalid denom, will panic", + proposal: types.NewChangeRewardDenomsProposal( + "title", "description", []string{"!@blah"}, []string{"denom2"}), + expectPanic: true, + }, + } + + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + if tc.expectPanic { + require.Panics(t, func() { tc.proposal.ValidateBasic() }) + return + } + err := tc.proposal.ValidateBasic() + if tc.expectError { + require.Error(t, err) + return + } + require.NoError(t, err) + }) + } +} diff --git a/x/ccv/provider/types/provider.pb.go b/x/ccv/provider/types/provider.pb.go index 398010307c..ef0aa6e5e1 100644 --- a/x/ccv/provider/types/provider.pb.go +++ b/x/ccv/provider/types/provider.pb.go @@ -268,6 +268,80 @@ func (m *EquivocationProposal) GetEquivocations() []*types1.Equivocation { return nil } +// ChangeRewardDenomsProposal is a governance proposal on the provider chain to +// mutate the set of denoms accepted by the provider as rewards. +type ChangeRewardDenomsProposal struct { + // the title of the proposal + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + // the description of the proposal + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + // the list of consumer reward denoms to add + DenomsToAdd []string `protobuf:"bytes,3,rep,name=denoms_to_add,json=denomsToAdd,proto3" json:"denoms_to_add,omitempty"` + // the list of consumer reward denoms to remove + DenomsToRemove []string `protobuf:"bytes,4,rep,name=denoms_to_remove,json=denomsToRemove,proto3" json:"denoms_to_remove,omitempty"` +} + +func (m *ChangeRewardDenomsProposal) Reset() { *m = ChangeRewardDenomsProposal{} } +func (m *ChangeRewardDenomsProposal) String() string { return proto.CompactTextString(m) } +func (*ChangeRewardDenomsProposal) ProtoMessage() {} +func (*ChangeRewardDenomsProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_f22ec409a72b7b72, []int{3} +} +func (m *ChangeRewardDenomsProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ChangeRewardDenomsProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ChangeRewardDenomsProposal.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 *ChangeRewardDenomsProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_ChangeRewardDenomsProposal.Merge(m, src) +} +func (m *ChangeRewardDenomsProposal) XXX_Size() int { + return m.Size() +} +func (m *ChangeRewardDenomsProposal) XXX_DiscardUnknown() { + xxx_messageInfo_ChangeRewardDenomsProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_ChangeRewardDenomsProposal proto.InternalMessageInfo + +func (m *ChangeRewardDenomsProposal) GetTitle() string { + if m != nil { + return m.Title + } + return "" +} + +func (m *ChangeRewardDenomsProposal) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *ChangeRewardDenomsProposal) GetDenomsToAdd() []string { + if m != nil { + return m.DenomsToAdd + } + return nil +} + +func (m *ChangeRewardDenomsProposal) GetDenomsToRemove() []string { + if m != nil { + return m.DenomsToRemove + } + return nil +} + // A persisted queue entry indicating that a slash packet data instance needs to // be handled. This type belongs in the "global" queue, to coordinate slash // packet handling times between consumers. @@ -292,7 +366,7 @@ func (m *GlobalSlashEntry) Reset() { *m = GlobalSlashEntry{} } func (m *GlobalSlashEntry) String() string { return proto.CompactTextString(m) } func (*GlobalSlashEntry) ProtoMessage() {} func (*GlobalSlashEntry) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{3} + return fileDescriptor_f22ec409a72b7b72, []int{4} } func (m *GlobalSlashEntry) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -382,7 +456,7 @@ func (m *Params) Reset() { *m = Params{} } func (m *Params) String() string { return proto.CompactTextString(m) } func (*Params) ProtoMessage() {} func (*Params) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{4} + return fileDescriptor_f22ec409a72b7b72, []int{5} } func (m *Params) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -484,7 +558,7 @@ func (m *SlashAcks) Reset() { *m = SlashAcks{} } func (m *SlashAcks) String() string { return proto.CompactTextString(m) } func (*SlashAcks) ProtoMessage() {} func (*SlashAcks) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{5} + return fileDescriptor_f22ec409a72b7b72, []int{6} } func (m *SlashAcks) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -531,7 +605,7 @@ func (m *ConsumerAdditionProposals) Reset() { *m = ConsumerAdditionPropo func (m *ConsumerAdditionProposals) String() string { return proto.CompactTextString(m) } func (*ConsumerAdditionProposals) ProtoMessage() {} func (*ConsumerAdditionProposals) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{6} + return fileDescriptor_f22ec409a72b7b72, []int{7} } func (m *ConsumerAdditionProposals) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -578,7 +652,7 @@ func (m *ConsumerRemovalProposals) Reset() { *m = ConsumerRemovalProposa func (m *ConsumerRemovalProposals) String() string { return proto.CompactTextString(m) } func (*ConsumerRemovalProposals) ProtoMessage() {} func (*ConsumerRemovalProposals) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{7} + return fileDescriptor_f22ec409a72b7b72, []int{8} } func (m *ConsumerRemovalProposals) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -623,7 +697,7 @@ func (m *AddressList) Reset() { *m = AddressList{} } func (m *AddressList) String() string { return proto.CompactTextString(m) } func (*AddressList) ProtoMessage() {} func (*AddressList) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{8} + return fileDescriptor_f22ec409a72b7b72, []int{9} } func (m *AddressList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -668,7 +742,7 @@ func (m *ChannelToChain) Reset() { *m = ChannelToChain{} } func (m *ChannelToChain) String() string { return proto.CompactTextString(m) } func (*ChannelToChain) ProtoMessage() {} func (*ChannelToChain) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{9} + return fileDescriptor_f22ec409a72b7b72, []int{10} } func (m *ChannelToChain) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -722,7 +796,7 @@ func (m *VscUnbondingOps) Reset() { *m = VscUnbondingOps{} } func (m *VscUnbondingOps) String() string { return proto.CompactTextString(m) } func (*VscUnbondingOps) ProtoMessage() {} func (*VscUnbondingOps) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{10} + return fileDescriptor_f22ec409a72b7b72, []int{11} } func (m *VscUnbondingOps) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -777,7 +851,7 @@ func (m *UnbondingOp) Reset() { *m = UnbondingOp{} } func (m *UnbondingOp) String() string { return proto.CompactTextString(m) } func (*UnbondingOp) ProtoMessage() {} func (*UnbondingOp) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{11} + return fileDescriptor_f22ec409a72b7b72, []int{12} } func (m *UnbondingOp) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -829,7 +903,7 @@ func (m *InitTimeoutTimestamp) Reset() { *m = InitTimeoutTimestamp{} } func (m *InitTimeoutTimestamp) String() string { return proto.CompactTextString(m) } func (*InitTimeoutTimestamp) ProtoMessage() {} func (*InitTimeoutTimestamp) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{12} + return fileDescriptor_f22ec409a72b7b72, []int{13} } func (m *InitTimeoutTimestamp) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -881,7 +955,7 @@ func (m *VscSendTimestamp) Reset() { *m = VscSendTimestamp{} } func (m *VscSendTimestamp) String() string { return proto.CompactTextString(m) } func (*VscSendTimestamp) ProtoMessage() {} func (*VscSendTimestamp) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{13} + return fileDescriptor_f22ec409a72b7b72, []int{14} } func (m *VscSendTimestamp) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -933,7 +1007,7 @@ func (m *ValidatorSetChangePackets) Reset() { *m = ValidatorSetChangePac func (m *ValidatorSetChangePackets) String() string { return proto.CompactTextString(m) } func (*ValidatorSetChangePackets) ProtoMessage() {} func (*ValidatorSetChangePackets) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{14} + return fileDescriptor_f22ec409a72b7b72, []int{15} } func (m *ValidatorSetChangePackets) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -979,7 +1053,7 @@ func (m *MaturedUnbondingOps) Reset() { *m = MaturedUnbondingOps{} } func (m *MaturedUnbondingOps) String() string { return proto.CompactTextString(m) } func (*MaturedUnbondingOps) ProtoMessage() {} func (*MaturedUnbondingOps) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{15} + return fileDescriptor_f22ec409a72b7b72, []int{16} } func (m *MaturedUnbondingOps) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1025,7 +1099,7 @@ func (m *ExportedVscSendTimestamp) Reset() { *m = ExportedVscSendTimesta func (m *ExportedVscSendTimestamp) String() string { return proto.CompactTextString(m) } func (*ExportedVscSendTimestamp) ProtoMessage() {} func (*ExportedVscSendTimestamp) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{16} + return fileDescriptor_f22ec409a72b7b72, []int{17} } func (m *ExportedVscSendTimestamp) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1078,7 +1152,7 @@ func (m *KeyAssignmentReplacement) Reset() { *m = KeyAssignmentReplaceme func (m *KeyAssignmentReplacement) String() string { return proto.CompactTextString(m) } func (*KeyAssignmentReplacement) ProtoMessage() {} func (*KeyAssignmentReplacement) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{17} + return fileDescriptor_f22ec409a72b7b72, []int{18} } func (m *KeyAssignmentReplacement) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1141,7 +1215,7 @@ func (m *ValidatorConsumerPubKey) Reset() { *m = ValidatorConsumerPubKey func (m *ValidatorConsumerPubKey) String() string { return proto.CompactTextString(m) } func (*ValidatorConsumerPubKey) ProtoMessage() {} func (*ValidatorConsumerPubKey) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{18} + return fileDescriptor_f22ec409a72b7b72, []int{19} } func (m *ValidatorConsumerPubKey) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1204,7 +1278,7 @@ func (m *ValidatorByConsumerAddr) Reset() { *m = ValidatorByConsumerAddr func (m *ValidatorByConsumerAddr) String() string { return proto.CompactTextString(m) } func (*ValidatorByConsumerAddr) ProtoMessage() {} func (*ValidatorByConsumerAddr) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{19} + return fileDescriptor_f22ec409a72b7b72, []int{20} } func (m *ValidatorByConsumerAddr) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1266,7 +1340,7 @@ func (m *ConsumerAddrsToPrune) Reset() { *m = ConsumerAddrsToPrune{} } func (m *ConsumerAddrsToPrune) String() string { return proto.CompactTextString(m) } func (*ConsumerAddrsToPrune) ProtoMessage() {} func (*ConsumerAddrsToPrune) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{20} + return fileDescriptor_f22ec409a72b7b72, []int{21} } func (m *ConsumerAddrsToPrune) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1320,6 +1394,7 @@ func init() { proto.RegisterType((*ConsumerAdditionProposal)(nil), "interchain_security.ccv.provider.v1.ConsumerAdditionProposal") proto.RegisterType((*ConsumerRemovalProposal)(nil), "interchain_security.ccv.provider.v1.ConsumerRemovalProposal") proto.RegisterType((*EquivocationProposal)(nil), "interchain_security.ccv.provider.v1.EquivocationProposal") + proto.RegisterType((*ChangeRewardDenomsProposal)(nil), "interchain_security.ccv.provider.v1.ChangeRewardDenomsProposal") proto.RegisterType((*GlobalSlashEntry)(nil), "interchain_security.ccv.provider.v1.GlobalSlashEntry") proto.RegisterType((*Params)(nil), "interchain_security.ccv.provider.v1.Params") proto.RegisterType((*SlashAcks)(nil), "interchain_security.ccv.provider.v1.SlashAcks") @@ -1345,112 +1420,115 @@ func init() { } var fileDescriptor_f22ec409a72b7b72 = []byte{ - // 1674 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, 0xea, 0x9f, 0x57, 0x72, 0x4c, 0xb9, 0x2a, 0x45, 0x6f, 0x9a, - 0x54, 0x45, 0x90, 0x65, 0x24, 0xa3, 0x40, 0x60, 0x34, 0x08, 0x24, 0xca, 0x89, 0x15, 0x35, 0xb1, - 0xb2, 0x52, 0x65, 0xb4, 0x3d, 0x2c, 0x86, 0xb3, 0x63, 0x72, 0xa0, 0xdd, 0x9d, 0xf5, 0xcc, 0xec, - 0xda, 0xbc, 0xf4, 0xdc, 0x63, 0x7a, 0x0b, 0xda, 0x4b, 0xda, 0x2f, 0xd0, 0xaf, 0x91, 0x63, 0x8e, - 0x3d, 0x25, 0x85, 0x7d, 0xe8, 0xa1, 0x5f, 0xa2, 0x98, 0xd9, 0xbf, 0xa4, 0x44, 0x95, 0x46, 0x9b, - 0xdb, 0xec, 0x9b, 0xf7, 0x7e, 0xef, 0xff, 0x7b, 0x43, 0xc2, 0x3e, 0x0d, 0x25, 0xe1, 0x78, 0x88, - 0x68, 0xe8, 0x0a, 0x82, 0x63, 0x4e, 0xe5, 0xa8, 0x8b, 0x71, 0xd2, 0x8d, 0x38, 0x4b, 0xa8, 0x47, - 0x78, 0x37, 0xd9, 0x2b, 0xce, 0x76, 0xc4, 0x99, 0x64, 0xe6, 0xdb, 0xd7, 0xc8, 0xd8, 0x18, 0x27, - 0x76, 0xc1, 0x97, 0xec, 0xdd, 0xfb, 0x60, 0x1a, 0x70, 0xb2, 0xd7, 0x15, 0x43, 0xc4, 0x89, 0xe7, - 0x62, 0x16, 0x8a, 0x38, 0xc8, 0x61, 0xef, 0xbd, 0x73, 0x83, 0xc4, 0x0b, 0xca, 0x49, 0xc6, 0xb6, - 0x39, 0x60, 0x03, 0xa6, 0x8f, 0x5d, 0x75, 0xca, 0xa8, 0x3b, 0x03, 0xc6, 0x06, 0x3e, 0xe9, 0xea, - 0xaf, 0x7e, 0xfc, 0xac, 0x2b, 0x69, 0x40, 0x84, 0x44, 0x41, 0x94, 0x31, 0xb4, 0x27, 0x19, 0xbc, - 0x98, 0x23, 0x49, 0x59, 0x98, 0x03, 0xd0, 0x3e, 0xee, 0x62, 0xc6, 0x49, 0x17, 0xfb, 0x94, 0x84, - 0x52, 0x69, 0x4d, 0x4f, 0x19, 0x43, 0x57, 0x31, 0xf8, 0x74, 0x30, 0x94, 0x29, 0x59, 0x74, 0x25, - 0x09, 0x3d, 0xc2, 0x03, 0x9a, 0x32, 0x97, 0x5f, 0x99, 0xc0, 0x76, 0xe5, 0x1e, 0xf3, 0x51, 0x24, - 0x59, 0xf7, 0x92, 0x8c, 0x44, 0x76, 0xfb, 0x2e, 0x66, 0x22, 0x60, 0xa2, 0x4b, 0x54, 0xc4, 0x42, - 0x4c, 0xba, 0xc9, 0x5e, 0x9f, 0x48, 0xb4, 0x57, 0x10, 0x72, 0xbb, 0x33, 0xbe, 0x3e, 0x12, 0x25, - 0x0f, 0x66, 0x34, 0xb3, 0xdb, 0xfa, 0x61, 0x11, 0x5a, 0xbd, 0x2c, 0x90, 0x07, 0x9e, 0x47, 0x95, - 0x4b, 0xa7, 0x9c, 0x45, 0x4c, 0x20, 0xdf, 0xdc, 0x84, 0x05, 0x49, 0xa5, 0x4f, 0x5a, 0x46, 0xc7, - 0xd8, 0x6d, 0x38, 0xe9, 0x87, 0xd9, 0x81, 0xa6, 0x47, 0x04, 0xe6, 0x34, 0x52, 0xcc, 0xad, 0x79, - 0x7d, 0x57, 0x25, 0x99, 0x5b, 0xb0, 0x94, 0xe6, 0x81, 0x7a, 0xad, 0x9a, 0xbe, 0xbe, 0xa5, 0xbf, - 0x8f, 0x3d, 0xf3, 0x53, 0x58, 0xa5, 0x21, 0x95, 0x14, 0xf9, 0xee, 0x90, 0xa8, 0x68, 0xb4, 0xea, - 0x1d, 0x63, 0xb7, 0xb9, 0x7f, 0xcf, 0xa6, 0x7d, 0x6c, 0xab, 0x00, 0xda, 0x59, 0xd8, 0x92, 0x3d, - 0xfb, 0xb1, 0xe6, 0x38, 0xac, 0x7f, 0xfb, 0xfd, 0xce, 0x9c, 0xb3, 0x92, 0xc9, 0xa5, 0x44, 0xf3, - 0x3e, 0x2c, 0x0f, 0x48, 0x48, 0x04, 0x15, 0xee, 0x10, 0x89, 0x61, 0x6b, 0xa1, 0x63, 0xec, 0x2e, - 0x3b, 0xcd, 0x8c, 0xf6, 0x18, 0x89, 0xa1, 0xb9, 0x03, 0xcd, 0x3e, 0x0d, 0x11, 0x1f, 0xa5, 0x1c, - 0x8b, 0x9a, 0x03, 0x52, 0x92, 0x66, 0xe8, 0x01, 0x88, 0x08, 0xbd, 0x08, 0x5d, 0x95, 0xed, 0xd6, - 0xad, 0xcc, 0x90, 0x34, 0xd3, 0x76, 0x9e, 0x69, 0xfb, 0x3c, 0x2f, 0x85, 0xc3, 0x25, 0x65, 0xc8, - 0x57, 0x3f, 0xec, 0x18, 0x4e, 0x43, 0xcb, 0xa9, 0x1b, 0xf3, 0x0b, 0x58, 0x8f, 0xc3, 0x3e, 0x0b, - 0x3d, 0x1a, 0x0e, 0xdc, 0x88, 0x70, 0xca, 0xbc, 0xd6, 0x92, 0x86, 0xda, 0xba, 0x02, 0x75, 0x94, - 0x15, 0x4d, 0x8a, 0xf4, 0xb5, 0x42, 0x5a, 0x2b, 0x84, 0x4f, 0xb5, 0xac, 0xf9, 0x25, 0x98, 0x18, - 0x27, 0xda, 0x24, 0x16, 0xcb, 0x1c, 0xb1, 0x31, 0x3b, 0xe2, 0x3a, 0xc6, 0xc9, 0x79, 0x2a, 0x9d, - 0x41, 0xfe, 0x1e, 0xee, 0x4a, 0x8e, 0x42, 0xf1, 0x8c, 0xf0, 0x49, 0x5c, 0x98, 0x1d, 0xf7, 0x4e, - 0x8e, 0x31, 0x0e, 0xfe, 0x18, 0x3a, 0x79, 0x27, 0xba, 0x9c, 0x78, 0x54, 0x48, 0x4e, 0xfb, 0xb1, - 0x92, 0x75, 0x9f, 0x71, 0x84, 0x75, 0x8d, 0x34, 0x75, 0x11, 0xb4, 0x73, 0x3e, 0x67, 0x8c, 0xed, - 0x93, 0x8c, 0xcb, 0x7c, 0x02, 0x3f, 0xeb, 0xfb, 0x0c, 0x5f, 0x0a, 0x65, 0x9c, 0x3b, 0x86, 0xa4, - 0x55, 0x07, 0x54, 0x08, 0x85, 0xb6, 0xdc, 0x31, 0x76, 0x6b, 0xce, 0xfd, 0x94, 0xf7, 0x94, 0xf0, - 0xa3, 0x0a, 0xe7, 0x79, 0x85, 0xd1, 0x7c, 0x1f, 0xcc, 0x21, 0x15, 0x92, 0x71, 0x8a, 0x91, 0xef, - 0x92, 0x50, 0x72, 0x4a, 0x44, 0x6b, 0x45, 0x8b, 0xdf, 0x2e, 0x6f, 0x1e, 0xa5, 0x17, 0xe6, 0x67, - 0x70, 0x7f, 0xaa, 0x52, 0x17, 0x0f, 0x51, 0x18, 0x12, 0xbf, 0xb5, 0xaa, 0x5d, 0xd9, 0xf1, 0xa6, - 0xe8, 0xec, 0xa5, 0x6c, 0x0f, 0x97, 0xfe, 0xf8, 0xcd, 0xce, 0xdc, 0xd7, 0xdf, 0xec, 0xcc, 0x59, - 0x7f, 0x37, 0xe0, 0x6e, 0xaf, 0x70, 0x3c, 0x60, 0x09, 0xf2, 0x7f, 0xcc, 0x06, 0x3b, 0x80, 0x86, - 0x90, 0x2c, 0x4a, 0x4b, 0xba, 0xfe, 0x06, 0x25, 0xbd, 0xa4, 0xc4, 0xd4, 0x85, 0xf5, 0x17, 0x03, - 0x36, 0x1f, 0x3d, 0x8f, 0x69, 0xc2, 0x30, 0xfa, 0xbf, 0xcc, 0x83, 0x13, 0x58, 0x21, 0x15, 0x3c, - 0xd1, 0xaa, 0x75, 0x6a, 0xbb, 0xcd, 0xfd, 0x77, 0xec, 0x74, 0x38, 0xd9, 0xc5, 0xcc, 0xca, 0x06, - 0x94, 0x5d, 0xd5, 0xee, 0x8c, 0xcb, 0x5a, 0xff, 0x36, 0x60, 0xfd, 0x53, 0x9f, 0xf5, 0x91, 0x7f, - 0xe6, 0x23, 0x31, 0x54, 0xc9, 0x1b, 0x29, 0xaf, 0x39, 0xc9, 0xba, 0x46, 0x5b, 0x37, 0xb3, 0xd7, - 0x4a, 0x4c, 0xf7, 0xf1, 0xc7, 0x70, 0xbb, 0xa8, 0xe3, 0x22, 0xb8, 0xda, 0x99, 0xc3, 0x8d, 0x57, - 0xdf, 0xef, 0xac, 0xe5, 0x39, 0xec, 0xe9, 0x40, 0x1f, 0x39, 0x6b, 0x78, 0x8c, 0xe0, 0x99, 0x6d, - 0x68, 0xd2, 0x3e, 0x76, 0x05, 0x79, 0xee, 0x86, 0x71, 0xa0, 0xf3, 0x52, 0x77, 0x1a, 0xb4, 0x8f, - 0xcf, 0xc8, 0xf3, 0x2f, 0xe2, 0xc0, 0x7c, 0x00, 0x6f, 0xe5, 0x1b, 0xce, 0x4d, 0x90, 0xaf, 0xf7, - 0x97, 0x8b, 0x3c, 0x8f, 0xeb, 0x34, 0x2d, 0x3b, 0x1b, 0xf9, 0xed, 0x05, 0xf2, 0x95, 0xb2, 0x03, - 0xcf, 0xe3, 0xd6, 0xbf, 0x16, 0x60, 0xf1, 0x14, 0x71, 0x14, 0x08, 0xf3, 0x1c, 0xd6, 0x24, 0x09, - 0x22, 0x1f, 0x49, 0xe2, 0xa6, 0x33, 0x32, 0xf3, 0xf4, 0x3d, 0x3d, 0x3b, 0xab, 0xbb, 0xc5, 0xae, - 0x6c, 0x93, 0x64, 0xcf, 0xee, 0x69, 0xea, 0x99, 0x44, 0x92, 0x38, 0xab, 0x39, 0x46, 0x4a, 0x34, - 0x3f, 0x84, 0x96, 0xe4, 0xb1, 0x90, 0xe5, 0xf4, 0x2a, 0xdb, 0x36, 0x4d, 0xe5, 0x5b, 0xf9, 0x7d, - 0xda, 0xf0, 0x45, 0xbb, 0x5e, 0x3f, 0xa8, 0x6a, 0xff, 0xcb, 0xa0, 0x3a, 0x83, 0x0d, 0x35, 0xe5, - 0x27, 0x31, 0xeb, 0xb3, 0x63, 0xde, 0x56, 0xf2, 0xe3, 0xa0, 0x5f, 0x82, 0x99, 0x08, 0x3c, 0x89, - 0xb9, 0xf0, 0x06, 0x76, 0x26, 0x02, 0x8f, 0x43, 0x7a, 0xb0, 0x2d, 0x54, 0xf1, 0xb9, 0x01, 0x91, - 0x7a, 0xec, 0x45, 0x3e, 0x09, 0xa9, 0x18, 0xe6, 0xe0, 0x8b, 0xb3, 0x83, 0x6f, 0x69, 0xa0, 0xcf, - 0x15, 0x8e, 0x93, 0xc3, 0x64, 0x5a, 0x7a, 0xd0, 0xbe, 0x5e, 0x4b, 0x91, 0xa0, 0x5b, 0x3a, 0x41, - 0x3f, 0xb9, 0x06, 0xa2, 0xc8, 0xd2, 0x3e, 0xdc, 0x09, 0xd0, 0x4b, 0x57, 0x0e, 0x39, 0x93, 0xd2, - 0x27, 0x9e, 0x1b, 0x21, 0x7c, 0x49, 0xa4, 0xd0, 0x3b, 0xaa, 0xe6, 0x6c, 0x04, 0xe8, 0xe5, 0x79, - 0x7e, 0x77, 0x9a, 0x5e, 0x99, 0x02, 0xde, 0xad, 0x8c, 0xf4, 0x17, 0x88, 0x7b, 0xae, 0x47, 0x42, - 0x16, 0xb8, 0x9c, 0x0c, 0xd4, 0xdc, 0x43, 0xe9, 0x74, 0x27, 0xa4, 0x58, 0x4b, 0x59, 0x23, 0xab, - 0x57, 0x46, 0xd1, 0xc4, 0x3d, 0x46, 0xc3, 0x6c, 0x77, 0x5b, 0xe5, 0xe4, 0x57, 0x68, 0x47, 0x0a, - 0xcc, 0xa9, 0x60, 0x7d, 0x42, 0x88, 0xf5, 0x0b, 0x68, 0xe8, 0x86, 0x3e, 0xc0, 0x97, 0xc2, 0xdc, - 0x86, 0x86, 0xea, 0x0c, 0x22, 0x04, 0x11, 0x2d, 0xa3, 0x53, 0xdb, 0x6d, 0x38, 0x25, 0xc1, 0x92, - 0xb0, 0x35, 0xed, 0xcd, 0x22, 0xcc, 0xa7, 0x70, 0x2b, 0x22, 0x7a, 0xa1, 0x6a, 0xc1, 0xe6, 0xfe, - 0x47, 0xf6, 0x0c, 0x0f, 0x4e, 0x7b, 0x1a, 0xa0, 0x93, 0xa3, 0x59, 0xbc, 0x7c, 0x29, 0x4d, 0xcc, - 0x71, 0x61, 0x5e, 0x4c, 0x2a, 0xfd, 0xd5, 0x1b, 0x29, 0x9d, 0xc0, 0x2b, 0x75, 0xbe, 0x07, 0xcd, - 0x83, 0xd4, 0xed, 0x5f, 0x53, 0x21, 0xaf, 0x86, 0x65, 0xb9, 0x1a, 0x96, 0xcf, 0x60, 0x35, 0x5b, - 0x3f, 0xe7, 0x4c, 0x0f, 0x25, 0xf3, 0xa7, 0x00, 0xd9, 0xde, 0x52, 0xc3, 0x2c, 0x9d, 0xda, 0x8d, - 0x8c, 0x72, 0xec, 0x8d, 0xad, 0x91, 0xf9, 0xb1, 0x35, 0x62, 0x39, 0xb0, 0x76, 0x21, 0xf0, 0x6f, - 0xf2, 0xb7, 0xc9, 0x93, 0x48, 0x98, 0x77, 0x60, 0x51, 0xf5, 0x51, 0x06, 0x54, 0x77, 0x16, 0x12, - 0x81, 0x8f, 0x3d, 0x73, 0xb7, 0xfa, 0xfe, 0x61, 0x91, 0x4b, 0x3d, 0xd1, 0x9a, 0xef, 0xd4, 0x76, - 0xeb, 0xce, 0x6a, 0x5c, 0x8a, 0x1f, 0x7b, 0xc2, 0xfa, 0x2d, 0x34, 0x2b, 0x80, 0xe6, 0x2a, 0xcc, - 0x17, 0x58, 0xf3, 0xd4, 0x33, 0x1f, 0xc2, 0x56, 0x09, 0x34, 0x3e, 0x8a, 0x53, 0xc4, 0x86, 0x73, - 0xb7, 0x60, 0x18, 0x9b, 0xc6, 0xc2, 0x7a, 0x02, 0x9b, 0xc7, 0x65, 0xe3, 0x17, 0x83, 0x7e, 0xcc, - 0x43, 0x63, 0x7c, 0x51, 0x6e, 0x43, 0xa3, 0x78, 0xe4, 0x6b, 0xef, 0xeb, 0x4e, 0x49, 0xb0, 0x02, - 0x58, 0xbf, 0x10, 0xf8, 0x8c, 0x84, 0x5e, 0x09, 0x36, 0x25, 0x00, 0x87, 0x93, 0x40, 0x33, 0x3f, - 0x22, 0x4b, 0x75, 0x0c, 0xb6, 0x2e, 0x90, 0x4f, 0x3d, 0x24, 0x19, 0x3f, 0x23, 0x52, 0xa5, 0x71, - 0x40, 0xf2, 0x76, 0x74, 0xa0, 0xee, 0x53, 0x21, 0xb3, 0xca, 0xfa, 0x70, 0x6a, 0x65, 0x25, 0x7b, - 0xf6, 0x34, 0x90, 0x23, 0x24, 0x51, 0xd6, 0x8b, 0x1a, 0xcb, 0xfa, 0x39, 0x6c, 0x7c, 0x8e, 0x64, - 0xcc, 0x89, 0x37, 0x96, 0xe3, 0x75, 0xa8, 0xa9, 0xfc, 0x19, 0x3a, 0x7f, 0xea, 0x68, 0xfd, 0xcd, - 0x80, 0xd6, 0xa3, 0x97, 0x11, 0xe3, 0x92, 0x78, 0x57, 0x22, 0x72, 0x43, 0x78, 0x2f, 0x61, 0x43, - 0x05, 0x4b, 0x90, 0xd0, 0x73, 0x0b, 0x3f, 0xd3, 0x3c, 0x36, 0xf7, 0x7f, 0x39, 0x53, 0x77, 0x4c, - 0xaa, 0xcb, 0x1c, 0xb8, 0x9d, 0x4c, 0xd0, 0x85, 0xf5, 0x27, 0x03, 0x5a, 0x27, 0x64, 0x74, 0x20, - 0x04, 0x1d, 0x84, 0x01, 0x09, 0xa5, 0x9a, 0x83, 0x08, 0x13, 0x75, 0x34, 0xdf, 0x86, 0x95, 0x62, - 0xef, 0xea, 0x75, 0x6b, 0xe8, 0x75, 0xbb, 0x9c, 0x13, 0x55, 0x83, 0x99, 0x0f, 0x01, 0x22, 0x4e, - 0x12, 0x17, 0xbb, 0x97, 0x64, 0x94, 0x65, 0x71, 0xbb, 0xba, 0x46, 0xd3, 0x9f, 0x60, 0xf6, 0x69, - 0xdc, 0xf7, 0x29, 0x3e, 0x21, 0x23, 0x67, 0x49, 0xf1, 0xf7, 0x4e, 0xc8, 0x48, 0x3d, 0x8b, 0x22, - 0xf6, 0x82, 0x70, 0xbd, 0xfb, 0x6a, 0x4e, 0xfa, 0x61, 0xfd, 0xd9, 0x80, 0xbb, 0x45, 0x3a, 0xf2, - 0x72, 0x3d, 0x8d, 0xfb, 0x4a, 0xe2, 0x86, 0xb8, 0x5d, 0xb1, 0x76, 0xfe, 0x1a, 0x6b, 0x3f, 0x86, - 0xe5, 0xa2, 0x41, 0x94, 0xbd, 0xb5, 0x19, 0xec, 0x6d, 0xe6, 0x12, 0x27, 0x64, 0x64, 0xfd, 0xa1, - 0x62, 0xdb, 0xe1, 0xa8, 0x32, 0xfb, 0xf8, 0x7f, 0xb1, 0xad, 0x50, 0x5b, 0xb5, 0x0d, 0x57, 0xe5, - 0xaf, 0x38, 0x50, 0xbb, 0xea, 0x80, 0xf5, 0x57, 0x03, 0x36, 0xab, 0x5a, 0xc5, 0x39, 0x3b, 0xe5, - 0x71, 0x48, 0x6e, 0xd2, 0x5e, 0xb6, 0xdf, 0x7c, 0xb5, 0xfd, 0x9e, 0xc2, 0xea, 0x98, 0x51, 0x22, - 0x8b, 0xc6, 0x07, 0x33, 0xd5, 0x58, 0x65, 0xba, 0x3a, 0x2b, 0x55, 0x3f, 0xc4, 0xe1, 0xd3, 0x6f, - 0x5f, 0xb5, 0x8d, 0xef, 0x5e, 0xb5, 0x8d, 0x7f, 0xbe, 0x6a, 0x1b, 0x5f, 0xbd, 0x6e, 0xcf, 0x7d, - 0xf7, 0xba, 0x3d, 0xf7, 0x8f, 0xd7, 0xed, 0xb9, 0xdf, 0x7d, 0x34, 0xa0, 0x72, 0x18, 0xf7, 0x6d, - 0xcc, 0x82, 0x6e, 0xf6, 0xfb, 0xba, 0xd4, 0xf5, 0x7e, 0xf1, 0xe7, 0x43, 0xf2, 0xa0, 0xfb, 0x72, - 0xfc, 0xcf, 0x10, 0x39, 0x8a, 0x88, 0xe8, 0x2f, 0xea, 0xa9, 0xf0, 0xe0, 0x3f, 0x01, 0x00, 0x00, - 0xff, 0xff, 0xcb, 0x43, 0xd2, 0x10, 0x3d, 0x11, 0x00, 0x00, + // 1723 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0x4b, 0x73, 0x1b, 0xc7, + 0x11, 0xe6, 0x12, 0x20, 0x45, 0x34, 0xf8, 0xd2, 0x92, 0xb2, 0x40, 0x85, 0x01, 0xa9, 0x75, 0xec, + 0x30, 0xe5, 0xf2, 0xc2, 0xa4, 0x2a, 0x55, 0x2e, 0x55, 0x5c, 0x2e, 0x12, 0x94, 0x2d, 0x9a, 0xb1, + 0x45, 0x2f, 0x19, 0xaa, 0x92, 0x1c, 0xb6, 0x06, 0x33, 0x23, 0x60, 0x8a, 0xbb, 0x3b, 0xab, 0x99, + 0xc1, 0x4a, 0xb8, 0xe4, 0x9c, 0xa3, 0x73, 0x73, 0x25, 0x17, 0x27, 0x7f, 0x20, 0x7f, 0xc3, 0x47, + 0x1f, 0x73, 0xb2, 0x53, 0xd2, 0x21, 0x87, 0xfc, 0x89, 0xd4, 0xcc, 0x3e, 0x01, 0x3e, 0x02, 0x95, + 0x93, 0xdb, 0xa2, 0xa7, 0xfb, 0xeb, 0x9e, 0x7e, 0x7c, 0x3d, 0x24, 0xec, 0xb1, 0x48, 0x51, 0x81, + 0x07, 0x88, 0x45, 0xbe, 0xa4, 0x78, 0x28, 0x98, 0x1a, 0x75, 0x30, 0x4e, 0x3a, 0xb1, 0xe0, 0x09, + 0x23, 0x54, 0x74, 0x92, 0xdd, 0xe2, 0xdb, 0x8d, 0x05, 0x57, 0xdc, 0x7e, 0xfb, 0x0a, 0x1b, 0x17, + 0xe3, 0xc4, 0x2d, 0xf4, 0x92, 0xdd, 0x7b, 0x1f, 0x5c, 0x07, 0x9c, 0xec, 0x76, 0xe4, 0x00, 0x09, + 0x4a, 0x7c, 0xcc, 0x23, 0x39, 0x0c, 0x73, 0xd8, 0x7b, 0xef, 0xdc, 0x60, 0xf1, 0x82, 0x09, 0x9a, + 0xa9, 0xad, 0xf7, 0x79, 0x9f, 0x9b, 0xcf, 0x8e, 0xfe, 0xca, 0xa4, 0x5b, 0x7d, 0xce, 0xfb, 0x01, + 0xed, 0x98, 0x5f, 0xbd, 0xe1, 0xb3, 0x8e, 0x62, 0x21, 0x95, 0x0a, 0x85, 0x71, 0xa6, 0xd0, 0x9e, + 0x54, 0x20, 0x43, 0x81, 0x14, 0xe3, 0x51, 0x0e, 0xc0, 0x7a, 0xb8, 0x83, 0xb9, 0xa0, 0x1d, 0x1c, + 0x30, 0x1a, 0x29, 0xed, 0x35, 0xfd, 0xca, 0x14, 0x3a, 0x5a, 0x21, 0x60, 0xfd, 0x81, 0x4a, 0xc5, + 0xb2, 0xa3, 0x68, 0x44, 0xa8, 0x08, 0x59, 0xaa, 0x5c, 0xfe, 0xca, 0x0c, 0x36, 0x2b, 0xe7, 0x58, + 0x8c, 0x62, 0xc5, 0x3b, 0x17, 0x74, 0x24, 0xb3, 0xd3, 0x77, 0x31, 0x97, 0x21, 0x97, 0x1d, 0xaa, + 0x33, 0x16, 0x61, 0xda, 0x49, 0x76, 0x7b, 0x54, 0xa1, 0xdd, 0x42, 0x90, 0xc7, 0x9d, 0xe9, 0xf5, + 0x90, 0x2c, 0x75, 0x30, 0x67, 0x59, 0xdc, 0xce, 0x0f, 0xf3, 0xd0, 0xea, 0x66, 0x89, 0xdc, 0x27, + 0x84, 0xe9, 0x2b, 0x9d, 0x08, 0x1e, 0x73, 0x89, 0x02, 0x7b, 0x1d, 0xe6, 0x14, 0x53, 0x01, 0x6d, + 0x59, 0xdb, 0xd6, 0x4e, 0xc3, 0x4b, 0x7f, 0xd8, 0xdb, 0xd0, 0x24, 0x54, 0x62, 0xc1, 0x62, 0xad, + 0xdc, 0x9a, 0x35, 0x67, 0x55, 0x91, 0xbd, 0x01, 0x0b, 0x69, 0x1d, 0x18, 0x69, 0xd5, 0xcc, 0xf1, + 0x2d, 0xf3, 0xfb, 0x88, 0xd8, 0x9f, 0xc2, 0x32, 0x8b, 0x98, 0x62, 0x28, 0xf0, 0x07, 0x54, 0x67, + 0xa3, 0x55, 0xdf, 0xb6, 0x76, 0x9a, 0x7b, 0xf7, 0x5c, 0xd6, 0xc3, 0xae, 0x4e, 0xa0, 0x9b, 0xa5, + 0x2d, 0xd9, 0x75, 0x1f, 0x1b, 0x8d, 0x83, 0xfa, 0xb7, 0xdf, 0x6f, 0xcd, 0x78, 0x4b, 0x99, 0x5d, + 0x2a, 0xb4, 0xef, 0xc3, 0x62, 0x9f, 0x46, 0x54, 0x32, 0xe9, 0x0f, 0x90, 0x1c, 0xb4, 0xe6, 0xb6, + 0xad, 0x9d, 0x45, 0xaf, 0x99, 0xc9, 0x1e, 0x23, 0x39, 0xb0, 0xb7, 0xa0, 0xd9, 0x63, 0x11, 0x12, + 0xa3, 0x54, 0x63, 0xde, 0x68, 0x40, 0x2a, 0x32, 0x0a, 0x5d, 0x00, 0x19, 0xa3, 0x17, 0x91, 0xaf, + 0xab, 0xdd, 0xba, 0x95, 0x05, 0x92, 0x56, 0xda, 0xcd, 0x2b, 0xed, 0x9e, 0xe5, 0xad, 0x70, 0xb0, + 0xa0, 0x03, 0xf9, 0xea, 0x87, 0x2d, 0xcb, 0x6b, 0x18, 0x3b, 0x7d, 0x62, 0x7f, 0x01, 0xab, 0xc3, + 0xa8, 0xc7, 0x23, 0xc2, 0xa2, 0xbe, 0x1f, 0x53, 0xc1, 0x38, 0x69, 0x2d, 0x18, 0xa8, 0x8d, 0x4b, + 0x50, 0x87, 0x59, 0xd3, 0xa4, 0x48, 0x5f, 0x6b, 0xa4, 0x95, 0xc2, 0xf8, 0xc4, 0xd8, 0xda, 0x5f, + 0x82, 0x8d, 0x71, 0x62, 0x42, 0xe2, 0x43, 0x95, 0x23, 0x36, 0xa6, 0x47, 0x5c, 0xc5, 0x38, 0x39, + 0x4b, 0xad, 0x33, 0xc8, 0xdf, 0xc3, 0x5d, 0x25, 0x50, 0x24, 0x9f, 0x51, 0x31, 0x89, 0x0b, 0xd3, + 0xe3, 0xde, 0xc9, 0x31, 0xc6, 0xc1, 0x1f, 0xc3, 0x76, 0x3e, 0x89, 0xbe, 0xa0, 0x84, 0x49, 0x25, + 0x58, 0x6f, 0xa8, 0x6d, 0xfd, 0x67, 0x02, 0x61, 0xd3, 0x23, 0x4d, 0xd3, 0x04, 0xed, 0x5c, 0xcf, + 0x1b, 0x53, 0xfb, 0x24, 0xd3, 0xb2, 0x9f, 0xc0, 0xcf, 0x7a, 0x01, 0xc7, 0x17, 0x52, 0x07, 0xe7, + 0x8f, 0x21, 0x19, 0xd7, 0x21, 0x93, 0x52, 0xa3, 0x2d, 0x6e, 0x5b, 0x3b, 0x35, 0xef, 0x7e, 0xaa, + 0x7b, 0x42, 0xc5, 0x61, 0x45, 0xf3, 0xac, 0xa2, 0x68, 0xbf, 0x0f, 0xf6, 0x80, 0x49, 0xc5, 0x05, + 0xc3, 0x28, 0xf0, 0x69, 0xa4, 0x04, 0xa3, 0xb2, 0xb5, 0x64, 0xcc, 0x6f, 0x97, 0x27, 0x8f, 0xd2, + 0x03, 0xfb, 0x33, 0xb8, 0x7f, 0xad, 0x53, 0x1f, 0x0f, 0x50, 0x14, 0xd1, 0xa0, 0xb5, 0x6c, 0xae, + 0xb2, 0x45, 0xae, 0xf1, 0xd9, 0x4d, 0xd5, 0x1e, 0x2e, 0xfc, 0xf1, 0x9b, 0xad, 0x99, 0xaf, 0xbf, + 0xd9, 0x9a, 0x71, 0xfe, 0x6e, 0xc1, 0xdd, 0x6e, 0x71, 0xf1, 0x90, 0x27, 0x28, 0xf8, 0x7f, 0x0e, + 0xd8, 0x3e, 0x34, 0xa4, 0xe2, 0x71, 0xda, 0xd2, 0xf5, 0x37, 0x68, 0xe9, 0x05, 0x6d, 0xa6, 0x0f, + 0x9c, 0xbf, 0x58, 0xb0, 0xfe, 0xe8, 0xf9, 0x90, 0x25, 0x1c, 0xa3, 0xff, 0x09, 0x1f, 0x1c, 0xc3, + 0x12, 0xad, 0xe0, 0xc9, 0x56, 0x6d, 0xbb, 0xb6, 0xd3, 0xdc, 0x7b, 0xc7, 0x4d, 0xc9, 0xc9, 0x2d, + 0x38, 0x2b, 0x23, 0x28, 0xb7, 0xea, 0xdd, 0x1b, 0xb7, 0x75, 0xfe, 0x66, 0xc1, 0x3d, 0x9d, 0xe5, + 0x3e, 0xf5, 0xe8, 0x0b, 0x24, 0xc8, 0x21, 0x8d, 0x78, 0x28, 0x7f, 0x74, 0x8c, 0x0e, 0x2c, 0x11, + 0x83, 0xe4, 0x2b, 0xee, 0x23, 0x42, 0x4c, 0x8c, 0x46, 0x47, 0x0b, 0xcf, 0xf8, 0x3e, 0x21, 0xf6, + 0x0e, 0xac, 0x96, 0x3a, 0x42, 0xd7, 0x52, 0xa7, 0x58, 0xab, 0x2d, 0xe7, 0x6a, 0xa6, 0xc2, 0xd4, + 0xf9, 0xb7, 0x05, 0xab, 0x9f, 0x06, 0xbc, 0x87, 0x82, 0xd3, 0x00, 0xc9, 0x81, 0xee, 0xb0, 0x91, + 0x2e, 0x8d, 0xa0, 0xd9, 0x68, 0x9b, 0xf0, 0xa6, 0x2e, 0x8d, 0x36, 0x33, 0x64, 0xf3, 0x31, 0xdc, + 0x2e, 0x86, 0xad, 0xe8, 0x00, 0x73, 0x9b, 0x83, 0xb5, 0x57, 0xdf, 0x6f, 0xad, 0xe4, 0x8d, 0xd6, + 0x35, 0xdd, 0x70, 0xe8, 0xad, 0xe0, 0x31, 0x01, 0xb1, 0xdb, 0xd0, 0x64, 0x3d, 0xec, 0x4b, 0xfa, + 0xdc, 0x8f, 0x86, 0xa1, 0x69, 0x9e, 0xba, 0xd7, 0x60, 0x3d, 0x7c, 0x4a, 0x9f, 0x7f, 0x31, 0x0c, + 0xed, 0x07, 0xf0, 0x56, 0xbe, 0x86, 0xfd, 0x04, 0x05, 0x66, 0xc9, 0xea, 0x74, 0x08, 0xd3, 0x4b, + 0x8b, 0xde, 0x5a, 0x7e, 0x7a, 0x8e, 0x02, 0xed, 0x6c, 0x9f, 0x10, 0xe1, 0xfc, 0x6b, 0x0e, 0xe6, + 0x4f, 0x90, 0x40, 0xa1, 0xb4, 0xcf, 0x60, 0x45, 0xd1, 0x30, 0x0e, 0x90, 0xa2, 0x7e, 0x4a, 0xe4, + 0xd9, 0x4d, 0xdf, 0x33, 0x04, 0x5f, 0x5d, 0x80, 0x6e, 0x65, 0xe5, 0x25, 0xbb, 0x6e, 0xd7, 0x48, + 0x4f, 0x15, 0x52, 0xd4, 0x5b, 0xce, 0x31, 0x52, 0xa1, 0xfd, 0x21, 0xb4, 0x94, 0x18, 0x4a, 0x55, + 0x52, 0x6c, 0xc9, 0x2d, 0x69, 0x2d, 0xdf, 0xca, 0xcf, 0x53, 0x56, 0x2a, 0x38, 0xe5, 0x6a, 0x36, + 0xad, 0xfd, 0x18, 0x36, 0x3d, 0x85, 0x35, 0xbd, 0x8a, 0x26, 0x31, 0xeb, 0xd3, 0x63, 0xde, 0xd6, + 0xf6, 0xe3, 0xa0, 0x5f, 0x82, 0x9d, 0x48, 0x3c, 0x89, 0x39, 0xf7, 0x06, 0x71, 0x26, 0x12, 0x8f, + 0x43, 0x12, 0xd8, 0x94, 0xba, 0xf9, 0xfc, 0x90, 0x2a, 0xc3, 0xcd, 0x71, 0x40, 0x23, 0x26, 0x07, + 0x39, 0xf8, 0xfc, 0xf4, 0xe0, 0x1b, 0x06, 0xe8, 0x73, 0x8d, 0xe3, 0xe5, 0x30, 0x99, 0x97, 0x2e, + 0xb4, 0xaf, 0xf6, 0x52, 0x14, 0xe8, 0x96, 0x29, 0xd0, 0x4f, 0xae, 0x80, 0x28, 0xaa, 0xb4, 0x07, + 0x77, 0x42, 0xf4, 0xd2, 0x57, 0x03, 0xc1, 0x95, 0x0a, 0x28, 0xf1, 0x63, 0x84, 0x2f, 0xa8, 0x92, + 0x66, 0x91, 0xd6, 0xbc, 0xb5, 0x10, 0xbd, 0x3c, 0xcb, 0xcf, 0x4e, 0xd2, 0x23, 0x5b, 0xc2, 0xbb, + 0x95, 0xbd, 0xa3, 0x99, 0xc0, 0x37, 0x43, 0xe8, 0x0b, 0xda, 0xd7, 0xe4, 0x8c, 0xd2, 0x15, 0x44, + 0x69, 0xb1, 0x3b, 0x33, 0xb6, 0xd1, 0x4f, 0xa1, 0x82, 0x69, 0xba, 0x9c, 0x45, 0xd9, 0x03, 0xc3, + 0x29, 0xd7, 0x53, 0xc1, 0x2b, 0x5e, 0x05, 0xeb, 0x13, 0x4a, 0x9d, 0x5f, 0x40, 0xc3, 0x0c, 0xf4, + 0x3e, 0xbe, 0x90, 0xf6, 0x26, 0x34, 0xf4, 0x64, 0x50, 0x29, 0xa9, 0x6c, 0x59, 0x86, 0x07, 0x4a, + 0x81, 0xa3, 0x60, 0xe3, 0xba, 0x87, 0x95, 0xb4, 0x9f, 0xc2, 0xad, 0x98, 0x9a, 0xad, 0x6f, 0x0c, + 0x9b, 0x7b, 0x1f, 0xb9, 0x53, 0xbc, 0x8a, 0xdd, 0xeb, 0x00, 0xbd, 0x1c, 0xcd, 0x11, 0xe5, 0x73, + 0x6e, 0x62, 0xd9, 0x48, 0xfb, 0x7c, 0xd2, 0xe9, 0xaf, 0xde, 0xc8, 0xe9, 0x04, 0x5e, 0xe9, 0xf3, + 0x3d, 0x68, 0xee, 0xa7, 0xd7, 0xfe, 0x35, 0x93, 0xea, 0x72, 0x5a, 0x16, 0xab, 0x69, 0xf9, 0x0c, + 0x96, 0xb3, 0x1d, 0x79, 0xc6, 0x0d, 0x29, 0xd9, 0x3f, 0x05, 0xc8, 0x96, 0xab, 0x26, 0xb3, 0x94, + 0xb6, 0x1b, 0x99, 0xe4, 0x88, 0x8c, 0xed, 0xba, 0xd9, 0xb1, 0x5d, 0xe7, 0x78, 0xb0, 0x72, 0x2e, + 0xf1, 0x6f, 0xf2, 0x07, 0xd4, 0x93, 0x58, 0xda, 0x77, 0x60, 0x5e, 0xcf, 0x51, 0x06, 0x54, 0xf7, + 0xe6, 0x12, 0x89, 0x8f, 0x0c, 0x73, 0x97, 0x8f, 0x34, 0x1e, 0xfb, 0x8c, 0xc8, 0xd6, 0xec, 0x76, + 0x6d, 0xa7, 0xee, 0x2d, 0x0f, 0x4b, 0xf3, 0x23, 0x22, 0x9d, 0xdf, 0x42, 0xb3, 0x02, 0x68, 0x2f, + 0xc3, 0x6c, 0x81, 0x35, 0xcb, 0x88, 0xfd, 0x10, 0x36, 0x4a, 0xa0, 0x71, 0x2a, 0x4e, 0x11, 0x1b, + 0xde, 0xdd, 0x42, 0x61, 0x8c, 0x8d, 0xa5, 0xf3, 0x04, 0xd6, 0x8f, 0xca, 0xc1, 0x2f, 0x88, 0x7e, + 0xec, 0x86, 0xd6, 0xf8, 0x36, 0xdf, 0x84, 0x46, 0xf1, 0x97, 0x88, 0xb9, 0x7d, 0xdd, 0x2b, 0x05, + 0x4e, 0x08, 0xab, 0xe7, 0x12, 0x9f, 0xd2, 0x88, 0x94, 0x60, 0xd7, 0x24, 0xe0, 0x60, 0x12, 0x68, + 0xea, 0x97, 0x6e, 0xe9, 0x8e, 0xc3, 0xc6, 0x39, 0x0a, 0x18, 0x41, 0x8a, 0x8b, 0x53, 0xaa, 0xd2, + 0x25, 0x9c, 0x8f, 0xa3, 0x07, 0xf5, 0x80, 0x49, 0x95, 0x75, 0xd6, 0x87, 0xd7, 0x76, 0x56, 0xb2, + 0xeb, 0x5e, 0x07, 0x72, 0x88, 0x14, 0xca, 0x66, 0xd1, 0x60, 0x39, 0x3f, 0x87, 0xb5, 0xcf, 0x91, + 0x1a, 0x0a, 0x4a, 0xc6, 0x6a, 0xbc, 0x0a, 0x35, 0x5d, 0x3f, 0xcb, 0xd4, 0x4f, 0x7f, 0xea, 0x37, + 0x41, 0xeb, 0xd1, 0xcb, 0x98, 0x0b, 0x45, 0xc9, 0xa5, 0x8c, 0xdc, 0x90, 0xde, 0x0b, 0x58, 0xd3, + 0xc9, 0x92, 0x34, 0x22, 0x7e, 0x71, 0xcf, 0xb4, 0x8e, 0xcd, 0xbd, 0x5f, 0x4e, 0x35, 0x1d, 0x93, + 0xee, 0xb2, 0x0b, 0xdc, 0x4e, 0x26, 0xe4, 0xd2, 0xf9, 0x93, 0x05, 0xad, 0x63, 0x3a, 0xda, 0x97, + 0x92, 0xf5, 0xa3, 0x90, 0x46, 0x4a, 0xf3, 0x20, 0xc2, 0x54, 0x7f, 0xda, 0x6f, 0xc3, 0x52, 0xb1, + 0x77, 0xcd, 0xba, 0xb5, 0xcc, 0xba, 0x5d, 0xcc, 0x85, 0x7a, 0xc0, 0xec, 0x87, 0x00, 0xb1, 0xa0, + 0x89, 0x8f, 0xfd, 0x0b, 0x3a, 0xca, 0xaa, 0xb8, 0x59, 0x5d, 0xa3, 0xe9, 0xdf, 0x89, 0xee, 0xc9, + 0xb0, 0x17, 0x30, 0x7c, 0x4c, 0x47, 0xde, 0x82, 0xd6, 0xef, 0x1e, 0xd3, 0x91, 0x7e, 0x17, 0xc5, + 0xfc, 0x05, 0x15, 0x66, 0xf7, 0xd5, 0xbc, 0xf4, 0x87, 0xf3, 0x67, 0x0b, 0xee, 0x16, 0xe5, 0xc8, + 0xdb, 0xf5, 0x64, 0xd8, 0xd3, 0x16, 0x37, 0xe4, 0xed, 0x52, 0xb4, 0xb3, 0x57, 0x44, 0xfb, 0x31, + 0x2c, 0x16, 0x03, 0xa2, 0xe3, 0xad, 0x4d, 0x11, 0x6f, 0x33, 0xb7, 0x38, 0xa6, 0x23, 0xe7, 0x0f, + 0x95, 0xd8, 0x0e, 0x46, 0x15, 0xee, 0x13, 0xff, 0x25, 0xb6, 0xc2, 0x6d, 0x35, 0x36, 0x5c, 0xb5, + 0xbf, 0x74, 0x81, 0xda, 0xe5, 0x0b, 0x38, 0x7f, 0xb5, 0x60, 0xbd, 0xea, 0x55, 0x9e, 0xf1, 0x13, + 0x31, 0x8c, 0xe8, 0x4d, 0xde, 0xcb, 0xf1, 0x9b, 0xad, 0x8e, 0xdf, 0x53, 0x58, 0x1e, 0x0b, 0x4a, + 0x66, 0xd9, 0xf8, 0x60, 0xaa, 0x1e, 0xab, 0xb0, 0xab, 0xb7, 0x54, 0xbd, 0x87, 0x3c, 0x78, 0xfa, + 0xed, 0xab, 0xb6, 0xf5, 0xdd, 0xab, 0xb6, 0xf5, 0xcf, 0x57, 0x6d, 0xeb, 0xab, 0xd7, 0xed, 0x99, + 0xef, 0x5e, 0xb7, 0x67, 0xfe, 0xf1, 0xba, 0x3d, 0xf3, 0xbb, 0x8f, 0xfa, 0x4c, 0x0d, 0x86, 0x3d, + 0x17, 0xf3, 0xb0, 0x93, 0xfd, 0x13, 0xa0, 0xf4, 0xf5, 0x7e, 0xf1, 0x1f, 0x92, 0xe4, 0x41, 0xe7, + 0xe5, 0xf8, 0x7f, 0x6c, 0xd4, 0x28, 0xa6, 0xb2, 0x37, 0x6f, 0x58, 0xe1, 0xc1, 0x7f, 0x02, 0x00, + 0x00, 0xff, 0xff, 0x47, 0xa2, 0xef, 0x46, 0xe2, 0x11, 0x00, 0x00, } func (m *ConsumerAdditionProposal) Marshal() (dAtA []byte, err error) { @@ -1680,6 +1758,61 @@ func (m *EquivocationProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *ChangeRewardDenomsProposal) 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 *ChangeRewardDenomsProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ChangeRewardDenomsProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.DenomsToRemove) > 0 { + for iNdEx := len(m.DenomsToRemove) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.DenomsToRemove[iNdEx]) + copy(dAtA[i:], m.DenomsToRemove[iNdEx]) + i = encodeVarintProvider(dAtA, i, uint64(len(m.DenomsToRemove[iNdEx]))) + i-- + dAtA[i] = 0x22 + } + } + if len(m.DenomsToAdd) > 0 { + for iNdEx := len(m.DenomsToAdd) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.DenomsToAdd[iNdEx]) + copy(dAtA[i:], m.DenomsToAdd[iNdEx]) + i = encodeVarintProvider(dAtA, i, uint64(len(m.DenomsToAdd[iNdEx]))) + i-- + dAtA[i] = 0x1a + } + } + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintProvider(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if len(m.Title) > 0 { + i -= len(m.Title) + copy(dAtA[i:], m.Title) + i = encodeVarintProvider(dAtA, i, uint64(len(m.Title))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *GlobalSlashEntry) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -2574,6 +2707,35 @@ func (m *EquivocationProposal) Size() (n int) { return n } +func (m *ChangeRewardDenomsProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Title) + if l > 0 { + n += 1 + l + sovProvider(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovProvider(uint64(l)) + } + if len(m.DenomsToAdd) > 0 { + for _, s := range m.DenomsToAdd { + l = len(s) + n += 1 + l + sovProvider(uint64(l)) + } + } + if len(m.DenomsToRemove) > 0 { + for _, s := range m.DenomsToRemove { + l = len(s) + n += 1 + l + sovProvider(uint64(l)) + } + } + return n +} + func (m *GlobalSlashEntry) Size() (n int) { if m == nil { return 0 @@ -3720,6 +3882,184 @@ func (m *EquivocationProposal) Unmarshal(dAtA []byte) error { } return nil } +func (m *ChangeRewardDenomsProposal) 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: ChangeRewardDenomsProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ChangeRewardDenomsProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Title", 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.Title = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", 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.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DenomsToAdd", 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.DenomsToAdd = append(m.DenomsToAdd, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DenomsToRemove", 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.DenomsToRemove = append(m.DenomsToRemove, string(dAtA[iNdEx:postIndex])) + 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 (m *GlobalSlashEntry) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/x/ccv/provider/types/tx.pb.go b/x/ccv/provider/types/tx.pb.go index 32bca37998..c5bebf0cd5 100644 --- a/x/ccv/provider/types/tx.pb.go +++ b/x/ccv/provider/types/tx.pb.go @@ -111,92 +111,9 @@ func (m *MsgAssignConsumerKeyResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgAssignConsumerKeyResponse proto.InternalMessageInfo -// MsgRegisterConsumerRewardDenom allows an account to register -// a consumer reward denom, i.e., add it to the list of denoms -// accepted by the provider as rewards. -type MsgRegisterConsumerRewardDenom struct { - Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"` - Depositor string `protobuf:"bytes,2,opt,name=depositor,proto3" json:"depositor,omitempty"` -} - -func (m *MsgRegisterConsumerRewardDenom) Reset() { *m = MsgRegisterConsumerRewardDenom{} } -func (m *MsgRegisterConsumerRewardDenom) String() string { return proto.CompactTextString(m) } -func (*MsgRegisterConsumerRewardDenom) ProtoMessage() {} -func (*MsgRegisterConsumerRewardDenom) Descriptor() ([]byte, []int) { - return fileDescriptor_43221a4391e9fbf4, []int{2} -} -func (m *MsgRegisterConsumerRewardDenom) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgRegisterConsumerRewardDenom) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgRegisterConsumerRewardDenom.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 *MsgRegisterConsumerRewardDenom) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgRegisterConsumerRewardDenom.Merge(m, src) -} -func (m *MsgRegisterConsumerRewardDenom) XXX_Size() int { - return m.Size() -} -func (m *MsgRegisterConsumerRewardDenom) XXX_DiscardUnknown() { - xxx_messageInfo_MsgRegisterConsumerRewardDenom.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgRegisterConsumerRewardDenom proto.InternalMessageInfo - -// MsgRegisterConsumerRewardDenomResponse defines the -// Msg/RegisterConsumerRewardDenom response type. -type MsgRegisterConsumerRewardDenomResponse struct { -} - -func (m *MsgRegisterConsumerRewardDenomResponse) Reset() { - *m = MsgRegisterConsumerRewardDenomResponse{} -} -func (m *MsgRegisterConsumerRewardDenomResponse) String() string { return proto.CompactTextString(m) } -func (*MsgRegisterConsumerRewardDenomResponse) ProtoMessage() {} -func (*MsgRegisterConsumerRewardDenomResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_43221a4391e9fbf4, []int{3} -} -func (m *MsgRegisterConsumerRewardDenomResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgRegisterConsumerRewardDenomResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgRegisterConsumerRewardDenomResponse.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 *MsgRegisterConsumerRewardDenomResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgRegisterConsumerRewardDenomResponse.Merge(m, src) -} -func (m *MsgRegisterConsumerRewardDenomResponse) XXX_Size() int { - return m.Size() -} -func (m *MsgRegisterConsumerRewardDenomResponse) XXX_DiscardUnknown() { - xxx_messageInfo_MsgRegisterConsumerRewardDenomResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgRegisterConsumerRewardDenomResponse proto.InternalMessageInfo - func init() { proto.RegisterType((*MsgAssignConsumerKey)(nil), "interchain_security.ccv.provider.v1.MsgAssignConsumerKey") proto.RegisterType((*MsgAssignConsumerKeyResponse)(nil), "interchain_security.ccv.provider.v1.MsgAssignConsumerKeyResponse") - proto.RegisterType((*MsgRegisterConsumerRewardDenom)(nil), "interchain_security.ccv.provider.v1.MsgRegisterConsumerRewardDenom") - proto.RegisterType((*MsgRegisterConsumerRewardDenomResponse)(nil), "interchain_security.ccv.provider.v1.MsgRegisterConsumerRewardDenomResponse") } func init() { @@ -204,36 +121,31 @@ func init() { } var fileDescriptor_43221a4391e9fbf4 = []byte{ - // 453 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x93, 0x3d, 0x6b, 0x14, 0x41, - 0x18, 0xc7, 0x77, 0x13, 0xd4, 0x64, 0x8c, 0x82, 0xc3, 0x15, 0x97, 0xf3, 0xd8, 0xd3, 0x15, 0x24, - 0x85, 0xee, 0x10, 0x53, 0x88, 0x01, 0x8b, 0x4b, 0x6c, 0x24, 0x5c, 0xb3, 0x8d, 0x60, 0xe1, 0xb1, - 0x37, 0x33, 0x4e, 0x06, 0xb3, 0xf3, 0x2c, 0xf3, 0xcc, 0xad, 0xd9, 0x6f, 0x60, 0xa9, 0x95, 0x6d, - 0xbe, 0x81, 0x5f, 0x43, 0xb0, 0x49, 0x69, 0x25, 0x72, 0xd7, 0x58, 0xfb, 0x09, 0x64, 0xdf, 0x3c, - 0xc5, 0xe3, 0x08, 0x92, 0xee, 0x79, 0xdb, 0xff, 0xff, 0xb7, 0x33, 0xf3, 0x90, 0x07, 0xda, 0x38, - 0x69, 0xf9, 0x71, 0xa2, 0xcd, 0x18, 0x25, 0x9f, 0x5a, 0xed, 0x0a, 0xc6, 0x79, 0xce, 0x32, 0x0b, - 0xb9, 0x16, 0xd2, 0xb2, 0x7c, 0x97, 0xb9, 0xd3, 0x28, 0xb3, 0xe0, 0x80, 0xde, 0x5b, 0x32, 0x1d, - 0x71, 0x9e, 0x47, 0xed, 0x74, 0x94, 0xef, 0xf6, 0xfa, 0x0a, 0x40, 0x9d, 0x48, 0x96, 0x64, 0x9a, - 0x25, 0xc6, 0x80, 0x4b, 0x9c, 0x06, 0x83, 0xb5, 0x44, 0xaf, 0xa3, 0x40, 0x41, 0x15, 0xb2, 0x32, - 0x6a, 0xaa, 0xdb, 0x1c, 0x30, 0x05, 0x1c, 0xd7, 0x8d, 0x3a, 0x69, 0x5b, 0x8d, 0x5c, 0x95, 0x4d, - 0xa6, 0xaf, 0x59, 0x62, 0x8a, 0xba, 0x15, 0x7e, 0xf4, 0x49, 0x67, 0x84, 0x6a, 0x88, 0xa8, 0x95, - 0x39, 0x04, 0x83, 0xd3, 0x54, 0xda, 0x23, 0x59, 0xd0, 0x6d, 0xb2, 0x51, 0x43, 0x6a, 0xd1, 0xf5, - 0xef, 0xf8, 0x3b, 0x9b, 0xf1, 0xb5, 0x2a, 0x7f, 0x2e, 0xe8, 0x63, 0x72, 0xa3, 0x85, 0x1d, 0x27, - 0x42, 0xd8, 0xee, 0x5a, 0xd9, 0x3f, 0xa0, 0x3f, 0xbf, 0x0d, 0x6e, 0x16, 0x49, 0x7a, 0xb2, 0x1f, - 0x96, 0x55, 0x89, 0x18, 0xc6, 0x5b, 0xed, 0xe0, 0x50, 0x08, 0x4b, 0xef, 0x92, 0x2d, 0xde, 0x58, - 0x8c, 0xdf, 0xc8, 0xa2, 0xbb, 0x5e, 0xe9, 0x5e, 0xe7, 0x0b, 0xdb, 0xfd, 0x8d, 0x77, 0x67, 0x03, - 0xef, 0xc7, 0xd9, 0xc0, 0x0b, 0x03, 0xd2, 0x5f, 0x06, 0x16, 0x4b, 0xcc, 0xc0, 0xa0, 0x0c, 0x5f, - 0x91, 0x60, 0x84, 0x2a, 0x96, 0x4a, 0xa3, 0x93, 0xb6, 0x9d, 0x88, 0xe5, 0xdb, 0xc4, 0x8a, 0x67, - 0xd2, 0x40, 0x4a, 0x3b, 0xe4, 0x8a, 0x28, 0x83, 0x86, 0xbf, 0x4e, 0x68, 0x9f, 0x6c, 0x0a, 0x99, - 0x01, 0x6a, 0x07, 0x0d, 0x79, 0xbc, 0x28, 0xfc, 0xe1, 0xbf, 0x43, 0xee, 0xaf, 0xd6, 0x6f, 0x49, - 0x1e, 0x7d, 0x59, 0x23, 0xeb, 0x23, 0x54, 0xf4, 0x83, 0x4f, 0x6e, 0xfd, 0x7b, 0x90, 0x4f, 0xa2, - 0x0b, 0xdc, 0x78, 0xb4, 0xec, 0x57, 0x7b, 0xc3, 0xff, 0xfe, 0xb4, 0x65, 0xa3, 0x9f, 0x7c, 0x72, - 0x7b, 0xd5, 0x19, 0x1d, 0x5e, 0xd4, 0x62, 0x85, 0x48, 0xef, 0xe8, 0x12, 0x44, 0x5a, 0xe2, 0x83, - 0x17, 0x9f, 0x67, 0x81, 0x7f, 0x3e, 0x0b, 0xfc, 0xef, 0xb3, 0xc0, 0x7f, 0x3f, 0x0f, 0xbc, 0xf3, - 0x79, 0xe0, 0x7d, 0x9d, 0x07, 0xde, 0xcb, 0xa7, 0x4a, 0xbb, 0xe3, 0xe9, 0x24, 0xe2, 0x90, 0x36, - 0xef, 0x9b, 0x2d, 0x7c, 0x1f, 0xfe, 0x5e, 0xbd, 0x7c, 0x8f, 0x9d, 0xfe, 0xbd, 0x7f, 0xae, 0xc8, - 0x24, 0x4e, 0xae, 0x56, 0x2f, 0x7e, 0xef, 0x57, 0x00, 0x00, 0x00, 0xff, 0xff, 0x72, 0xb0, 0xd5, - 0x84, 0xb0, 0x03, 0x00, 0x00, + // 375 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x52, 0x3d, 0x4f, 0xeb, 0x30, + 0x14, 0x8d, 0x5f, 0xa5, 0xf7, 0xfa, 0xfc, 0xfa, 0x9e, 0xf4, 0xa2, 0x0e, 0x6d, 0x55, 0xa5, 0x10, + 0x16, 0x06, 0x88, 0x55, 0x3a, 0x20, 0x2a, 0x31, 0xb4, 0x4c, 0x08, 0x75, 0xe9, 0x82, 0xc4, 0x12, + 0xa5, 0x8e, 0x71, 0x2d, 0x1a, 0x3b, 0xb2, 0x9d, 0xa8, 0xf9, 0x07, 0x8c, 0x30, 0x21, 0xb6, 0xfe, + 0x1c, 0xc6, 0x8e, 0x4c, 0x08, 0xb5, 0x0b, 0x33, 0xbf, 0x00, 0x35, 0x1f, 0x54, 0x88, 0x0e, 0x88, + 0xed, 0xde, 0x7b, 0x8e, 0xcf, 0x39, 0xf2, 0xbd, 0x70, 0x8f, 0x71, 0x4d, 0x24, 0x1e, 0x7b, 0x8c, + 0xbb, 0x8a, 0xe0, 0x48, 0x32, 0x9d, 0x20, 0x8c, 0x63, 0x14, 0x4a, 0x11, 0x33, 0x9f, 0x48, 0x14, + 0xb7, 0x91, 0x9e, 0x3a, 0xa1, 0x14, 0x5a, 0x98, 0x3b, 0x1b, 0xd8, 0x0e, 0xc6, 0xb1, 0x53, 0xb0, + 0x9d, 0xb8, 0xdd, 0x68, 0x52, 0x21, 0xe8, 0x84, 0x20, 0x2f, 0x64, 0xc8, 0xe3, 0x5c, 0x68, 0x4f, + 0x33, 0xc1, 0x55, 0x26, 0xd1, 0xa8, 0x52, 0x41, 0x45, 0x5a, 0xa2, 0x55, 0x95, 0x4f, 0xeb, 0x58, + 0xa8, 0x40, 0x28, 0x37, 0x03, 0xb2, 0xa6, 0x80, 0x72, 0xb9, 0xb4, 0x1b, 0x45, 0x97, 0xc8, 0xe3, + 0x49, 0x06, 0xd9, 0x77, 0x00, 0x56, 0x07, 0x8a, 0xf6, 0x94, 0x62, 0x94, 0x9f, 0x08, 0xae, 0xa2, + 0x80, 0xc8, 0x33, 0x92, 0x98, 0x75, 0x58, 0xce, 0x42, 0x32, 0xbf, 0x06, 0xb6, 0xc0, 0xee, 0xef, + 0xe1, 0xaf, 0xb4, 0x3f, 0xf5, 0xcd, 0x43, 0xf8, 0xb7, 0x08, 0xeb, 0x7a, 0xbe, 0x2f, 0x6b, 0x3f, + 0x56, 0x78, 0xdf, 0x7c, 0x7d, 0x6a, 0xfd, 0x4b, 0xbc, 0x60, 0xd2, 0xb5, 0x57, 0x53, 0xa2, 0x94, + 0x3d, 0xac, 0x14, 0xc4, 0x9e, 0xef, 0x4b, 0x73, 0x1b, 0x56, 0x70, 0x6e, 0xe1, 0x5e, 0x91, 0xa4, + 0x56, 0x4a, 0x75, 0xff, 0xe0, 0xb5, 0x6d, 0xb7, 0x7c, 0x3d, 0x6b, 0x19, 0x2f, 0xb3, 0x96, 0x61, + 0x5b, 0xb0, 0xb9, 0x29, 0xd8, 0x90, 0xa8, 0x50, 0x70, 0x45, 0x0e, 0xee, 0x01, 0x2c, 0x0d, 0x14, + 0x35, 0x6f, 0x01, 0xfc, 0xff, 0x39, 0xfe, 0x91, 0xf3, 0x85, 0x7f, 0x76, 0x36, 0x19, 0x34, 0x7a, + 0xdf, 0x7e, 0x5a, 0x64, 0xeb, 0x9f, 0x3f, 0x2c, 0x2c, 0x30, 0x5f, 0x58, 0xe0, 0x79, 0x61, 0x81, + 0x9b, 0xa5, 0x65, 0xcc, 0x97, 0x96, 0xf1, 0xb8, 0xb4, 0x8c, 0x8b, 0x63, 0xca, 0xf4, 0x38, 0x1a, + 0x39, 0x58, 0x04, 0xf9, 0x8e, 0xd0, 0xda, 0x6d, 0xff, 0xfd, 0x7c, 0xe2, 0x0e, 0x9a, 0x7e, 0xbc, + 0x21, 0x9d, 0x84, 0x44, 0x8d, 0x7e, 0xa6, 0x5b, 0xeb, 0xbc, 0x05, 0x00, 0x00, 0xff, 0xff, 0x92, + 0xca, 0xcf, 0xe2, 0x74, 0x02, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -249,7 +161,6 @@ const _ = grpc.SupportPackageIsVersion4 // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type MsgClient interface { AssignConsumerKey(ctx context.Context, in *MsgAssignConsumerKey, opts ...grpc.CallOption) (*MsgAssignConsumerKeyResponse, error) - RegisterConsumerRewardDenom(ctx context.Context, in *MsgRegisterConsumerRewardDenom, opts ...grpc.CallOption) (*MsgRegisterConsumerRewardDenomResponse, error) } type msgClient struct { @@ -269,19 +180,9 @@ func (c *msgClient) AssignConsumerKey(ctx context.Context, in *MsgAssignConsumer return out, nil } -func (c *msgClient) RegisterConsumerRewardDenom(ctx context.Context, in *MsgRegisterConsumerRewardDenom, opts ...grpc.CallOption) (*MsgRegisterConsumerRewardDenomResponse, error) { - out := new(MsgRegisterConsumerRewardDenomResponse) - err := c.cc.Invoke(ctx, "/interchain_security.ccv.provider.v1.Msg/RegisterConsumerRewardDenom", 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) - RegisterConsumerRewardDenom(context.Context, *MsgRegisterConsumerRewardDenom) (*MsgRegisterConsumerRewardDenomResponse, error) } // UnimplementedMsgServer can be embedded to have forward compatible implementations. @@ -291,9 +192,6 @@ type UnimplementedMsgServer struct { func (*UnimplementedMsgServer) AssignConsumerKey(ctx context.Context, req *MsgAssignConsumerKey) (*MsgAssignConsumerKeyResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method AssignConsumerKey not implemented") } -func (*UnimplementedMsgServer) RegisterConsumerRewardDenom(ctx context.Context, req *MsgRegisterConsumerRewardDenom) (*MsgRegisterConsumerRewardDenomResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method RegisterConsumerRewardDenom not implemented") -} func RegisterMsgServer(s grpc1.Server, srv MsgServer) { s.RegisterService(&_Msg_serviceDesc, srv) @@ -317,24 +215,6 @@ func _Msg_AssignConsumerKey_Handler(srv interface{}, ctx context.Context, dec fu return interceptor(ctx, in, info, handler) } -func _Msg_RegisterConsumerRewardDenom_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgRegisterConsumerRewardDenom) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).RegisterConsumerRewardDenom(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/interchain_security.ccv.provider.v1.Msg/RegisterConsumerRewardDenom", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).RegisterConsumerRewardDenom(ctx, req.(*MsgRegisterConsumerRewardDenom)) - } - return interceptor(ctx, in, info, handler) -} - var _Msg_serviceDesc = grpc.ServiceDesc{ ServiceName: "interchain_security.ccv.provider.v1.Msg", HandlerType: (*MsgServer)(nil), @@ -343,10 +223,6 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ MethodName: "AssignConsumerKey", Handler: _Msg_AssignConsumerKey_Handler, }, - { - MethodName: "RegisterConsumerRewardDenom", - Handler: _Msg_RegisterConsumerRewardDenom_Handler, - }, }, Streams: []grpc.StreamDesc{}, Metadata: "interchain_security/ccv/provider/v1/tx.proto", @@ -419,66 +295,6 @@ func (m *MsgAssignConsumerKeyResponse) MarshalToSizedBuffer(dAtA []byte) (int, e return len(dAtA) - i, nil } -func (m *MsgRegisterConsumerRewardDenom) 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 *MsgRegisterConsumerRewardDenom) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgRegisterConsumerRewardDenom) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Depositor) > 0 { - i -= len(m.Depositor) - copy(dAtA[i:], m.Depositor) - i = encodeVarintTx(dAtA, i, uint64(len(m.Depositor))) - i-- - dAtA[i] = 0x12 - } - if len(m.Denom) > 0 { - i -= len(m.Denom) - copy(dAtA[i:], m.Denom) - i = encodeVarintTx(dAtA, i, uint64(len(m.Denom))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *MsgRegisterConsumerRewardDenomResponse) 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 *MsgRegisterConsumerRewardDenomResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgRegisterConsumerRewardDenomResponse) 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 @@ -520,32 +336,6 @@ func (m *MsgAssignConsumerKeyResponse) Size() (n int) { return n } -func (m *MsgRegisterConsumerRewardDenom) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Denom) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - l = len(m.Depositor) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - return n -} - -func (m *MsgRegisterConsumerRewardDenomResponse) 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 } @@ -748,170 +538,6 @@ func (m *MsgAssignConsumerKeyResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgRegisterConsumerRewardDenom) 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: MsgRegisterConsumerRewardDenom: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgRegisterConsumerRewardDenom: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Denom", 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.Denom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Depositor", 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.Depositor = 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 *MsgRegisterConsumerRewardDenomResponse) 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: MsgRegisterConsumerRewardDenomResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgRegisterConsumerRewardDenomResponse: 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 8bd3549393..82462f6530 100644 --- a/x/ccv/types/events.go +++ b/x/ccv/types/events.go @@ -2,13 +2,14 @@ package types // CCV events const ( - EventTypeTimeout = "timeout" - EventTypePacket = "ccv_packet" - EventTypeChannelEstablished = "channel_established" - EventTypeFeeTransferChannelOpened = "fee_transfer_channel_opened" - EventTypeConsumerClientCreated = "consumer_client_created" - EventTypeAssignConsumerKey = "assign_consumer_key" - EventTypeRegisterConsumerRewardDenom = "register_consumer_reward_denom" + EventTypeTimeout = "timeout" + EventTypePacket = "ccv_packet" + EventTypeChannelEstablished = "channel_established" + EventTypeFeeTransferChannelOpened = "fee_transfer_channel_opened" + EventTypeConsumerClientCreated = "consumer_client_created" + EventTypeAssignConsumerKey = "assign_consumer_key" + EventTypeAddConsumerRewardDenom = "add_consumer_reward_denom" + EventTypeRemoveConsumerRewardDenom = "remove_consumer_reward_denom" EventTypeExecuteConsumerChainSlash = "execute_consumer_chain_slash" EventTypeFeeDistribution = "fee_distribution" @@ -41,6 +42,5 @@ const ( AttributeDistributionTotal = "total" AttributeDistributionToProvider = "provider_amount" - AttributeConsumerRewardDenom = "consumer_reward_denom" - AttributeConsumerRewardDepositor = "consumer_reward_depositor" + AttributeConsumerRewardDenom = "consumer_reward_denom" ) From 1a009e75531278a1841e70a23a17c27182f89678 Mon Sep 17 00:00:00 2001 From: insumity Date: Wed, 13 Sep 2023 12:44:12 +0200 Subject: [PATCH 114/134] docs: introduce ADR on slashing on the provider chain (#1252) * initial draft of the adr * small change on intro.md to avoid huge diff * clean up * take into account Marius' comments * rewrite v0.47 Cosmos SDK link because it was returning 404 and redirecting * more cleaning up * update based on comments * removed confusing sentence on voting power * add missing ADRs in the intro file * add tokens to power conversion * add paragraph on key pruning and references to light-client attacks code * Update template title * Took into account comments. * augment pseudocode to skip redelegation/undelegation entries * fix identation issue --------- Co-authored-by: Karolos Antoniadis --- .../adrs/adr-011-improving-test-confidence.md | 2 +- .../adrs/adr-013-equivocation-slashing.md | 147 ++++++++++++++++++ docs/docs/adrs/intro.md | 5 +- 3 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 docs/docs/adrs/adr-013-equivocation-slashing.md diff --git a/docs/docs/adrs/adr-011-improving-test-confidence.md b/docs/docs/adrs/adr-011-improving-test-confidence.md index 8ba0e6e5a1..397f8f5e01 100644 --- a/docs/docs/adrs/adr-011-improving-test-confidence.md +++ b/docs/docs/adrs/adr-011-improving-test-confidence.md @@ -1,6 +1,6 @@ --- sidebar_position: 12 -title: ADR Template +title: Improving testing and increasing confidence --- # ADR 11: Improving testing and increasing confidence diff --git a/docs/docs/adrs/adr-013-equivocation-slashing.md b/docs/docs/adrs/adr-013-equivocation-slashing.md new file mode 100644 index 0000000000..1351cf5234 --- /dev/null +++ b/docs/docs/adrs/adr-013-equivocation-slashing.md @@ -0,0 +1,147 @@ +--- +sidebar_position: 14 +title: Slashing on the provider for consumer equivocation +--- +# ADR 013: Slashing on the provider for consumer equivocation + +## Changelog +* 1st Sept. 2023: Initial draft + +## Status +Proposed + +## Context +This ADR presents some approaches on how to slash on the provider chain validators that performed equivocations on consumer chains. +Currently, the provider chain can [receive and verify evidence of equivocation](https://github.com/cosmos/interchain-security/pull/1232), but it cannot slash the misbehaving validator. + +In the remainder of this section, we explain how slashing is performed on a single chain and show why slashing on the provider for equivocation on the consumer is challenging. + +Note that future versions of the Cosmos SDK, CometBFT, and ibc-go could modify the way we slash, etc. Therefore, a future reader of this ADR, should note that when we refer to Cosmos SDK, CometBFT, and ibc-go we specifically refer to their [v0.47](https://docs.cosmos.network/v0.47/intro/overview), [v0.37](https://docs.cometbft.com/v0.37/) and [v7.3.0](https://github.com/cosmos/ibc-go/blob/v7.3.0) versions respectively. + +### Single-chain slashing +Slashing is implemented across the [slashing](https://docs.cosmos.network/v0.47/modules/slashing) +and [staking](https://docs.cosmos.network/v0.47/modules/staking) modules. +The slashing module's keeper calls the staking module's `Slash()` method, passing among others, the `infractionHeight` (i.e., the height when the equivocation occurred), the validator's `power` at the infraction height, and the `slashFactor` (currently set to `5%` in case of equivocation on the Cosmos Hub). + +#### Slashing undelegations and redelegations +To slash undelegations, `Slash` goes through all undelegations and checks whether they started before or after the infraction occurred. If an undelegation started before the `infractionHeight`, then it is **not** slashed, otherwise it is slashed by `slashFactor`. + +The slashing of redelegations happens in a similar way, meaning that `Slash` goes through all redelegations and checks whether the redelegations started before or after the `infractionHeight`. + +#### Slashing delegations +Besides undelegations and redelegations, the validator's delegations need to also be slashed. +This is performed by deducting the appropriate amount of tokens from the validator. Note that this deduction is computed based on the voting `power` the misbehaving validator had at the height of the equivocation. As a result of the tokens deduction, +the [tokens per share](https://docs.cosmos.network/v0.47/modules/staking#delegator-shares) +reduce and hence later on, when delegators undelegate or redelegate, the delegators retrieve back less +tokens, effectively having their tokens slashed. The rationale behind this slashing mechanism, as mentioned in the [Cosmos SDK documentation](https://docs.cosmos.network/v0.47/modules/staking#delegator-shares) +> [...] is to simplify the accounting around slashing. Rather than iteratively slashing the tokens of every delegation entry, instead the Validators total bonded tokens can be slashed, effectively reducing the value of each issued delegator share. + +This approach of slashing delegations does not utilize the +`infractionHeight` in any way and hence the following scenario could occur: + 1. a validator `V` performs an equivocation at a height `Hi` + 2. a new delegator `D` delegates to `V` after height `Hi` + 3. evidence of the equivocation by validator `V` is received + 4. the tokens of delegator `D` are slashed + +In the above scenario, delegator `D` is slashed, even though `D`'s voting power did not contribute to the infraction. + + +#### Old evidence +In the single-chain case, old evidence (e.g., from 3 years ago) is ignored. This is achieved through +[CometBFT](https://docs.cometbft.com/v0.37/spec/consensus/evidence) that ignores old evidence based on the parameters `MaxAgeNumBlocks` and `MaxAgeDuration` (see [here](https://github.com/cometbft/cometbft/blob/v0.37.0/evidence/pool.go#271)). +Additionally, note that when the evidence is sent by CometBFT to the application, the evidence is rechecked in the [evidence module](https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/evidence/keeper/infraction.go#L54) of Cosmos SDK and if it is old, the evidence is ignored. +In Cosmos Hub, the `MaxAgeNumBlocks` is set to 1000000 (i.e., ~70 days if we assume we need ~6 sec per block) and `MaxAgeDuration` is set to 172800000000000 ns (i.e., 2 days). Because of this check, we can easily exclude old evidence. + +### Slashing for equivocation on the consumer +In the single-chain case, slashing requires both the `infractionHeight` and the voting `power`. +In order to slash on the provider for an equivocation on a consumer, we need to have both the provider's `infractionHeight` and voting `power`. +Note that the `infractionHeight` on the consumer chain must be mapped to a height on the provider chain. +Unless we have a way to find the corresponding `infractionHeight` and `power` on the provider chain, we cannot slash for equivocation on the consumer in the same way as we would slash in the single-chain case. + + +The challenge of figuring out the corresponding `infractionHeight` and `power` values on the provider chain is due to the following trust assumption: + +- We trust the consensus layer and validator set of the consumer chains, _but we do not trust the application layer_. + +As a result, we cannot trust anything that stems from the _application state_ of a consumer chain. + +Note that when a relayer or a user sends evidence through a [MsgSubmitConsumerDoubleVoting](https://github.com/cosmos/interchain-security/pull/1232) message, the provider gets access to [DuplicateVoteEvidence](https://github.com/cometbft/cometbft/blob/v0.37.0/types/evidence.go#L35): +```protobuf +type DuplicateVoteEvidence struct { + VoteA *Vote `json:"vote_a"` + VoteB *Vote `json:"vote_b"` + + // abci specific information + TotalVotingPower int64 + ValidatorPower int64 + Timestamp time.Time +} +``` +The "abci specific information" fields cannot be trusted because they are not signed. Therefore, +we can use neither `ValidatorPower` for slashing on the provider chain, nor the `Timestamp` to check the evidence age. We can get the `infractionHeight` from the votes, but this `infractionHeight` corresponds to the infraction height on the consumer and **not** on the provider chain. +Similarly, when a relayer or a user sends evidence through a [MsgSubmitConsumerMisbehaviour](https://github.com/cosmos/interchain-security/pull/826) message, the provider gets access to [Misbehaviour](https://github.com/cosmos/ibc-go/blob/v7.3.0/proto/ibc/lightclients/tendermint/v1/tendermint.proto#L79) that we cannot use to extract the infraction height, power, or the time on the provider chain. + +## Proposed solution +As a first iteration, we propose the following approach. At the moment the provider receives evidence of equivocation on a consumer: +1. slash all the undelegations and redelegations using `slashFactor`; +2. slash all delegations using as voting `power` the sum of the voting power of the misbehaving validator and the power of all the ongoing undelegations and redelegations. + +**Evidence expiration:** Additionally, because we cannot infer the actual time of the evidence (i.e., the timestamp of the evidence cannot be trusted), we do not consider _evidence expiration_ and hence old evidence is never ignored (e.g., the provider would act on 3 year-old evidence of equivocation on a consumer). +Additionally, we do not need to store equivocation evidence to avoid slashing a validator more than once, because we [do not slash](https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/evidence/keeper/infraction.go#L94) tombstoned validators and we [tombstone](https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/evidence/keeper/infraction.go#L138) a validator when slashed. + +We do not act on evidence that was signed by a validator [consensus key](https://tutorials.cosmos.network/tutorials/9-path-to-prod/3-keys.html#what-validator-keys) that is _pruned_ when we receive the evidence. We prune a validator's consensus key if the validator has assigned a new consumer key (using `MsgAssignConsumerKey`) and an unbonding period on the consumer chain has elapsed (see [key assignment ADR](https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-001-key-assignment.md)). Note that the provider chain is informed that the unbonding period has elapsed on the consumer when the provider receives a `VSCMaturedPacket` and because of this, if the consumer delays the sending of a `VSCMaturedPacket`, we would delay the pruning of the key as well. + +### Implementation +The following logic needs to be added to the [HandleConsumerDoubleVoting](https://github.com/cosmos/interchain-security/pull/1232) and [HandleConsumerMisbehaviour](https://github.com/cosmos/interchain-security/pull/826) methods: +```go +undelegationsInTokens := sdk.NewInt(0) +for _, v := range k.stakingKeeper.GetUnbondingDelegationsFromValidator(ctx, validatorAddress) { + for _, entry := range v.Entries { + if entry.IsMature(now) && !entry.OnHold() { + // undelegation no longer eligible for slashing, skip it + continue + } + undelegationsInTokens = undelegationsInTokens.Add(entry.InitialBalance) + } +} + +redelegationsInTokens := sdk.NewInt(0) +for _, v := range k.stakingKeeper.GetRedelegationsFromSrcValidator(ctx, validatorAddress) { + for _, entry := range v.Entries { + if entry.IsMature(now) && !entry.OnHold() { + // redelegation no longer eligible for slashing, skip it + continue + } + redelegationsInTokens = redelegationsInTokens.Add(entry.InitialBalance) + } +} + +infractionHeight := 0 +undelegationsAndRedelegationsInPower = sdk.TokensToConsensusPower(undelegationsInTokens.Add(redelegationsInTokens)) +totalPower := validator's voting power + undelegationsAndRedelegationsInPower +slashFraction := k.slashingKeeper.SlashFractionDoubleSign(ctx) + +k.stakingKeeper.Slash(ctx, validatorConsAddress, infractionHeight, totalPower, slashFraction, DoubleSign) +``` + +**Infraction height:** We provide a zero `infractionHeight` to the [Slash](https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L33) method in order to slash all ongoing undelegations and redelegations (see checks in [Slash](https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L92), [SlashUnbondingDelegation](https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L195), and [SlashRedelegation](https://github.com/cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/slash.go#L249)). + +**Power:** We pass the sum of the voting power of the misbehaving validator when the evidence was received (i.e., at evidence height) and the power of all the ongoing undelegations and redelegations. +If we assume that the `slashFactor` is `5%`, then the voting power we pass is `power + totalPower(undelegations) + totalPower(redelegations)`. +Hence, when the `Slash` method slashes all the undelegations and redelegations it would end up with `0.05 * power + 0.05 * totalPower(undelegations) + 0.05 * totalPower(redelegations) - 0.05 * totalPower(undelegations) - 0.05 * totalPower(redelegations) = 0.05 * power` and hence it would slash `5%` of the validator's power when the evidence is received. + +### Positive +With the proposed approach we can quickly implement slashing functionality on the provider chain for consumer chain equivocations. +This approach does not need to change the staking module and therefore does not change in any way how slashing is performed today for a single chain. + +### Negative + +- We _definitely_ slash more when it comes to undelegations and redelegations because we slash for all of them without considering an `infractionHeight`. +- We _potentially_ slash more than what we would have slashed if we knew the voting `power` at the corresponding `infractionHeight` in the provider chain. +- We slash on old evidence of equivocation on a consumer. + + +## References +* [ADR 005: Cryptographic verification of equivocation evidence](https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md) +* [EPIC tracking cryptographic equivocation feature](https://github.com/cosmos/interchain-security/issues/732) +* [Cosmos Hub Forum discussion on cryptographic equivocation slashing](https://forum.cosmos.network/t/cryptographic-equivocation-slashing-design/11400) diff --git a/docs/docs/adrs/intro.md b/docs/docs/adrs/intro.md index 0c1c722366..5ab86c2a93 100644 --- a/docs/docs/adrs/intro.md +++ b/docs/docs/adrs/intro.md @@ -40,4 +40,7 @@ To suggest an ADR, please make use of the [ADR template](./adr-template.md) prov | [007](./adr-007-pause-unbonding-on-eqv-prop.md) | Pause validator unbonding during equivocation proposal | Proposed | | [008](./adr-008-throttle-retries.md) | Throttle with retries | Accepted, In-progress | | [009](./adr-009-soft-opt-out.md) | Soft Opt-out | Accepted, Implemented | -| [009](./adr-010-standalone-changeover.md) | Standalone to Consumer Changeover | Accepted, Implemented | +| [010](./adr-010-standalone-changeover.md) | Standalone to Consumer Changeover | Accepted, Implemented | +| [011](./adr-011-improving-test-confidence.md) | Improving testing and increasing confidence | Proposed | +| [012](./adr-012-separate-releasing.md) | Separate Releasing | Proposed | +| [013](./adr-013-equivocation-slashing.md) | Slashing on the provider for consumer equivocation | Proposed | From f23cbbb7883eb6c95330db81441cdb6de5b2027c Mon Sep 17 00:00:00 2001 From: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Thu, 14 Sep 2023 00:53:05 -0700 Subject: [PATCH 115/134] ci: update mergify and dependabot for v3.2.x-consumer (#1297) * update ymls * add newline --------- Co-authored-by: mpoke --- .github/dependabot.yml | 10 ++++++++++ .mergify.yml | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 404825428c..e197c1eab2 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -67,3 +67,13 @@ updates: open-pull-requests-limit: 0 labels: - dependencies + + - package-ecosystem: gomod + directory: "/" + schedule: + interval: daily + target-branch: "release/v3.2.x-consumer" + # Only allow automated security-related dependency updates on release branches. + open-pull-requests-limit: 0 + labels: + - dependencies diff --git a/.mergify.yml b/.mergify.yml index 226075ed45..9b6159b9f8 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -50,3 +50,11 @@ pull_request_rules: backport: branches: - release/v3.1.x + - name: Backport patches to the release/v3.2.x-consumer branch + conditions: + - base=main + - label=A:backport/v3.2.x-consumer + actions: + backport: + branches: + - release/v3.2.x-consumer From b3b7818dafe9e74f556a674b0d013a777e66e825 Mon Sep 17 00:00:00 2001 From: Marius Poke Date: Thu, 14 Sep 2023 19:59:36 +0200 Subject: [PATCH 116/134] ci: update bots for v2.1.x-provider-lsm (#1305) update bots for v2.1.x-provider-lsm --- .github/dependabot.yml | 2 +- .mergify.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index e197c1eab2..773e5a783f 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -42,7 +42,7 @@ updates: directory: "/" schedule: interval: daily - target-branch: "release/v2.1.x-lsm" + target-branch: "release/v2.1.x-provider-lsm" # Only allow automated security-related dependency updates on release branches. open-pull-requests-limit: 0 labels: diff --git a/.mergify.yml b/.mergify.yml index 9b6159b9f8..00764d0a8c 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -26,14 +26,14 @@ pull_request_rules: backport: branches: - release/v2.0.x-lsm - - name: Backport patches to the release/v2.1.x-lsm branch + - name: Backport patches to the release/v2.1.x-provider-lsm branch conditions: - base=main - - label=A:backport/v2.1.x-lsm + - label=A:backport/v2.1.x-provider-lsm actions: backport: branches: - - release/v2.1.x-lsm + - release/v2.1.x-provider-lsm - name: Backport patches to the release/v3.0.x branch conditions: - base=main From d064649b53e143ed3347b310291ecb05dd8679c5 Mon Sep 17 00:00:00 2001 From: Simon Noetzlin Date: Fri, 15 Sep 2023 09:05:39 +0200 Subject: [PATCH 117/134] Fix `build` in makefile (#1303) fix build in makefile --- .gitignore | 1 + Makefile | 2 ++ 2 files changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index a0a3488545..e83a69a504 100644 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,6 @@ release/ docs/tla/states/ *.out vendor/ +build/ .vscode .idea diff --git a/Makefile b/Makefile index ac7c38f068..a65db076ab 100644 --- a/Makefile +++ b/Makefile @@ -97,6 +97,8 @@ mockgen_cmd=go run github.com/golang/mock/mockgen mocks: $(mockgen_cmd) -package=keeper -destination=testutil/keeper/mocks.go -source=x/ccv/types/expected_keepers.go + +BUILDDIR ?= $(CURDIR)/build BUILD_TARGETS := build build: BUILD_ARGS=-o $(BUILDDIR)/ From df12b7e6d6d58ea21ba584e66bbcf8350e9c22cf Mon Sep 17 00:00:00 2001 From: bernd-m <43466467+bermuell@users.noreply.github.com> Date: Fri, 15 Sep 2023 17:25:44 +0200 Subject: [PATCH 118/134] refactor: Vaguely named consumer structs (#1288) * Rename GenesisState proto * make proto-gen * proto rename: Params -> ConsumerParams * make proto-gen * App, fix type change for Param renaming * App, fix type change for GenesisState renaming * Fix unit-tests for GenesisState renaming * Fix unit-tests for Params renaming * Addressed review comments * Fix linter issues --- app/consumer-democracy/app.go | 2 +- .../ccv/consumer/v1/query.proto | 2 +- .../ccv/provider/v1/genesis.proto | 2 +- .../ccv/provider/v1/query.proto | 2 +- .../ccv/v1/shared_consumer.proto | 15 +- tests/difference/core/driver/setup.go | 6 +- tests/integration/setup.go | 2 +- testutil/ibc_testing/specific_setup.go | 4 +- x/ccv/consumer/keeper/genesis.go | 12 +- x/ccv/consumer/keeper/genesis_test.go | 22 +- x/ccv/consumer/keeper/keeper.go | 4 +- x/ccv/consumer/keeper/params.go | 4 +- x/ccv/consumer/module.go | 6 +- x/ccv/consumer/types/genesis_test.go | 70 ++-- x/ccv/consumer/types/params_test.go | 2 +- x/ccv/consumer/types/query.pb.go | 93 +++--- x/ccv/provider/keeper/genesis_test.go | 6 +- x/ccv/provider/keeper/keeper.go | 8 +- x/ccv/provider/keeper/key_assignment_test.go | 1 + x/ccv/provider/keeper/proposal.go | 4 +- x/ccv/provider/keeper/proposal_test.go | 2 +- x/ccv/provider/types/consumer.go | 2 +- x/ccv/provider/types/genesis.pb.go | 125 ++++--- x/ccv/provider/types/genesis_test.go | 6 +- x/ccv/provider/types/query.pb.go | 174 +++++----- x/ccv/types/genesis.go | 28 +- x/ccv/types/params.go | 12 +- x/ccv/types/shared_consumer.pb.go | 310 +++++++++--------- 28 files changed, 460 insertions(+), 466 deletions(-) diff --git a/app/consumer-democracy/app.go b/app/consumer-democracy/app.go index 1a35a89a8a..09b13520ae 100644 --- a/app/consumer-democracy/app.go +++ b/app/consumer-democracy/app.go @@ -713,7 +713,7 @@ func New( return fromVM, fmt.Errorf("failed to unmarshal genesis state: %w", err) } - consumerGenesis := ccvtypes.GenesisState{} + consumerGenesis := ccvtypes.ConsumerGenesisState{} appCodec.MustUnmarshalJSON(appState[consumertypes.ModuleName], &consumerGenesis) consumerGenesis.PreCCV = true diff --git a/proto/interchain_security/ccv/consumer/v1/query.proto b/proto/interchain_security/ccv/consumer/v1/query.proto index ff2a5901fe..b21e07341a 100644 --- a/proto/interchain_security/ccv/consumer/v1/query.proto +++ b/proto/interchain_security/ccv/consumer/v1/query.proto @@ -55,7 +55,7 @@ message QueryParamsRequest {} // QueryParamsResponse is response type for the Query/Params RPC method. message QueryParamsResponse { // params holds all the parameters of this module. - interchain_security.ccv.v1.Params params = 1 [ (gogoproto.nullable) = false ]; + interchain_security.ccv.v1.ConsumerParams params = 1 [ (gogoproto.nullable) = false ]; } message QueryProviderInfoRequest {} diff --git a/proto/interchain_security/ccv/provider/v1/genesis.proto b/proto/interchain_security/ccv/provider/v1/genesis.proto index 22da5c4200..9cefe26ee0 100644 --- a/proto/interchain_security/ccv/provider/v1/genesis.proto +++ b/proto/interchain_security/ccv/provider/v1/genesis.proto @@ -64,7 +64,7 @@ message ConsumerState { // InitalHeight defines the initial block height for the consumer chain uint64 initial_height = 4; // ConsumerGenesis defines the initial consumer chain genesis states - interchain_security.ccv.v1.GenesisState consumer_genesis = 5 + interchain_security.ccv.v1.ConsumerGenesisState consumer_genesis = 5 [ (gogoproto.nullable) = false ]; // PendingValsetChanges defines the pending validator set changes for the // consumer chain diff --git a/proto/interchain_security/ccv/provider/v1/query.proto b/proto/interchain_security/ccv/provider/v1/query.proto index b0c1dc2b47..6dfcdcb320 100644 --- a/proto/interchain_security/ccv/provider/v1/query.proto +++ b/proto/interchain_security/ccv/provider/v1/query.proto @@ -86,7 +86,7 @@ service Query { message QueryConsumerGenesisRequest { string chain_id = 1; } message QueryConsumerGenesisResponse { - interchain_security.ccv.v1.GenesisState genesis_state = 1 + interchain_security.ccv.v1.ConsumerGenesisState genesis_state = 1 [ (gogoproto.nullable) = false ]; } diff --git a/proto/interchain_security/ccv/v1/shared_consumer.proto b/proto/interchain_security/ccv/v1/shared_consumer.proto index 825a84e346..4a44548ea3 100644 --- a/proto/interchain_security/ccv/v1/shared_consumer.proto +++ b/proto/interchain_security/ccv/v1/shared_consumer.proto @@ -17,13 +17,12 @@ import "google/protobuf/timestamp.proto"; // but not sent over the wire. These schemas could change, only with careful consideration of effects! // -// Params defines the parameters for CCV consumer module. +// ConsumerParams defines the parameters for CCV consumer module. // // Note this type is referenced in both the consumer and provider CCV modules, // and persisted on the provider, see MakeConsumerGenesis and SetConsumerGenesis. // -// TODO: Rename to ConsumerParams. See https://github.com/cosmos/interchain-security/issues/1206 -message Params { +message ConsumerParams { // TODO: Remove enabled flag and find a better way to setup integration tests // See: https://github.com/cosmos/interchain-security/issues/339 bool enabled = 1; @@ -79,19 +78,17 @@ message Params { repeated string provider_reward_denoms = 12; } -// GenesisState defines the CCV consumer chain genesis state. +// ConsumerGenesisState defines the CCV consumer chain genesis state. // // Note this type is referenced in both the consumer and provider CCV modules, // and persisted on the provider, see MakeConsumerGenesis and SetConsumerGenesis. -// -// TODO: Rename to ConsumerGenesisState. See https://github.com/cosmos/interchain-security/issues/1206 -message GenesisState { - Params params = 1 [ (gogoproto.nullable) = false ]; +message ConsumerGenesisState { + ConsumerParams params = 1 [ (gogoproto.nullable) = false ]; string provider_client_id = 2; // empty for a new chain, filled in on restart. string provider_channel_id = 3; // empty for a new chain, filled in on restart. bool new_chain = - 4; // true for new chain GenesisState, false for chain restart. + 4; // true for new chain, false for chain restart. // ProviderClientState filled in on new chain, nil on restart. ibc.lightclients.tendermint.v1.ClientState provider_client_state = 5; // ProviderConsensusState filled in on new chain, nil on restart. diff --git a/tests/difference/core/driver/setup.go b/tests/difference/core/driver/setup.go index 2a4b17eddf..c1d1c272ff 100644 --- a/tests/difference/core/driver/setup.go +++ b/tests/difference/core/driver/setup.go @@ -207,7 +207,7 @@ func (b *Builder) getAppBytesAndSenders( bondDenom := sdk.DefaultBondDenom genesisStaking := stakingtypes.GenesisState{} - genesisConsumer := ccv.GenesisState{} + genesisConsumer := ccv.ConsumerGenesisState{} if genesis[stakingtypes.ModuleName] != nil { // If staking module genesis already exists @@ -522,7 +522,7 @@ func (b *Builder) createConsumersLocalClientGenesis() *ibctmtypes.ClientState { ) } -func (b *Builder) createConsumerGenesis(client *ibctmtypes.ClientState) *ccv.GenesisState { +func (b *Builder) createConsumerGenesis(client *ibctmtypes.ClientState) *ccv.ConsumerGenesisState { providerConsState := b.provider().LastHeader.ConsensusState() valUpdates := tmtypes.TM2PB.ValidatorUpdates(b.provider().Vals) @@ -540,7 +540,7 @@ func (b *Builder) createConsumerGenesis(client *ibctmtypes.ClientState) *ccv.Gen []string{}, []string{}, ) - return ccv.NewInitialGenesisState(client, providerConsState, valUpdates, params) + return ccv.NewInitialConsumerGenesisState(client, providerConsState, valUpdates, params) } // The state of the data returned is equivalent to the state of two chains diff --git a/tests/integration/setup.go b/tests/integration/setup.go index 76f6311dab..8db75519c0 100644 --- a/tests/integration/setup.go +++ b/tests/integration/setup.go @@ -182,7 +182,7 @@ func (s *CCVTestSuite) getSentPacket(chain *ibctesting.TestChain, sequence uint6 func initConsumerChain( s *CCVTestSuite, chainID string, - genesisState *ccv.GenesisState, + genesisState *ccv.ConsumerGenesisState, ) { providerKeeper := s.providerApp.GetProviderKeeper() bundle := s.consumerBundles[chainID] diff --git a/testutil/ibc_testing/specific_setup.go b/testutil/ibc_testing/specific_setup.go index 8ac559d740..1c5529e22a 100644 --- a/testutil/ibc_testing/specific_setup.go +++ b/testutil/ibc_testing/specific_setup.go @@ -51,7 +51,7 @@ func ConsumerAppIniter(initValPowers []types.ValidatorUpdate) AppIniter { }, ) // Feed consumer genesis with provider validators - var consumerGenesis ccvtypes.GenesisState + var consumerGenesis ccvtypes.ConsumerGenesisState encoding.Codec.MustUnmarshalJSON(genesisState[consumertypes.ModuleName], &consumerGenesis) consumerGenesis.InitialValSet = initValPowers consumerGenesis.Params.Enabled = true @@ -69,7 +69,7 @@ func DemocracyConsumerAppIniter(initValPowers []types.ValidatorUpdate) AppIniter genesisState := appConsumerDemocracy.NewDefaultGenesisState(encoding.Codec) // Feed consumer genesis with provider validators // TODO See if useful for democracy - var consumerGenesis ccvtypes.GenesisState + var consumerGenesis ccvtypes.ConsumerGenesisState encoding.Codec.MustUnmarshalJSON(genesisState[consumertypes.ModuleName], &consumerGenesis) consumerGenesis.InitialValSet = initValPowers consumerGenesis.Params.Enabled = true diff --git a/x/ccv/consumer/keeper/genesis.go b/x/ccv/consumer/keeper/genesis.go index 2ac38f650c..f20d8849dc 100644 --- a/x/ccv/consumer/keeper/genesis.go +++ b/x/ccv/consumer/keeper/genesis.go @@ -16,7 +16,7 @@ import ( // 1. A client to the provider was never created, i.e. a new consumer chain is started for the first time. // 2. A consumer chain restarts after a client to the provider was created, but the CCV channel handshake is still in progress // 3. A consumer chain restarts after the CCV channel handshake was completed. -func (k Keeper) InitGenesis(ctx sdk.Context, state *ccv.GenesisState) []abci.ValidatorUpdate { +func (k Keeper) InitGenesis(ctx sdk.Context, state *ccv.ConsumerGenesisState) []abci.ValidatorUpdate { // PreCCV is true during the process of a standalone to consumer changeover. // At the PreCCV point in the process, the standalone chain has just been upgraded to include // the consumer ccv module, but the standalone staking keeper is still managing the validator set. @@ -115,10 +115,10 @@ func (k Keeper) InitGenesis(ctx sdk.Context, state *ccv.GenesisState) []abci.Val } // ExportGenesis returns the CCV consumer module's exported genesis -func (k Keeper) ExportGenesis(ctx sdk.Context) (genesis *ccv.GenesisState) { +func (k Keeper) ExportGenesis(ctx sdk.Context) (genesis *ccv.ConsumerGenesisState) { params := k.GetConsumerParams(ctx) if !params.Enabled { - return ccv.DefaultGenesisState() + return ccv.DefaultConsumerGenesisState() } // export the current validator set @@ -137,7 +137,7 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) (genesis *ccv.GenesisState) { panic("provider client does not exist although provider channel does exist") } - genesis = ccv.NewRestartGenesisState( + genesis = ccv.NewRestartConsumerGenesisState( clientID, channelID, k.GetAllPacketMaturityTimes(ctx), @@ -153,11 +153,11 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) (genesis *ccv.GenesisState) { // if provider clientID and channelID don't exist on the consumer chain, // then CCV protocol is disabled for this chain return a default genesis state if !ok { - return ccv.DefaultGenesisState() + return ccv.DefaultConsumerGenesisState() } // export client states and pending slashing requests into a new chain genesis - genesis = ccv.NewRestartGenesisState( + genesis = ccv.NewRestartConsumerGenesisState( clientID, "", nil, diff --git a/x/ccv/consumer/keeper/genesis_test.go b/x/ccv/consumer/keeper/genesis_test.go index 9cb489b3c0..a07388a6cb 100644 --- a/x/ccv/consumer/keeper/genesis_test.go +++ b/x/ccv/consumer/keeper/genesis_test.go @@ -100,8 +100,8 @@ func TestInitGenesis(t *testing.T) { testCases := []struct { name string malleate func(sdk.Context, testkeeper.MockedKeepers) - genesis *ccv.GenesisState - assertStates func(sdk.Context, consumerkeeper.Keeper, *ccv.GenesisState) + genesis *ccv.ConsumerGenesisState + assertStates func(sdk.Context, consumerkeeper.Keeper, *ccv.ConsumerGenesisState) }{ { "start a new chain", @@ -112,13 +112,13 @@ func TestInitGenesis(t *testing.T) { testkeeper.ExpectGetCapabilityMock(ctx, mocks, 1), ) }, - ccv.NewInitialGenesisState( + ccv.NewInitialConsumerGenesisState( provClientState, provConsState, valset, params, ), - func(ctx sdk.Context, ck consumerkeeper.Keeper, gs *ccv.GenesisState) { + func(ctx sdk.Context, ck consumerkeeper.Keeper, gs *ccv.ConsumerGenesisState) { assertConsumerPortIsBound(t, ctx, &ck) assertProviderClientID(t, ctx, &ck, provClientID) @@ -134,7 +134,7 @@ func TestInitGenesis(t *testing.T) { testkeeper.ExpectGetCapabilityMock(ctx, mocks, 2), ) }, - ccv.NewRestartGenesisState( + ccv.NewRestartConsumerGenesisState( provClientID, "", matPackets, @@ -145,7 +145,7 @@ func TestInitGenesis(t *testing.T) { ccv.LastTransmissionBlockHeight{}, params, ), - func(ctx sdk.Context, ck consumerkeeper.Keeper, gs *ccv.GenesisState) { + func(ctx sdk.Context, ck consumerkeeper.Keeper, gs *ccv.ConsumerGenesisState) { assertConsumerPortIsBound(t, ctx, &ck) obtainedPendingPackets := ck.GetPendingPackets(ctx) @@ -170,7 +170,7 @@ func TestInitGenesis(t *testing.T) { ) }, // create a genesis for a restarted chain - ccv.NewRestartGenesisState( + ccv.NewRestartConsumerGenesisState( provClientID, provChannelID, matPackets, @@ -183,7 +183,7 @@ func TestInitGenesis(t *testing.T) { ccv.LastTransmissionBlockHeight{Height: int64(100)}, params, ), - func(ctx sdk.Context, ck consumerkeeper.Keeper, gs *ccv.GenesisState) { + func(ctx sdk.Context, ck consumerkeeper.Keeper, gs *ccv.ConsumerGenesisState) { assertConsumerPortIsBound(t, ctx, &ck) gotChannelID, ok := ck.GetProviderChannel(ctx) @@ -289,7 +289,7 @@ func TestExportGenesis(t *testing.T) { testCases := []struct { name string malleate func(sdk.Context, consumerkeeper.Keeper, testkeeper.MockedKeepers) - expGenesis *ccv.GenesisState + expGenesis *ccv.ConsumerGenesisState }{ { "export a chain without an established CCV channel", @@ -307,7 +307,7 @@ func TestExportGenesis(t *testing.T) { ck.SetHeightValsetUpdateID(ctx, defaultHeightValsetUpdateIDs[0].Height, defaultHeightValsetUpdateIDs[0].ValsetUpdateId) }, - ccv.NewRestartGenesisState( + ccv.NewRestartConsumerGenesisState( provClientID, "", nil, @@ -343,7 +343,7 @@ func TestExportGenesis(t *testing.T) { ck.SetOutstandingDowntime(ctx, sdk.ConsAddress(validator.Address.Bytes())) ck.SetLastTransmissionBlockHeight(ctx, ltbh) }, - ccv.NewRestartGenesisState( + ccv.NewRestartConsumerGenesisState( provClientID, provChannelID, matPackets, diff --git a/x/ccv/consumer/keeper/keeper.go b/x/ccv/consumer/keeper/keeper.go index 2d3e78e0f8..b84f3d1864 100644 --- a/x/ccv/consumer/keeper/keeper.go +++ b/x/ccv/consumer/keeper/keeper.go @@ -309,7 +309,7 @@ func (k Keeper) DeletePreCCV(ctx sdk.Context) { func (k Keeper) SetInitialValSet(ctx sdk.Context, initialValSet []tmtypes.ValidatorUpdate) { store := ctx.KVStore(k.storeKey) - initialValSetState := ccv.GenesisState{ + initialValSetState := ccv.ConsumerGenesisState{ InitialValSet: initialValSet, } bz := k.cdc.MustMarshal(&initialValSetState) @@ -318,7 +318,7 @@ func (k Keeper) SetInitialValSet(ctx sdk.Context, initialValSet []tmtypes.Valida func (k Keeper) GetInitialValSet(ctx sdk.Context) []tmtypes.ValidatorUpdate { store := ctx.KVStore(k.storeKey) - initialValSet := ccv.GenesisState{} + initialValSet := ccv.ConsumerGenesisState{} bz := store.Get(types.InitialValSetKey()) if bz != nil { k.cdc.MustUnmarshal(bz, &initialValSet) diff --git a/x/ccv/consumer/keeper/params.go b/x/ccv/consumer/keeper/params.go index 770edf229e..12524fe3d2 100644 --- a/x/ccv/consumer/keeper/params.go +++ b/x/ccv/consumer/keeper/params.go @@ -11,7 +11,7 @@ import ( // GetParams returns the params for the consumer ccv module // NOTE: it is different from the GetParams method which is required to implement StakingKeeper interface -func (k Keeper) GetConsumerParams(ctx sdk.Context) ccvtypes.Params { +func (k Keeper) GetConsumerParams(ctx sdk.Context) ccvtypes.ConsumerParams { return ccvtypes.NewParams( k.GetEnabled(ctx), k.GetBlocksPerDistributionTransmission(ctx), @@ -29,7 +29,7 @@ func (k Keeper) GetConsumerParams(ctx sdk.Context) ccvtypes.Params { } // SetParams sets the paramset for the consumer module -func (k Keeper) SetParams(ctx sdk.Context, params ccvtypes.Params) { +func (k Keeper) SetParams(ctx sdk.Context, params ccvtypes.ConsumerParams) { k.paramStore.SetParamSet(ctx, ¶ms) } diff --git a/x/ccv/consumer/module.go b/x/ccv/consumer/module.go index a9f4a4fc7e..e175205530 100644 --- a/x/ccv/consumer/module.go +++ b/x/ccv/consumer/module.go @@ -52,12 +52,12 @@ func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) // DefaultGenesis returns default genesis state as raw bytes for the ibc // consumer module. func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { - return cdc.MustMarshalJSON(ccvtypes.DefaultGenesisState()) + return cdc.MustMarshalJSON(ccvtypes.DefaultConsumerGenesisState()) } // ValidateGenesis performs genesis state validation for the ibc consumer module. func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { - var data ccvtypes.GenesisState + var data ccvtypes.ConsumerGenesisState if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", consumertypes.ModuleName, err) } @@ -112,7 +112,7 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { // InitGenesis performs genesis initialization for the consumer module. It returns // no validator updates. func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { - var genesisState ccvtypes.GenesisState + var genesisState ccvtypes.ConsumerGenesisState cdc.MustUnmarshalJSON(data, &genesisState) return am.keeper.InitGenesis(ctx, &genesisState) } diff --git a/x/ccv/consumer/types/genesis_test.go b/x/ccv/consumer/types/genesis_test.go index 453a3aab20..d543c4df21 100644 --- a/x/ccv/consumer/types/genesis_test.go +++ b/x/ccv/consumer/types/genesis_test.go @@ -52,39 +52,39 @@ func TestValidateInitialGenesisState(t *testing.T) { cases := []struct { name string - gs *types.GenesisState + gs *types.ConsumerGenesisState expError bool }{ { "valid new consumer genesis state", - types.NewInitialGenesisState(cs, consensusState, valUpdates, params), + types.NewInitialConsumerGenesisState(cs, consensusState, valUpdates, params), false, }, { "invalid new consumer genesis state: nil client state", - types.NewInitialGenesisState(nil, consensusState, valUpdates, params), + types.NewInitialConsumerGenesisState(nil, consensusState, valUpdates, params), true, }, { "invalid new consumer genesis state: invalid client state", - types.NewInitialGenesisState(&ibctmtypes.ClientState{ChainId: "badClientState"}, + types.NewInitialConsumerGenesisState(&ibctmtypes.ClientState{ChainId: "badClientState"}, consensusState, valUpdates, params), true, }, { "invalid new consumer genesis state: nil consensus state", - types.NewInitialGenesisState(cs, nil, valUpdates, params), + types.NewInitialConsumerGenesisState(cs, nil, valUpdates, params), true, }, { "invalid new consumer genesis state: invalid consensus state", - types.NewInitialGenesisState(cs, &ibctmtypes.ConsensusState{Timestamp: time.Now()}, + types.NewInitialConsumerGenesisState(cs, &ibctmtypes.ConsensusState{Timestamp: time.Now()}, valUpdates, params), true, }, { "invalid new consumer genesis state: client id not empty", - &types.GenesisState{ + &types.ConsumerGenesisState{ Params: params, ProviderClientId: "ccvclient", ProviderChannelId: "", @@ -103,7 +103,7 @@ func TestValidateInitialGenesisState(t *testing.T) { }, { "invalid new consumer genesis state: channel id not empty", - &types.GenesisState{ + &types.ConsumerGenesisState{ Params: params, ProviderClientId: "", ProviderChannelId: "ccvchannel", @@ -122,7 +122,7 @@ func TestValidateInitialGenesisState(t *testing.T) { }, { "invalid new consumer genesis state: non-empty unbonding sequences", - &types.GenesisState{ + &types.ConsumerGenesisState{ Params: params, ProviderClientId: "", ProviderChannelId: "", @@ -141,7 +141,7 @@ func TestValidateInitialGenesisState(t *testing.T) { }, { "invalid new consumer genesis state: non-empty last transmission packet", - &types.GenesisState{ + &types.ConsumerGenesisState{ Params: params, ProviderClientId: "", ProviderChannelId: "", @@ -160,7 +160,7 @@ func TestValidateInitialGenesisState(t *testing.T) { }, { "invalid new consumer genesis state: non-empty pending consumer packets", - &types.GenesisState{ + &types.ConsumerGenesisState{ Params: params, ProviderClientId: "", ProviderChannelId: "", @@ -179,12 +179,12 @@ func TestValidateInitialGenesisState(t *testing.T) { }, { "invalid new consumer genesis state: nil initial validator set", - types.NewInitialGenesisState(cs, consensusState, nil, params), + types.NewInitialConsumerGenesisState(cs, consensusState, nil, params), true, }, { "invalid new consumer genesis state: invalid consensus state validator set hash", - types.NewInitialGenesisState( + types.NewInitialConsumerGenesisState( cs, ibctmtypes.NewConsensusState( time.Now(), commitmenttypes.NewMerkleRoot([]byte("apphash")), []byte("wrong_length_hash")), valUpdates, params), @@ -192,7 +192,7 @@ func TestValidateInitialGenesisState(t *testing.T) { }, { "invalid new consumer genesis state: initial validator set does not match validator set hash", - types.NewInitialGenesisState( + types.NewInitialConsumerGenesisState( cs, ibctmtypes.NewConsensusState( time.Now(), commitmenttypes.NewMerkleRoot([]byte("apphash")), []byte("9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08")), valUpdates, params), @@ -200,7 +200,7 @@ func TestValidateInitialGenesisState(t *testing.T) { }, { "invalid new consumer genesis state: initial validator set does not match validator set hash", - types.NewInitialGenesisState( + types.NewInitialConsumerGenesisState( cs, ibctmtypes.NewConsensusState( time.Now(), commitmenttypes.NewMerkleRoot([]byte("apphash")), []byte("9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08")), valUpdates, params), @@ -208,7 +208,7 @@ func TestValidateInitialGenesisState(t *testing.T) { }, { "invalid new consumer genesis state: invalid params - ccvTimeoutPeriod", - types.NewInitialGenesisState(cs, consensusState, valUpdates, + types.NewInitialConsumerGenesisState(cs, consensusState, valUpdates, types.NewParams( true, types.DefaultBlocksPerDistributionTransmission, @@ -227,7 +227,7 @@ func TestValidateInitialGenesisState(t *testing.T) { }, { "invalid new consumer genesis state: invalid params - distributionTransmissionChannel", - types.NewInitialGenesisState(cs, consensusState, valUpdates, + types.NewInitialConsumerGenesisState(cs, consensusState, valUpdates, types.NewParams( true, types.DefaultBlocksPerDistributionTransmission, @@ -256,9 +256,9 @@ func TestValidateInitialGenesisState(t *testing.T) { } } -// TestValidateRestartGenesisState tests a NewRestartGenesisState instantiation, +// TestValidateRestartConsumerGenesisState tests a NewRestartGenesisState instantiation, // and its Validate() method over different genesis scenarios -func TestValidateRestartGenesisState(t *testing.T) { +func TestValidateRestartConsumerGenesisState(t *testing.T) { // generate validator private/public key cId := crypto.NewCryptoIdentityFromIntSeed(234234) pubKey := cId.TMCryptoPubKey() @@ -299,25 +299,25 @@ func TestValidateRestartGenesisState(t *testing.T) { cases := []struct { name string - gs *types.GenesisState + gs *types.ConsumerGenesisState expError bool }{ { "valid restart consumer genesis state: empty maturing packets", - types.NewRestartGenesisState("ccvclient", "ccvchannel", nil, valUpdates, heightToValsetUpdateID, + types.NewRestartConsumerGenesisState("ccvclient", "ccvchannel", nil, valUpdates, heightToValsetUpdateID, types.ConsumerPacketDataList{List: []types.ConsumerPacketData{matConsumerPacket, slashConsumerPacket}}, nil, types.LastTransmissionBlockHeight{Height: 100}, params), false, }, { "valid restart consumer genesis state: handshake in progress ", - types.NewRestartGenesisState("ccvclient", "", nil, valUpdates, heightToValsetUpdateID, + types.NewRestartConsumerGenesisState("ccvclient", "", nil, valUpdates, heightToValsetUpdateID, types.ConsumerPacketDataList{List: []types.ConsumerPacketData{slashConsumerPacket}}, nil, types.LastTransmissionBlockHeight{}, params), false, }, { "valid restart consumer genesis state: maturing packets", - types.NewRestartGenesisState("ccvclient", "ccvchannel", []types.MaturingVSCPacket{ + types.NewRestartConsumerGenesisState("ccvclient", "ccvchannel", []types.MaturingVSCPacket{ {VscId: 1, MaturityTime: time.Now().UTC()}, {VscId: 3, MaturityTime: time.Now().UTC()}, {VscId: 5, MaturityTime: time.Now().UTC()}, @@ -328,26 +328,26 @@ func TestValidateRestartGenesisState(t *testing.T) { }, { "invalid restart consumer genesis state: provider id is empty", - types.NewRestartGenesisState("", "ccvchannel", nil, valUpdates, heightToValsetUpdateID, types.ConsumerPacketDataList{}, nil, types.LastTransmissionBlockHeight{}, params), + types.NewRestartConsumerGenesisState("", "ccvchannel", nil, valUpdates, heightToValsetUpdateID, types.ConsumerPacketDataList{}, nil, types.LastTransmissionBlockHeight{}, params), true, }, { "invalid restart consumer genesis state: maturing packet vscId is invalid", - types.NewRestartGenesisState("ccvclient", "ccvchannel", []types.MaturingVSCPacket{ + types.NewRestartConsumerGenesisState("ccvclient", "ccvchannel", []types.MaturingVSCPacket{ {VscId: 0, MaturityTime: time.Now().UTC()}, }, valUpdates, nil, types.ConsumerPacketDataList{}, nil, types.LastTransmissionBlockHeight{}, params), true, }, { "invalid restart consumer genesis state: maturing packet time is invalid", - types.NewRestartGenesisState("ccvclient", "ccvchannel", []types.MaturingVSCPacket{ + types.NewRestartConsumerGenesisState("ccvclient", "ccvchannel", []types.MaturingVSCPacket{ {VscId: 1, MaturityTime: time.Time{}}, }, valUpdates, nil, types.ConsumerPacketDataList{}, nil, types.LastTransmissionBlockHeight{}, params), true, }, { "invalid restart consumer genesis: client state defined", - &types.GenesisState{ + &types.ConsumerGenesisState{ Params: params, ProviderClientId: "ccvclient", ProviderChannelId: "ccvchannel", @@ -366,7 +366,7 @@ func TestValidateRestartGenesisState(t *testing.T) { }, { "invalid restart consumer genesis: consensus state defined", - &types.GenesisState{ + &types.ConsumerGenesisState{ Params: params, ProviderClientId: "ccvclient", ProviderChannelId: "ccvchannel", @@ -385,37 +385,37 @@ func TestValidateRestartGenesisState(t *testing.T) { }, { "invalid restart consumer genesis state: nil initial validator set", - types.NewRestartGenesisState("ccvclient", "ccvchannel", nil, nil, nil, types.ConsumerPacketDataList{}, nil, types.LastTransmissionBlockHeight{}, params), + types.NewRestartConsumerGenesisState("ccvclient", "ccvchannel", nil, nil, nil, types.ConsumerPacketDataList{}, nil, types.LastTransmissionBlockHeight{}, params), true, }, { "invalid restart consumer genesis state: nil height to validator set id mapping", - types.NewRestartGenesisState("ccvclient", "", + types.NewRestartConsumerGenesisState("ccvclient", "", []types.MaturingVSCPacket{{VscId: 1, MaturityTime: time.Time{}}}, valUpdates, nil, types.ConsumerPacketDataList{}, nil, types.LastTransmissionBlockHeight{}, params), true, }, { "invalid restart consumer genesis state: maturing packet defined when handshake is still in progress", - types.NewRestartGenesisState("ccvclient", "", + types.NewRestartConsumerGenesisState("ccvclient", "", []types.MaturingVSCPacket{{VscId: 1, MaturityTime: time.Time{}}}, valUpdates, heightToValsetUpdateID, types.ConsumerPacketDataList{}, nil, types.LastTransmissionBlockHeight{}, params), true, }, { "invalid restart consumer genesis state: outstanding downtime defined when handshake is still in progress", - types.NewRestartGenesisState("ccvclient", "", + types.NewRestartConsumerGenesisState("ccvclient", "", nil, valUpdates, heightToValsetUpdateID, types.ConsumerPacketDataList{}, []types.OutstandingDowntime{{ValidatorConsensusAddress: "cosmosvalconsxxx"}}, types.LastTransmissionBlockHeight{}, params), true, }, { "invalid restart consumer genesis state: last transmission block height defined when handshake is still in progress", - types.NewRestartGenesisState("ccvclient", "", + types.NewRestartConsumerGenesisState("ccvclient", "", nil, valUpdates, heightToValsetUpdateID, types.ConsumerPacketDataList{}, nil, types.LastTransmissionBlockHeight{Height: int64(1)}, params), true, }, { "invalid restart consumer genesis state: pending maturing packets defined when handshake is still in progress", - types.NewRestartGenesisState("ccvclient", "", + types.NewRestartConsumerGenesisState("ccvclient", "", nil, valUpdates, heightToValsetUpdateID, types.ConsumerPacketDataList{ List: []types.ConsumerPacketData{ { @@ -428,7 +428,7 @@ func TestValidateRestartGenesisState(t *testing.T) { }, { "invalid restart consumer genesis state: invalid params", - types.NewRestartGenesisState("ccvclient", "ccvchannel", nil, valUpdates, nil, types.ConsumerPacketDataList{}, nil, types.LastTransmissionBlockHeight{}, + types.NewRestartConsumerGenesisState("ccvclient", "ccvchannel", nil, valUpdates, nil, types.ConsumerPacketDataList{}, nil, types.LastTransmissionBlockHeight{}, types.NewParams( true, types.DefaultBlocksPerDistributionTransmission, diff --git a/x/ccv/consumer/types/params_test.go b/x/ccv/consumer/types/params_test.go index ff5d0f325f..e401ba3e47 100644 --- a/x/ccv/consumer/types/params_test.go +++ b/x/ccv/consumer/types/params_test.go @@ -13,7 +13,7 @@ import ( func TestValidateParams(t *testing.T) { testCases := []struct { name string - params ccvtypes.Params + params ccvtypes.ConsumerParams expPass bool }{ {"default params", ccvtypes.DefaultParams(), true}, diff --git a/x/ccv/consumer/types/query.pb.go b/x/ccv/consumer/types/query.pb.go index 5ed38da3f8..45e3586424 100644 --- a/x/ccv/consumer/types/query.pb.go +++ b/x/ccv/consumer/types/query.pb.go @@ -253,7 +253,7 @@ var xxx_messageInfo_QueryParamsRequest proto.InternalMessageInfo // QueryParamsResponse is response type for the Query/Params RPC method. type QueryParamsResponse struct { // params holds all the parameters of this module. - Params types.Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` + Params types.ConsumerParams `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` } func (m *QueryParamsResponse) Reset() { *m = QueryParamsResponse{} } @@ -289,11 +289,11 @@ func (m *QueryParamsResponse) XXX_DiscardUnknown() { var xxx_messageInfo_QueryParamsResponse proto.InternalMessageInfo -func (m *QueryParamsResponse) GetParams() types.Params { +func (m *QueryParamsResponse) GetParams() types.ConsumerParams { if m != nil { return m.Params } - return types.Params{} + return types.ConsumerParams{} } type QueryProviderInfoRequest struct { @@ -468,50 +468,51 @@ func init() { } var fileDescriptor_f627751d3cc10225 = []byte{ - // 686 bytes of a gzipped FileDescriptorProto + // 689 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x55, 0x4f, 0x6b, 0x13, 0x41, - 0x14, 0xcf, 0xa6, 0x4d, 0xdb, 0x4c, 0xf5, 0xe0, 0x18, 0x21, 0xae, 0x65, 0x2d, 0xab, 0x60, 0x14, - 0xb2, 0xdb, 0xb4, 0x87, 0xea, 0xa1, 0x5a, 0x6c, 0x2c, 0x06, 0x54, 0xea, 0x22, 0x14, 0xbc, 0x94, - 0xe9, 0x64, 0x9a, 0x0c, 0x24, 0x33, 0xe9, 0xcc, 0xec, 0xd2, 0xde, 0x44, 0xf1, 0x2a, 0x82, 0xdf, - 0xc4, 0x2f, 0xe0, 0xb5, 0xe0, 0xa5, 0xe0, 0xc5, 0x93, 0x48, 0xeb, 0x87, 0xf0, 0x28, 0x3b, 0x3b, - 0x9b, 0x6e, 0xe8, 0xbf, 0xad, 0x7a, 0x9b, 0x79, 0xbf, 0xf7, 0x7e, 0xef, 0xf7, 0xde, 0xbc, 0xb7, - 0x0b, 0x7c, 0xca, 0x14, 0x11, 0xb8, 0x8b, 0x28, 0xdb, 0x90, 0x04, 0x87, 0x82, 0xaa, 0x5d, 0x1f, - 0xe3, 0xc8, 0xc7, 0x9c, 0xc9, 0xb0, 0x4f, 0x84, 0x1f, 0x35, 0xfc, 0xed, 0x90, 0x88, 0x5d, 0x6f, - 0x20, 0xb8, 0xe2, 0xf0, 0xd6, 0x09, 0x01, 0x1e, 0xc6, 0x91, 0x97, 0x06, 0x78, 0x51, 0xc3, 0x9e, - 0x3b, 0x8d, 0x35, 0x6a, 0xf8, 0xb2, 0x8b, 0x04, 0x69, 0x6f, 0x0c, 0xdd, 0x35, 0xad, 0x5d, 0xe9, - 0xf0, 0x0e, 0xd7, 0x47, 0x3f, 0x3e, 0x19, 0xeb, 0x4c, 0x87, 0xf3, 0x4e, 0x8f, 0xf8, 0x68, 0x40, - 0x7d, 0xc4, 0x18, 0x57, 0x48, 0x51, 0xce, 0xa4, 0x41, 0xe7, 0xf3, 0x68, 0x1f, 0xcd, 0xe3, 0x7e, - 0x28, 0x82, 0x1b, 0x2f, 0xc8, 0x8e, 0x5a, 0x25, 0xa4, 0x49, 0xa5, 0x12, 0x74, 0x33, 0x8c, 0x29, - 0x9f, 0x48, 0x45, 0xfb, 0x48, 0x11, 0x78, 0x1b, 0x5c, 0xc6, 0xa1, 0x10, 0x84, 0xa9, 0xa7, 0x84, - 0x76, 0xba, 0xaa, 0x6a, 0xcd, 0x5a, 0xb5, 0xb1, 0x60, 0xd4, 0x08, 0x1d, 0x00, 0x7a, 0x48, 0xa6, - 0x2e, 0x45, 0xed, 0x92, 0xb1, 0xc4, 0x38, 0x23, 0x3b, 0x29, 0x3e, 0x96, 0xe0, 0x47, 0x16, 0xb8, - 0x00, 0xae, 0xb5, 0x33, 0xd9, 0x37, 0xb6, 0x04, 0xc2, 0xf1, 0xa1, 0x3a, 0x3e, 0x6b, 0xd5, 0xca, - 0x41, 0x25, 0x0b, 0xae, 0x1a, 0x0c, 0x56, 0x40, 0x49, 0x71, 0x85, 0x7a, 0xd5, 0x92, 0x76, 0x4a, - 0x2e, 0x71, 0x2a, 0xc5, 0xd7, 0x04, 0x8f, 0x68, 0x9b, 0x88, 0xea, 0x84, 0x86, 0x32, 0x96, 0x04, - 0x5f, 0x31, 0x4d, 0xa8, 0x4e, 0xa6, 0x78, 0x6a, 0x71, 0xef, 0x82, 0x3b, 0x2f, 0xe3, 0xe7, 0x3d, - 0xa3, 0x29, 0x01, 0xd9, 0x0e, 0x89, 0x54, 0xee, 0x1b, 0x0b, 0xd4, 0xce, 0xf7, 0x95, 0x03, 0xce, - 0x24, 0x81, 0xaf, 0xc0, 0x78, 0x1b, 0x29, 0xa4, 0xfb, 0x37, 0x3d, 0xbf, 0xec, 0xe5, 0x18, 0x1b, - 0xef, 0x2c, 0x5e, 0xcd, 0xe6, 0x56, 0x00, 0xd4, 0x0a, 0xd6, 0x90, 0x40, 0x7d, 0x99, 0x0a, 0x5b, - 0x07, 0x57, 0x47, 0xac, 0x46, 0xc2, 0x32, 0x98, 0x18, 0x68, 0x8b, 0x11, 0xe1, 0x9e, 0x2a, 0x22, - 0x6a, 0x78, 0x49, 0xec, 0xe3, 0xf1, 0xbd, 0x1f, 0x37, 0x0b, 0x81, 0x89, 0x73, 0x6d, 0x50, 0x4d, - 0x88, 0x4d, 0x37, 0x5b, 0x6c, 0x8b, 0xa7, 0x49, 0xbf, 0x58, 0xe0, 0xfa, 0x09, 0xa0, 0xc9, 0xbd, - 0x06, 0xa6, 0xd2, 0xca, 0x4c, 0x76, 0x2f, 0x57, 0x0b, 0x56, 0x62, 0x38, 0x66, 0x32, 0x4a, 0x86, - 0x2c, 0x31, 0xe3, 0x20, 0x7d, 0xe6, 0xe2, 0xbf, 0x30, 0xa6, 0x2c, 0xee, 0x3b, 0x0b, 0x94, 0x87, - 0x28, 0xac, 0x82, 0x49, 0xcd, 0xd4, 0x6a, 0x6a, 0xc1, 0xe5, 0x20, 0xbd, 0x42, 0x1b, 0x4c, 0xe1, - 0x1e, 0x25, 0x4c, 0xb5, 0x9a, 0x3a, 0x73, 0x39, 0x18, 0xde, 0xa1, 0x0b, 0x2e, 0x61, 0xce, 0x18, - 0xd1, 0x23, 0xda, 0x6a, 0xea, 0x59, 0x2f, 0x07, 0x23, 0x36, 0x38, 0x03, 0xca, 0xb8, 0x8b, 0x18, - 0x23, 0xbd, 0x56, 0xd3, 0x4c, 0xf8, 0x91, 0x61, 0xfe, 0x7d, 0x09, 0x94, 0x74, 0x1f, 0xe1, 0x6f, - 0xcb, 0xb4, 0xfb, 0x84, 0x39, 0x80, 0xcf, 0x72, 0x15, 0x9b, 0x73, 0x94, 0xed, 0xe7, 0xff, 0x89, - 0x2d, 0x79, 0x6d, 0xf7, 0xd1, 0xdb, 0x6f, 0xbf, 0x3e, 0x15, 0x1f, 0xc0, 0xc5, 0xf3, 0x3f, 0xa7, - 0xf1, 0x57, 0xa0, 0xbe, 0x45, 0x48, 0x3d, 0xbb, 0xe3, 0xf0, 0xb3, 0x05, 0xa6, 0x33, 0x23, 0x0c, - 0x17, 0xf3, 0xeb, 0x1b, 0x59, 0x05, 0xfb, 0xfe, 0xc5, 0x03, 0x4d, 0x0d, 0x73, 0xba, 0x86, 0x7b, - 0xb0, 0x76, 0x7e, 0x0d, 0xc9, 0x76, 0xc0, 0xaf, 0x16, 0xb8, 0x72, 0x6c, 0x03, 0xe0, 0xd2, 0x05, - 0x14, 0x1c, 0x5f, 0x2b, 0xfb, 0xe1, 0xdf, 0x86, 0x9b, 0x32, 0x16, 0x75, 0x19, 0x0d, 0xe8, 0xe7, - 0x28, 0xc3, 0xc4, 0xd7, 0x69, 0xbc, 0x1d, 0xeb, 0x7b, 0x07, 0x8e, 0xb5, 0x7f, 0xe0, 0x58, 0x3f, - 0x0f, 0x1c, 0xeb, 0xe3, 0xa1, 0x53, 0xd8, 0x3f, 0x74, 0x0a, 0xdf, 0x0f, 0x9d, 0xc2, 0xeb, 0xa5, - 0x0e, 0x55, 0xdd, 0x70, 0xd3, 0xc3, 0xbc, 0xef, 0x63, 0x2e, 0xfb, 0x5c, 0x66, 0xb8, 0xeb, 0x43, - 0xee, 0x68, 0xc1, 0xdf, 0x19, 0x4d, 0xa0, 0x76, 0x07, 0x44, 0x6e, 0x4e, 0xe8, 0x3f, 0xcf, 0xc2, - 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x18, 0x69, 0x59, 0x43, 0x6b, 0x07, 0x00, 0x00, + 0x14, 0xcf, 0xa6, 0x4d, 0xdb, 0x4c, 0xf5, 0xe0, 0x18, 0x61, 0x5d, 0xcb, 0x5a, 0x56, 0xc1, 0x58, + 0xc8, 0x6e, 0xd3, 0x1e, 0xaa, 0x87, 0xaa, 0xd8, 0x58, 0x1a, 0x50, 0xa9, 0x8b, 0x20, 0x78, 0x09, + 0xd3, 0xc9, 0x34, 0x59, 0x48, 0x66, 0xd2, 0x99, 0xd9, 0xa5, 0xbd, 0x89, 0xe2, 0x55, 0x04, 0xbf, + 0x89, 0x5f, 0xc0, 0x6b, 0xc1, 0x4b, 0xc1, 0x8b, 0x27, 0x91, 0xd6, 0x0f, 0xe1, 0x51, 0x76, 0x76, + 0x36, 0xdd, 0xd0, 0x3f, 0xd9, 0xaa, 0xb7, 0x99, 0xf7, 0x7b, 0xef, 0xf7, 0x7e, 0xef, 0xcd, 0x7b, + 0xbb, 0xc0, 0x0b, 0xa8, 0x24, 0x1c, 0x77, 0x51, 0x40, 0x5b, 0x82, 0xe0, 0x90, 0x07, 0x72, 0xcf, + 0xc3, 0x38, 0xf2, 0x30, 0xa3, 0x22, 0xec, 0x13, 0xee, 0x45, 0x75, 0x6f, 0x27, 0x24, 0x7c, 0xcf, + 0x1d, 0x70, 0x26, 0x19, 0xbc, 0x75, 0x4a, 0x80, 0x8b, 0x71, 0xe4, 0xa6, 0x01, 0x6e, 0x54, 0xb7, + 0x16, 0xcf, 0x62, 0x8d, 0xea, 0x9e, 0xe8, 0x22, 0x4e, 0xda, 0xad, 0xa1, 0xbb, 0xa2, 0xb5, 0x2a, + 0x1d, 0xd6, 0x61, 0xea, 0xe8, 0xc5, 0x27, 0x6d, 0x9d, 0xeb, 0x30, 0xd6, 0xe9, 0x11, 0x0f, 0x0d, + 0x02, 0x0f, 0x51, 0xca, 0x24, 0x92, 0x01, 0xa3, 0x42, 0xa3, 0x4b, 0x79, 0xb4, 0x8f, 0xe6, 0x71, + 0x3e, 0x14, 0xc1, 0x8d, 0xe7, 0x64, 0x57, 0xae, 0x13, 0xd2, 0x08, 0x84, 0xe4, 0xc1, 0x56, 0x18, + 0x53, 0x3e, 0x11, 0x32, 0xe8, 0x23, 0x49, 0xe0, 0x6d, 0x70, 0x19, 0x87, 0x9c, 0x13, 0x2a, 0x37, + 0x48, 0xd0, 0xe9, 0x4a, 0xd3, 0x98, 0x37, 0xaa, 0x13, 0xfe, 0xa8, 0x11, 0xda, 0x00, 0xf4, 0x90, + 0x48, 0x5d, 0x8a, 0xca, 0x25, 0x63, 0x89, 0x71, 0x4a, 0x76, 0x53, 0x7c, 0x22, 0xc1, 0x8f, 0x2d, + 0x70, 0x19, 0x5c, 0x6b, 0x67, 0xb2, 0xb7, 0xb6, 0x39, 0xc2, 0xf1, 0xc1, 0x9c, 0x9c, 0x37, 0xaa, + 0x65, 0xbf, 0x92, 0x05, 0xd7, 0x35, 0x06, 0x2b, 0xa0, 0x24, 0x99, 0x44, 0x3d, 0xb3, 0xa4, 0x9c, + 0x92, 0x4b, 0x9c, 0x4a, 0xb2, 0x4d, 0xce, 0xa2, 0xa0, 0x4d, 0xb8, 0x39, 0xa5, 0xa0, 0x8c, 0x25, + 0xc1, 0xd7, 0x74, 0x13, 0xcc, 0xe9, 0x14, 0x4f, 0x2d, 0xce, 0x5d, 0x70, 0xe7, 0x45, 0xfc, 0xbc, + 0xe7, 0x34, 0xc5, 0x27, 0x3b, 0x21, 0x11, 0xd2, 0x79, 0x63, 0x80, 0xea, 0x78, 0x5f, 0x31, 0x60, + 0x54, 0x10, 0xf8, 0x12, 0x4c, 0xb6, 0x91, 0x44, 0xaa, 0x7f, 0xb3, 0x4b, 0x8f, 0xdc, 0x1c, 0x63, + 0xe3, 0x9e, 0xc7, 0xab, 0xd8, 0x9c, 0x0a, 0x80, 0x4a, 0xc1, 0x26, 0xe2, 0xa8, 0x2f, 0x52, 0x61, + 0x2d, 0x70, 0x75, 0xc4, 0xaa, 0x25, 0x6c, 0x80, 0xa9, 0x81, 0xb2, 0x68, 0x11, 0x0b, 0x67, 0x8a, + 0x88, 0xea, 0x6e, 0xda, 0x90, 0x84, 0xe3, 0xf1, 0xe4, 0xfe, 0x8f, 0x9b, 0x05, 0x5f, 0xc7, 0x3b, + 0x16, 0x30, 0x93, 0x04, 0xba, 0xab, 0x4d, 0xba, 0xcd, 0xd2, 0xe4, 0x5f, 0x0c, 0x70, 0xfd, 0x14, + 0x50, 0x6b, 0xd8, 0x04, 0x33, 0x69, 0x85, 0x5a, 0x85, 0x9b, 0xab, 0x15, 0x6b, 0x31, 0x1c, 0x33, + 0x69, 0x25, 0x43, 0x96, 0x98, 0x71, 0x90, 0x3e, 0x77, 0xf1, 0x5f, 0x18, 0x53, 0x16, 0xe7, 0x9d, + 0x01, 0xca, 0x43, 0x14, 0x9a, 0x60, 0x5a, 0x31, 0x35, 0x1b, 0x4a, 0x70, 0xd9, 0x4f, 0xaf, 0xd0, + 0x02, 0x33, 0xb8, 0x17, 0x10, 0x2a, 0x9b, 0x0d, 0x95, 0xb9, 0xec, 0x0f, 0xef, 0xd0, 0x01, 0x97, + 0x30, 0xa3, 0x94, 0xa8, 0x51, 0x6d, 0x36, 0xd4, 0xcc, 0x97, 0xfd, 0x11, 0x1b, 0x9c, 0x03, 0x65, + 0xdc, 0x45, 0x94, 0x92, 0x5e, 0xb3, 0xa1, 0x27, 0xfd, 0xd8, 0xb0, 0xf4, 0xbe, 0x04, 0x4a, 0xaa, + 0x8f, 0xf0, 0xb7, 0xa1, 0xdb, 0x7d, 0xca, 0x3c, 0xc0, 0xa7, 0xb9, 0x8a, 0xcd, 0x39, 0xd2, 0xd6, + 0xb3, 0xff, 0xc4, 0x96, 0xbc, 0xb6, 0xf3, 0xf0, 0xed, 0xb7, 0x5f, 0x9f, 0x8a, 0xf7, 0xe1, 0xca, + 0xf8, 0xcf, 0x6a, 0xfc, 0x35, 0xa8, 0x6d, 0x13, 0x52, 0xcb, 0xee, 0x3a, 0xfc, 0x6c, 0x80, 0xd9, + 0xcc, 0x28, 0xc3, 0x95, 0xfc, 0xfa, 0x46, 0x56, 0xc2, 0xba, 0x77, 0xf1, 0x40, 0x5d, 0xc3, 0xa2, + 0xaa, 0x61, 0x01, 0x56, 0xc7, 0xd7, 0x90, 0x6c, 0x07, 0xfc, 0x6a, 0x80, 0x2b, 0x27, 0x36, 0x00, + 0xae, 0x5e, 0x40, 0xc1, 0xc9, 0xb5, 0xb2, 0x1e, 0xfc, 0x6d, 0xb8, 0x2e, 0x63, 0x45, 0x95, 0x51, + 0x87, 0x5e, 0x8e, 0x32, 0x74, 0x7c, 0x2d, 0x88, 0xb7, 0xe3, 0xd5, 0xfe, 0xa1, 0x6d, 0x1c, 0x1c, + 0xda, 0xc6, 0xcf, 0x43, 0xdb, 0xf8, 0x78, 0x64, 0x17, 0x0e, 0x8e, 0xec, 0xc2, 0xf7, 0x23, 0xbb, + 0xf0, 0x7a, 0xb5, 0x13, 0xc8, 0x6e, 0xb8, 0xe5, 0x62, 0xd6, 0xf7, 0x30, 0x13, 0x7d, 0x26, 0x32, + 0xdc, 0xb5, 0x21, 0x77, 0xb4, 0xec, 0xed, 0x8e, 0x26, 0x90, 0x7b, 0x03, 0x22, 0xb6, 0xa6, 0xd4, + 0x1f, 0x68, 0xf9, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x91, 0xe8, 0xb3, 0x96, 0x73, 0x07, 0x00, + 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/x/ccv/provider/keeper/genesis_test.go b/x/ccv/provider/keeper/genesis_test.go index 8b101a1ce9..ecde91253c 100644 --- a/x/ccv/provider/keeper/genesis_test.go +++ b/x/ccv/provider/keeper/genesis_test.go @@ -71,7 +71,7 @@ func TestInitAndExportGenesis(t *testing.T) { expClientID, "channel", initHeight, - *ccv.DefaultGenesisState(), + *ccv.DefaultConsumerGenesisState(), []providertypes.VscUnbondingOps{ {VscId: vscID, UnbondingOpIds: ubdIndex}, }, @@ -83,7 +83,7 @@ func TestInitAndExportGenesis(t *testing.T) { expClientID, "", 0, - *ccv.DefaultGenesisState(), + *ccv.DefaultConsumerGenesisState(), nil, []ccv.ValidatorSetChangePacketData{{ValsetUpdateId: vscID}}, nil, @@ -218,7 +218,7 @@ func assertConsumerChainStates(t *testing.T, ctx sdk.Context, pk keeper.Keeper, chainID := cs.ChainId gen, found := pk.GetConsumerGenesis(ctx, chainID) require.True(t, found) - require.Equal(t, *ccv.DefaultGenesisState(), gen) + require.Equal(t, *ccv.DefaultConsumerGenesisState(), gen) clientID, found := pk.GetConsumerClientId(ctx, chainID) require.True(t, found) diff --git a/x/ccv/provider/keeper/keeper.go b/x/ccv/provider/keeper/keeper.go index bebef70c56..e9bb1d1bd0 100644 --- a/x/ccv/provider/keeper/keeper.go +++ b/x/ccv/provider/keeper/keeper.go @@ -251,7 +251,7 @@ func (k Keeper) GetAllChannelToChains(ctx sdk.Context) (channels []types.Channel return channels } -func (k Keeper) SetConsumerGenesis(ctx sdk.Context, chainID string, gen ccv.GenesisState) error { +func (k Keeper) SetConsumerGenesis(ctx sdk.Context, chainID string, gen ccv.ConsumerGenesisState) error { store := ctx.KVStore(k.storeKey) bz, err := gen.Marshal() if err != nil { @@ -262,14 +262,14 @@ func (k Keeper) SetConsumerGenesis(ctx sdk.Context, chainID string, gen ccv.Gene return nil } -func (k Keeper) GetConsumerGenesis(ctx sdk.Context, chainID string) (ccv.GenesisState, bool) { +func (k Keeper) GetConsumerGenesis(ctx sdk.Context, chainID string) (ccv.ConsumerGenesisState, bool) { store := ctx.KVStore(k.storeKey) bz := store.Get(types.ConsumerGenesisKey(chainID)) if bz == nil { - return ccv.GenesisState{}, false + return ccv.ConsumerGenesisState{}, false } - var data ccv.GenesisState + var data ccv.ConsumerGenesisState if err := data.Unmarshal(bz); err != nil { // An error here would indicate something is very wrong, // the ConsumerGenesis is assumed to be correctly serialized in SetConsumerGenesis. diff --git a/x/ccv/provider/keeper/key_assignment_test.go b/x/ccv/provider/keeper/key_assignment_test.go index 8da633a5c9..e9cb1dd646 100644 --- a/x/ccv/provider/keeper/key_assignment_test.go +++ b/x/ccv/provider/keeper/key_assignment_test.go @@ -346,6 +346,7 @@ func checkCorrectPruningProperty(ctx sdk.Context, k providerkeeper.Keeper, chain good := true for _, valByConsAddr := range k.GetAllValidatorsByConsumerAddr(ctx, nil) { + valByConsAddr := valByConsAddr // Fix linter error G601 if _, ok := willBePruned[string(valByConsAddr.ConsumerAddr)]; ok { // Address will be pruned, everything is fine. continue diff --git a/x/ccv/provider/keeper/proposal.go b/x/ccv/provider/keeper/proposal.go index 53c5f4396f..7ea7433770 100644 --- a/x/ccv/provider/keeper/proposal.go +++ b/x/ccv/provider/keeper/proposal.go @@ -238,7 +238,7 @@ func (k Keeper) StopConsumerChain(ctx sdk.Context, chainID string, closeChan boo func (k Keeper) MakeConsumerGenesis( ctx sdk.Context, prop *types.ConsumerAdditionProposal, -) (gen ccv.GenesisState, nextValidatorsHash []byte, err error) { +) (gen ccv.ConsumerGenesisState, nextValidatorsHash []byte, err error) { chainID := prop.ChainId providerUnbondingPeriod := k.stakingKeeper.UnbondingTime(ctx) height := clienttypes.GetSelfHeight(ctx) @@ -316,7 +316,7 @@ func (k Keeper) MakeConsumerGenesis( []string{}, ) - gen = *ccv.NewInitialGenesisState( + gen = *ccv.NewInitialConsumerGenesisState( clientState, consState.(*ibctmtypes.ConsensusState), initialUpdatesWithConsumerKeys, diff --git a/x/ccv/provider/keeper/proposal_test.go b/x/ccv/provider/keeper/proposal_test.go index e6b8573e24..135e16eaae 100644 --- a/x/ccv/provider/keeper/proposal_test.go +++ b/x/ccv/provider/keeper/proposal_test.go @@ -907,7 +907,7 @@ func TestMakeConsumerGenesis(t *testing.T) { ] }` - var expectedGenesis ccvtypes.GenesisState + var expectedGenesis ccvtypes.ConsumerGenesisState err = json.Unmarshal([]byte(jsonString), &expectedGenesis) // ignores tabs, newlines and spaces require.NoError(t, err) diff --git a/x/ccv/provider/types/consumer.go b/x/ccv/provider/types/consumer.go index b9eefc3b45..b2621dd001 100644 --- a/x/ccv/provider/types/consumer.go +++ b/x/ccv/provider/types/consumer.go @@ -9,7 +9,7 @@ func NewConsumerStates( clientID, channelID string, initialHeight uint64, - genesis ccv.GenesisState, + genesis ccv.ConsumerGenesisState, unbondingOpsIndexes []VscUnbondingOps, pendingValsetChanges []ccv.ValidatorSetChangePacketData, slashDowntimeAck []string, diff --git a/x/ccv/provider/types/genesis.pb.go b/x/ccv/provider/types/genesis.pb.go index fa952b9b13..e08947ea5e 100644 --- a/x/ccv/provider/types/genesis.pb.go +++ b/x/ccv/provider/types/genesis.pb.go @@ -189,7 +189,7 @@ type ConsumerState struct { // InitalHeight defines the initial block height for the consumer chain InitialHeight uint64 `protobuf:"varint,4,opt,name=initial_height,json=initialHeight,proto3" json:"initial_height,omitempty"` // ConsumerGenesis defines the initial consumer chain genesis states - ConsumerGenesis types.GenesisState `protobuf:"bytes,5,opt,name=consumer_genesis,json=consumerGenesis,proto3" json:"consumer_genesis"` + ConsumerGenesis types.ConsumerGenesisState `protobuf:"bytes,5,opt,name=consumer_genesis,json=consumerGenesis,proto3" json:"consumer_genesis"` // PendingValsetChanges defines the pending validator set changes for the // consumer chain PendingValsetChanges []types.ValidatorSetChangePacketData `protobuf:"bytes,6,rep,name=pending_valset_changes,json=pendingValsetChanges,proto3" json:"pending_valset_changes"` @@ -260,11 +260,11 @@ func (m *ConsumerState) GetInitialHeight() uint64 { return 0 } -func (m *ConsumerState) GetConsumerGenesis() types.GenesisState { +func (m *ConsumerState) GetConsumerGenesis() types.ConsumerGenesisState { if m != nil { return m.ConsumerGenesis } - return types.GenesisState{} + return types.ConsumerGenesisState{} } func (m *ConsumerState) GetPendingValsetChanges() []types.ValidatorSetChangePacketData { @@ -353,66 +353,65 @@ func init() { } var fileDescriptor_48411d9c7900d48e = []byte{ - // 929 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xcd, 0x6e, 0x1b, 0x37, - 0x17, 0xf5, 0xd8, 0x8e, 0x63, 0xd1, 0x3f, 0x9f, 0x3f, 0xd6, 0x55, 0xc6, 0x76, 0xaa, 0x18, 0x2a, - 0x02, 0x08, 0x68, 0xab, 0x89, 0x9c, 0x2e, 0xd2, 0x9f, 0x2c, 0xe2, 0xa4, 0x68, 0x85, 0xa2, 0xa8, - 0x20, 0x3b, 0x2e, 0x9a, 0x2e, 0x08, 0x8a, 0x24, 0x24, 0xc6, 0x33, 0xe4, 0x80, 0xe4, 0x8c, 0x2d, - 0x14, 0x05, 0x5a, 0xb4, 0x0f, 0xd0, 0xc7, 0xca, 0xd2, 0xcb, 0xae, 0x82, 0xc2, 0x7e, 0x83, 0xae, - 0xba, 0x2c, 0x86, 0xc3, 0x99, 0x8c, 0x5c, 0x39, 0x90, 0xba, 0xb2, 0xc5, 0xc3, 0x7b, 0xce, 0xb9, - 0xbc, 0xe4, 0xbd, 0x03, 0x3a, 0x5c, 0x18, 0xa6, 0xc8, 0x08, 0x73, 0x81, 0x34, 0x23, 0x89, 0xe2, - 0x66, 0x1c, 0x10, 0x92, 0x06, 0xb1, 0x92, 0x29, 0xa7, 0x4c, 0x05, 0x69, 0x27, 0x18, 0x32, 0xc1, - 0x34, 0xd7, 0xed, 0x58, 0x49, 0x23, 0xe1, 0xfb, 0x53, 0x42, 0xda, 0x84, 0xa4, 0xed, 0x22, 0xa4, - 0x9d, 0x76, 0x76, 0xb7, 0x87, 0x72, 0x28, 0xed, 0xfe, 0x20, 0xfb, 0x2f, 0x0f, 0xdd, 0x7d, 0x70, - 0x93, 0x5a, 0xda, 0x09, 0xf4, 0x08, 0x2b, 0x46, 0x11, 0x91, 0x42, 0x27, 0x11, 0x53, 0x2e, 0xe2, - 0xfe, 0x5b, 0x22, 0xce, 0xb8, 0x62, 0x6e, 0xdb, 0xc1, 0x2c, 0x69, 0x94, 0xfe, 0xf2, 0x98, 0xbb, - 0x86, 0x09, 0xca, 0x54, 0xc4, 0x85, 0x09, 0x88, 0x1a, 0xc7, 0x46, 0x06, 0xa7, 0x6c, 0xec, 0xb2, - 0x6c, 0x5e, 0xac, 0x81, 0xf5, 0x2f, 0xf3, 0xbc, 0x8f, 0x0c, 0x36, 0x0c, 0xb6, 0xc0, 0x56, 0x8a, - 0x43, 0xcd, 0x0c, 0x4a, 0x62, 0x8a, 0x0d, 0x43, 0x9c, 0xfa, 0xde, 0xbe, 0xd7, 0x5a, 0xee, 0x6f, - 0xe6, 0xeb, 0xcf, 0xed, 0x72, 0x97, 0xc2, 0x1f, 0xc1, 0xff, 0x8a, 0x2c, 0x90, 0xce, 0x62, 0xb5, - 0xbf, 0xb8, 0xbf, 0xd4, 0x5a, 0x3b, 0x38, 0x68, 0xcf, 0x70, 0x74, 0xed, 0xa7, 0x2e, 0xd6, 0xca, - 0x1e, 0x36, 0x5e, 0xbd, 0xbe, 0xb7, 0xf0, 0xd7, 0xeb, 0x7b, 0xf5, 0x31, 0x8e, 0xc2, 0x4f, 0x9b, - 0xd7, 0x88, 0x9b, 0xfd, 0x4d, 0x52, 0xdd, 0xae, 0xe1, 0x0f, 0x60, 0x23, 0x11, 0x03, 0x29, 0x28, - 0x17, 0x43, 0x24, 0x63, 0xed, 0x2f, 0x59, 0xe9, 0x07, 0x33, 0x49, 0x3f, 0x2f, 0x22, 0xbf, 0x8d, - 0x0f, 0x97, 0x33, 0xe1, 0xfe, 0x7a, 0xf2, 0x66, 0x49, 0xc3, 0x97, 0x60, 0x3b, 0xc2, 0x26, 0x51, - 0x0c, 0x4d, 0x6a, 0x2c, 0xef, 0x7b, 0xad, 0xb5, 0x83, 0x47, 0x33, 0x69, 0x7c, 0x63, 0x09, 0x68, - 0x45, 0x4a, 0xf7, 0x61, 0xce, 0x5a, 0x5d, 0x83, 0x3f, 0x81, 0xdd, 0xeb, 0xe7, 0x8d, 0x8c, 0x44, - 0x23, 0xc6, 0x87, 0x23, 0xe3, 0xdf, 0xb2, 0x59, 0x7d, 0x36, 0x93, 0xe2, 0xc9, 0x44, 0x79, 0x8e, - 0xe5, 0x57, 0x96, 0xc2, 0x25, 0x58, 0x4f, 0xa7, 0xa2, 0xf0, 0x57, 0x0f, 0xec, 0x95, 0x87, 0x8d, - 0x29, 0xe5, 0x86, 0x4b, 0x81, 0x62, 0x25, 0x63, 0xa9, 0x71, 0xa8, 0xfd, 0x15, 0x6b, 0xe0, 0xf1, - 0x5c, 0x15, 0x7d, 0xe2, 0x68, 0x7a, 0x8e, 0xc5, 0x59, 0xd8, 0x21, 0x37, 0xe0, 0x1a, 0xfe, 0xec, - 0x81, 0xdd, 0xd2, 0x85, 0x62, 0x91, 0x4c, 0x71, 0x58, 0x31, 0x71, 0xdb, 0x9a, 0xf8, 0x7c, 0x2e, - 0x13, 0xfd, 0x9c, 0xe5, 0x9a, 0x07, 0x9f, 0x4c, 0x87, 0x35, 0xec, 0x82, 0x95, 0x18, 0x2b, 0x1c, - 0x69, 0x7f, 0xd5, 0x56, 0xf9, 0x83, 0x99, 0xd4, 0x7a, 0x36, 0xc4, 0x91, 0x3b, 0x02, 0x9b, 0x4d, - 0x8a, 0x43, 0x4e, 0xb1, 0x91, 0xaa, 0x7c, 0xe9, 0x28, 0x4e, 0x06, 0xd9, 0xc3, 0xf3, 0x6b, 0x73, - 0x64, 0x73, 0x52, 0xd0, 0x14, 0x69, 0xf5, 0x92, 0xc1, 0xd7, 0x6c, 0x5c, 0x64, 0x93, 0x4e, 0x81, - 0x33, 0x0d, 0xf8, 0x8b, 0x07, 0xf6, 0x4a, 0x50, 0xa3, 0xc1, 0x18, 0x55, 0x8b, 0xac, 0x7c, 0xf0, - 0x5f, 0x3c, 0x1c, 0x8e, 0x2b, 0x15, 0x56, 0xff, 0xf2, 0xa0, 0x27, 0x71, 0x98, 0x82, 0x3b, 0x13, - 0xa2, 0x3a, 0xbb, 0xd7, 0xb1, 0x4a, 0x04, 0xf3, 0xd7, 0xac, 0xfc, 0x27, 0xf3, 0xde, 0x2a, 0xa5, - 0x8f, 0x65, 0x2f, 0x23, 0x70, 0xda, 0xdb, 0x64, 0x0a, 0x06, 0xcf, 0xc0, 0x1d, 0x2e, 0xb8, 0x41, - 0x86, 0x47, 0x4c, 0x26, 0xf9, 0x5f, 0x6d, 0x70, 0x14, 0x6b, 0x7f, 0x7d, 0x0e, 0xdd, 0xae, 0xe0, - 0xe6, 0x38, 0xa7, 0x38, 0x2e, 0x18, 0x9c, 0xee, 0xbb, 0x7c, 0x0a, 0xa6, 0xe1, 0x6f, 0x1e, 0xb8, - 0xcb, 0xce, 0x63, 0xa9, 0x0c, 0xa3, 0x28, 0xd5, 0x04, 0x69, 0x26, 0x68, 0x55, 0x7e, 0x63, 0x8e, - 0xc7, 0xf4, 0x85, 0x23, 0x3a, 0xd1, 0xe4, 0x88, 0x09, 0x7a, 0xdd, 0xc2, 0x0e, 0xbb, 0x01, 0xd7, - 0xcd, 0xbf, 0x97, 0xc0, 0xc6, 0x44, 0x73, 0x85, 0x3b, 0x60, 0x35, 0x57, 0x73, 0xbd, 0xbc, 0xd6, - 0xbf, 0x6d, 0x7f, 0x77, 0x29, 0x7c, 0x0f, 0x00, 0x32, 0xc2, 0x42, 0xb0, 0x30, 0x03, 0x17, 0x2d, - 0x58, 0x73, 0x2b, 0x5d, 0x0a, 0xf7, 0x40, 0x8d, 0x84, 0x9c, 0x09, 0x93, 0xa1, 0x4b, 0x16, 0x5d, - 0xcd, 0x17, 0xba, 0x14, 0xde, 0x07, 0x9b, 0xd9, 0x41, 0x70, 0x1c, 0x16, 0xed, 0x6a, 0xd9, 0x0e, - 0x8a, 0x0d, 0xb7, 0xea, 0x5a, 0xcc, 0xf7, 0x60, 0xab, 0xbc, 0x07, 0x6e, 0xc4, 0xfa, 0xb7, 0xec, - 0x1b, 0x6b, 0xdd, 0x78, 0x12, 0x69, 0xa7, 0x5d, 0x9d, 0x4a, 0x2e, 0xe9, 0x72, 0xde, 0x38, 0x0c, - 0x1a, 0x50, 0x8f, 0x59, 0xde, 0x9f, 0x5d, 0x13, 0xcd, 0xac, 0x0f, 0x59, 0xd1, 0xb7, 0x1e, 0xbd, - 0x4d, 0xa0, 0xbc, 0xd7, 0x47, 0xcc, 0x3c, 0xb5, 0x61, 0x3d, 0x4c, 0x4e, 0x99, 0x79, 0x86, 0x0d, - 0x2e, 0x2e, 0x98, 0x63, 0xcf, 0x5b, 0x6b, 0xbe, 0x49, 0xc3, 0x0f, 0x01, 0xd4, 0x21, 0xd6, 0x23, - 0x44, 0xe5, 0x99, 0xc8, 0xca, 0x8b, 0x30, 0x39, 0xb5, 0x4d, 0xaa, 0xd6, 0xdf, 0xb2, 0xc8, 0x33, - 0x07, 0x3c, 0x21, 0xa7, 0xf0, 0x25, 0x78, 0x67, 0x62, 0x8a, 0x20, 0x2e, 0x28, 0x3b, 0xf7, 0x57, - 0xad, 0xc1, 0x8f, 0x67, 0x7b, 0x81, 0x9a, 0x54, 0x67, 0x86, 0x33, 0xf7, 0xff, 0xea, 0xcc, 0xea, - 0x66, 0xa4, 0xcd, 0x17, 0xa0, 0x3e, 0x7d, 0x0a, 0xcc, 0x31, 0xd6, 0xeb, 0x60, 0xc5, 0x55, 0x73, - 0xd1, 0xe2, 0xee, 0xd7, 0xe1, 0x77, 0xaf, 0x2e, 0x1b, 0xde, 0xc5, 0x65, 0xc3, 0xfb, 0xf3, 0xb2, - 0xe1, 0xfd, 0x7e, 0xd5, 0x58, 0xb8, 0xb8, 0x6a, 0x2c, 0xfc, 0x71, 0xd5, 0x58, 0x78, 0xf1, 0x78, - 0xc8, 0xcd, 0x28, 0x19, 0xb4, 0x89, 0x8c, 0x02, 0x22, 0x75, 0x24, 0x75, 0xf0, 0x26, 0xab, 0x8f, - 0xca, 0xef, 0x94, 0xf4, 0x61, 0x70, 0x3e, 0xf9, 0xb1, 0x62, 0xc6, 0x31, 0xd3, 0x83, 0x15, 0xfb, - 0x25, 0xf2, 0xf0, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x76, 0xce, 0xb9, 0x61, 0xa4, 0x09, 0x00, - 0x00, + // 925 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xdd, 0x6e, 0xdb, 0x36, + 0x14, 0x8e, 0x12, 0x37, 0x8d, 0x99, 0x9f, 0x65, 0x5c, 0xe6, 0x2a, 0x49, 0xe7, 0x06, 0x1e, 0x0a, + 0x04, 0xd8, 0x66, 0x35, 0xe9, 0x2e, 0xba, 0x9f, 0x5e, 0x34, 0xed, 0xb0, 0x19, 0xc3, 0x30, 0xc3, + 0x49, 0x33, 0xa0, 0xbb, 0x20, 0x68, 0x92, 0xb0, 0xd9, 0x48, 0xa4, 0x40, 0x52, 0x4a, 0x8c, 0x61, + 0x40, 0x87, 0xed, 0x01, 0xf6, 0x58, 0xbd, 0xcc, 0xe5, 0xae, 0x8a, 0x21, 0x79, 0x83, 0x3d, 0xc1, + 0x20, 0x8a, 0x52, 0xe5, 0xcc, 0x2e, 0xec, 0x5d, 0xd9, 0x3a, 0x1f, 0xcf, 0xf7, 0x9d, 0xc3, 0x43, + 0x9e, 0x43, 0x70, 0xc0, 0x85, 0x61, 0x8a, 0x0c, 0x31, 0x17, 0x48, 0x33, 0x92, 0x28, 0x6e, 0x46, + 0x01, 0x21, 0x69, 0x10, 0x2b, 0x99, 0x72, 0xca, 0x54, 0x90, 0x1e, 0x04, 0x03, 0x26, 0x98, 0xe6, + 0xba, 0x1d, 0x2b, 0x69, 0x24, 0xfc, 0x78, 0x82, 0x4b, 0x9b, 0x90, 0xb4, 0x5d, 0xb8, 0xb4, 0xd3, + 0x83, 0x9d, 0xad, 0x81, 0x1c, 0x48, 0xbb, 0x3e, 0xc8, 0xfe, 0xe5, 0xae, 0x3b, 0x0f, 0xa6, 0xa9, + 0xa5, 0x07, 0x81, 0x1e, 0x62, 0xc5, 0x28, 0x22, 0x52, 0xe8, 0x24, 0x62, 0xca, 0x79, 0xdc, 0x7f, + 0x87, 0xc7, 0x39, 0x57, 0xcc, 0x2d, 0x3b, 0x9c, 0x25, 0x8d, 0x32, 0xbe, 0xdc, 0xe7, 0xae, 0x61, + 0x82, 0x32, 0x15, 0x71, 0x61, 0x02, 0xa2, 0x46, 0xb1, 0x91, 0xc1, 0x19, 0x1b, 0xb9, 0x2c, 0x5b, + 0x97, 0xab, 0x60, 0xed, 0xdb, 0x3c, 0xef, 0x63, 0x83, 0x0d, 0x83, 0xfb, 0x60, 0x33, 0xc5, 0xa1, + 0x66, 0x06, 0x25, 0x31, 0xc5, 0x86, 0x21, 0x4e, 0x7d, 0x6f, 0xcf, 0xdb, 0xaf, 0xf5, 0x36, 0x72, + 0xfb, 0x73, 0x6b, 0xee, 0x50, 0xf8, 0x0b, 0x78, 0xaf, 0xc8, 0x02, 0xe9, 0xcc, 0x57, 0xfb, 0x8b, + 0x7b, 0x4b, 0xfb, 0xab, 0x87, 0x87, 0xed, 0x19, 0xb6, 0xae, 0xfd, 0xd4, 0xf9, 0x5a, 0xd9, 0xa3, + 0xe6, 0xeb, 0x37, 0xf7, 0x16, 0xfe, 0x79, 0x73, 0xaf, 0x31, 0xc2, 0x51, 0xf8, 0x65, 0xeb, 0x06, + 0x71, 0xab, 0xb7, 0x41, 0xaa, 0xcb, 0x35, 0xfc, 0x19, 0xac, 0x27, 0xa2, 0x2f, 0x05, 0xe5, 0x62, + 0x80, 0x64, 0xac, 0xfd, 0x25, 0x2b, 0xfd, 0x60, 0x26, 0xe9, 0xe7, 0x85, 0xe7, 0x8f, 0xf1, 0x51, + 0x2d, 0x13, 0xee, 0xad, 0x25, 0x6f, 0x4d, 0x1a, 0xbe, 0x04, 0x5b, 0x11, 0x36, 0x89, 0x62, 0x68, + 0x5c, 0xa3, 0xb6, 0xe7, 0xed, 0xaf, 0x1e, 0x3e, 0x9a, 0x49, 0xe3, 0x07, 0x4b, 0x40, 0x2b, 0x52, + 0xba, 0x07, 0x73, 0xd6, 0xaa, 0x0d, 0xfe, 0x0a, 0x76, 0x6e, 0xee, 0x37, 0x32, 0x12, 0x0d, 0x19, + 0x1f, 0x0c, 0x8d, 0x7f, 0xcb, 0x66, 0xf5, 0xd5, 0x4c, 0x8a, 0xa7, 0x63, 0xe5, 0x39, 0x91, 0xdf, + 0x59, 0x0a, 0x97, 0x60, 0x23, 0x9d, 0x88, 0xc2, 0xdf, 0x3d, 0xb0, 0x5b, 0x6e, 0x36, 0xa6, 0x94, + 0x1b, 0x2e, 0x05, 0x8a, 0x95, 0x8c, 0xa5, 0xc6, 0xa1, 0xf6, 0x97, 0x6d, 0x00, 0x8f, 0xe7, 0xaa, + 0xe8, 0x13, 0x47, 0xd3, 0x75, 0x2c, 0x2e, 0x84, 0x6d, 0x32, 0x05, 0xd7, 0xf0, 0x95, 0x07, 0x76, + 0xca, 0x28, 0x14, 0x8b, 0x64, 0x8a, 0xc3, 0x4a, 0x10, 0xb7, 0x6d, 0x10, 0x5f, 0xcf, 0x15, 0x44, + 0x2f, 0x67, 0xb9, 0x11, 0x83, 0x4f, 0x26, 0xc3, 0x1a, 0x76, 0xc0, 0x72, 0x8c, 0x15, 0x8e, 0xb4, + 0xbf, 0x62, 0xab, 0xfc, 0xc9, 0x4c, 0x6a, 0x5d, 0xeb, 0xe2, 0xc8, 0x1d, 0x81, 0xcd, 0x26, 0xc5, + 0x21, 0xa7, 0xd8, 0x48, 0x55, 0xde, 0x74, 0x14, 0x27, 0xfd, 0xec, 0xe2, 0xf9, 0xf5, 0x39, 0xb2, + 0x39, 0x2d, 0x68, 0x8a, 0xb4, 0xba, 0x49, 0xff, 0x7b, 0x36, 0x2a, 0xb2, 0x49, 0x27, 0xc0, 0x99, + 0x06, 0xfc, 0xcd, 0x03, 0xbb, 0x25, 0xa8, 0x51, 0x7f, 0x84, 0xaa, 0x45, 0x56, 0x3e, 0xf8, 0x3f, + 0x31, 0x1c, 0x8d, 0x2a, 0x15, 0x56, 0xff, 0x89, 0x41, 0x8f, 0xe3, 0x30, 0x05, 0x77, 0xc6, 0x44, + 0x75, 0x76, 0xae, 0x63, 0x95, 0x08, 0xe6, 0xaf, 0x5a, 0xf9, 0x2f, 0xe6, 0x3d, 0x55, 0x4a, 0x9f, + 0xc8, 0x6e, 0x46, 0xe0, 0xb4, 0xb7, 0xc8, 0x04, 0x0c, 0x9e, 0x83, 0x3b, 0x5c, 0x70, 0x83, 0x0c, + 0x8f, 0x98, 0x4c, 0xf2, 0x5f, 0x6d, 0x70, 0x14, 0x6b, 0x7f, 0x6d, 0x0e, 0xdd, 0x8e, 0xe0, 0xe6, + 0x24, 0xa7, 0x38, 0x29, 0x18, 0x9c, 0xee, 0x87, 0x7c, 0x02, 0xa6, 0xe1, 0x1f, 0x1e, 0xb8, 0xcb, + 0x2e, 0x62, 0xa9, 0x0c, 0xa3, 0x28, 0xd5, 0x04, 0x69, 0x26, 0x68, 0x55, 0x7e, 0x7d, 0x8e, 0xcb, + 0xf4, 0x8d, 0x23, 0x3a, 0xd5, 0xe4, 0x98, 0x09, 0x7a, 0x33, 0x84, 0x6d, 0x36, 0x05, 0xd7, 0xad, + 0x57, 0x35, 0xb0, 0x3e, 0xd6, 0x5c, 0xe1, 0x36, 0x58, 0xc9, 0xd5, 0x5c, 0x2f, 0xaf, 0xf7, 0x6e, + 0xdb, 0xef, 0x0e, 0x85, 0x1f, 0x01, 0x40, 0x86, 0x58, 0x08, 0x16, 0x66, 0xe0, 0xa2, 0x05, 0xeb, + 0xce, 0xd2, 0xa1, 0x70, 0x17, 0xd4, 0x49, 0xc8, 0x99, 0x30, 0x19, 0xba, 0x64, 0xd1, 0x95, 0xdc, + 0xd0, 0xa1, 0xf0, 0x3e, 0xd8, 0xc8, 0x36, 0x82, 0xe3, 0xb0, 0x68, 0x57, 0x35, 0x3b, 0x28, 0xd6, + 0x9d, 0xd5, 0xb5, 0x18, 0x0c, 0x36, 0xcb, 0x73, 0xe0, 0x46, 0xac, 0x7f, 0xcb, 0xde, 0xb1, 0xe9, + 0xdd, 0xba, 0x52, 0xf7, 0xea, 0x74, 0x72, 0xc9, 0x97, 0x73, 0xc7, 0x61, 0xd0, 0x80, 0x46, 0xcc, + 0xf2, 0x3e, 0xed, 0x9a, 0x69, 0x96, 0xc2, 0x80, 0x15, 0xfd, 0xeb, 0xd1, 0xbb, 0x84, 0xca, 0xf3, + 0x7d, 0xcc, 0xcc, 0x53, 0xeb, 0xd6, 0xc5, 0xe4, 0x8c, 0x99, 0x67, 0xd8, 0xe0, 0xe2, 0xa0, 0x39, + 0xf6, 0xbc, 0xc5, 0xe6, 0x8b, 0x34, 0xfc, 0x14, 0x40, 0x1d, 0x62, 0x3d, 0x44, 0x54, 0x9e, 0x8b, + 0xac, 0xcc, 0x08, 0x93, 0x33, 0xdb, 0xac, 0xea, 0xbd, 0x4d, 0x8b, 0x3c, 0x73, 0xc0, 0x13, 0x72, + 0x06, 0x5f, 0x82, 0x0f, 0xc6, 0xa6, 0x09, 0xe2, 0x82, 0xb2, 0x0b, 0x7f, 0xc5, 0x06, 0xf8, 0xf9, + 0x6c, 0x37, 0x51, 0x93, 0xea, 0xec, 0x70, 0xc1, 0xbd, 0x5f, 0x9d, 0x5d, 0x9d, 0x8c, 0xb4, 0xf5, + 0x02, 0x34, 0x26, 0x4f, 0x83, 0x39, 0xc6, 0x7b, 0x03, 0x2c, 0xbb, 0xaa, 0x2e, 0x5a, 0xdc, 0x7d, + 0x1d, 0xfd, 0xf4, 0xfa, 0xaa, 0xe9, 0x5d, 0x5e, 0x35, 0xbd, 0xbf, 0xaf, 0x9a, 0xde, 0x9f, 0xd7, + 0xcd, 0x85, 0xcb, 0xeb, 0xe6, 0xc2, 0x5f, 0xd7, 0xcd, 0x85, 0x17, 0x8f, 0x07, 0xdc, 0x0c, 0x93, + 0x7e, 0x9b, 0xc8, 0x28, 0x20, 0x52, 0x47, 0x52, 0x07, 0x6f, 0xb3, 0xfa, 0xac, 0x7c, 0xaf, 0xa4, + 0x0f, 0x83, 0x8b, 0xf1, 0x47, 0x8b, 0x19, 0xc5, 0x4c, 0xf7, 0x97, 0xed, 0x8b, 0xe4, 0xe1, 0xbf, + 0x01, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x6e, 0x42, 0x2b, 0xac, 0x09, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { diff --git a/x/ccv/provider/types/genesis_test.go b/x/ccv/provider/types/genesis_test.go index aba1a72e0e..7878afb0a4 100644 --- a/x/ccv/provider/types/genesis_test.go +++ b/x/ccv/provider/types/genesis_test.go @@ -452,7 +452,7 @@ func TestValidateGenesisState(t *testing.T) { nil, []types.ConsumerState{{ ChainId: "chainid", ChannelId: "channel-0", ClientId: "client-id", - ConsumerGenesis: ccv.GenesisState{}, + ConsumerGenesis: ccv.ConsumerGenesisState{}, }}, nil, nil, @@ -757,7 +757,7 @@ func TestValidateGenesisState(t *testing.T) { } } -func getInitialConsumerGenesis(t *testing.T, chainID string) ccv.GenesisState { +func getInitialConsumerGenesis(t *testing.T, chainID string) ccv.ConsumerGenesisState { t.Helper() // generate validator public key cId := crypto.NewCryptoIdentityFromIntSeed(239668) @@ -782,5 +782,5 @@ func getInitialConsumerGenesis(t *testing.T, chainID string) ccv.GenesisState { params := ccv.DefaultParams() params.Enabled = true - return *ccv.NewInitialGenesisState(cs, consensusState, valUpdates, params) + return *ccv.NewInitialConsumerGenesisState(cs, consensusState, valUpdates, params) } diff --git a/x/ccv/provider/types/query.pb.go b/x/ccv/provider/types/query.pb.go index 9fc9178e09..eac75ded70 100644 --- a/x/ccv/provider/types/query.pb.go +++ b/x/ccv/provider/types/query.pb.go @@ -79,7 +79,7 @@ func (m *QueryConsumerGenesisRequest) GetChainId() string { } type QueryConsumerGenesisResponse struct { - GenesisState types.GenesisState `protobuf:"bytes,1,opt,name=genesis_state,json=genesisState,proto3" json:"genesis_state"` + GenesisState types.ConsumerGenesisState `protobuf:"bytes,1,opt,name=genesis_state,json=genesisState,proto3" json:"genesis_state"` } func (m *QueryConsumerGenesisResponse) Reset() { *m = QueryConsumerGenesisResponse{} } @@ -115,11 +115,11 @@ func (m *QueryConsumerGenesisResponse) XXX_DiscardUnknown() { var xxx_messageInfo_QueryConsumerGenesisResponse proto.InternalMessageInfo -func (m *QueryConsumerGenesisResponse) GetGenesisState() types.GenesisState { +func (m *QueryConsumerGenesisResponse) GetGenesisState() types.ConsumerGenesisState { if m != nil { return m.GenesisState } - return types.GenesisState{} + return types.ConsumerGenesisState{} } type QueryConsumerChainsRequest struct { @@ -1068,90 +1068,90 @@ func init() { } var fileDescriptor_422512d7b7586cd7 = []byte{ - // 1323 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x57, 0xcf, 0x6f, 0x1b, 0xc5, - 0x1f, 0xf5, 0x3a, 0x69, 0x9a, 0x4c, 0xfa, 0xfd, 0xb6, 0x4c, 0x4b, 0x71, 0xb7, 0x95, 0x5d, 0xb6, - 0x02, 0xd2, 0x16, 0x76, 0x1b, 0x57, 0x48, 0x6d, 0x21, 0x75, 0xed, 0x24, 0xa4, 0x51, 0x1b, 0x35, - 0xac, 0xab, 0x56, 0x02, 0xd4, 0x65, 0xb2, 0x3b, 0xd8, 0x2b, 0xd6, 0x3b, 0xdb, 0x99, 0xb1, 0xd3, - 0x80, 0x38, 0x00, 0x12, 0xf4, 0x58, 0x09, 0x71, 0xe3, 0xd0, 0x13, 0xff, 0x05, 0xf7, 0xde, 0xa8, - 0xe8, 0xa5, 0xa7, 0x82, 0x12, 0x0e, 0x1c, 0x11, 0x77, 0x24, 0xb4, 0xb3, 0xb3, 0xfe, 0x11, 0x6f, - 0xec, 0xb5, 0x9b, 0x9b, 0x3d, 0x3b, 0x9f, 0xf7, 0x79, 0xef, 0xe9, 0x33, 0xb3, 0x6f, 0x81, 0xe1, - 0xfa, 0x1c, 0x53, 0xbb, 0x8e, 0x5c, 0xdf, 0x62, 0xd8, 0x6e, 0x52, 0x97, 0x6f, 0x19, 0xb6, 0xdd, - 0x32, 0x02, 0x4a, 0x5a, 0xae, 0x83, 0xa9, 0xd1, 0x9a, 0x37, 0xee, 0x37, 0x31, 0xdd, 0xd2, 0x03, - 0x4a, 0x38, 0x81, 0x67, 0x12, 0x0a, 0x74, 0xdb, 0x6e, 0xe9, 0x71, 0x81, 0xde, 0x9a, 0x57, 0x4f, - 0xd5, 0x08, 0xa9, 0x79, 0xd8, 0x40, 0x81, 0x6b, 0x20, 0xdf, 0x27, 0x1c, 0x71, 0x97, 0xf8, 0x2c, - 0x82, 0x50, 0x8f, 0xd5, 0x48, 0x8d, 0x88, 0x9f, 0x46, 0xf8, 0x4b, 0xae, 0x16, 0x64, 0x8d, 0xf8, - 0xb7, 0xd1, 0xfc, 0xcc, 0xe0, 0x6e, 0x03, 0x33, 0x8e, 0x1a, 0x81, 0xdc, 0x50, 0x4c, 0x43, 0xb5, - 0xcd, 0x22, 0xaa, 0xb9, 0xb0, 0x57, 0x4d, 0x6b, 0xde, 0x60, 0x75, 0x44, 0xb1, 0x63, 0xd9, 0xc4, - 0x67, 0xcd, 0x46, 0xbb, 0xe2, 0x8d, 0x01, 0x15, 0x9b, 0x2e, 0xc5, 0xd1, 0x36, 0xed, 0x12, 0x38, - 0xf9, 0x61, 0xe8, 0xca, 0xa2, 0xac, 0x5e, 0xc1, 0x3e, 0x66, 0x2e, 0x33, 0xf1, 0xfd, 0x26, 0x66, - 0x1c, 0x9e, 0x00, 0xd3, 0x11, 0x84, 0xeb, 0xe4, 0x94, 0xd3, 0xca, 0xdc, 0x8c, 0x79, 0x50, 0xfc, - 0x5f, 0x75, 0x34, 0x06, 0x4e, 0x25, 0x57, 0xb2, 0x80, 0xf8, 0x0c, 0xc3, 0x2a, 0xf8, 0x5f, 0x2d, - 0x5a, 0xb2, 0x18, 0x47, 0x1c, 0x8b, 0xfa, 0xd9, 0xe2, 0x9c, 0xbe, 0x97, 0xf1, 0xad, 0x79, 0x5d, - 0x62, 0x54, 0xc3, 0xfd, 0x95, 0xc9, 0x27, 0x2f, 0x0a, 0x19, 0xf3, 0x50, 0xad, 0x6b, 0x4d, 0x3b, - 0x05, 0xd4, 0x9e, 0xa6, 0x8b, 0x21, 0x4c, 0xcc, 0x56, 0x43, 0xbb, 0xc4, 0xc4, 0x4f, 0x25, 0xa3, - 0x0a, 0x98, 0x12, 0x6d, 0x59, 0x4e, 0x39, 0x3d, 0x31, 0x37, 0x5b, 0x3c, 0xa7, 0xa7, 0x98, 0x01, - 0x5d, 0x80, 0x98, 0xb2, 0x52, 0x3b, 0x0b, 0xde, 0xea, 0x6f, 0x51, 0xe5, 0x88, 0xf2, 0x75, 0x4a, - 0x02, 0xc2, 0x90, 0xd7, 0x66, 0xf3, 0x50, 0x01, 0x73, 0xc3, 0xf7, 0x4a, 0x6e, 0x9f, 0x80, 0x99, - 0x20, 0x5e, 0x94, 0x4e, 0x5d, 0x4d, 0x47, 0x4f, 0x82, 0x97, 0x1d, 0xc7, 0x0d, 0x87, 0xb3, 0x03, - 0xdd, 0x01, 0xd4, 0xe6, 0xc0, 0x9b, 0x49, 0x4c, 0x48, 0xd0, 0x47, 0xfa, 0x3b, 0x25, 0x59, 0x60, - 0xcf, 0x56, 0xc9, 0xf9, 0xe3, 0x7e, 0xce, 0x0b, 0x23, 0x71, 0x36, 0x71, 0x83, 0xb4, 0x90, 0x97, - 0x48, 0xb9, 0x04, 0x0e, 0x88, 0xd6, 0x03, 0x46, 0x10, 0x9e, 0x04, 0x33, 0xb6, 0xe7, 0x62, 0x9f, - 0x87, 0xcf, 0xb2, 0xe2, 0xd9, 0x74, 0xb4, 0xb0, 0xea, 0x68, 0xdf, 0x2b, 0xe0, 0x75, 0xa1, 0xe4, - 0x0e, 0xf2, 0x5c, 0x07, 0x71, 0x42, 0xbb, 0xac, 0xa2, 0xc3, 0x07, 0x1c, 0x2e, 0x80, 0x23, 0x31, - 0x69, 0x0b, 0x39, 0x0e, 0xc5, 0x8c, 0x45, 0x4d, 0x2a, 0xf0, 0x9f, 0x17, 0x85, 0xff, 0x6f, 0xa1, - 0x86, 0x77, 0x45, 0x93, 0x0f, 0x34, 0xf3, 0x70, 0xbc, 0xb7, 0x1c, 0xad, 0x5c, 0x99, 0x7e, 0xf8, - 0xb8, 0x90, 0xf9, 0xeb, 0x71, 0x21, 0xa3, 0xdd, 0x02, 0xda, 0x20, 0x22, 0xd2, 0xcd, 0xb3, 0xe0, - 0x48, 0x7c, 0x84, 0xdb, 0xed, 0x22, 0x46, 0x87, 0xed, 0xae, 0xfd, 0x61, 0xb3, 0x7e, 0x69, 0xeb, - 0x5d, 0xcd, 0xd3, 0x49, 0xeb, 0xeb, 0x35, 0x40, 0xda, 0xae, 0xfe, 0x83, 0xa4, 0xf5, 0x12, 0xe9, - 0x48, 0xeb, 0x73, 0x52, 0x4a, 0xdb, 0xe5, 0x9a, 0x76, 0x12, 0x9c, 0x10, 0x80, 0xb7, 0xeb, 0x94, - 0x70, 0xee, 0x61, 0x71, 0xec, 0xe3, 0xe1, 0xfc, 0x39, 0x2b, 0x8f, 0xff, 0xae, 0xa7, 0xb2, 0x4d, - 0x01, 0xcc, 0x32, 0x0f, 0xb1, 0xba, 0xd5, 0xc0, 0x1c, 0x53, 0xd1, 0x61, 0xc2, 0x04, 0x62, 0x69, - 0x2d, 0x5c, 0x81, 0x45, 0xf0, 0x6a, 0xd7, 0x06, 0x0b, 0x79, 0x1e, 0xd9, 0x44, 0xbe, 0x8d, 0x85, - 0xf6, 0x09, 0xf3, 0x68, 0x67, 0x6b, 0x39, 0x7e, 0x04, 0xef, 0x81, 0x9c, 0x8f, 0x1f, 0x70, 0x8b, - 0xe2, 0xc0, 0xc3, 0xbe, 0xcb, 0xea, 0x96, 0x8d, 0x7c, 0x27, 0x14, 0x8b, 0x73, 0x13, 0x62, 0xe6, - 0x55, 0x3d, 0xba, 0xf1, 0xf5, 0xf8, 0xc6, 0xd7, 0x6f, 0xc7, 0x37, 0x7e, 0x65, 0x3a, 0xbc, 0xc3, - 0x1e, 0xfd, 0x5e, 0x50, 0xcc, 0xe3, 0x21, 0x8a, 0x19, 0x83, 0x2c, 0xc6, 0x18, 0xb0, 0x0a, 0x0e, - 0x06, 0xc8, 0xfe, 0x1c, 0x73, 0x96, 0x9b, 0x14, 0xb7, 0xd2, 0xe5, 0x54, 0x47, 0x28, 0x76, 0xc0, - 0xa9, 0x86, 0x9c, 0xd7, 0x05, 0x82, 0x19, 0x23, 0x69, 0x4b, 0xf2, 0x10, 0xb7, 0x77, 0xc5, 0x13, - 0x17, 0x6d, 0x5c, 0x42, 0x1c, 0xa5, 0xb8, 0xe1, 0x7f, 0x8b, 0x2f, 0xb0, 0x81, 0x30, 0xd2, 0xfc, - 0x01, 0xd3, 0x06, 0xc1, 0x24, 0x73, 0xbf, 0x88, 0x5c, 0x9e, 0x34, 0xc5, 0x6f, 0xb8, 0x09, 0x8e, - 0x06, 0x6d, 0x90, 0x55, 0x9f, 0xf1, 0xd0, 0x6c, 0x96, 0x9b, 0x10, 0x16, 0x94, 0x46, 0xb3, 0xa0, - 0xc3, 0xe6, 0x2e, 0x45, 0x41, 0x80, 0xa9, 0x7c, 0x75, 0x24, 0x75, 0xd0, 0x7e, 0x51, 0xc0, 0xb1, - 0x24, 0xf3, 0xe0, 0x3d, 0x70, 0xa8, 0xe6, 0x91, 0x0d, 0xe4, 0x59, 0xd8, 0xe7, 0x74, 0x4b, 0x5e, - 0x68, 0xef, 0xa6, 0xa2, 0xb2, 0x22, 0x0a, 0x05, 0xda, 0x72, 0x58, 0x2c, 0x09, 0xcc, 0x46, 0x80, - 0x62, 0x09, 0x2e, 0x83, 0x49, 0x07, 0x71, 0x24, 0x5c, 0x98, 0x2d, 0x9e, 0x1f, 0xf4, 0x1a, 0xec, - 0xa2, 0x15, 0x92, 0x97, 0x68, 0xa2, 0x5c, 0x7b, 0xae, 0x00, 0x75, 0x6f, 0xe5, 0x70, 0x1d, 0x1c, - 0x8a, 0x46, 0x3c, 0xd2, 0x2e, 0x55, 0x8c, 0xd2, 0xed, 0x7a, 0xc6, 0x8c, 0x8e, 0x91, 0xf4, 0xe5, - 0x53, 0x00, 0x5b, 0xcc, 0xb6, 0x1a, 0x88, 0x37, 0xc3, 0x98, 0x21, 0x71, 0x23, 0x15, 0x17, 0x06, - 0xe1, 0xde, 0xa9, 0x2e, 0xae, 0x45, 0x45, 0x3d, 0xe0, 0x47, 0x5a, 0xcc, 0xee, 0x59, 0xaf, 0x4c, - 0x45, 0xce, 0x68, 0x6f, 0x83, 0x73, 0x62, 0xdc, 0x4c, 0x5c, 0x73, 0x19, 0xc7, 0xb4, 0x33, 0x6f, - 0x26, 0xde, 0x44, 0xd4, 0x59, 0xc2, 0x3e, 0x69, 0xb4, 0xdf, 0x54, 0xcb, 0xe0, 0x7c, 0xaa, 0xdd, - 0x72, 0x3e, 0x8f, 0x83, 0x29, 0x47, 0xac, 0x88, 0x97, 0xff, 0x8c, 0x29, 0xff, 0x15, 0x7f, 0x7a, - 0x05, 0x1c, 0x10, 0x38, 0x70, 0x5b, 0x01, 0xc7, 0x92, 0x12, 0x0d, 0xbc, 0x96, 0x6a, 0x06, 0x06, - 0xc4, 0x28, 0xb5, 0xfc, 0x12, 0x08, 0x11, 0x7f, 0x6d, 0xf9, 0x9b, 0x67, 0x7f, 0xfe, 0x90, 0x2d, - 0xc1, 0x85, 0xe1, 0x49, 0xb7, 0x7d, 0xb5, 0xcb, 0xe8, 0x64, 0x7c, 0x19, 0x9f, 0xcc, 0xaf, 0xe0, - 0x33, 0x05, 0x1c, 0x4d, 0xc8, 0x48, 0xb0, 0x34, 0x3a, 0xc3, 0x9e, 0xec, 0xa5, 0x5e, 0x1b, 0x1f, - 0x40, 0x2a, 0xbc, 0x2c, 0x14, 0x5e, 0x84, 0xf3, 0x23, 0x28, 0x8c, 0x52, 0x19, 0xfc, 0x3a, 0x0b, - 0x72, 0x7b, 0x44, 0x2d, 0x06, 0x6f, 0x8e, 0xc9, 0x2c, 0x31, 0xd5, 0xa9, 0x6b, 0xfb, 0x84, 0x26, - 0x45, 0x5f, 0x17, 0xa2, 0x2b, 0xf0, 0xda, 0xa8, 0xa2, 0xc3, 0x50, 0x4d, 0xb9, 0xd5, 0x0e, 0x4c, - 0xf0, 0x5f, 0x05, 0xbc, 0x96, 0x9c, 0xdc, 0x18, 0xbc, 0x31, 0x36, 0xe9, 0xfe, 0x88, 0xa8, 0xde, - 0xdc, 0x1f, 0x30, 0x69, 0xc0, 0x8a, 0x30, 0xa0, 0x0c, 0x4b, 0x63, 0x18, 0x40, 0x82, 0x2e, 0xfd, - 0x7f, 0x2b, 0x32, 0x1c, 0x24, 0xc6, 0x2c, 0xf8, 0x41, 0x7a, 0xd6, 0x83, 0x02, 0xa3, 0xba, 0xf2, - 0xd2, 0x38, 0x52, 0x78, 0x59, 0x08, 0x7f, 0x0f, 0x5e, 0x4e, 0xf1, 0xe9, 0x1a, 0x03, 0x59, 0x3d, - 0xa9, 0x2d, 0x41, 0x72, 0x77, 0xfc, 0x1a, 0x4b, 0x72, 0x42, 0x90, 0x1c, 0x4b, 0x72, 0x52, 0x0e, - 0x1c, 0x4f, 0x72, 0x4f, 0x72, 0x84, 0xbf, 0x2a, 0x00, 0xf6, 0x47, 0x40, 0x78, 0x35, 0x3d, 0xc5, - 0xa4, 0x64, 0xa9, 0x96, 0xc6, 0xae, 0x97, 0xd2, 0x2e, 0x09, 0x69, 0x45, 0x78, 0x61, 0xb8, 0x34, - 0x2e, 0x01, 0xa2, 0xcf, 0x62, 0xf8, 0x6d, 0x16, 0x9c, 0x1e, 0x96, 0xb2, 0x46, 0xb9, 0xc3, 0x86, - 0x67, 0xbe, 0x51, 0xee, 0xb0, 0x14, 0xd1, 0x4f, 0xab, 0x08, 0xed, 0xef, 0xc3, 0x2b, 0xc3, 0xb5, - 0x07, 0xd8, 0x77, 0x5c, 0xbf, 0xd6, 0x99, 0x63, 0x99, 0x58, 0xe1, 0x8f, 0x59, 0x70, 0x26, 0xc5, - 0xeb, 0x1c, 0xde, 0x4a, 0x4f, 0x3d, 0x55, 0x8c, 0x50, 0xd7, 0xf7, 0x0f, 0x50, 0xda, 0x71, 0x43, - 0xd8, 0xb1, 0x0c, 0x17, 0x87, 0xdb, 0x41, 0xdb, 0x88, 0x1d, 0x47, 0xa8, 0xc0, 0xb4, 0xa2, 0x78, - 0x52, 0xb9, 0xfb, 0x64, 0x3b, 0xaf, 0x3c, 0xdd, 0xce, 0x2b, 0x7f, 0x6c, 0xe7, 0x95, 0x47, 0x3b, - 0xf9, 0xcc, 0xd3, 0x9d, 0x7c, 0xe6, 0xf9, 0x4e, 0x3e, 0xf3, 0xd1, 0x42, 0xcd, 0xe5, 0xf5, 0xe6, - 0x86, 0x6e, 0x93, 0x86, 0x61, 0x13, 0xd6, 0x20, 0xac, 0xab, 0xdf, 0x3b, 0xed, 0x7e, 0xad, 0x8b, - 0xc6, 0x83, 0x5d, 0xf3, 0xb7, 0x15, 0x60, 0xb6, 0x31, 0x25, 0xbe, 0x56, 0x2e, 0xfe, 0x17, 0x00, - 0x00, 0xff, 0xff, 0x84, 0xab, 0xda, 0x7b, 0x39, 0x13, 0x00, 0x00, + // 1321 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x57, 0xcf, 0x8f, 0x14, 0x45, + 0x18, 0x9d, 0x9e, 0x5d, 0x96, 0xdd, 0x5a, 0x14, 0x2c, 0x10, 0x87, 0x86, 0xcc, 0x60, 0x13, 0x75, + 0x01, 0xed, 0x66, 0x87, 0x98, 0x00, 0xba, 0x0c, 0x33, 0xcb, 0xba, 0x10, 0x20, 0xac, 0xbd, 0x04, + 0x12, 0x35, 0xb4, 0xb5, 0xdd, 0xe5, 0x4c, 0xc7, 0x9e, 0xae, 0xa6, 0xaa, 0x66, 0x96, 0x95, 0x78, + 0x50, 0x13, 0xe5, 0x48, 0x62, 0xbc, 0x79, 0xe0, 0xe4, 0x7f, 0xe1, 0x9d, 0x9b, 0x44, 0x2e, 0x9c, + 0xd0, 0x2c, 0x1e, 0x3c, 0x1a, 0xef, 0x26, 0xa6, 0xab, 0xab, 0x7b, 0x7e, 0xf5, 0xce, 0xf4, 0x0c, + 0xdc, 0x66, 0xaa, 0xeb, 0x7b, 0xdf, 0x7b, 0x6f, 0xbe, 0xaa, 0x7e, 0x03, 0x0c, 0xd7, 0xe7, 0x98, + 0xda, 0x0d, 0xe4, 0xfa, 0x16, 0xc3, 0x76, 0x8b, 0xba, 0x7c, 0xcb, 0xb0, 0xed, 0xb6, 0x11, 0x50, + 0xd2, 0x76, 0x1d, 0x4c, 0x8d, 0xf6, 0xa2, 0x71, 0xa7, 0x85, 0xe9, 0x96, 0x1e, 0x50, 0xc2, 0x09, + 0x3c, 0x96, 0x52, 0xa0, 0xdb, 0x76, 0x5b, 0x8f, 0x0b, 0xf4, 0xf6, 0xa2, 0x7a, 0xa4, 0x4e, 0x48, + 0xdd, 0xc3, 0x06, 0x0a, 0x5c, 0x03, 0xf9, 0x3e, 0xe1, 0x88, 0xbb, 0xc4, 0x67, 0x11, 0x84, 0x7a, + 0xa0, 0x4e, 0xea, 0x44, 0x7c, 0x34, 0xc2, 0x4f, 0x72, 0xb5, 0x24, 0x6b, 0xc4, 0xb7, 0x8d, 0xd6, + 0x17, 0x06, 0x77, 0x9b, 0x98, 0x71, 0xd4, 0x0c, 0xe4, 0x86, 0x72, 0x16, 0xaa, 0x09, 0x8b, 0xa8, + 0xe6, 0xd4, 0x4e, 0x35, 0xed, 0x45, 0x83, 0x35, 0x10, 0xc5, 0x8e, 0x65, 0x13, 0x9f, 0xb5, 0x9a, + 0x49, 0xc5, 0x5b, 0x43, 0x2a, 0x36, 0x5d, 0x8a, 0xa3, 0x6d, 0xda, 0x19, 0x70, 0xf8, 0xe3, 0xd0, + 0x95, 0x65, 0x59, 0xbd, 0x8a, 0x7d, 0xcc, 0x5c, 0x66, 0xe2, 0x3b, 0x2d, 0xcc, 0x38, 0x3c, 0x04, + 0x66, 0x23, 0x08, 0xd7, 0x29, 0x28, 0x47, 0x95, 0x85, 0x39, 0x73, 0xb7, 0xf8, 0x7e, 0xd9, 0xd1, + 0xee, 0x81, 0x23, 0xe9, 0x95, 0x2c, 0x20, 0x3e, 0xc3, 0xf0, 0x53, 0xf0, 0x4a, 0x3d, 0x5a, 0xb2, + 0x18, 0x47, 0x1c, 0x8b, 0xfa, 0xf9, 0xf2, 0x29, 0x7d, 0x27, 0xe3, 0xdb, 0x8b, 0x7a, 0x1f, 0xd6, + 0x7a, 0x58, 0x57, 0x9b, 0x7e, 0xf4, 0xac, 0x94, 0x33, 0xf7, 0xd4, 0xbb, 0xd6, 0xb4, 0x23, 0x40, + 0xed, 0x69, 0xbe, 0x1c, 0xc2, 0xc5, 0xac, 0x35, 0xd4, 0x27, 0x2a, 0x7e, 0x2a, 0x99, 0xd5, 0xc0, + 0x8c, 0x68, 0xcf, 0x0a, 0xca, 0xd1, 0xa9, 0x85, 0xf9, 0xf2, 0x09, 0x3d, 0xc3, 0x2c, 0xe8, 0x02, + 0xc4, 0x94, 0x95, 0xda, 0x71, 0xf0, 0xce, 0x60, 0x8b, 0x75, 0x8e, 0x28, 0x5f, 0xa3, 0x24, 0x20, + 0x0c, 0x79, 0x09, 0x9b, 0xfb, 0x0a, 0x58, 0x18, 0xbd, 0x57, 0x72, 0xfb, 0x0c, 0xcc, 0x05, 0xf1, + 0xa2, 0x74, 0xec, 0x7c, 0x36, 0x7a, 0x12, 0xbc, 0xea, 0x38, 0x6e, 0x38, 0xa4, 0x1d, 0xe8, 0x0e, + 0xa0, 0xb6, 0x00, 0xde, 0x4e, 0x63, 0x42, 0x82, 0x01, 0xd2, 0xdf, 0x2b, 0xe9, 0x02, 0x7b, 0xb6, + 0x26, 0xbf, 0xf4, 0x00, 0xe7, 0xa5, 0xb1, 0x38, 0x9b, 0xb8, 0x49, 0xda, 0xc8, 0x4b, 0xa5, 0x5c, + 0x01, 0xbb, 0x44, 0xeb, 0x21, 0xa3, 0x08, 0x0f, 0x83, 0x39, 0xdb, 0x73, 0xb1, 0xcf, 0xc3, 0x67, + 0x79, 0xf1, 0x6c, 0x36, 0x5a, 0xb8, 0xec, 0x68, 0x3f, 0x28, 0xe0, 0x4d, 0xa1, 0xe4, 0x26, 0xf2, + 0x5c, 0x07, 0x71, 0x42, 0xbb, 0xac, 0xa2, 0xa3, 0x07, 0x1d, 0x2e, 0x81, 0x7d, 0x31, 0x69, 0x0b, + 0x39, 0x0e, 0xc5, 0x8c, 0x45, 0x4d, 0x6a, 0xf0, 0xdf, 0x67, 0xa5, 0x57, 0xb7, 0x50, 0xd3, 0x3b, + 0xa7, 0xc9, 0x07, 0x9a, 0xb9, 0x37, 0xde, 0x5b, 0x8d, 0x56, 0xce, 0xcd, 0xde, 0x7f, 0x58, 0xca, + 0xfd, 0xfd, 0xb0, 0x94, 0xd3, 0xae, 0x03, 0x6d, 0x18, 0x11, 0xe9, 0xe6, 0x71, 0xb0, 0x2f, 0x3e, + 0xca, 0x49, 0xbb, 0x88, 0xd1, 0x5e, 0xbb, 0x6b, 0x7f, 0xd8, 0x6c, 0x50, 0xda, 0x5a, 0x57, 0xf3, + 0x6c, 0xd2, 0x06, 0x7a, 0x0d, 0x91, 0xd6, 0xd7, 0x7f, 0x98, 0xb4, 0x5e, 0x22, 0x1d, 0x69, 0x03, + 0x4e, 0x4a, 0x69, 0x7d, 0xae, 0x69, 0x87, 0xc1, 0x21, 0x01, 0x78, 0xa3, 0x41, 0x09, 0xe7, 0x1e, + 0x16, 0xc7, 0x3e, 0x1e, 0xce, 0x5f, 0xf2, 0xf2, 0xf8, 0xf7, 0x3d, 0x95, 0x6d, 0x4a, 0x60, 0x9e, + 0x79, 0x88, 0x35, 0xac, 0x26, 0xe6, 0x98, 0x8a, 0x0e, 0x53, 0x26, 0x10, 0x4b, 0xd7, 0xc2, 0x15, + 0x58, 0x06, 0xaf, 0x77, 0x6d, 0xb0, 0x90, 0xe7, 0x91, 0x4d, 0xe4, 0xdb, 0x58, 0x68, 0x9f, 0x32, + 0xf7, 0x77, 0xb6, 0x56, 0xe3, 0x47, 0xf0, 0x36, 0x28, 0xf8, 0xf8, 0x2e, 0xb7, 0x28, 0x0e, 0x3c, + 0xec, 0xbb, 0xac, 0x61, 0xd9, 0xc8, 0x77, 0x42, 0xb1, 0xb8, 0x30, 0x25, 0x66, 0x5e, 0xd5, 0xa3, + 0x9b, 0x5f, 0x8f, 0x6f, 0x7e, 0xfd, 0x46, 0x7c, 0xf3, 0xd7, 0x66, 0xc3, 0x3b, 0xec, 0xc1, 0x1f, + 0x25, 0xc5, 0x3c, 0x18, 0xa2, 0x98, 0x31, 0xc8, 0x72, 0x8c, 0x01, 0xd7, 0xc1, 0xee, 0x00, 0xd9, + 0x5f, 0x62, 0xce, 0x0a, 0xd3, 0xe2, 0x56, 0x3a, 0x9b, 0xe9, 0x08, 0xc5, 0x0e, 0x38, 0xeb, 0x21, + 0xe7, 0x35, 0x81, 0x60, 0xc6, 0x48, 0xda, 0x45, 0x79, 0x88, 0x93, 0x5d, 0xf1, 0xc4, 0x45, 0x1b, + 0x2f, 0x22, 0x8e, 0x32, 0xdc, 0xf4, 0xbf, 0xc7, 0x17, 0xd8, 0x50, 0x18, 0x69, 0xfe, 0x90, 0x69, + 0x83, 0x60, 0x9a, 0xb9, 0x5f, 0x45, 0x2e, 0x4f, 0x9b, 0xe2, 0x33, 0xdc, 0x04, 0xfb, 0x83, 0x04, + 0xe4, 0xb2, 0xcf, 0x78, 0x68, 0x36, 0x2b, 0x4c, 0x09, 0x0b, 0x2a, 0xe3, 0x59, 0xd0, 0x61, 0x73, + 0x8b, 0xa2, 0x20, 0xc0, 0x54, 0xbe, 0x3a, 0xd2, 0x3a, 0x68, 0xbf, 0x2a, 0xe0, 0x40, 0x9a, 0x79, + 0xf0, 0x36, 0xd8, 0x53, 0xf7, 0xc8, 0x06, 0xf2, 0x2c, 0xec, 0x73, 0xba, 0x25, 0x2f, 0xb4, 0xf7, + 0x33, 0x51, 0x59, 0x15, 0x85, 0x02, 0x6d, 0x25, 0x2c, 0x96, 0x04, 0xe6, 0x23, 0x40, 0xb1, 0x04, + 0x57, 0xc0, 0xb4, 0x83, 0x38, 0x12, 0x2e, 0xcc, 0x97, 0x4f, 0x0e, 0x7b, 0x1d, 0x76, 0xd1, 0x0a, + 0xc9, 0x4b, 0x34, 0x51, 0xae, 0x3d, 0x55, 0x80, 0xba, 0xb3, 0x72, 0xb8, 0x06, 0xf6, 0x44, 0x23, + 0x1e, 0x69, 0x97, 0x2a, 0xc6, 0xe9, 0x76, 0x29, 0x67, 0x46, 0xc7, 0x48, 0xfa, 0xf2, 0x39, 0x80, + 0x6d, 0x66, 0x5b, 0x4d, 0xc4, 0x5b, 0x61, 0xdc, 0x90, 0xb8, 0xf9, 0xd1, 0x2f, 0xf5, 0x9b, 0xeb, + 0xcb, 0xd7, 0xa2, 0xa2, 0x1e, 0xf0, 0x7d, 0x6d, 0x66, 0xf7, 0xac, 0xd7, 0x66, 0x22, 0x67, 0xb4, + 0x77, 0xc1, 0x09, 0x31, 0x6e, 0x26, 0xae, 0xbb, 0x8c, 0x63, 0xda, 0x99, 0x37, 0x13, 0x6f, 0x22, + 0xea, 0x5c, 0xc4, 0x3e, 0x69, 0x26, 0x6f, 0xaa, 0x15, 0x70, 0x32, 0xd3, 0x6e, 0x39, 0x9f, 0x07, + 0xc1, 0x8c, 0x23, 0x56, 0xc4, 0xcb, 0x7f, 0xce, 0x94, 0xdf, 0xca, 0x3f, 0xbf, 0x06, 0x76, 0x09, + 0x1c, 0xb8, 0xad, 0x80, 0x03, 0x69, 0xc9, 0x06, 0x5e, 0xc8, 0x34, 0x03, 0x43, 0xe2, 0x94, 0x5a, + 0x7d, 0x01, 0x84, 0x88, 0xbf, 0xb6, 0xf2, 0xed, 0x93, 0xbf, 0x7e, 0xcc, 0x57, 0xe0, 0xd2, 0xe8, + 0xc4, 0x9b, 0x5c, 0xed, 0x32, 0x3a, 0x19, 0xf7, 0xe2, 0x93, 0xf9, 0x35, 0x7c, 0xa2, 0x80, 0xfd, + 0x29, 0x19, 0x09, 0x56, 0xc6, 0x67, 0xd8, 0x93, 0xbd, 0xd4, 0x0b, 0x93, 0x03, 0x48, 0x85, 0x67, + 0x85, 0xc2, 0xd3, 0x70, 0x71, 0x0c, 0x85, 0x51, 0x2a, 0x83, 0xdf, 0xe4, 0x41, 0x61, 0x87, 0xa8, + 0xc5, 0xe0, 0xd5, 0x09, 0x99, 0xa5, 0xa6, 0x3a, 0xf5, 0xda, 0x4b, 0x42, 0x93, 0xa2, 0x2f, 0x09, + 0xd1, 0x35, 0x78, 0x61, 0x5c, 0xd1, 0x61, 0xb8, 0xa6, 0xdc, 0x4a, 0x02, 0x13, 0xfc, 0x4f, 0x01, + 0x6f, 0xa4, 0x27, 0x37, 0x06, 0xaf, 0x4c, 0x4c, 0x7a, 0x30, 0x22, 0xaa, 0x57, 0x5f, 0x0e, 0x98, + 0x34, 0x60, 0x55, 0x18, 0x50, 0x85, 0x95, 0x09, 0x0c, 0x20, 0x41, 0x97, 0xfe, 0x7f, 0x14, 0x19, + 0x0e, 0x52, 0x63, 0x16, 0xfc, 0x28, 0x3b, 0xeb, 0x61, 0x81, 0x51, 0x5d, 0x7d, 0x61, 0x1c, 0x29, + 0xbc, 0x2a, 0x84, 0x7f, 0x00, 0xcf, 0x66, 0xf8, 0x0b, 0x1b, 0x03, 0x59, 0x3d, 0xa9, 0x2d, 0x45, + 0x72, 0x77, 0xfc, 0x9a, 0x48, 0x72, 0x4a, 0x90, 0x9c, 0x48, 0x72, 0x5a, 0x0e, 0x9c, 0x4c, 0x72, + 0x4f, 0x72, 0x84, 0xbf, 0x29, 0x00, 0x0e, 0x46, 0x40, 0x78, 0x3e, 0x3b, 0xc5, 0xb4, 0x64, 0xa9, + 0x56, 0x26, 0xae, 0x97, 0xd2, 0xce, 0x08, 0x69, 0x65, 0x78, 0x6a, 0xb4, 0x34, 0x2e, 0x01, 0xa2, + 0xbf, 0xc7, 0xf0, 0xbb, 0x3c, 0x38, 0x3a, 0x2a, 0x65, 0x8d, 0x73, 0x87, 0x8d, 0xce, 0x7c, 0xe3, + 0xdc, 0x61, 0x19, 0xa2, 0x9f, 0x56, 0x13, 0xda, 0x3f, 0x84, 0xe7, 0x46, 0x6b, 0x0f, 0xb0, 0xef, + 0xb8, 0x7e, 0xbd, 0x33, 0xc7, 0x32, 0xb1, 0xc2, 0x9f, 0xf2, 0xe0, 0x58, 0x86, 0xd7, 0x39, 0xbc, + 0x9e, 0x9d, 0x7a, 0xa6, 0x18, 0xa1, 0xae, 0xbd, 0x3c, 0x40, 0x69, 0xc7, 0x15, 0x61, 0xc7, 0x0a, + 0x5c, 0x1e, 0x6d, 0x07, 0x4d, 0x10, 0x3b, 0x8e, 0x50, 0x81, 0x69, 0x45, 0xf1, 0xa4, 0x76, 0xeb, + 0xd1, 0x76, 0x51, 0x79, 0xbc, 0x5d, 0x54, 0xfe, 0xdc, 0x2e, 0x2a, 0x0f, 0x9e, 0x17, 0x73, 0x8f, + 0x9f, 0x17, 0x73, 0x4f, 0x9f, 0x17, 0x73, 0x9f, 0x2c, 0xd5, 0x5d, 0xde, 0x68, 0x6d, 0xe8, 0x36, + 0x69, 0x1a, 0x36, 0x61, 0x4d, 0xc2, 0xba, 0xfa, 0xbd, 0x97, 0xf4, 0x6b, 0x9f, 0x36, 0xee, 0xf6, + 0xcd, 0xdf, 0x56, 0x80, 0xd9, 0xc6, 0x8c, 0xf8, 0xb7, 0x72, 0xfa, 0xff, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x03, 0xbe, 0x75, 0x9c, 0x41, 0x13, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/x/ccv/types/genesis.go b/x/ccv/types/genesis.go index ff18480ecb..5aae1ed9b5 100644 --- a/x/ccv/types/genesis.go +++ b/x/ccv/types/genesis.go @@ -8,11 +8,11 @@ import ( abci "github.com/cometbft/cometbft/abci/types" ) -// NewInitialGenesisState returns a consumer GenesisState for a completely new consumer chain. -func NewInitialGenesisState(cs *ibctmtypes.ClientState, consState *ibctmtypes.ConsensusState, - initValSet []abci.ValidatorUpdate, params Params, -) *GenesisState { - return &GenesisState{ +// NewInitialConsumerGenesisState returns a ConsumerGenesisState for a completely new consumer chain. +func NewInitialConsumerGenesisState(cs *ibctmtypes.ClientState, consState *ibctmtypes.ConsensusState, + initValSet []abci.ValidatorUpdate, params ConsumerParams, +) *ConsumerGenesisState { + return &ConsumerGenesisState{ Params: params, NewChain: true, ProviderClientState: cs, @@ -21,8 +21,8 @@ func NewInitialGenesisState(cs *ibctmtypes.ClientState, consState *ibctmtypes.Co } } -// NewRestartGenesisState returns a consumer GenesisState that has already been established. -func NewRestartGenesisState( +// NewRestartConsumerGenesisState returns a ConsumerGenesisState that has already been established. +func NewRestartConsumerGenesisState( clientID, channelID string, maturingPackets []MaturingVSCPacket, initValSet []abci.ValidatorUpdate, @@ -30,9 +30,9 @@ func NewRestartGenesisState( pendingConsumerPackets ConsumerPacketDataList, outstandingDowntimes []OutstandingDowntime, lastTransBlockHeight LastTransmissionBlockHeight, - params Params, -) *GenesisState { - return &GenesisState{ + params ConsumerParams, +) *ConsumerGenesisState { + return &ConsumerGenesisState{ Params: params, ProviderClientId: clientID, ProviderChannelId: channelID, @@ -46,10 +46,10 @@ func NewRestartGenesisState( } } -// DefaultGenesisState returns a default disabled consumer chain genesis state. This allows the module to be hooked up to app without getting use +// DefaultConsumerGenesisState returns a default disabled consumer chain genesis state. This allows the module to be hooked up to app without getting use // unless explicitly specified in genesis. -func DefaultGenesisState() *GenesisState { - return &GenesisState{ +func DefaultConsumerGenesisState() *ConsumerGenesisState { + return &ConsumerGenesisState{ Params: DefaultParams(), } } @@ -71,7 +71,7 @@ func DefaultGenesisState() *GenesisState { // - MaturingVSCPackets, OutstandingDowntime, PendingConsumerPacket, LastTransmissionBlockHeight // optional // -func (gs GenesisState) Validate() error { +func (gs ConsumerGenesisState) Validate() error { if !gs.Params.Enabled { return nil } diff --git a/x/ccv/types/params.go b/x/ccv/types/params.go index 6a903c0d8f..1e2d6d180a 100644 --- a/x/ccv/types/params.go +++ b/x/ccv/types/params.go @@ -58,7 +58,7 @@ var ( // ParamKeyTable type declaration for parameters func ParamKeyTable() paramtypes.KeyTable { - return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) + return paramtypes.NewKeyTable().RegisterParamSet(&ConsumerParams{}) } // NewParams creates new consumer parameters with provided arguments @@ -67,8 +67,8 @@ func NewParams(enabled bool, blocksPerDistributionTransmission int64, ccvTimeoutPeriod, transferTimeoutPeriod time.Duration, consumerRedistributionFraction string, historicalEntries int64, consumerUnbondingPeriod time.Duration, softOptOutThreshold string, rewardDenoms, providerRewardDenoms []string, -) Params { - return Params{ +) ConsumerParams { + return ConsumerParams{ Enabled: enabled, BlocksPerDistributionTransmission: blocksPerDistributionTransmission, DistributionTransmissionChannel: distributionTransmissionChannel, @@ -85,7 +85,7 @@ func NewParams(enabled bool, blocksPerDistributionTransmission int64, } // DefaultParams is the default params for the consumer module -func DefaultParams() Params { +func DefaultParams() ConsumerParams { var rewardDenoms []string var provideRewardDenoms []string return NewParams( @@ -105,7 +105,7 @@ func DefaultParams() Params { } // Validate all ccv-consumer module parameters -func (p Params) Validate() error { +func (p ConsumerParams) Validate() error { if err := ValidateBool(p.Enabled); err != nil { return err } @@ -146,7 +146,7 @@ func (p Params) Validate() error { } // ParamSetPairs implements params.ParamSet -func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { +func (p *ConsumerParams) ParamSetPairs() paramtypes.ParamSetPairs { return paramtypes.ParamSetPairs{ paramtypes.NewParamSetPair(KeyEnabled, p.Enabled, ValidateBool), paramtypes.NewParamSetPair(KeyBlocksPerDistributionTransmission, diff --git a/x/ccv/types/shared_consumer.pb.go b/x/ccv/types/shared_consumer.pb.go index 4cf8860269..d52508dc6b 100644 --- a/x/ccv/types/shared_consumer.pb.go +++ b/x/ccv/types/shared_consumer.pb.go @@ -31,13 +31,11 @@ var _ = time.Kitchen // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// Params defines the parameters for CCV consumer module. +// ConsumerParams defines the parameters for CCV consumer module. // // Note this type is referenced in both the consumer and provider CCV modules, // and persisted on the provider, see MakeConsumerGenesis and SetConsumerGenesis. -// -// TODO: Rename to ConsumerParams. See https://github.com/cosmos/interchain-security/issues/1206 -type Params struct { +type ConsumerParams struct { // TODO: Remove enabled flag and find a better way to setup integration tests // See: https://github.com/cosmos/interchain-security/issues/339 Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` @@ -81,18 +79,18 @@ type Params struct { ProviderRewardDenoms []string `protobuf:"bytes,12,rep,name=provider_reward_denoms,json=providerRewardDenoms,proto3" json:"provider_reward_denoms,omitempty"` } -func (m *Params) Reset() { *m = Params{} } -func (m *Params) String() string { return proto.CompactTextString(m) } -func (*Params) ProtoMessage() {} -func (*Params) Descriptor() ([]byte, []int) { +func (m *ConsumerParams) Reset() { *m = ConsumerParams{} } +func (m *ConsumerParams) String() string { return proto.CompactTextString(m) } +func (*ConsumerParams) ProtoMessage() {} +func (*ConsumerParams) Descriptor() ([]byte, []int) { return fileDescriptor_d0a8be0efc64dfbc, []int{0} } -func (m *Params) XXX_Unmarshal(b []byte) error { +func (m *ConsumerParams) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *ConsumerParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_Params.Marshal(b, m, deterministic) + return xxx_messageInfo_ConsumerParams.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -102,113 +100,111 @@ func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return b[:n], nil } } -func (m *Params) XXX_Merge(src proto.Message) { - xxx_messageInfo_Params.Merge(m, src) +func (m *ConsumerParams) XXX_Merge(src proto.Message) { + xxx_messageInfo_ConsumerParams.Merge(m, src) } -func (m *Params) XXX_Size() int { +func (m *ConsumerParams) XXX_Size() int { return m.Size() } -func (m *Params) XXX_DiscardUnknown() { - xxx_messageInfo_Params.DiscardUnknown(m) +func (m *ConsumerParams) XXX_DiscardUnknown() { + xxx_messageInfo_ConsumerParams.DiscardUnknown(m) } -var xxx_messageInfo_Params proto.InternalMessageInfo +var xxx_messageInfo_ConsumerParams proto.InternalMessageInfo -func (m *Params) GetEnabled() bool { +func (m *ConsumerParams) GetEnabled() bool { if m != nil { return m.Enabled } return false } -func (m *Params) GetBlocksPerDistributionTransmission() int64 { +func (m *ConsumerParams) GetBlocksPerDistributionTransmission() int64 { if m != nil { return m.BlocksPerDistributionTransmission } return 0 } -func (m *Params) GetDistributionTransmissionChannel() string { +func (m *ConsumerParams) GetDistributionTransmissionChannel() string { if m != nil { return m.DistributionTransmissionChannel } return "" } -func (m *Params) GetProviderFeePoolAddrStr() string { +func (m *ConsumerParams) GetProviderFeePoolAddrStr() string { if m != nil { return m.ProviderFeePoolAddrStr } return "" } -func (m *Params) GetCcvTimeoutPeriod() time.Duration { +func (m *ConsumerParams) GetCcvTimeoutPeriod() time.Duration { if m != nil { return m.CcvTimeoutPeriod } return 0 } -func (m *Params) GetTransferTimeoutPeriod() time.Duration { +func (m *ConsumerParams) GetTransferTimeoutPeriod() time.Duration { if m != nil { return m.TransferTimeoutPeriod } return 0 } -func (m *Params) GetConsumerRedistributionFraction() string { +func (m *ConsumerParams) GetConsumerRedistributionFraction() string { if m != nil { return m.ConsumerRedistributionFraction } return "" } -func (m *Params) GetHistoricalEntries() int64 { +func (m *ConsumerParams) GetHistoricalEntries() int64 { if m != nil { return m.HistoricalEntries } return 0 } -func (m *Params) GetUnbondingPeriod() time.Duration { +func (m *ConsumerParams) GetUnbondingPeriod() time.Duration { if m != nil { return m.UnbondingPeriod } return 0 } -func (m *Params) GetSoftOptOutThreshold() string { +func (m *ConsumerParams) GetSoftOptOutThreshold() string { if m != nil { return m.SoftOptOutThreshold } return "" } -func (m *Params) GetRewardDenoms() []string { +func (m *ConsumerParams) GetRewardDenoms() []string { if m != nil { return m.RewardDenoms } return nil } -func (m *Params) GetProviderRewardDenoms() []string { +func (m *ConsumerParams) GetProviderRewardDenoms() []string { if m != nil { return m.ProviderRewardDenoms } return nil } -// GenesisState defines the CCV consumer chain genesis state. +// ConsumerGenesisState defines the CCV consumer chain genesis state. // // Note this type is referenced in both the consumer and provider CCV modules, // and persisted on the provider, see MakeConsumerGenesis and SetConsumerGenesis. -// -// TODO: Rename to ConsumerGenesisState. See https://github.com/cosmos/interchain-security/issues/1206 -type GenesisState struct { - Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` - ProviderClientId string `protobuf:"bytes,2,opt,name=provider_client_id,json=providerClientId,proto3" json:"provider_client_id,omitempty"` - ProviderChannelId string `protobuf:"bytes,3,opt,name=provider_channel_id,json=providerChannelId,proto3" json:"provider_channel_id,omitempty"` - NewChain bool `protobuf:"varint,4,opt,name=new_chain,json=newChain,proto3" json:"new_chain,omitempty"` +type ConsumerGenesisState struct { + Params ConsumerParams `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` + ProviderClientId string `protobuf:"bytes,2,opt,name=provider_client_id,json=providerClientId,proto3" json:"provider_client_id,omitempty"` + ProviderChannelId string `protobuf:"bytes,3,opt,name=provider_channel_id,json=providerChannelId,proto3" json:"provider_channel_id,omitempty"` + NewChain bool `protobuf:"varint,4,opt,name=new_chain,json=newChain,proto3" json:"new_chain,omitempty"` // ProviderClientState filled in on new chain, nil on restart. ProviderClientState *_07_tendermint.ClientState `protobuf:"bytes,5,opt,name=provider_client_state,json=providerClientState,proto3" json:"provider_client_state,omitempty"` // ProviderConsensusState filled in on new chain, nil on restart. @@ -228,18 +224,18 @@ type GenesisState struct { PreCCV bool `protobuf:"varint,13,opt,name=preCCV,proto3" json:"preCCV,omitempty"` } -func (m *GenesisState) Reset() { *m = GenesisState{} } -func (m *GenesisState) String() string { return proto.CompactTextString(m) } -func (*GenesisState) ProtoMessage() {} -func (*GenesisState) Descriptor() ([]byte, []int) { +func (m *ConsumerGenesisState) Reset() { *m = ConsumerGenesisState{} } +func (m *ConsumerGenesisState) String() string { return proto.CompactTextString(m) } +func (*ConsumerGenesisState) ProtoMessage() {} +func (*ConsumerGenesisState) Descriptor() ([]byte, []int) { return fileDescriptor_d0a8be0efc64dfbc, []int{1} } -func (m *GenesisState) XXX_Unmarshal(b []byte) error { +func (m *ConsumerGenesisState) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *ConsumerGenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_GenesisState.Marshal(b, m, deterministic) + return xxx_messageInfo_ConsumerGenesisState.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -249,103 +245,103 @@ func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) return b[:n], nil } } -func (m *GenesisState) XXX_Merge(src proto.Message) { - xxx_messageInfo_GenesisState.Merge(m, src) +func (m *ConsumerGenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_ConsumerGenesisState.Merge(m, src) } -func (m *GenesisState) XXX_Size() int { +func (m *ConsumerGenesisState) XXX_Size() int { return m.Size() } -func (m *GenesisState) XXX_DiscardUnknown() { - xxx_messageInfo_GenesisState.DiscardUnknown(m) +func (m *ConsumerGenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_ConsumerGenesisState.DiscardUnknown(m) } -var xxx_messageInfo_GenesisState proto.InternalMessageInfo +var xxx_messageInfo_ConsumerGenesisState proto.InternalMessageInfo -func (m *GenesisState) GetParams() Params { +func (m *ConsumerGenesisState) GetParams() ConsumerParams { if m != nil { return m.Params } - return Params{} + return ConsumerParams{} } -func (m *GenesisState) GetProviderClientId() string { +func (m *ConsumerGenesisState) GetProviderClientId() string { if m != nil { return m.ProviderClientId } return "" } -func (m *GenesisState) GetProviderChannelId() string { +func (m *ConsumerGenesisState) GetProviderChannelId() string { if m != nil { return m.ProviderChannelId } return "" } -func (m *GenesisState) GetNewChain() bool { +func (m *ConsumerGenesisState) GetNewChain() bool { if m != nil { return m.NewChain } return false } -func (m *GenesisState) GetProviderClientState() *_07_tendermint.ClientState { +func (m *ConsumerGenesisState) GetProviderClientState() *_07_tendermint.ClientState { if m != nil { return m.ProviderClientState } return nil } -func (m *GenesisState) GetProviderConsensusState() *_07_tendermint.ConsensusState { +func (m *ConsumerGenesisState) GetProviderConsensusState() *_07_tendermint.ConsensusState { if m != nil { return m.ProviderConsensusState } return nil } -func (m *GenesisState) GetMaturingPackets() []MaturingVSCPacket { +func (m *ConsumerGenesisState) GetMaturingPackets() []MaturingVSCPacket { if m != nil { return m.MaturingPackets } return nil } -func (m *GenesisState) GetInitialValSet() []types.ValidatorUpdate { +func (m *ConsumerGenesisState) GetInitialValSet() []types.ValidatorUpdate { if m != nil { return m.InitialValSet } return nil } -func (m *GenesisState) GetHeightToValsetUpdateId() []HeightToValsetUpdateID { +func (m *ConsumerGenesisState) GetHeightToValsetUpdateId() []HeightToValsetUpdateID { if m != nil { return m.HeightToValsetUpdateId } return nil } -func (m *GenesisState) GetOutstandingDowntimeSlashing() []OutstandingDowntime { +func (m *ConsumerGenesisState) GetOutstandingDowntimeSlashing() []OutstandingDowntime { if m != nil { return m.OutstandingDowntimeSlashing } return nil } -func (m *GenesisState) GetPendingConsumerPackets() ConsumerPacketDataList { +func (m *ConsumerGenesisState) GetPendingConsumerPackets() ConsumerPacketDataList { if m != nil { return m.PendingConsumerPackets } return ConsumerPacketDataList{} } -func (m *GenesisState) GetLastTransmissionBlockHeight() LastTransmissionBlockHeight { +func (m *ConsumerGenesisState) GetLastTransmissionBlockHeight() LastTransmissionBlockHeight { if m != nil { return m.LastTransmissionBlockHeight } return LastTransmissionBlockHeight{} } -func (m *GenesisState) GetPreCCV() bool { +func (m *ConsumerGenesisState) GetPreCCV() bool { if m != nil { return m.PreCCV } @@ -607,8 +603,8 @@ func (m *ConsumerPacketDataList) GetList() []ConsumerPacketData { } func init() { - proto.RegisterType((*Params)(nil), "interchain_security.ccv.v1.Params") - proto.RegisterType((*GenesisState)(nil), "interchain_security.ccv.v1.GenesisState") + proto.RegisterType((*ConsumerParams)(nil), "interchain_security.ccv.v1.ConsumerParams") + proto.RegisterType((*ConsumerGenesisState)(nil), "interchain_security.ccv.v1.ConsumerGenesisState") proto.RegisterType((*HeightToValsetUpdateID)(nil), "interchain_security.ccv.v1.HeightToValsetUpdateID") proto.RegisterType((*OutstandingDowntime)(nil), "interchain_security.ccv.v1.OutstandingDowntime") proto.RegisterType((*LastTransmissionBlockHeight)(nil), "interchain_security.ccv.v1.LastTransmissionBlockHeight") @@ -621,84 +617,84 @@ func init() { } var fileDescriptor_d0a8be0efc64dfbc = []byte{ - // 1178 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x56, 0x4d, 0x6f, 0x1b, 0x45, - 0x18, 0x8e, 0x9b, 0x34, 0xb5, 0x27, 0x09, 0x4d, 0x27, 0xad, 0xd9, 0x26, 0xc2, 0x71, 0x0d, 0x48, - 0x96, 0xa0, 0xbb, 0x24, 0x2d, 0x42, 0xe2, 0x80, 0x68, 0x6c, 0x4a, 0x83, 0x4a, 0x13, 0x36, 0x69, - 0x0e, 0x45, 0x62, 0x34, 0x9e, 0x99, 0xd8, 0xa3, 0xae, 0x67, 0xac, 0x99, 0xd9, 0x0d, 0xb9, 0x22, - 0x7e, 0x40, 0x8f, 0xfc, 0xa4, 0x1e, 0x7b, 0xe4, 0x04, 0xa8, 0xfd, 0x23, 0x68, 0x3e, 0xd6, 0xb1, - 0xf3, 0x61, 0xca, 0x6d, 0x67, 0xde, 0xe7, 0x79, 0xbf, 0xdf, 0x79, 0x17, 0x7c, 0xc1, 0x85, 0x61, - 0x8a, 0x0c, 0x30, 0x17, 0x48, 0x33, 0x92, 0x2b, 0x6e, 0x4e, 0x13, 0x42, 0x8a, 0xa4, 0xd8, 0x4a, - 0xf4, 0x00, 0x2b, 0x46, 0x11, 0x91, 0x42, 0xe7, 0x43, 0xa6, 0xe2, 0x91, 0x92, 0x46, 0xc2, 0xf5, - 0x4b, 0x18, 0x31, 0x21, 0x45, 0x5c, 0x6c, 0xad, 0x6f, 0x18, 0x26, 0x28, 0x53, 0x43, 0x2e, 0x4c, - 0x82, 0x7b, 0x84, 0x27, 0xe6, 0x74, 0xc4, 0xb4, 0x27, 0xae, 0x27, 0xbc, 0x47, 0x92, 0x8c, 0xf7, - 0x07, 0x86, 0x64, 0x9c, 0x09, 0xa3, 0x93, 0x09, 0x74, 0xb1, 0x35, 0x71, 0x0a, 0x84, 0x7b, 0x96, - 0x40, 0xa4, 0x62, 0x09, 0x19, 0x60, 0x21, 0x58, 0x66, 0x51, 0xe1, 0x33, 0x40, 0x1a, 0x7d, 0x29, - 0xfb, 0x19, 0x4b, 0xdc, 0xa9, 0x97, 0x1f, 0x27, 0x34, 0x57, 0xd8, 0x70, 0x29, 0x82, 0xfc, 0x76, - 0x5f, 0xf6, 0xa5, 0xfb, 0x4c, 0xec, 0x57, 0xb8, 0xfd, 0x74, 0x46, 0xd0, 0x27, 0x5c, 0xb1, 0x00, - 0xdb, 0x3c, 0xaf, 0xdc, 0xf0, 0x21, 0xd3, 0x06, 0x0f, 0x47, 0x1e, 0xd0, 0xfa, 0x7d, 0x11, 0x2c, - 0xee, 0x63, 0x85, 0x87, 0x1a, 0x46, 0xe0, 0x06, 0x13, 0xb8, 0x97, 0x31, 0x1a, 0x55, 0x9a, 0x95, - 0x76, 0x35, 0x2d, 0x8f, 0x70, 0x0f, 0x7c, 0xd2, 0xcb, 0x24, 0x79, 0xa9, 0xd1, 0x88, 0x29, 0x44, - 0xb9, 0x36, 0x8a, 0xf7, 0x72, 0xeb, 0x23, 0x32, 0x0a, 0x0b, 0x3d, 0xe4, 0x5a, 0x73, 0x29, 0xa2, - 0x6b, 0xcd, 0x4a, 0x7b, 0x3e, 0xbd, 0xe7, 0xb1, 0xfb, 0x4c, 0x75, 0x27, 0x90, 0x87, 0x13, 0x40, - 0xf8, 0x03, 0xb8, 0x77, 0xa5, 0x16, 0x14, 0xd2, 0x13, 0xcd, 0x37, 0x2b, 0xed, 0x5a, 0xba, 0x49, - 0xaf, 0x50, 0xd2, 0xf1, 0x30, 0xf8, 0x35, 0x58, 0x1f, 0x29, 0x59, 0x70, 0xca, 0x14, 0x3a, 0x66, - 0x0c, 0x8d, 0xa4, 0xcc, 0x10, 0xa6, 0x54, 0x21, 0x6d, 0x54, 0xb4, 0xe0, 0x94, 0xd4, 0x4b, 0xc4, - 0x63, 0xc6, 0xf6, 0xa5, 0xcc, 0x1e, 0x51, 0xaa, 0x0e, 0x8c, 0x82, 0x3f, 0x01, 0x48, 0x48, 0x81, - 0x6c, 0x52, 0x64, 0x6e, 0x6c, 0x74, 0x5c, 0xd2, 0xe8, 0x7a, 0xb3, 0xd2, 0x5e, 0xda, 0xbe, 0x1b, - 0xfb, 0xdc, 0xc5, 0x65, 0xee, 0xe2, 0x6e, 0x28, 0xcc, 0x4e, 0xf5, 0xf5, 0x5f, 0x9b, 0x73, 0x7f, - 0xfc, 0xbd, 0x59, 0x49, 0x57, 0x09, 0x29, 0x0e, 0x3d, 0x7b, 0xdf, 0x91, 0xe1, 0xcf, 0xe0, 0x43, - 0x17, 0xcd, 0x31, 0x53, 0xe7, 0xf5, 0x2e, 0xbe, 0xbf, 0xde, 0x3b, 0xa5, 0x8e, 0x69, 0xe5, 0x4f, - 0x40, 0xb3, 0x6c, 0x65, 0xa4, 0xd8, 0x54, 0x0a, 0x8f, 0x15, 0x26, 0xf6, 0x23, 0xba, 0xe1, 0x22, - 0x6e, 0x94, 0xb8, 0x74, 0x0a, 0xf6, 0x38, 0xa0, 0xe0, 0x7d, 0x00, 0x07, 0x5c, 0x1b, 0xa9, 0x38, - 0xc1, 0x19, 0x62, 0xc2, 0x28, 0xce, 0x74, 0x54, 0x75, 0x05, 0xbc, 0x75, 0x26, 0xf9, 0xce, 0x0b, - 0xe0, 0x33, 0xb0, 0x9a, 0x8b, 0x9e, 0x14, 0x94, 0x8b, 0x7e, 0x19, 0x4e, 0xed, 0xfd, 0xc3, 0xb9, - 0x39, 0x26, 0x87, 0x40, 0x1e, 0x80, 0xba, 0x96, 0xc7, 0x06, 0xc9, 0x91, 0x41, 0x36, 0x43, 0x66, - 0xa0, 0x98, 0x1e, 0xc8, 0x8c, 0x46, 0xc0, 0xb9, 0xbf, 0x66, 0xa5, 0x7b, 0x23, 0xb3, 0x97, 0x9b, - 0xc3, 0x52, 0x04, 0x3f, 0x06, 0x2b, 0x8a, 0x9d, 0x60, 0x45, 0x11, 0x65, 0x42, 0x0e, 0x75, 0xb4, - 0xd4, 0x9c, 0x6f, 0xd7, 0xd2, 0x65, 0x7f, 0xd9, 0x75, 0x77, 0xf0, 0x21, 0x18, 0x17, 0x1b, 0x4d, - 0xa3, 0x97, 0x1d, 0xfa, 0x76, 0x29, 0x4d, 0x27, 0x58, 0xad, 0xd7, 0x55, 0xb0, 0xfc, 0x3d, 0x13, - 0x4c, 0x73, 0x7d, 0x60, 0xb0, 0x61, 0xf0, 0x5b, 0xb0, 0x38, 0x72, 0x63, 0xe1, 0x66, 0x61, 0x69, - 0xbb, 0x15, 0x5f, 0xfd, 0x66, 0xc4, 0x7e, 0x80, 0x76, 0x16, 0x6c, 0xbc, 0x69, 0xe0, 0xc1, 0xcf, - 0x01, 0x1c, 0x3b, 0xe2, 0x5f, 0x0b, 0xc4, 0xa9, 0x1b, 0x91, 0x5a, 0xba, 0x5a, 0x4a, 0x3a, 0x4e, - 0xb0, 0x4b, 0x61, 0x0c, 0xd6, 0xce, 0xd0, 0xbe, 0xb3, 0x2d, 0xdc, 0xcf, 0xc0, 0xad, 0x31, 0xdc, - 0x4b, 0x76, 0x29, 0xdc, 0x00, 0x35, 0xc1, 0x4e, 0x90, 0xf3, 0xc7, 0x35, 0x79, 0x35, 0xad, 0x0a, - 0x76, 0xd2, 0xb1, 0x67, 0x88, 0xc0, 0x9d, 0xf3, 0xa6, 0xb5, 0x8d, 0x2a, 0x74, 0xf6, 0x67, 0x31, - 0xef, 0x91, 0x78, 0xf2, 0x19, 0x8b, 0x27, 0x1e, 0xae, 0x62, 0x2b, 0xf6, 0x5e, 0xb9, 0x44, 0xa4, - 0x6b, 0xd3, 0xae, 0xfa, 0xec, 0x0c, 0x40, 0x74, 0x66, 0x40, 0x0a, 0xcd, 0x84, 0xce, 0x75, 0xb0, - 0xe1, 0xbb, 0x3c, 0xfe, 0x4f, 0x1b, 0x25, 0xcd, 0x9b, 0x19, 0x17, 0x6d, 0xfa, 0x1e, 0xfe, 0x02, - 0x56, 0x87, 0xd8, 0xe4, 0xca, 0xf5, 0x1d, 0x26, 0x2f, 0x99, 0xd1, 0xd1, 0x8d, 0xe6, 0x7c, 0x7b, - 0x69, 0xfb, 0xfe, 0xac, 0x8a, 0xfc, 0x18, 0x38, 0x47, 0x07, 0x9d, 0x7d, 0xc7, 0x0a, 0xc5, 0xb9, - 0x59, 0x2a, 0xf3, 0xb7, 0xb6, 0xb1, 0x6f, 0x72, 0xc1, 0x0d, 0xc7, 0x19, 0x2a, 0x70, 0x86, 0x34, - 0x33, 0x51, 0xd5, 0xa9, 0x6f, 0x4e, 0xfa, 0x6b, 0x17, 0x41, 0x7c, 0x84, 0x33, 0x4e, 0xb1, 0x91, - 0xea, 0xf9, 0x88, 0x62, 0xc3, 0x82, 0xc6, 0x95, 0x40, 0x3f, 0xc2, 0xd9, 0x01, 0x33, 0xd0, 0x80, - 0xf5, 0x01, 0xb3, 0x51, 0x23, 0x23, 0xad, 0x46, 0xcd, 0x0c, 0xca, 0x1d, 0xde, 0x96, 0xb3, 0xe6, - 0x54, 0x6f, 0xcf, 0xf2, 0xfc, 0x89, 0x63, 0x1f, 0xca, 0x23, 0xc7, 0xf5, 0xa6, 0x76, 0xbb, 0xc1, - 0x58, 0x7d, 0x70, 0x99, 0x94, 0xc2, 0x53, 0xf0, 0x91, 0xcc, 0x8d, 0x36, 0xd8, 0x0f, 0x28, 0x95, - 0x27, 0xc2, 0xbe, 0x3d, 0x48, 0x67, 0x58, 0x0f, 0xb8, 0xe8, 0x47, 0xc0, 0x19, 0x4e, 0x66, 0x19, - 0xde, 0x3b, 0x53, 0xd0, 0x0d, 0xfc, 0x60, 0x75, 0x43, 0x5e, 0x14, 0x1d, 0x04, 0xcd, 0x50, 0x81, - 0x68, 0xc4, 0xbc, 0xd9, 0xf1, 0xd3, 0x54, 0x16, 0x6a, 0xc9, 0xb5, 0xc2, 0xcc, 0x70, 0x3b, 0x81, - 0xe3, 0xeb, 0xd1, 0xc5, 0x06, 0x3f, 0xe5, 0xba, 0xac, 0x56, 0x3d, 0x68, 0x9e, 0x06, 0x69, 0xf8, - 0x5b, 0x05, 0x34, 0x32, 0xac, 0xcd, 0xf4, 0xde, 0x70, 0x6b, 0x07, 0xf9, 0x0c, 0x45, 0xcb, 0xce, - 0xf4, 0x57, 0xb3, 0x4c, 0x3f, 0xc5, 0xda, 0x4c, 0x2e, 0x94, 0x1d, 0xcb, 0xf7, 0xe9, 0x2f, 0x03, - 0xcf, 0xae, 0x86, 0xc0, 0x3a, 0x58, 0x1c, 0x29, 0xd6, 0xe9, 0x1c, 0x45, 0x2b, 0x6e, 0xfc, 0xc2, - 0xa9, 0xf5, 0x02, 0xd4, 0x2f, 0xaf, 0xa1, 0x65, 0x04, 0xef, 0xec, 0x9b, 0xb2, 0x90, 0x86, 0x13, - 0x6c, 0x83, 0xd5, 0x0b, 0x9d, 0x72, 0xcd, 0x21, 0x3e, 0x28, 0xa6, 0xea, 0xdc, 0x7a, 0x0e, 0xd6, - 0x2e, 0x29, 0x13, 0xfc, 0x06, 0x6c, 0x14, 0x65, 0x73, 0x4e, 0xcc, 0xa3, 0x5d, 0x82, 0x4c, 0xfb, - 0x17, 0xac, 0x96, 0xde, 0x1d, 0x43, 0xc6, 0x23, 0xf6, 0xc8, 0x03, 0x5a, 0x5f, 0x82, 0x8d, 0xa7, - 0xb3, 0x23, 0x9d, 0xf0, 0x7b, 0xbe, 0xf4, 0xbb, 0x65, 0xc0, 0xad, 0x0b, 0x73, 0x06, 0x6f, 0x83, - 0xeb, 0x85, 0x26, 0xbb, 0x34, 0xc4, 0xe8, 0x0f, 0x70, 0x17, 0xac, 0xf8, 0xc9, 0x33, 0xa7, 0x6e, - 0x2b, 0xba, 0xf8, 0x96, 0xb6, 0xd7, 0x2f, 0x2c, 0x8f, 0xc3, 0xf2, 0xff, 0xc4, 0x6f, 0x8f, 0x57, - 0x76, 0x7b, 0x2c, 0x97, 0x54, 0x2b, 0x6c, 0xf5, 0x40, 0xfd, 0xf2, 0xa6, 0x81, 0x4f, 0xc0, 0x42, - 0xc6, 0xb5, 0xf5, 0x72, 0xde, 0xbf, 0x40, 0xff, 0xa7, 0xed, 0x42, 0xc9, 0x9d, 0x86, 0x9d, 0x67, - 0xaf, 0xdf, 0x36, 0x2a, 0x6f, 0xde, 0x36, 0x2a, 0xff, 0xbc, 0x6d, 0x54, 0x5e, 0xbd, 0x6b, 0xcc, - 0xbd, 0x79, 0xd7, 0x98, 0xfb, 0xf3, 0x5d, 0x63, 0xee, 0xc5, 0xc3, 0x3e, 0x37, 0x83, 0xbc, 0x17, - 0x13, 0x39, 0x4c, 0x88, 0xd4, 0x43, 0xa9, 0x93, 0x33, 0x33, 0xf7, 0xc7, 0x7f, 0x62, 0xc5, 0x83, - 0xe4, 0x57, 0xf7, 0x3b, 0xe6, 0xfe, 0x1e, 0x7b, 0x8b, 0x2e, 0xbe, 0x07, 0xff, 0x06, 0x00, 0x00, - 0xff, 0xff, 0xd1, 0x28, 0xd8, 0xb6, 0xab, 0x0a, 0x00, 0x00, -} - -func (m *Params) Marshal() (dAtA []byte, err error) { + // 1182 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x56, 0x4f, 0x53, 0x1b, 0x37, + 0x14, 0xc7, 0x81, 0x10, 0x5b, 0x40, 0x42, 0x04, 0x71, 0x37, 0x30, 0x35, 0x8e, 0xdb, 0xce, 0x78, + 0xda, 0x66, 0xb7, 0x21, 0xe9, 0x74, 0xa6, 0x87, 0xce, 0x04, 0xd3, 0x14, 0x3a, 0x69, 0xa0, 0x0b, + 0xe1, 0x90, 0xce, 0x54, 0x23, 0x4b, 0xc2, 0xd6, 0x64, 0x2d, 0x79, 0x24, 0xed, 0x52, 0xae, 0x3d, + 0xf7, 0x90, 0x63, 0x3f, 0x52, 0x8e, 0x39, 0xe6, 0xd4, 0x76, 0x92, 0x2f, 0xd2, 0xd1, 0x9f, 0x35, + 0x76, 0x00, 0x97, 0xde, 0x56, 0x7a, 0xbf, 0xdf, 0xfb, 0xff, 0xf4, 0x16, 0x7c, 0xc5, 0x85, 0x61, + 0x8a, 0xf4, 0x31, 0x17, 0x48, 0x33, 0x92, 0x2b, 0x6e, 0x4e, 0x13, 0x42, 0x8a, 0xa4, 0x78, 0x90, + 0xe8, 0x3e, 0x56, 0x8c, 0x22, 0x22, 0x85, 0xce, 0x07, 0x4c, 0xc5, 0x43, 0x25, 0x8d, 0x84, 0x6b, + 0x17, 0x30, 0x62, 0x42, 0x8a, 0xb8, 0x78, 0xb0, 0xb6, 0x6e, 0x98, 0xa0, 0x4c, 0x0d, 0xb8, 0x30, + 0x09, 0xee, 0x12, 0x9e, 0x98, 0xd3, 0x21, 0xd3, 0x9e, 0xb8, 0x96, 0xf0, 0x2e, 0x49, 0x32, 0xde, + 0xeb, 0x1b, 0x92, 0x71, 0x26, 0x8c, 0x4e, 0xc6, 0xd0, 0xc5, 0x83, 0xb1, 0x53, 0x20, 0xdc, 0xb3, + 0x04, 0x22, 0x15, 0x4b, 0x48, 0x1f, 0x0b, 0xc1, 0x32, 0x8b, 0x0a, 0x9f, 0x01, 0xd2, 0xe8, 0x49, + 0xd9, 0xcb, 0x58, 0xe2, 0x4e, 0xdd, 0xfc, 0x38, 0xa1, 0xb9, 0xc2, 0x86, 0x4b, 0x11, 0xe4, 0xab, + 0x3d, 0xd9, 0x93, 0xee, 0x33, 0xb1, 0x5f, 0xe1, 0xf6, 0xb3, 0x29, 0x41, 0x9f, 0x70, 0xc5, 0x02, + 0x6c, 0xe3, 0x43, 0xe5, 0x86, 0x0f, 0x98, 0x36, 0x78, 0x30, 0xf4, 0x80, 0xd6, 0x1f, 0xf3, 0xe0, + 0x66, 0x27, 0x64, 0x67, 0x1f, 0x2b, 0x3c, 0xd0, 0x30, 0x02, 0x37, 0x98, 0xc0, 0xdd, 0x8c, 0xd1, + 0xa8, 0xd2, 0xac, 0xb4, 0xab, 0x69, 0x79, 0x84, 0x7b, 0xe0, 0xd3, 0x6e, 0x26, 0xc9, 0x4b, 0x8d, + 0x86, 0x4c, 0x21, 0xca, 0xb5, 0x51, 0xbc, 0x9b, 0x5b, 0x5f, 0x91, 0x51, 0x58, 0xe8, 0x01, 0xd7, + 0x9a, 0x4b, 0x11, 0x5d, 0x6b, 0x56, 0xda, 0xb3, 0xe9, 0x3d, 0x8f, 0xdd, 0x67, 0x6a, 0x7b, 0x0c, + 0x79, 0x38, 0x06, 0x84, 0x3f, 0x82, 0x7b, 0x97, 0x6a, 0x41, 0x21, 0x4d, 0xd1, 0x6c, 0xb3, 0xd2, + 0xae, 0xa5, 0x1b, 0xf4, 0x12, 0x25, 0x1d, 0x0f, 0x83, 0xdf, 0x82, 0xb5, 0xa1, 0x92, 0x05, 0xa7, + 0x4c, 0xa1, 0x63, 0xc6, 0xd0, 0x50, 0xca, 0x0c, 0x61, 0x4a, 0x15, 0xd2, 0x46, 0x45, 0x73, 0x4e, + 0x49, 0xbd, 0x44, 0x3c, 0x61, 0x6c, 0x5f, 0xca, 0xec, 0x31, 0xa5, 0xea, 0xc0, 0x28, 0xf8, 0x33, + 0x80, 0x84, 0x14, 0xc8, 0x26, 0x47, 0xe6, 0xc6, 0x46, 0xc7, 0x25, 0x8d, 0xae, 0x37, 0x2b, 0xed, + 0x85, 0xcd, 0xbb, 0xb1, 0xcf, 0x61, 0x5c, 0xe6, 0x30, 0xde, 0x0e, 0x05, 0xda, 0xaa, 0xbe, 0xfe, + 0x6b, 0x63, 0xe6, 0xcf, 0xbf, 0x37, 0x2a, 0xe9, 0x32, 0x21, 0xc5, 0xa1, 0x67, 0xef, 0x3b, 0x32, + 0xfc, 0x05, 0x7c, 0xe4, 0xa2, 0x39, 0x66, 0xea, 0x43, 0xbd, 0xf3, 0x57, 0xd7, 0x7b, 0xa7, 0xd4, + 0x31, 0xa9, 0x7c, 0x07, 0x34, 0xcb, 0x96, 0x46, 0x8a, 0x4d, 0xa4, 0xf0, 0x58, 0x61, 0x62, 0x3f, + 0xa2, 0x1b, 0x2e, 0xe2, 0x46, 0x89, 0x4b, 0x27, 0x60, 0x4f, 0x02, 0x0a, 0xde, 0x07, 0xb0, 0xcf, + 0xb5, 0x91, 0x8a, 0x13, 0x9c, 0x21, 0x26, 0x8c, 0xe2, 0x4c, 0x47, 0x55, 0x57, 0xc0, 0xdb, 0x67, + 0x92, 0xef, 0xbd, 0x00, 0x3e, 0x03, 0xcb, 0xb9, 0xe8, 0x4a, 0x41, 0xb9, 0xe8, 0x95, 0xe1, 0xd4, + 0xae, 0x1e, 0xce, 0xad, 0x11, 0x39, 0x04, 0xf2, 0x10, 0xd4, 0xb5, 0x3c, 0x36, 0x48, 0x0e, 0x0d, + 0xb2, 0x19, 0x32, 0x7d, 0xc5, 0x74, 0x5f, 0x66, 0x34, 0x02, 0xce, 0xfd, 0x15, 0x2b, 0xdd, 0x1b, + 0x9a, 0xbd, 0xdc, 0x1c, 0x96, 0x22, 0xf8, 0x09, 0x58, 0x52, 0xec, 0x04, 0x2b, 0x8a, 0x28, 0x13, + 0x72, 0xa0, 0xa3, 0x85, 0xe6, 0x6c, 0xbb, 0x96, 0x2e, 0xfa, 0xcb, 0x6d, 0x77, 0x07, 0x1f, 0x81, + 0x51, 0xb1, 0xd1, 0x24, 0x7a, 0xd1, 0xa1, 0x57, 0x4b, 0x69, 0x3a, 0xc6, 0x6a, 0xbd, 0xad, 0x82, + 0xd5, 0x72, 0x1c, 0x7e, 0x60, 0x82, 0x69, 0xae, 0x0f, 0x0c, 0x36, 0x0c, 0xee, 0x80, 0xf9, 0xa1, + 0x1b, 0x0f, 0x37, 0x13, 0x0b, 0x9b, 0x9f, 0xc7, 0x97, 0xbf, 0x21, 0xf1, 0xe4, 0x40, 0x6d, 0xcd, + 0xd9, 0xf8, 0xd3, 0xc0, 0x87, 0x5f, 0x02, 0x38, 0x72, 0xcc, 0xbf, 0x22, 0x88, 0x53, 0x37, 0x32, + 0xb5, 0x74, 0xb9, 0x94, 0x74, 0x9c, 0x60, 0x97, 0xc2, 0x18, 0xac, 0x9c, 0xa1, 0x7d, 0xa7, 0x5b, + 0xb8, 0x9f, 0x89, 0xdb, 0x23, 0xb8, 0x97, 0xec, 0x52, 0xb8, 0x0e, 0x6a, 0x82, 0x9d, 0x20, 0xe7, + 0x97, 0x6b, 0xfa, 0x6a, 0x5a, 0x15, 0xec, 0xa4, 0x63, 0xcf, 0x10, 0x81, 0x3b, 0x1f, 0x9a, 0xd6, + 0x36, 0xba, 0xd0, 0xe9, 0x5f, 0xc4, 0xbc, 0x4b, 0xe2, 0xf1, 0xe7, 0x2d, 0x1e, 0x7b, 0xd0, 0x6c, + 0x5c, 0xee, 0xd6, 0x25, 0x24, 0x5d, 0x99, 0x74, 0xd5, 0x67, 0xa9, 0x0f, 0xa2, 0x33, 0x03, 0x52, + 0x68, 0x26, 0x74, 0xae, 0x83, 0x0d, 0xdf, 0xf5, 0xf1, 0x7f, 0xda, 0x28, 0x69, 0xde, 0xcc, 0xa8, + 0x88, 0x93, 0xf7, 0xf0, 0x57, 0xb0, 0x3c, 0xc0, 0x26, 0x57, 0xae, 0x0f, 0x31, 0x79, 0xc9, 0x8c, + 0x8e, 0x6e, 0x34, 0x67, 0xdb, 0x0b, 0x9b, 0xf7, 0xa7, 0x55, 0xe6, 0xa7, 0xc0, 0x39, 0x3a, 0xe8, + 0xec, 0x3b, 0x56, 0x28, 0xce, 0xad, 0x52, 0x99, 0xbf, 0xb5, 0x8d, 0x7e, 0x8b, 0x0b, 0x6e, 0x38, + 0xce, 0x50, 0x81, 0x33, 0xa4, 0x99, 0x89, 0xaa, 0x4e, 0x7d, 0x73, 0xdc, 0x5f, 0xbb, 0x20, 0xe2, + 0x23, 0x9c, 0x71, 0x8a, 0x8d, 0x54, 0xcf, 0x87, 0x14, 0x1b, 0x16, 0x34, 0x2e, 0x05, 0xfa, 0x11, + 0xce, 0x0e, 0x98, 0x81, 0x06, 0xac, 0xf5, 0x99, 0x8d, 0x1a, 0x19, 0x69, 0x35, 0x6a, 0x66, 0x50, + 0xee, 0xf0, 0xb6, 0x9c, 0x35, 0xa7, 0x7a, 0x73, 0x9a, 0xe7, 0x3b, 0x8e, 0x7d, 0x28, 0x8f, 0x1c, + 0xd7, 0x9b, 0xda, 0xdd, 0x0e, 0xc6, 0xea, 0xfd, 0x8b, 0xa4, 0x14, 0x9e, 0x82, 0x8f, 0x65, 0x6e, + 0xb4, 0xc1, 0x7e, 0x60, 0xa9, 0x3c, 0x11, 0xf6, 0x2d, 0x42, 0x3a, 0xc3, 0xba, 0xcf, 0x45, 0x2f, + 0x02, 0xce, 0x70, 0x32, 0xcd, 0xf0, 0xde, 0x99, 0x82, 0xed, 0xc0, 0x0f, 0x56, 0xd7, 0xe5, 0x79, + 0xd1, 0x41, 0xd0, 0x0c, 0x15, 0x88, 0x86, 0xcc, 0x9b, 0x1d, 0x3d, 0x55, 0x65, 0xa1, 0x16, 0x5c, + 0x2b, 0x6c, 0x5e, 0x6d, 0x84, 0x2c, 0x65, 0x1b, 0x1b, 0xfc, 0x94, 0xeb, 0xb2, 0x5a, 0xf5, 0xa0, + 0x79, 0x12, 0xa4, 0xe1, 0xef, 0x15, 0xd0, 0xc8, 0xb0, 0x36, 0x93, 0x7b, 0xc4, 0xad, 0x21, 0xe4, + 0x33, 0x14, 0x2d, 0x3a, 0xd3, 0xdf, 0x4c, 0x33, 0xfd, 0x14, 0x6b, 0x33, 0xbe, 0x60, 0xb6, 0x2c, + 0xdf, 0xa7, 0xbf, 0x0c, 0x3c, 0xbb, 0x1c, 0x02, 0xeb, 0x60, 0x7e, 0xa8, 0x58, 0xa7, 0x73, 0x14, + 0x2d, 0xb9, 0xf1, 0x0b, 0xa7, 0xd6, 0x0b, 0x50, 0xbf, 0xb8, 0x86, 0x96, 0x11, 0xbc, 0xb3, 0x6f, + 0xcb, 0x5c, 0x1a, 0x4e, 0xb0, 0x0d, 0x96, 0xcf, 0x75, 0xca, 0x35, 0x87, 0xb8, 0x59, 0x4c, 0xd4, + 0xb9, 0xf5, 0x1c, 0xac, 0x5c, 0x50, 0x26, 0xf8, 0x1d, 0x58, 0x2f, 0xca, 0xe6, 0x1c, 0x9b, 0x47, + 0xbb, 0x14, 0x99, 0xf6, 0x2f, 0x59, 0x2d, 0xbd, 0x3b, 0x82, 0x8c, 0x46, 0xec, 0xb1, 0x07, 0xb4, + 0xbe, 0x06, 0xeb, 0x4f, 0xa7, 0x47, 0x3a, 0xe6, 0xf7, 0x6c, 0xe9, 0x77, 0xcb, 0x80, 0xdb, 0xe7, + 0xe6, 0x0c, 0xae, 0x82, 0xeb, 0x85, 0x26, 0xbb, 0x34, 0xc4, 0xe8, 0x0f, 0x70, 0x17, 0x2c, 0xf9, + 0xc9, 0x33, 0xa7, 0x6e, 0x4b, 0xba, 0xf8, 0x16, 0x36, 0xd7, 0xce, 0x2d, 0x93, 0xc3, 0xf2, 0xbf, + 0xc5, 0x6f, 0x93, 0x57, 0x76, 0x9b, 0x2c, 0x96, 0x54, 0x2b, 0x6c, 0x75, 0x41, 0xfd, 0xe2, 0xa6, + 0x81, 0x3b, 0x60, 0x2e, 0xe3, 0xda, 0x7a, 0x39, 0xeb, 0x5f, 0xa0, 0xff, 0xd3, 0x76, 0xa1, 0xe4, + 0x4e, 0xc3, 0xd6, 0xb3, 0xd7, 0xef, 0x1a, 0x95, 0x37, 0xef, 0x1a, 0x95, 0x7f, 0xde, 0x35, 0x2a, + 0xaf, 0xde, 0x37, 0x66, 0xde, 0xbc, 0x6f, 0xcc, 0xbc, 0x7d, 0xdf, 0x98, 0x79, 0xf1, 0xa8, 0xc7, + 0x4d, 0x3f, 0xef, 0xc6, 0x44, 0x0e, 0x12, 0x22, 0xf5, 0x40, 0xea, 0xe4, 0xcc, 0xcc, 0xfd, 0xd1, + 0x1f, 0x5a, 0xf1, 0x30, 0xf9, 0xcd, 0xfd, 0xa6, 0xb9, 0xbf, 0xca, 0xee, 0xbc, 0x8b, 0xef, 0xe1, + 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xe0, 0xb5, 0xe5, 0x15, 0xc3, 0x0a, 0x00, 0x00, +} + +func (m *ConsumerParams) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -708,12 +704,12 @@ func (m *Params) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *Params) MarshalTo(dAtA []byte) (int, error) { +func (m *ConsumerParams) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *ConsumerParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -811,7 +807,7 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *GenesisState) Marshal() (dAtA []byte, err error) { +func (m *ConsumerGenesisState) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -821,12 +817,12 @@ func (m *GenesisState) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *GenesisState) MarshalTo(dAtA []byte) (int, error) { +func (m *ConsumerGenesisState) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *ConsumerGenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -1153,7 +1149,7 @@ func encodeVarintSharedConsumer(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } -func (m *Params) Size() (n int) { +func (m *ConsumerParams) Size() (n int) { if m == nil { return 0 } @@ -1205,7 +1201,7 @@ func (m *Params) Size() (n int) { return n } -func (m *GenesisState) Size() (n int) { +func (m *ConsumerGenesisState) Size() (n int) { if m == nil { return 0 } @@ -1341,7 +1337,7 @@ func sovSharedConsumer(x uint64) (n int) { func sozSharedConsumer(x uint64) (n int) { return sovSharedConsumer(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } -func (m *Params) Unmarshal(dAtA []byte) error { +func (m *ConsumerParams) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1364,10 +1360,10 @@ func (m *Params) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: Params: wiretype end group for non-group") + return fmt.Errorf("proto: ConsumerParams: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: ConsumerParams: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -1740,7 +1736,7 @@ func (m *Params) Unmarshal(dAtA []byte) error { } return nil } -func (m *GenesisState) Unmarshal(dAtA []byte) error { +func (m *ConsumerGenesisState) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1763,10 +1759,10 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: GenesisState: wiretype end group for non-group") + return fmt.Errorf("proto: ConsumerGenesisState: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: ConsumerGenesisState: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: From ee48da4e0460711406867e63f068f34ec1a7b63f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 17 Sep 2023 23:09:18 -0700 Subject: [PATCH 119/134] build(deps): bump google.golang.org/grpc from 1.58.0 to 1.58.1 (#1306) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.58.0 to 1.58.1. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.58.0...v1.58.1) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 3fc1b177b7..1f05100cd2 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( golang.org/x/net v0.12.0 // indirect golang.org/x/sys v0.11.0 // indirect google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 // indirect - google.golang.org/grpc v1.58.0 + google.golang.org/grpc v1.58.1 google.golang.org/protobuf v1.31.0 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index 033aa8adf2..2246f9decf 100644 --- a/go.sum +++ b/go.sum @@ -1813,8 +1813,8 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.58.0 h1:32JY8YpPMSR45K+c3o6b8VL73V+rR8k+DeMIr4vRH8o= -google.golang.org/grpc v1.58.0/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/grpc v1.58.1 h1:OL+Vz23DTtrrldqHK49FUOPHyY75rvFqJfXC84NYW58= +google.golang.org/grpc v1.58.1/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= From 27ef1d22fb358ce1159f846fc299ac8b02a2f83e Mon Sep 17 00:00:00 2001 From: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Tue, 19 Sep 2023 10:36:51 -0700 Subject: [PATCH 120/134] feat: increment consensus ver and register migration (#1295) * increment consensus ver and register migration * Update CHANGELOG.md * Update migration.go * Update module.go --- CHANGELOG.md | 1 + x/ccv/consumer/keeper/migration.go | 13 +++++++++---- x/ccv/consumer/module.go | 12 ++++++------ 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 032927214a..29b6328e94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ Note: Changes: +* (feat) [#1295](https://github.com/cosmos/interchain-security/pull/1295) increment consumer consensus version and register consumer packet migration. * (fix!) [#1262](https://github.com/cosmos/interchain-security/pull/1262) Remove incorrect address validation on `ProviderFeePoolAddrStr` param. * (feature!) [#1244](https://github.com/cosmos/interchain-security/pull/1244) Update the default consumer unbonding period to 2 weeks. * (fix!) [#1244](https://github.com/cosmos/interchain-security/pull/1244) Validate token transfer messages before calling `Transfer()`. diff --git a/x/ccv/consumer/keeper/migration.go b/x/ccv/consumer/keeper/migration.go index 361bb2a62f..5d5d913b9b 100644 --- a/x/ccv/consumer/keeper/migration.go +++ b/x/ccv/consumer/keeper/migration.go @@ -21,23 +21,27 @@ func NewMigrator(ccvConsumerKeeper Keeper, ccvConsumerParamSpace paramtypes.Subs return Migrator{ccvConsumerKeeper: ccvConsumerKeeper, ccvConsumerParamSpace: ccvConsumerParamSpace} } +// Migrate1to2 migrates x/ccvconsumer state from consensus version 1 to 2. +func (m Migrator) Migrate1to2(ctx sdk.Context) error { + return m.ccvConsumerKeeper.MigrateConsumerPacketData(ctx) +} + // MigrateConsumerPacketData migrates consumer packet data according to // https://github.com/cosmos/interchain-security/pull/1037 // // Note an equivalent migration is not required for providers. -func (k Keeper) MigrateConsumerPacketData(ctx sdk.Context) { +func (k Keeper) MigrateConsumerPacketData(ctx sdk.Context) error { // deserialize packet data from old format var depreciatedType ccvtypes.ConsumerPacketDataList store := ctx.KVStore(k.storeKey) bz := store.Get([]byte{consumertypes.PendingDataPacketsBytePrefix}) if bz == nil { ctx.Logger().Info("no pending data packets to migrate") - return + return nil } err := depreciatedType.Unmarshal(bz) if err != nil { - // An error here would indicate something is very wrong - panic(fmt.Errorf("failed to unmarshal pending data packets: %w", err)) + return fmt.Errorf("failed to unmarshal pending data packets: %w", err) } // Delete old data @@ -48,6 +52,7 @@ func (k Keeper) MigrateConsumerPacketData(ctx sdk.Context) { for _, data := range depreciatedType.List { k.AppendPendingPacket(ctx, data.Type, data.Data) } + return nil } // TODO: the following hackyness could be removed if we're able to reference older versions of ICS. diff --git a/x/ccv/consumer/module.go b/x/ccv/consumer/module.go index e175205530..ba38b01d73 100644 --- a/x/ccv/consumer/module.go +++ b/x/ccv/consumer/module.go @@ -107,6 +107,11 @@ func (AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { // RegisterServices registers module services. func (am AppModule) RegisterServices(cfg module.Configurator) { consumertypes.RegisterQueryServer(cfg.QueryServer(), am.keeper) + + m := keeper.NewMigrator(am.keeper, am.paramSpace) + if err := cfg.RegisterMigration(consumertypes.ModuleName, 1, m.Migrate1to2); err != nil { + panic(fmt.Sprintf("failed to register migrator for %s: %s", consumertypes.ModuleName, err)) + } } // InitGenesis performs genesis initialization for the consumer module. It returns @@ -126,12 +131,7 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.Raw // ConsensusVersion implements AppModule/ConsensusVersion. func (AppModule) ConsensusVersion() uint64 { - // Note that v1.0.0 consumers should technically be on a different consensus version - // than v1.2.0-multiden and v2.0.0. However, Neutron was the first consumer to launch - // in prod, and they've started on v1.2.0-multiden (which has a ConsensusVersion of 1). - // - // v1.2.0-multiden and v2.0.0 are consensus compatible, so they need return the same ConsensusVersion of 1. - return 1 + return 2 } // BeginBlock implements the AppModule interface From 99a171f4fddda9ecdfc6c7e4963b5d3afb8665b1 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Date: Tue, 19 Sep 2023 20:39:11 +0200 Subject: [PATCH 121/134] tests: Export struct fields in the e2e tests (#1313) * Make struct fields in e2e exported * Un-capitalize binary name * Remove prop type * Channel to channel in comments --- tests/e2e/actions.go | 995 +++++++++--------- tests/e2e/actions_sovereign_chain.go | 84 +- tests/e2e/config.go | 350 +++--- tests/e2e/main.go | 20 +- tests/e2e/state.go | 180 ++-- tests/e2e/step_delegation.go | 452 ++++---- tests/e2e/steps.go | 8 +- tests/e2e/steps_democracy.go | 314 +++--- tests/e2e/steps_double_sign.go | 152 +-- tests/e2e/steps_downtime.go | 512 ++++----- tests/e2e/steps_light_client_attack.go | 164 +-- tests/e2e/steps_multi_consumer_delegation.go | 380 +++---- tests/e2e/steps_multi_consumer_double_sign.go | 280 ++--- tests/e2e/steps_multi_consumer_downtime.go | 518 ++++----- tests/e2e/steps_reward_denom.go | 316 +++--- tests/e2e/steps_sovereign_changeover.go | 362 +++---- tests/e2e/steps_start_chains.go | 312 +++--- tests/e2e/steps_stop_chain.go | 96 +- .../e2e/steps_submit_equivocation_proposal.go | 148 +-- 19 files changed, 2824 insertions(+), 2819 deletions(-) diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index 2256156958..36e0c47dd2 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -23,10 +23,10 @@ import ( ) type SendTokensAction struct { - chain chainID - from validatorID - to validatorID - amount uint + Chain ChainID + From ValidatorID + To ValidatorID + Amount uint } const done = "done!!!!!!!!" @@ -35,18 +35,18 @@ func (tr TestRun) sendTokens( action SendTokensAction, verbose bool, ) { - binaryName := tr.chainConfigs[action.chain].binaryName + binaryName := tr.chainConfigs[action.Chain].BinaryName //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, binaryName, + cmd := exec.Command("docker", "exec", tr.containerConfig.InstanceName, binaryName, "tx", "bank", "send", - tr.validatorConfigs[action.from].delAddress, - tr.validatorConfigs[action.to].delAddress, - fmt.Sprint(action.amount)+`stake`, + tr.validatorConfigs[action.From].DelAddress, + tr.validatorConfigs[action.To].DelAddress, + fmt.Sprint(action.Amount)+`stake`, - `--chain-id`, string(tr.chainConfigs[action.chain].chainId), - `--home`, tr.getValidatorHome(action.chain, action.from), - `--node`, tr.getValidatorNode(action.chain, action.from), + `--chain-id`, string(tr.chainConfigs[action.Chain].ChainId), + `--home`, tr.getValidatorHome(action.Chain, action.From), + `--node`, tr.getValidatorNode(action.Chain, action.From), `--keyring-backend`, `test`, `-y`, ) @@ -59,28 +59,28 @@ func (tr TestRun) sendTokens( } // wait for inclusion in a block -> '--broadcast-mode block' is deprecated - tr.waitBlocks(action.chain, 2, 30*time.Second) + tr.waitBlocks(action.Chain, 2, 30*time.Second) } type StartChainAction struct { - chain chainID - validators []StartChainValidator + Chain ChainID + Validators []StartChainValidator // Genesis changes specific to this action, appended to genesis changes defined in chain config - genesisChanges string - skipGentx bool + GenesisChanges string + SkipGentx bool } type StartChainValidator struct { - id validatorID - allocation uint - stake uint + Id ValidatorID + Allocation uint + Stake uint } func (tr *TestRun) startChain( action StartChainAction, verbose bool, ) { - chainConfig := tr.chainConfigs[action.chain] + chainConfig := tr.chainConfigs[action.Chain] type jsonValAttrs struct { Mnemonic string `json:"mnemonic"` Allocation string `json:"allocation"` @@ -96,20 +96,20 @@ func (tr *TestRun) startChain( } var validators []jsonValAttrs - for _, val := range action.validators { + for _, val := range action.Validators { validators = append(validators, jsonValAttrs{ - Mnemonic: tr.validatorConfigs[val.id].mnemonic, - NodeKey: tr.validatorConfigs[val.id].nodeKey, - ValId: fmt.Sprint(val.id), - PrivValidatorKey: tr.validatorConfigs[val.id].privValidatorKey, - Allocation: fmt.Sprint(val.allocation) + "stake", - Stake: fmt.Sprint(val.stake) + "stake", - IpSuffix: tr.validatorConfigs[val.id].ipSuffix, - - ConsumerMnemonic: tr.validatorConfigs[val.id].consumerMnemonic, - ConsumerPrivValidatorKey: tr.validatorConfigs[val.id].consumerPrivValidatorKey, + Mnemonic: tr.validatorConfigs[val.Id].Mnemonic, + NodeKey: tr.validatorConfigs[val.Id].NodeKey, + ValId: fmt.Sprint(val.Id), + PrivValidatorKey: tr.validatorConfigs[val.Id].PrivValidatorKey, + Allocation: fmt.Sprint(val.Allocation) + "stake", + Stake: fmt.Sprint(val.Stake) + "stake", + IpSuffix: tr.validatorConfigs[val.Id].IpSuffix, + + ConsumerMnemonic: tr.validatorConfigs[val.Id].ConsumerMnemonic, + ConsumerPrivValidatorKey: tr.validatorConfigs[val.Id].ConsumerPrivValidatorKey, // if true node will be started with consumer key for each consumer chain - StartWithConsumerKey: tr.validatorConfigs[val.id].useConsumerKey, + StartWithConsumerKey: tr.validatorConfigs[val.Id].UseConsumerKey, }) } @@ -120,10 +120,10 @@ func (tr *TestRun) startChain( // Concat genesis changes defined in chain config, with any custom genesis changes for this chain instantiation var genesisChanges string - if action.genesisChanges != "" { - genesisChanges = chainConfig.genesisChanges + " | " + action.genesisChanges + if action.GenesisChanges != "" { + genesisChanges = chainConfig.GenesisChanges + " | " + action.GenesisChanges } else { - genesisChanges = chainConfig.genesisChanges + genesisChanges = chainConfig.GenesisChanges } var cometmockArg string @@ -134,10 +134,10 @@ func (tr *TestRun) startChain( } //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, "/bin/bash", - "/testnet-scripts/start-chain.sh", chainConfig.binaryName, string(vals), - string(chainConfig.chainId), chainConfig.ipPrefix, genesisChanges, - fmt.Sprint(action.skipGentx), + cmd := exec.Command("docker", "exec", tr.containerConfig.InstanceName, "/bin/bash", + "/testnet-scripts/start-chain.sh", chainConfig.BinaryName, string(vals), + string(chainConfig.ChainId), chainConfig.IpPrefix, genesisChanges, + fmt.Sprint(action.SkipGentx), // override config/config.toml for each node on chain // usually timeout_commit and peer_gossip_sleep_duration are changed to vary the test run duration // lower timeout_commit means the blocks are produced faster making the test run shorter @@ -172,25 +172,25 @@ func (tr *TestRun) startChain( } tr.addChainToRelayer(addChainToRelayerAction{ - chain: action.chain, - validator: action.validators[0].id, + Chain: action.Chain, + Validator: action.Validators[0].Id, }, verbose) // store the fact that we started the chain - tr.runningChains[action.chain] = true - fmt.Println("Started chain", action.chain) + tr.runningChains[action.Chain] = true + fmt.Println("Started chain", action.Chain) if tr.timeOffset != 0 { // advance time for this chain so that it is in sync with the rest of the network - tr.AdvanceTimeForChain(action.chain, tr.timeOffset) + tr.AdvanceTimeForChain(action.Chain, tr.timeOffset) } } type submitTextProposalAction struct { - chain chainID - from validatorID - deposit uint - title string - description string + Chain ChainID + From ValidatorID + Deposit uint + Title string + Description string } func (tr TestRun) submitTextProposal( @@ -199,15 +199,15 @@ func (tr TestRun) submitTextProposal( ) { // TEXT PROPOSAL //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - bz, err := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[action.chain].binaryName, + bz, err := exec.Command("docker", "exec", tr.containerConfig.InstanceName, tr.chainConfigs[action.Chain].BinaryName, "tx", "gov", "submit-legacy-proposal", - `--title`, action.title, - `--description`, action.description, - `--deposit`, fmt.Sprint(action.deposit)+`stake`, - `--from`, `validator`+fmt.Sprint(action.from), - `--chain-id`, string(tr.chainConfigs[action.chain].chainId), - `--home`, tr.getValidatorHome(action.chain, action.from), - `--node`, tr.getValidatorNode(action.chain, action.from), + `--title`, action.Title, + `--description`, action.Description, + `--deposit`, fmt.Sprint(action.Deposit)+`stake`, + `--from`, `validator`+fmt.Sprint(action.From), + `--chain-id`, string(tr.chainConfigs[action.Chain].ChainId), + `--home`, tr.getValidatorHome(action.Chain, action.From), + `--node`, tr.getValidatorNode(action.Chain, action.From), `--keyring-backend`, `test`, `-y`, ).CombinedOutput() @@ -216,31 +216,31 @@ func (tr TestRun) submitTextProposal( } // wait for inclusion in a block -> '--broadcast-mode block' is deprecated - tr.waitBlocks(action.chain, 1, 10*time.Second) + tr.waitBlocks(action.Chain, 1, 10*time.Second) } type submitConsumerAdditionProposalAction struct { - preCCV bool - chain chainID - from validatorID - deposit uint - consumerChain chainID - spawnTime uint - initialHeight clienttypes.Height - distributionChannel string + PreCCV bool + Chain ChainID + From ValidatorID + Deposit uint + ConsumerChain ChainID + SpawnTime uint + InitialHeight clienttypes.Height + DistributionChannel string } func (tr TestRun) submitConsumerAdditionProposal( action submitConsumerAdditionProposalAction, verbose bool, ) { - spawnTime := tr.containerConfig.now.Add(time.Duration(action.spawnTime) * time.Millisecond) + spawnTime := tr.containerConfig.Now.Add(time.Duration(action.SpawnTime) * time.Millisecond) params := ccvtypes.DefaultParams() prop := client.ConsumerAdditionProposalJSON{ Title: "Propose the addition of a new chain", Summary: "Gonna be a great chain", - ChainId: string(tr.chainConfigs[action.consumerChain].chainId), - InitialHeight: action.initialHeight, + ChainId: string(tr.chainConfigs[action.ConsumerChain].ChainId), + InitialHeight: action.InitialHeight, GenesisHash: []byte("gen_hash"), BinaryHash: []byte("bin_hash"), SpawnTime: spawnTime, @@ -250,8 +250,8 @@ func (tr TestRun) submitConsumerAdditionProposal( CcvTimeoutPeriod: params.CcvTimeoutPeriod, TransferTimeoutPeriod: params.TransferTimeoutPeriod, UnbondingPeriod: params.UnbondingPeriod, - Deposit: fmt.Sprint(action.deposit) + `stake`, - DistributionTransmissionChannel: action.distributionChannel, + Deposit: fmt.Sprint(action.Deposit) + `stake`, + DistributionTransmissionChannel: action.DistributionChannel, } bz, err := json.Marshal(prop) @@ -265,7 +265,7 @@ func (tr TestRun) submitConsumerAdditionProposal( } //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - bz, err = exec.Command("docker", "exec", tr.containerConfig.instanceName, + bz, err = exec.Command("docker", "exec", tr.containerConfig.InstanceName, "/bin/bash", "-c", fmt.Sprintf(`echo '%s' > %s`, jsonStr, "/temp-proposal.json")).CombinedOutput() if err != nil { @@ -274,13 +274,13 @@ func (tr TestRun) submitConsumerAdditionProposal( //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. // CONSUMER ADDITION PROPOSAL - bz, err = exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[action.chain].binaryName, + bz, err = exec.Command("docker", "exec", tr.containerConfig.InstanceName, tr.chainConfigs[action.Chain].BinaryName, "tx", "gov", "submit-legacy-proposal", "consumer-addition", "/temp-proposal.json", - `--from`, `validator`+fmt.Sprint(action.from), - `--chain-id`, string(tr.chainConfigs[action.chain].chainId), - `--home`, tr.getValidatorHome(action.chain, action.from), + `--from`, `validator`+fmt.Sprint(action.From), + `--chain-id`, string(tr.chainConfigs[action.Chain].ChainId), + `--home`, tr.getValidatorHome(action.Chain, action.From), `--gas`, `900000`, - `--node`, tr.getValidatorNode(action.chain, action.from), + `--node`, tr.getValidatorNode(action.Chain, action.From), `--keyring-backend`, `test`, `-y`, ).CombinedOutput() @@ -290,28 +290,28 @@ func (tr TestRun) submitConsumerAdditionProposal( } // wait for inclusion in a block -> '--broadcast-mode block' is deprecated - tr.waitBlocks(chainID("provi"), 2, 10*time.Second) + tr.waitBlocks(ChainID("provi"), 2, 10*time.Second) } type submitConsumerRemovalProposalAction struct { - chain chainID - from validatorID - deposit uint - consumerChain chainID - stopTimeOffset time.Duration // offset from time.Now() + Chain ChainID + From ValidatorID + Deposit uint + ConsumerChain ChainID + StopTimeOffset time.Duration // offset from time.Now() } func (tr TestRun) submitConsumerRemovalProposal( action submitConsumerRemovalProposalAction, verbose bool, ) { - stopTime := tr.containerConfig.now.Add(action.stopTimeOffset) + stopTime := tr.containerConfig.Now.Add(action.StopTimeOffset) prop := client.ConsumerRemovalProposalJSON{ - Title: fmt.Sprintf("Stop the %v chain", action.consumerChain), + Title: fmt.Sprintf("Stop the %v chain", action.ConsumerChain), Summary: "It was a great chain", - ChainId: string(tr.chainConfigs[action.consumerChain].chainId), + ChainId: string(tr.chainConfigs[action.ConsumerChain].ChainId), StopTime: stopTime, - Deposit: fmt.Sprint(action.deposit) + `stake`, + Deposit: fmt.Sprint(action.Deposit) + `stake`, } bz, err := json.Marshal(prop) @@ -325,7 +325,7 @@ func (tr TestRun) submitConsumerRemovalProposal( } //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - bz, err = exec.Command("docker", "exec", tr.containerConfig.instanceName, + bz, err = exec.Command("docker", "exec", tr.containerConfig.InstanceName, "/bin/bash", "-c", fmt.Sprintf(`echo '%s' > %s`, jsonStr, "/temp-proposal.json")).CombinedOutput() if err != nil { @@ -333,13 +333,14 @@ func (tr TestRun) submitConsumerRemovalProposal( } //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - // CONSUMER REMOVAL PROPOSAL - bz, err = exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[action.chain].binaryName, - "tx", "gov", "submit-legacy-proposal", "consumer-removal", "/temp-proposal.json", - `--from`, `validator`+fmt.Sprint(action.from), - `--chain-id`, string(tr.chainConfigs[action.chain].chainId), - `--home`, tr.getValidatorHome(action.chain, action.from), - `--node`, tr.getValidatorNode(action.chain, action.from), + bz, err = exec.Command("docker", "exec", tr.containerConfig.InstanceName, tr.chainConfigs[action.Chain].BinaryName, + + "tx", "gov", "submit-legacy-proposal", "consumer-removal", + "/temp-proposal.json", + `--from`, `validator`+fmt.Sprint(action.From), + `--chain-id`, string(tr.chainConfigs[action.Chain].ChainId), + `--home`, tr.getValidatorHome(action.Chain, action.From), + `--node`, tr.getValidatorNode(action.Chain, action.From), `--gas`, "900000", `--keyring-backend`, `test`, `-y`, @@ -350,16 +351,16 @@ func (tr TestRun) submitConsumerRemovalProposal( } // wait for inclusion in a block -> '--broadcast-mode block' is deprecated - tr.waitBlocks(chainID("provi"), 2, 20*time.Second) + tr.waitBlocks(ChainID("provi"), 2, 20*time.Second) } type submitParamChangeLegacyProposalAction struct { - chain chainID - from validatorID - deposit uint - subspace string - key string - value interface{} + Chain ChainID + From ValidatorID + Deposit uint + Subspace string + Key string + Value interface{} } type paramChangeProposalJSON struct { @@ -384,8 +385,8 @@ func (tr TestRun) submitParamChangeProposal( Title: "Legacy Param change", Summary: "Changing legacy module params", Description: "Changing legacy module params", - Changes: []paramChangeJSON{{Subspace: action.subspace, Key: action.key, Value: action.value}}, - Deposit: fmt.Sprint(action.deposit) + `stake`, + Changes: []paramChangeJSON{{Subspace: action.Subspace, Key: action.Key, Value: action.Value}}, + Deposit: fmt.Sprint(action.Deposit) + `stake`, } bz, err := json.Marshal(prop) @@ -399,7 +400,7 @@ func (tr TestRun) submitParamChangeProposal( } //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - bz, err = exec.Command("docker", "exec", tr.containerConfig.instanceName, + bz, err = exec.Command("docker", "exec", tr.containerConfig.InstanceName, "/bin/bash", "-c", fmt.Sprintf(`echo '%s' > %s`, jsonStr, "/params-proposal.json")).CombinedOutput() if err != nil { @@ -407,13 +408,15 @@ func (tr TestRun) submitParamChangeProposal( } //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - // PARAM CHANGE PROPOSAL // we should be able to make these all one command which will be cool - cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[action.chain].binaryName, + // PARAM CHANGE PROPOSAL + cmd := exec.Command("docker", "exec", tr.containerConfig.InstanceName, tr.chainConfigs[action.Chain].BinaryName, + "tx", "gov", "submit-legacy-proposal", "param-change", "/params-proposal.json", - `--from`, `validator`+fmt.Sprint(action.from), - `--chain-id`, string(tr.chainConfigs[action.chain].chainId), - `--home`, tr.getValidatorHome(action.chain, action.from), - `--node`, tr.getValidatorNode(action.chain, action.from), + + `--from`, `validator`+fmt.Sprint(action.From), + `--chain-id`, string(tr.chainConfigs[action.Chain].ChainId), + `--home`, tr.getValidatorHome(action.Chain, action.From), + `--node`, tr.getValidatorNode(action.Chain, action.From), `--gas`, "900000", `--keyring-backend`, `test`, `-y`, @@ -425,38 +428,38 @@ func (tr TestRun) submitParamChangeProposal( } // wait for inclusion in a block -> '--broadcast-mode block' is deprecated - tr.waitBlocks(action.chain, 2, 60*time.Second) + tr.waitBlocks(action.Chain, 2, 60*time.Second) } type submitEquivocationProposalAction struct { - chain chainID - height int64 - time time.Time - power int64 - validator validatorID - deposit uint - from validatorID + Chain ChainID + Height int64 + Time time.Time + Power int64 + Validator ValidatorID + Deposit uint + From ValidatorID } func (tr TestRun) submitEquivocationProposal(action submitEquivocationProposalAction, verbose bool) { - val := tr.validatorConfigs[action.validator] - providerChain := tr.chainConfigs[chainID("provi")] + val := tr.validatorConfigs[action.Validator] + providerChain := tr.chainConfigs[ChainID("provi")] prop := client.EquivocationProposalJSON{ Summary: "Validator equivocation!", EquivocationProposal: types.EquivocationProposal{ Title: "Validator equivocation!", - Description: fmt.Sprintf("Validator: %s has committed an equivocation infraction on chainID: %s", action.validator, action.chain), + Description: fmt.Sprintf("Validator: %s has committed an equivocation infraction on ChainID: %s", action.Validator, action.Chain), Equivocations: []*evidencetypes.Equivocation{ { - Height: action.height, - Time: action.time, - Power: action.power, - ConsensusAddress: val.valconsAddress, + Height: action.Height, + Time: action.Time, + Power: action.Power, + ConsensusAddress: val.ValconsAddress, }, }, }, - Deposit: fmt.Sprint(action.deposit) + `stake`, + Deposit: fmt.Sprint(action.Deposit) + `stake`, } bz, err := json.Marshal(prop) @@ -470,7 +473,7 @@ func (tr TestRun) submitEquivocationProposal(action submitEquivocationProposalAc } //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - bz, err = exec.Command("docker", "exec", tr.containerConfig.instanceName, + bz, err = exec.Command("docker", "exec", tr.containerConfig.InstanceName, "/bin/bash", "-c", fmt.Sprintf(`echo '%s' > %s`, jsonStr, "/equivocation-proposal.json")).CombinedOutput() if err != nil { @@ -479,12 +482,14 @@ func (tr TestRun) submitEquivocationProposal(action submitEquivocationProposalAc //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. // EQUIVOCATION PROPOSAL - bz, err = exec.Command("docker", "exec", tr.containerConfig.instanceName, providerChain.binaryName, + bz, err = exec.Command("docker", "exec", tr.containerConfig.InstanceName, providerChain.BinaryName, + "tx", "gov", "submit-legacy-proposal", "equivocation", "/equivocation-proposal.json", - `--from`, `validator`+fmt.Sprint(action.from), - `--chain-id`, string(providerChain.chainId), - `--home`, tr.getValidatorHome(providerChain.chainId, action.from), - `--node`, tr.getValidatorNode(providerChain.chainId, action.from), + + `--from`, `validator`+fmt.Sprint(action.From), + `--chain-id`, string(providerChain.ChainId), + `--home`, tr.getValidatorHome(providerChain.ChainId, action.From), + `--node`, tr.getValidatorNode(providerChain.ChainId, action.From), `--gas`, "9000000", `--keyring-backend`, `test`, `-y`, @@ -495,14 +500,14 @@ func (tr TestRun) submitEquivocationProposal(action submitEquivocationProposalAc } // wait for inclusion in a block -> '--broadcast-mode block' is deprecated - tr.waitBlocks(chainID("provi"), 2, 30*time.Second) + tr.waitBlocks(ChainID("provi"), 2, 30*time.Second) } type voteGovProposalAction struct { - chain chainID - from []validatorID - vote []string - propNumber uint + Chain ChainID + From []ValidatorID + Vote []string + PropNumber uint } func (tr *TestRun) voteGovProposal( @@ -510,21 +515,21 @@ func (tr *TestRun) voteGovProposal( verbose bool, ) { var wg sync.WaitGroup - for i, val := range action.from { + for i, val := range action.From { wg.Add(1) - vote := action.vote[i] - go func(val validatorID, vote string) { + vote := action.Vote[i] + go func(val ValidatorID, vote string) { defer wg.Done() //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - bz, err := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[action.chain].binaryName, + bz, err := exec.Command("docker", "exec", tr.containerConfig.InstanceName, tr.chainConfigs[action.Chain].BinaryName, "tx", "gov", "vote", - fmt.Sprint(action.propNumber), vote, + fmt.Sprint(action.PropNumber), vote, `--from`, `validator`+fmt.Sprint(val), - `--chain-id`, string(tr.chainConfigs[action.chain].chainId), - `--home`, tr.getValidatorHome(action.chain, val), - `--node`, tr.getValidatorNode(action.chain, val), + `--chain-id`, string(tr.chainConfigs[action.Chain].ChainId), + `--home`, tr.getValidatorHome(action.Chain, val), + `--node`, tr.getValidatorNode(action.Chain, val), `--keyring-backend`, `test`, `--gas`, "900000", `-y`, @@ -537,15 +542,15 @@ func (tr *TestRun) voteGovProposal( wg.Wait() // wait for inclusion in a block -> '--broadcast-mode block' is deprecated - tr.waitBlocks(action.chain, 1, 10*time.Second) - tr.WaitTime(time.Duration(tr.chainConfigs[action.chain].votingWaitTime) * time.Second) + tr.waitBlocks(action.Chain, 1, 10*time.Second) + tr.WaitTime(time.Duration(tr.chainConfigs[action.Chain].VotingWaitTime) * time.Second) } type startConsumerChainAction struct { - consumerChain chainID - providerChain chainID - validators []StartChainValidator - genesisChanges string + ConsumerChain ChainID + ProviderChain ChainID + Validators []StartChainValidator + GenesisChanges string } func (tr *TestRun) startConsumerChain( @@ -553,12 +558,12 @@ func (tr *TestRun) startConsumerChain( verbose bool, ) { //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[action.providerChain].binaryName, + cmd := exec.Command("docker", "exec", tr.containerConfig.InstanceName, tr.chainConfigs[action.ProviderChain].BinaryName, "query", "provider", "consumer-genesis", - string(tr.chainConfigs[action.consumerChain].chainId), + string(tr.chainConfigs[action.ConsumerChain].ChainId), - `--node`, tr.getQueryNode(action.providerChain), + `--node`, tr.getQueryNode(action.ProviderChain), `-o`, `json`, ) @@ -572,24 +577,24 @@ func (tr *TestRun) startConsumerChain( } consumerGenesis := ".app_state.ccvconsumer = " + string(bz) - consumerGenesisChanges := tr.chainConfigs[action.consumerChain].genesisChanges + consumerGenesisChanges := tr.chainConfigs[action.ConsumerChain].GenesisChanges if consumerGenesisChanges != "" { - consumerGenesis = consumerGenesis + " | " + consumerGenesisChanges + " | " + action.genesisChanges + consumerGenesis = consumerGenesis + " | " + consumerGenesisChanges + " | " + action.GenesisChanges } tr.startChain(StartChainAction{ - chain: action.consumerChain, - validators: action.validators, - genesisChanges: consumerGenesis, - skipGentx: true, + Chain: action.ConsumerChain, + Validators: action.Validators, + GenesisChanges: consumerGenesis, + SkipGentx: true, }, verbose) } type ChangeoverChainAction struct { - sovereignChain chainID - providerChain chainID - validators []StartChainValidator - genesisChanges string + SovereignChain ChainID + ProviderChain ChainID + Validators []StartChainValidator + GenesisChanges string } func (tr TestRun) changeoverChain( @@ -599,12 +604,12 @@ func (tr TestRun) changeoverChain( // sleep until the consumer chain genesis is ready on consumer time.Sleep(5 * time.Second) //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[action.providerChain].binaryName, + cmd := exec.Command("docker", "exec", tr.containerConfig.InstanceName, tr.chainConfigs[action.ProviderChain].BinaryName, "query", "provider", "consumer-genesis", - string(tr.chainConfigs[action.sovereignChain].chainId), + string(tr.chainConfigs[action.SovereignChain].ChainId), - `--node`, tr.getQueryNode(action.providerChain), + `--node`, tr.getQueryNode(action.ProviderChain), `-o`, `json`, ) @@ -618,14 +623,14 @@ func (tr TestRun) changeoverChain( } consumerGenesis := ".app_state.ccvconsumer = " + string(bz) - consumerGenesisChanges := tr.chainConfigs[action.sovereignChain].genesisChanges + consumerGenesisChanges := tr.chainConfigs[action.SovereignChain].GenesisChanges if consumerGenesisChanges != "" { - consumerGenesis = consumerGenesis + " | " + consumerGenesisChanges + " | " + action.genesisChanges + consumerGenesis = consumerGenesis + " | " + consumerGenesisChanges + " | " + action.GenesisChanges } tr.startChangeover(ChangeoverChainAction{ - validators: action.validators, - genesisChanges: consumerGenesis, + Validators: action.Validators, + GenesisChanges: consumerGenesis, }, verbose) } @@ -633,7 +638,7 @@ func (tr TestRun) startChangeover( action ChangeoverChainAction, verbose bool, ) { - chainConfig := tr.chainConfigs[chainID("sover")] + chainConfig := tr.chainConfigs[ChainID("sover")] type jsonValAttrs struct { Mnemonic string `json:"mnemonic"` Allocation string `json:"allocation"` @@ -649,20 +654,20 @@ func (tr TestRun) startChangeover( } var validators []jsonValAttrs - for _, val := range action.validators { + for _, val := range action.Validators { validators = append(validators, jsonValAttrs{ - Mnemonic: tr.validatorConfigs[val.id].mnemonic, - NodeKey: tr.validatorConfigs[val.id].nodeKey, - ValId: fmt.Sprint(val.id), - PrivValidatorKey: tr.validatorConfigs[val.id].privValidatorKey, - Allocation: fmt.Sprint(val.allocation) + "stake", - Stake: fmt.Sprint(val.stake) + "stake", - IpSuffix: tr.validatorConfigs[val.id].ipSuffix, - - ConsumerMnemonic: tr.validatorConfigs[val.id].consumerMnemonic, - ConsumerPrivValidatorKey: tr.validatorConfigs[val.id].consumerPrivValidatorKey, + Mnemonic: tr.validatorConfigs[val.Id].Mnemonic, + NodeKey: tr.validatorConfigs[val.Id].NodeKey, + ValId: fmt.Sprint(val.Id), + PrivValidatorKey: tr.validatorConfigs[val.Id].PrivValidatorKey, + Allocation: fmt.Sprint(val.Allocation) + "stake", + Stake: fmt.Sprint(val.Stake) + "stake", + IpSuffix: tr.validatorConfigs[val.Id].IpSuffix, + + ConsumerMnemonic: tr.validatorConfigs[val.Id].ConsumerMnemonic, + ConsumerPrivValidatorKey: tr.validatorConfigs[val.Id].ConsumerPrivValidatorKey, // if true node will be started with consumer key for each consumer chain - StartWithConsumerKey: tr.validatorConfigs[val.id].useConsumerKey, + StartWithConsumerKey: tr.validatorConfigs[val.Id].UseConsumerKey, }) } @@ -673,16 +678,16 @@ func (tr TestRun) startChangeover( // Concat genesis changes defined in chain config, with any custom genesis changes for this chain instantiation var genesisChanges string - if action.genesisChanges != "" { - genesisChanges = chainConfig.genesisChanges + " | " + action.genesisChanges + if action.GenesisChanges != "" { + genesisChanges = chainConfig.GenesisChanges + " | " + action.GenesisChanges } else { - genesisChanges = chainConfig.genesisChanges + genesisChanges = chainConfig.GenesisChanges } //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, "/bin/bash", - "/testnet-scripts/start-changeover.sh", chainConfig.upgradeBinary, string(vals), - "sover", chainConfig.ipPrefix, genesisChanges, + cmd := exec.Command("docker", "exec", tr.containerConfig.InstanceName, "/bin/bash", + "/testnet-scripts/start-changeover.sh", chainConfig.UpgradeBinary, string(vals), + "sover", chainConfig.IpPrefix, genesisChanges, tr.tendermintConfigOverride, ) @@ -713,8 +718,8 @@ func (tr TestRun) startChangeover( } type addChainToRelayerAction struct { - chain chainID - validator validatorID + Chain ChainID + Validator ValidatorID } const hermesChainConfigTemplate = ` @@ -779,37 +784,37 @@ func (tr TestRun) addChainToGorelayer( action addChainToRelayerAction, verbose bool, ) { - queryNodeIP := tr.getQueryNodeIP(action.chain) - chainId := tr.chainConfigs[action.chain].chainId + queryNodeIP := tr.getQueryNodeIP(action.Chain) + ChainId := tr.chainConfigs[action.Chain].ChainId rpcAddr := "http://" + queryNodeIP + ":26658" chainConfig := fmt.Sprintf(gorelayerChainConfigTemplate, - chainId, + ChainId, rpcAddr, ) //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - bz, err := exec.Command("docker", "exec", tr.containerConfig.instanceName, "rly", "config", "init").CombinedOutput() + bz, err := exec.Command("docker", "exec", tr.containerConfig.InstanceName, "rly", "config", "init").CombinedOutput() if err != nil && !strings.Contains(string(bz), "config already exists") { log.Fatal(err, "\n", string(bz)) } - chainConfigFileName := fmt.Sprintf("/root/%s_config.json", chainId) + chainConfigFileName := fmt.Sprintf("/root/%s_config.json", ChainId) bashCommand := fmt.Sprintf(`echo '%s' >> %s`, chainConfig, chainConfigFileName) //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - bz, err = exec.Command("docker", "exec", tr.containerConfig.instanceName, "bash", "-c", + bz, err = exec.Command("docker", "exec", tr.containerConfig.InstanceName, "bash", "-c", bashCommand).CombinedOutput() if err != nil { log.Fatal(err, "\n", string(bz)) } //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - addChainCommand := exec.Command("docker", "exec", tr.containerConfig.instanceName, "rly", "chains", "add", "--file", chainConfigFileName, string(chainId)) + addChainCommand := exec.Command("docker", "exec", tr.containerConfig.InstanceName, "rly", "chains", "add", "--file", chainConfigFileName, string(ChainId)) executeCommand(addChainCommand, "add chain") //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - keyRestoreCommand := exec.Command("docker", "exec", tr.containerConfig.instanceName, "rly", "keys", "restore", string(chainId), "default", tr.validatorConfigs[action.validator].mnemonic) + keyRestoreCommand := exec.Command("docker", "exec", tr.containerConfig.InstanceName, "rly", "keys", "restore", string(ChainId), "default", tr.validatorConfigs[action.Validator].Mnemonic) executeCommand(keyRestoreCommand, "restore keys") } @@ -817,8 +822,8 @@ func (tr TestRun) addChainToHermes( action addChainToRelayerAction, verbose bool, ) { - queryNodeIP := tr.getQueryNodeIP(action.chain) - chainId := tr.chainConfigs[action.chain].chainId + queryNodeIP := tr.getQueryNodeIP(action.Chain) + ChainId := tr.chainConfigs[action.Chain].ChainId keyName := "query" rpcAddr := "http://" + queryNodeIP + ":26658" grpcAddr := "tcp://" + queryNodeIP + ":9091" @@ -826,7 +831,7 @@ func (tr TestRun) addChainToHermes( chainConfig := fmt.Sprintf(hermesChainConfigTemplate, grpcAddr, - chainId, + ChainId, keyName, rpcAddr, wsAddr, @@ -836,7 +841,7 @@ func (tr TestRun) addChainToHermes( bashCommand := fmt.Sprintf(`echo '%s' >> %s`, chainConfig, "/root/.hermes/config.toml") //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - bz, err := exec.Command("docker", "exec", tr.containerConfig.instanceName, "bash", "-c", + bz, err := exec.Command("docker", "exec", tr.containerConfig.InstanceName, "bash", "-c", bashCommand, ).CombinedOutput() if err != nil { @@ -844,9 +849,9 @@ func (tr TestRun) addChainToHermes( } // Save mnemonic to file within container - saveMnemonicCommand := fmt.Sprintf(`echo '%s' > %s`, tr.validatorConfigs[action.validator].mnemonic, "/root/.hermes/mnemonic.txt") + saveMnemonicCommand := fmt.Sprintf(`echo '%s' > %s`, tr.validatorConfigs[action.Validator].Mnemonic, "/root/.hermes/mnemonic.txt") //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - bz, err = exec.Command("docker", "exec", tr.containerConfig.instanceName, "bash", "-c", + bz, err = exec.Command("docker", "exec", tr.containerConfig.InstanceName, "bash", "-c", saveMnemonicCommand, ).CombinedOutput() if err != nil { @@ -854,9 +859,9 @@ func (tr TestRun) addChainToHermes( } //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - bz, err = exec.Command("docker", "exec", tr.containerConfig.instanceName, "hermes", + bz, err = exec.Command("docker", "exec", tr.containerConfig.InstanceName, "hermes", "keys", "add", - "--chain", string(tr.chainConfigs[action.chain].chainId), + "--chain", string(tr.chainConfigs[action.Chain].ChainId), "--mnemonic-file", "/root/.hermes/mnemonic.txt", ).CombinedOutput() @@ -886,10 +891,10 @@ const gorelayerPathConfigTemplate = `{ ` type addIbcConnectionAction struct { - chainA chainID - chainB chainID - clientA uint - clientB uint + ChainA ChainID + ChainB ChainID + ClientA uint + ClientB uint } func (tr TestRun) addIbcConnection( @@ -907,23 +912,23 @@ func (tr TestRun) addIbcConnectionGorelayer( action addIbcConnectionAction, verbose bool, ) { - pathName := tr.GetPathNameForGorelayer(action.chainA, action.chainB) + pathName := tr.GetPathNameForGorelayer(action.ChainA, action.ChainB) - pathConfig := fmt.Sprintf(gorelayerPathConfigTemplate, action.chainA, action.clientA, action.chainB, action.clientB) + pathConfig := fmt.Sprintf(gorelayerPathConfigTemplate, action.ChainA, action.ClientA, action.ChainB, action.ClientB) pathConfigFileName := fmt.Sprintf("/root/%s_config.json", pathName) bashCommand := fmt.Sprintf(`echo '%s' >> %s`, pathConfig, pathConfigFileName) //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - pathConfigCommand := exec.Command("docker", "exec", tr.containerConfig.instanceName, "bash", "-c", + pathConfigCommand := exec.Command("docker", "exec", tr.containerConfig.InstanceName, "bash", "-c", bashCommand) executeCommand(pathConfigCommand, "add path config") //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - newPathCommand := exec.Command("docker", "exec", tr.containerConfig.instanceName, "rly", + newPathCommand := exec.Command("docker", "exec", tr.containerConfig.InstanceName, "rly", "paths", "add", - string(tr.chainConfigs[action.chainA].chainId), - string(tr.chainConfigs[action.chainB].chainId), + string(tr.chainConfigs[action.ChainA].ChainId), + string(tr.chainConfigs[action.ChainB].ChainId), pathName, "--file", pathConfigFileName, ) @@ -931,31 +936,31 @@ func (tr TestRun) addIbcConnectionGorelayer( executeCommand(newPathCommand, "new path") //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - newClientsCommand := exec.Command("docker", "exec", tr.containerConfig.instanceName, "rly", + newClientsCommand := exec.Command("docker", "exec", tr.containerConfig.InstanceName, "rly", "transact", "clients", pathName, ) executeCommand(newClientsCommand, "new clients") - tr.waitBlocks(action.chainA, 1, 10*time.Second) - tr.waitBlocks(action.chainB, 1, 10*time.Second) + tr.waitBlocks(action.ChainA, 1, 10*time.Second) + tr.waitBlocks(action.ChainB, 1, 10*time.Second) //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - newConnectionCommand := exec.Command("docker", "exec", tr.containerConfig.instanceName, "rly", + newConnectionCommand := exec.Command("docker", "exec", tr.containerConfig.InstanceName, "rly", "transact", "connection", pathName, ) executeCommand(newConnectionCommand, "new connection") - tr.waitBlocks(action.chainA, 1, 10*time.Second) - tr.waitBlocks(action.chainB, 1, 10*time.Second) + tr.waitBlocks(action.ChainA, 1, 10*time.Second) + tr.waitBlocks(action.ChainB, 1, 10*time.Second) } type createIbcClientsAction struct { - chainA chainID - chainB chainID + ChainA ChainID + ChainB ChainID } // if clients are not provided hermes will first @@ -966,10 +971,10 @@ func (tr TestRun) createIbcClientsHermes( verbose bool, ) { //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, "hermes", + cmd := exec.Command("docker", "exec", tr.containerConfig.InstanceName, "hermes", "create", "connection", - "--a-chain", string(tr.chainConfigs[action.chainA].chainId), - "--b-chain", string(tr.chainConfigs[action.chainB].chainId), + "--a-chain", string(tr.chainConfigs[action.ChainA].ChainId), + "--b-chain", string(tr.chainConfigs[action.ChainB].ChainId), ) cmdReader, err := cmd.StdoutPipe() @@ -1003,11 +1008,11 @@ func (tr TestRun) addIbcConnectionHermes( verbose bool, ) { //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, "hermes", + cmd := exec.Command("docker", "exec", tr.containerConfig.InstanceName, "hermes", "create", "connection", - "--a-chain", string(tr.chainConfigs[action.chainA].chainId), - "--a-client", "07-tendermint-"+fmt.Sprint(action.clientA), - "--b-client", "07-tendermint-"+fmt.Sprint(action.clientB), + "--a-chain", string(tr.chainConfigs[action.ChainA].ChainId), + "--a-client", "07-tendermint-"+fmt.Sprint(action.ClientA), + "--b-client", "07-tendermint-"+fmt.Sprint(action.ClientB), ) cmdReader, err := cmd.StdoutPipe() @@ -1037,13 +1042,13 @@ func (tr TestRun) addIbcConnectionHermes( } type addIbcChannelAction struct { - chainA chainID - chainB chainID - connectionA uint - portA string - portB string - order string - version string + ChainA ChainID + ChainB ChainID + ConnectionA uint + PortA string + PortB string + Order string + Version string } type startRelayerAction struct{} @@ -1065,7 +1070,7 @@ func (tr TestRun) startGorelayer( ) { // gorelayer start is running in detached mode //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - cmd := exec.Command("docker", "exec", "-d", tr.containerConfig.instanceName, "rly", + cmd := exec.Command("docker", "exec", "-d", tr.containerConfig.InstanceName, "rly", "start", ) @@ -1084,7 +1089,7 @@ func (tr TestRun) startHermes( ) { // hermes start is running in detached mode //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - cmd := exec.Command("docker", "exec", "-d", tr.containerConfig.instanceName, "hermes", + cmd := exec.Command("docker", "exec", "-d", tr.containerConfig.InstanceName, "hermes", "start", ) @@ -1112,15 +1117,15 @@ func (tr TestRun) addIbcChannelGorelayer( action addIbcChannelAction, verbose bool, ) { - pathName := tr.GetPathNameForGorelayer(action.chainA, action.chainB) + pathName := tr.GetPathNameForGorelayer(action.ChainA, action.ChainB) //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, "rly", + cmd := exec.Command("docker", "exec", tr.containerConfig.InstanceName, "rly", "transact", "channel", pathName, - "--src-port", action.portA, - "--dst-port", action.portB, - "--version", tr.containerConfig.ccvVersion, - "--order", action.order, + "--src-port", action.PortA, + "--dst-port", action.PortB, + "--version", tr.containerConfig.CcvVersion, + "--order", action.Order, "--debug", ) executeCommand(cmd, "addChannel") @@ -1132,20 +1137,20 @@ func (tr TestRun) addIbcChannelHermes( ) { // if version is not specified, use the default version when creating ccv connections // otherwise, use the provided version schema (usually it is ICS20-1 for IBC transfer) - chanVersion := action.version + chanVersion := action.Version if chanVersion == "" { - chanVersion = tr.containerConfig.ccvVersion + chanVersion = tr.containerConfig.CcvVersion } //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, "hermes", + cmd := exec.Command("docker", "exec", tr.containerConfig.InstanceName, "hermes", "create", "channel", - "--a-chain", string(tr.chainConfigs[action.chainA].chainId), - "--a-connection", "connection-"+fmt.Sprint(action.connectionA), - "--a-port", action.portA, - "--b-port", action.portB, + "--a-chain", string(tr.chainConfigs[action.ChainA].ChainId), + "--a-connection", "connection-"+fmt.Sprint(action.ConnectionA), + "--a-port", action.PortA, + "--b-port", action.PortB, "--channel-version", chanVersion, - "--order", action.order, + "--order", action.Order, ) if verbose { @@ -1179,14 +1184,14 @@ func (tr TestRun) addIbcChannelHermes( } type transferChannelCompleteAction struct { - chainA chainID - chainB chainID - connectionA uint - portA string - portB string - order string - channelA uint - channelB uint + ChainA ChainID + ChainB ChainID + ConnectionA uint + PortA string + PortB string + Order string + ChannelA uint + ChannelB uint } func (tr TestRun) transferChannelComplete( @@ -1198,41 +1203,41 @@ func (tr TestRun) transferChannelComplete( } //#nosec G204 -- Bypass linter warning for spawning subprocess with chanOpenTryCmd arguments. - chanOpenTryCmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, "hermes", + chanOpenTryCmd := exec.Command("docker", "exec", tr.containerConfig.InstanceName, "hermes", "tx", "chan-open-try", - "--dst-chain", string(tr.chainConfigs[action.chainB].chainId), - "--src-chain", string(tr.chainConfigs[action.chainA].chainId), - "--dst-connection", "connection-"+fmt.Sprint(action.connectionA), - "--dst-port", action.portB, - "--src-port", action.portA, - "--src-channel", "channel-"+fmt.Sprint(action.channelA), + "--dst-chain", string(tr.chainConfigs[action.ChainB].ChainId), + "--src-chain", string(tr.chainConfigs[action.ChainA].ChainId), + "--dst-connection", "connection-"+fmt.Sprint(action.ConnectionA), + "--dst-port", action.PortB, + "--src-port", action.PortA, + "--src-channel", "channel-"+fmt.Sprint(action.ChannelA), ) executeCommand(chanOpenTryCmd, "transferChanOpenTry") //#nosec G204 -- Bypass linter warning for spawning subprocess with chanOpenAckCmd arguments. - chanOpenAckCmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, "hermes", + chanOpenAckCmd := exec.Command("docker", "exec", tr.containerConfig.InstanceName, "hermes", "tx", "chan-open-ack", - "--dst-chain", string(tr.chainConfigs[action.chainA].chainId), - "--src-chain", string(tr.chainConfigs[action.chainB].chainId), - "--dst-connection", "connection-"+fmt.Sprint(action.connectionA), - "--dst-port", action.portA, - "--src-port", action.portB, - "--dst-channel", "channel-"+fmt.Sprint(action.channelA), - "--src-channel", "channel-"+fmt.Sprint(action.channelB), + "--dst-chain", string(tr.chainConfigs[action.ChainA].ChainId), + "--src-chain", string(tr.chainConfigs[action.ChainB].ChainId), + "--dst-connection", "connection-"+fmt.Sprint(action.ConnectionA), + "--dst-port", action.PortA, + "--src-port", action.PortB, + "--dst-channel", "channel-"+fmt.Sprint(action.ChannelA), + "--src-channel", "channel-"+fmt.Sprint(action.ChannelB), ) executeCommand(chanOpenAckCmd, "transferChanOpenAck") //#nosec G204 -- Bypass linter warning for spawning subprocess with chanOpenConfirmCmd arguments. - chanOpenConfirmCmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, "hermes", + chanOpenConfirmCmd := exec.Command("docker", "exec", tr.containerConfig.InstanceName, "hermes", "tx", "chan-open-confirm", - "--dst-chain", string(tr.chainConfigs[action.chainB].chainId), - "--src-chain", string(tr.chainConfigs[action.chainA].chainId), - "--dst-connection", "connection-"+fmt.Sprint(action.connectionA), - "--dst-port", action.portB, - "--src-port", action.portA, - "--dst-channel", "channel-"+fmt.Sprint(action.channelB), - "--src-channel", "channel-"+fmt.Sprint(action.channelA), + "--dst-chain", string(tr.chainConfigs[action.ChainB].ChainId), + "--src-chain", string(tr.chainConfigs[action.ChainA].ChainId), + "--dst-connection", "connection-"+fmt.Sprint(action.ConnectionA), + "--dst-port", action.PortB, + "--src-port", action.PortA, + "--dst-channel", "channel-"+fmt.Sprint(action.ChannelB), + "--src-channel", "channel-"+fmt.Sprint(action.ChannelA), ) executeCommand(chanOpenConfirmCmd, "transferChanOpenConfirm") } @@ -1271,10 +1276,10 @@ func executeCommand(cmd *exec.Cmd, cmdName string) { } type relayPacketsAction struct { - chainA chainID - chainB chainID - port string - channel uint + ChainA ChainID + ChainB ChainID + Port string + Channel uint } func (tr TestRun) relayPackets( @@ -1292,13 +1297,13 @@ func (tr TestRun) relayPacketsGorelayer( action relayPacketsAction, verbose bool, ) { - pathName := tr.GetPathNameForGorelayer(action.chainA, action.chainB) + pathName := tr.GetPathNameForGorelayer(action.ChainA, action.ChainB) // rly transact relay-packets [path-name] --channel [channel-id] //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, "rly", "transact", "flush", + cmd := exec.Command("docker", "exec", tr.containerConfig.InstanceName, "rly", "transact", "flush", pathName, - "channel-"+fmt.Sprint(action.channel), + "channel-"+fmt.Sprint(action.Channel), ) if verbose { log.Println("relayPackets cmd:", cmd.String()) @@ -1308,8 +1313,8 @@ func (tr TestRun) relayPacketsGorelayer( log.Fatal(err, "\n", string(bz)) } - tr.waitBlocks(action.chainA, 1, 30*time.Second) - tr.waitBlocks(action.chainB, 1, 30*time.Second) + tr.waitBlocks(action.ChainA, 1, 30*time.Second) + tr.waitBlocks(action.ChainB, 1, 30*time.Second) } func (tr TestRun) relayPacketsHermes( @@ -1318,10 +1323,10 @@ func (tr TestRun) relayPacketsHermes( ) { // hermes clear packets ibc0 transfer channel-13 //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, "hermes", "clear", "packets", - "--chain", string(tr.chainConfigs[action.chainA].chainId), - "--port", action.port, - "--channel", "channel-"+fmt.Sprint(action.channel), + cmd := exec.Command("docker", "exec", tr.containerConfig.InstanceName, "hermes", "clear", "packets", + "--chain", string(tr.chainConfigs[action.ChainA].ChainId), + "--port", action.Port, + "--channel", "channel-"+fmt.Sprint(action.Channel), ) if verbose { log.Println("relayPackets cmd:", cmd.String()) @@ -1332,58 +1337,58 @@ func (tr TestRun) relayPacketsHermes( log.Fatal(err, "\n", string(bz)) } - tr.waitBlocks(action.chainA, 1, 30*time.Second) - tr.waitBlocks(action.chainB, 1, 30*time.Second) + tr.waitBlocks(action.ChainA, 1, 30*time.Second) + tr.waitBlocks(action.ChainB, 1, 30*time.Second) } type relayRewardPacketsToProviderAction struct { - consumerChain chainID - providerChain chainID - port string - channel uint + ConsumerChain ChainID + ProviderChain ChainID + Port string + Channel uint } func (tr TestRun) relayRewardPacketsToProvider( action relayRewardPacketsToProviderAction, verbose bool, ) { - blockPerDistribution, _ := strconv.ParseUint(strings.Trim(tr.getParam(action.consumerChain, Param{Subspace: "ccvconsumer", Key: "BlocksPerDistributionTransmission"}), "\""), 10, 64) - currentBlock := uint64(tr.getBlockHeight(action.consumerChain)) + blockPerDistribution, _ := strconv.ParseUint(strings.Trim(tr.getParam(action.ConsumerChain, Param{Subspace: "ccvconsumer", Key: "BlocksPerDistributionTransmission"}), "\""), 10, 64) + currentBlock := uint64(tr.getBlockHeight(action.ConsumerChain)) if currentBlock <= blockPerDistribution { - tr.waitBlocks(action.consumerChain, uint(blockPerDistribution-currentBlock+1), 60*time.Second) + tr.waitBlocks(action.ConsumerChain, uint(blockPerDistribution-currentBlock+1), 60*time.Second) } - tr.relayPackets(relayPacketsAction{chainA: action.consumerChain, chainB: action.providerChain, port: action.port, channel: action.channel}, verbose) - tr.waitBlocks(action.providerChain, 1, 10*time.Second) + tr.relayPackets(relayPacketsAction{ChainA: action.ConsumerChain, ChainB: action.ProviderChain, Port: action.Port, Channel: action.Channel}, verbose) + tr.waitBlocks(action.ProviderChain, 1, 10*time.Second) } type delegateTokensAction struct { - chain chainID - from validatorID - to validatorID - amount uint + Chain ChainID + From ValidatorID + To ValidatorID + Amount uint } func (tr TestRun) delegateTokens( action delegateTokensAction, verbose bool, ) { - toValCfg := tr.validatorConfigs[action.to] - delegateAddr := toValCfg.valoperAddress - if action.chain != chainID("provi") && toValCfg.useConsumerKey { - delegateAddr = toValCfg.consumerValoperAddress + toValCfg := tr.validatorConfigs[action.To] + delegateAddr := toValCfg.ValoperAddress + if action.Chain != ChainID("provi") && toValCfg.UseConsumerKey { + delegateAddr = toValCfg.ConsumerValoperAddress } //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[action.chain].binaryName, + cmd := exec.Command("docker", "exec", tr.containerConfig.InstanceName, tr.chainConfigs[action.Chain].BinaryName, "tx", "staking", "delegate", delegateAddr, - fmt.Sprint(action.amount)+`stake`, + 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), - `--node`, tr.getValidatorNode(action.chain, action.from), + `--from`, `validator`+fmt.Sprint(action.From), + `--chain-id`, string(tr.chainConfigs[action.Chain].ChainId), + `--home`, tr.getValidatorHome(action.Chain, action.From), + `--node`, tr.getValidatorNode(action.Chain, action.From), `--keyring-backend`, `test`, `-y`, ) @@ -1398,36 +1403,36 @@ func (tr TestRun) delegateTokens( } // wait for inclusion in a block -> '--broadcast-mode block' is deprecated - tr.waitBlocks(action.chain, 2, 10*time.Second) + tr.waitBlocks(action.Chain, 2, 10*time.Second) } type unbondTokensAction struct { - chain chainID - sender validatorID - unbondFrom validatorID - amount uint + Chain ChainID + Sender ValidatorID + UnbondFrom ValidatorID + Amount uint } func (tr TestRun) unbondTokens( action unbondTokensAction, verbose bool, ) { - unbondFrom := tr.validatorConfigs[action.unbondFrom].valoperAddress - if tr.validatorConfigs[action.unbondFrom].useConsumerKey { - unbondFrom = tr.validatorConfigs[action.unbondFrom].consumerValoperAddress + unbondFrom := tr.validatorConfigs[action.UnbondFrom].ValoperAddress + if tr.validatorConfigs[action.UnbondFrom].UseConsumerKey { + unbondFrom = tr.validatorConfigs[action.UnbondFrom].ConsumerValoperAddress } //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[action.chain].binaryName, + cmd := exec.Command("docker", "exec", tr.containerConfig.InstanceName, tr.chainConfigs[action.Chain].BinaryName, "tx", "staking", "unbond", unbondFrom, - fmt.Sprint(action.amount)+`stake`, + fmt.Sprint(action.Amount)+`stake`, - `--from`, `validator`+fmt.Sprint(action.sender), - `--chain-id`, string(tr.chainConfigs[action.chain].chainId), - `--home`, tr.getValidatorHome(action.chain, action.sender), - `--node`, tr.getValidatorNode(action.chain, action.sender), + `--from`, `validator`+fmt.Sprint(action.Sender), + `--chain-id`, string(tr.chainConfigs[action.Chain].ChainId), + `--home`, tr.getValidatorHome(action.Chain, action.Sender), + `--node`, tr.getValidatorNode(action.Chain, action.Sender), `--gas`, "900000", `--keyring-backend`, `test`, `-y`, @@ -1443,33 +1448,33 @@ func (tr TestRun) unbondTokens( } // wait for inclusion in a block -> '--broadcast-mode block' is deprecated - tr.waitBlocks(action.chain, 2, 20*time.Second) + tr.waitBlocks(action.Chain, 2, 20*time.Second) } type cancelUnbondTokensAction struct { - chain chainID - delegator validatorID - validator validatorID - amount uint + Chain ChainID + Delegator ValidatorID + Validator ValidatorID + Amount uint } func (tr TestRun) cancelUnbondTokens( action cancelUnbondTokensAction, verbose bool, ) { - validator := tr.validatorConfigs[action.validator].valoperAddress - if tr.validatorConfigs[action.validator].useConsumerKey { - validator = tr.validatorConfigs[action.validator].consumerValoperAddress + validator := tr.validatorConfigs[action.Validator].ValoperAddress + if tr.validatorConfigs[action.Validator].UseConsumerKey { + validator = tr.validatorConfigs[action.Validator].ConsumerValoperAddress } // get creation-height from state //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[action.chain].binaryName, + cmd := exec.Command("docker", "exec", tr.containerConfig.InstanceName, tr.chainConfigs[action.Chain].BinaryName, "q", "staking", "unbonding-delegation", - tr.validatorConfigs[action.delegator].delAddress, + tr.validatorConfigs[action.Delegator].DelAddress, validator, - `--home`, tr.getValidatorHome(action.chain, action.delegator), - `--node`, tr.getValidatorNode(action.chain, action.delegator), + `--home`, tr.getValidatorHome(action.Chain, action.Delegator), + `--node`, tr.getValidatorNode(action.Chain, action.Delegator), `-o`, `json`, ) if verbose { @@ -1486,15 +1491,15 @@ func (tr TestRun) cancelUnbondTokens( } //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - cmd = exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[action.chain].binaryName, + cmd = exec.Command("docker", "exec", tr.containerConfig.InstanceName, tr.chainConfigs[action.Chain].BinaryName, "tx", "staking", "cancel-unbond", validator, - fmt.Sprint(action.amount)+`stake`, + fmt.Sprint(action.Amount)+`stake`, fmt.Sprint(creationHeight), - `--from`, `validator`+fmt.Sprint(action.delegator), - `--chain-id`, string(tr.chainConfigs[action.chain].chainId), - `--home`, tr.getValidatorHome(action.chain, action.delegator), - `--node`, tr.getValidatorNode(action.chain, action.delegator), + `--from`, `validator`+fmt.Sprint(action.Delegator), + `--chain-id`, string(tr.chainConfigs[action.Chain].ChainId), + `--home`, tr.getValidatorHome(action.Chain, action.Delegator), + `--node`, tr.getValidatorNode(action.Chain, action.Delegator), `--gas`, "900000", `--keyring-backend`, `test`, `-o`, `json`, @@ -1511,43 +1516,43 @@ func (tr TestRun) cancelUnbondTokens( } // wait for inclusion in a block -> '--broadcast-mode block' is deprecated - tr.waitBlocks(action.chain, 2, 20*time.Second) + tr.waitBlocks(action.Chain, 2, 20*time.Second) } type redelegateTokensAction struct { - chain chainID - src validatorID - dst validatorID - txSender validatorID - amount uint + Chain ChainID + Src ValidatorID + Dst ValidatorID + TxSender ValidatorID + Amount uint } func (tr TestRun) redelegateTokens(action redelegateTokensAction, verbose bool) { - srcCfg := tr.validatorConfigs[action.src] - dstCfg := tr.validatorConfigs[action.dst] + srcCfg := tr.validatorConfigs[action.Src] + dstCfg := tr.validatorConfigs[action.Dst] - redelegateSrc := srcCfg.valoperAddress - if action.chain != chainID("provi") && srcCfg.useConsumerKey { - redelegateSrc = srcCfg.consumerValoperAddress + redelegateSrc := srcCfg.ValoperAddress + if action.Chain != ChainID("provi") && srcCfg.UseConsumerKey { + redelegateSrc = srcCfg.ConsumerValoperAddress } - redelegateDst := dstCfg.valoperAddress - if action.chain != chainID("provi") && dstCfg.useConsumerKey { - redelegateDst = dstCfg.consumerValoperAddress + redelegateDst := dstCfg.ValoperAddress + if action.Chain != ChainID("provi") && dstCfg.UseConsumerKey { + redelegateDst = dstCfg.ConsumerValoperAddress } //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. cmd := exec.Command("docker", "exec", - tr.containerConfig.instanceName, - tr.chainConfigs[action.chain].binaryName, + tr.containerConfig.InstanceName, + tr.chainConfigs[action.Chain].BinaryName, "tx", "staking", "redelegate", redelegateSrc, redelegateDst, - fmt.Sprint(action.amount)+`stake`, - `--from`, `validator`+fmt.Sprint(action.txSender), - `--chain-id`, string(tr.chainConfigs[action.chain].chainId), - `--home`, tr.getValidatorHome(action.chain, action.txSender), - `--node`, tr.getValidatorNode(action.chain, action.txSender), + fmt.Sprint(action.Amount)+`stake`, + `--from`, `validator`+fmt.Sprint(action.TxSender), + `--chain-id`, string(tr.chainConfigs[action.Chain].ChainId), + `--home`, tr.getValidatorHome(action.Chain, action.TxSender), + `--node`, tr.getValidatorNode(action.Chain, action.TxSender), // Need to manually set gas limit past default (200000), since redelegate has a lot of operations `--gas`, "900000", `--keyring-backend`, `test`, @@ -1564,12 +1569,12 @@ func (tr TestRun) redelegateTokens(action redelegateTokensAction, verbose bool) } // wait for inclusion in a block -> '--broadcast-mode block' is deprecated - tr.waitBlocks(action.chain, 2, 10*time.Second) + tr.waitBlocks(action.Chain, 2, 10*time.Second) } type downtimeSlashAction struct { - chain chainID - validator validatorID + Chain ChainID + Validator ValidatorID } // takes a string representation of the private key like @@ -1588,15 +1593,15 @@ func (tr TestRun) getValidatorKeyAddressFromString(keystring string) string { func (tr TestRun) invokeDowntimeSlash(action downtimeSlashAction, verbose bool) { // Bring validator down - tr.setValidatorDowntime(action.chain, action.validator, true, verbose) + tr.setValidatorDowntime(action.Chain, action.Validator, true, verbose) // Wait appropriate amount of blocks for validator to be slashed - tr.waitBlocks(action.chain, 10, 3*time.Minute) + tr.waitBlocks(action.Chain, 10, 3*time.Minute) // Bring validator back up - tr.setValidatorDowntime(action.chain, action.validator, false, verbose) + tr.setValidatorDowntime(action.Chain, action.Validator, false, verbose) } // Sets validator downtime by setting the virtual ethernet interface of a node to "up" or "down" -func (tr TestRun) setValidatorDowntime(chain chainID, validator validatorID, down, verbose bool) { +func (tr TestRun) setValidatorDowntime(chain ChainID, validator ValidatorID, down, verbose bool) { var lastArg string if down { lastArg = "down" @@ -1621,7 +1626,7 @@ func (tr TestRun) setValidatorDowntime(chain chainID, validator validatorID, dow cmd := exec.Command( "docker", "exec", - tr.containerConfig.instanceName, + tr.containerConfig.InstanceName, "ip", "link", "set", @@ -1639,16 +1644,16 @@ func (tr TestRun) setValidatorDowntime(chain chainID, validator validatorID, dow } } -func (tr TestRun) GetValidatorPrivateKeyAddress(chain chainID, validator validatorID) string { +func (tr TestRun) GetValidatorPrivateKeyAddress(chain ChainID, validator ValidatorID) string { var validatorPrivateKeyAddress string - if chain == chainID("provi") { - validatorPrivateKeyAddress = tr.getValidatorKeyAddressFromString(tr.validatorConfigs[validator].privValidatorKey) + if chain == ChainID("provi") { + validatorPrivateKeyAddress = tr.getValidatorKeyAddressFromString(tr.validatorConfigs[validator].PrivValidatorKey) } else { var valAddressString string - if tr.validatorConfigs[validator].useConsumerKey { - valAddressString = tr.validatorConfigs[validator].consumerPrivValidatorKey + if tr.validatorConfigs[validator].UseConsumerKey { + valAddressString = tr.validatorConfigs[validator].ConsumerPrivValidatorKey } else { - valAddressString = tr.validatorConfigs[validator].privValidatorKey + valAddressString = tr.validatorConfigs[validator].PrivValidatorKey } validatorPrivateKeyAddress = tr.getValidatorKeyAddressFromString(valAddressString) } @@ -1656,8 +1661,8 @@ func (tr TestRun) GetValidatorPrivateKeyAddress(chain chainID, validator validat } type unjailValidatorAction struct { - provider chainID - validator validatorID + Provider ChainID + Validator ValidatorID } // Sends an unjail transaction to the provider chain @@ -1667,14 +1672,14 @@ func (tr TestRun) unjailValidator(action unjailValidatorAction, verbose bool) { //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. cmd := exec.Command("docker", "exec", - tr.containerConfig.instanceName, - tr.chainConfigs[action.provider].binaryName, + tr.containerConfig.InstanceName, + tr.chainConfigs[action.Provider].BinaryName, "tx", "slashing", "unjail", // Validator is sender here - `--from`, `validator`+fmt.Sprint(action.validator), - `--chain-id`, string(tr.chainConfigs[action.provider].chainId), - `--home`, tr.getValidatorHome(action.provider, action.validator), - `--node`, tr.getValidatorNode(action.provider, action.validator), + `--from`, `validator`+fmt.Sprint(action.Validator), + `--chain-id`, string(tr.chainConfigs[action.Provider].ChainId), + `--home`, tr.getValidatorHome(action.Provider, action.Validator), + `--node`, tr.getValidatorNode(action.Provider, action.Validator), `--gas`, "900000", `--keyring-backend`, `test`, `-y`, @@ -1691,13 +1696,13 @@ func (tr TestRun) unjailValidator(action unjailValidatorAction, verbose bool) { // wait for 1 blocks to make sure that tx got included // in a block and packets committed before proceeding - tr.waitBlocks(action.provider, 2, time.Minute) + tr.waitBlocks(action.Provider, 2, time.Minute) } type registerRepresentativeAction struct { - chain chainID - representatives []validatorID - stakes []uint + Chain ChainID + Representatives []ValidatorID + Stakes []uint } func (tr TestRun) registerRepresentative( @@ -1705,16 +1710,16 @@ func (tr TestRun) registerRepresentative( verbose bool, ) { var wg sync.WaitGroup - for i, val := range action.representatives { + for i, val := range action.Representatives { wg.Add(1) - stake := action.stakes[i] - go func(val validatorID, stake uint) { + stake := action.Stakes[i] + go func(val ValidatorID, stake uint) { defer wg.Done() //#nosec G204 -- Bypass linter warning for spawning subprocess with pubKeycmd arguments. - pubKeycmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[action.chain].binaryName, + pubKeycmd := exec.Command("docker", "exec", tr.containerConfig.InstanceName, tr.chainConfigs[action.Chain].BinaryName, "tendermint", "show-validator", - `--home`, tr.getValidatorHome(action.chain, val), + `--home`, tr.getValidatorHome(action.Chain, val), ) bzPubKey, err := pubKeycmd.CombinedOutput() @@ -1723,7 +1728,7 @@ func (tr TestRun) registerRepresentative( } //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - bz, err := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[action.chain].binaryName, + bz, err := exec.Command("docker", "exec", tr.containerConfig.InstanceName, tr.chainConfigs[action.Chain].BinaryName, "tx", "staking", "create-validator", `--amount`, fmt.Sprint(stake)+"stake", `--pubkey`, string(bzPubKey), @@ -1733,9 +1738,9 @@ func (tr TestRun) registerRepresentative( `--commission-max-change-rate`, "0.01", `--min-self-delegation`, "1", `--from`, `validator`+fmt.Sprint(val), - `--chain-id`, string(tr.chainConfigs[action.chain].chainId), - `--home`, tr.getValidatorHome(action.chain, val), - `--node`, tr.getValidatorNode(action.chain, val), + `--chain-id`, string(tr.chainConfigs[action.Chain].ChainId), + `--home`, tr.getValidatorHome(action.Chain, val), + `--node`, tr.getValidatorNode(action.Chain, val), `--keyring-backend`, `test`, `-y`, ).CombinedOutput() @@ -1744,7 +1749,7 @@ func (tr TestRun) registerRepresentative( } // wait for inclusion in a block -> '--broadcast-mode block' is deprecated - tr.waitBlocks(action.chain, 1, 10*time.Second) + tr.waitBlocks(action.Chain, 1, 10*time.Second) }(val, stake) } @@ -1752,23 +1757,23 @@ func (tr TestRun) registerRepresentative( } type submitChangeRewardDenomsProposalAction struct { - denom string - deposit uint - from validatorID + Denom string + Deposit uint + From ValidatorID } func (tr TestRun) submitChangeRewardDenomsProposal(action submitChangeRewardDenomsProposalAction, verbose bool) { - providerChain := tr.chainConfigs[chainID("provi")] + providerChain := tr.chainConfigs[ChainID("provi")] prop := client.ChangeRewardDenomsProposalJSON{ Summary: "Change reward denoms", ChangeRewardDenomsProposal: types.ChangeRewardDenomsProposal{ Title: "Change reward denoms", Description: "Change reward denoms", - DenomsToAdd: []string{action.denom}, + DenomsToAdd: []string{action.Denom}, DenomsToRemove: []string{"stake"}, }, - Deposit: fmt.Sprint(action.deposit) + `stake`, + Deposit: fmt.Sprint(action.Deposit) + `stake`, } bz, err := json.Marshal(prop) @@ -1782,7 +1787,7 @@ func (tr TestRun) submitChangeRewardDenomsProposal(action submitChangeRewardDeno } //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - bz, err = exec.Command("docker", "exec", tr.containerConfig.instanceName, + bz, err = exec.Command("docker", "exec", tr.containerConfig.InstanceName, "/bin/bash", "-c", fmt.Sprintf(`echo '%s' > %s`, jsonStr, "/change-reward-denoms-proposal.json")).CombinedOutput() if err != nil { @@ -1791,12 +1796,12 @@ func (tr TestRun) submitChangeRewardDenomsProposal(action submitChangeRewardDeno //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. // CHANGE REWARDS DENOM PROPOSAL - bz, err = exec.Command("docker", "exec", tr.containerConfig.instanceName, providerChain.binaryName, + bz, err = exec.Command("docker", "exec", tr.containerConfig.InstanceName, providerChain.BinaryName, "tx", "gov", "submit-legacy-proposal", "change-reward-denoms", "/change-reward-denoms-proposal.json", - `--from`, `validator`+fmt.Sprint(action.from), - `--chain-id`, string(providerChain.chainId), - `--home`, tr.getValidatorHome(providerChain.chainId, action.from), - `--node`, tr.getValidatorNode(providerChain.chainId, action.from), + `--from`, `validator`+fmt.Sprint(action.From), + `--chain-id`, string(providerChain.ChainId), + `--home`, tr.getValidatorHome(providerChain.ChainId, action.From), + `--node`, tr.getValidatorNode(providerChain.ChainId, action.From), `--gas`, "9000000", `--keyring-backend`, `test`, `-y`, @@ -1807,7 +1812,7 @@ func (tr TestRun) submitChangeRewardDenomsProposal(action submitChangeRewardDeno } // wait for inclusion in a block -> '--broadcast-mode block' is deprecated - tr.waitBlocks(chainID("provi"), 2, 30*time.Second) + tr.waitBlocks(ChainID("provi"), 2, 30*time.Second) } // Creates an additional node on selected chain @@ -1821,9 +1826,9 @@ func (tr TestRun) submitChangeRewardDenomsProposal(action submitChangeRewardDeno // - start the new node // Double sign should be registered within couple blocks. type doublesignSlashAction struct { - // start another node for this validator - validator validatorID - chain chainID + // start another node for this Validator + Validator ValidatorID + Chain ChainID } func (tr TestRun) invokeDoublesignSlash( @@ -1831,25 +1836,25 @@ func (tr TestRun) invokeDoublesignSlash( verbose bool, ) { if !tr.useCometmock { - chainConfig := tr.chainConfigs[action.chain] + chainConfig := tr.chainConfigs[action.Chain] //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - bz, err := exec.Command("docker", "exec", tr.containerConfig.instanceName, "/bin/bash", - "/testnet-scripts/cause-doublesign.sh", chainConfig.binaryName, string(action.validator), - string(chainConfig.chainId), chainConfig.ipPrefix).CombinedOutput() + bz, err := exec.Command("docker", "exec", tr.containerConfig.InstanceName, "/bin/bash", + "/testnet-scripts/cause-doublesign.sh", chainConfig.BinaryName, string(action.Validator), + string(chainConfig.ChainId), chainConfig.IpPrefix).CombinedOutput() if err != nil { log.Fatal(err, "\n", string(bz)) } tr.waitBlocks("provi", 10, 2*time.Minute) } else { // tr.useCometMock - validatorPrivateKeyAddress := tr.GetValidatorPrivateKeyAddress(action.chain, action.validator) + validatorPrivateKeyAddress := tr.GetValidatorPrivateKeyAddress(action.Chain, action.Validator) method := "cause_double_sign" params := fmt.Sprintf(`{"private_key_address":"%s"}`, validatorPrivateKeyAddress) - address := tr.getQueryNodeRPCAddress(action.chain) + address := tr.getQueryNodeRPCAddress(action.Chain) tr.curlJsonRPCRequest(method, params, address) - tr.waitBlocks(action.chain, 1, 10*time.Second) + tr.waitBlocks(action.Chain, 1, 10*time.Second) return } } @@ -1859,15 +1864,15 @@ func (tr TestRun) invokeDoublesignSlash( // See https://github.com/cometbft/cometbft/tree/main/spec/light-client/accountability // for more information about light client attacks. type lightClientEquivocationAttackAction struct { - validator validatorID - chain chainID + Validator ValidatorID + Chain ChainID } func (tr TestRun) lightClientEquivocationAttack( action lightClientEquivocationAttackAction, verbose bool, ) { - tr.lightClientAttack(action.validator, action.chain, LightClientEquivocationAttack) + tr.lightClientAttack(action.Validator, action.Chain, LightClientEquivocationAttack) } // Cause light client attack evidence for a certain validator to appear on the given chain. @@ -1875,15 +1880,15 @@ func (tr TestRun) lightClientEquivocationAttack( // See https://github.com/cometbft/cometbft/tree/main/spec/light-client/accountability // for more information about light client attacks. type lightClientAmnesiaAttackAction struct { - validator validatorID - chain chainID + Validator ValidatorID + Chain ChainID } func (tr TestRun) lightClientAmnesiaAttack( action lightClientAmnesiaAttackAction, verbose bool, ) { - tr.lightClientAttack(action.validator, action.chain, LightClientAmnesiaAttack) + tr.lightClientAttack(action.Validator, action.Chain, LightClientAmnesiaAttack) } // Cause light client attack evidence for a certain validator to appear on the given chain. @@ -1891,15 +1896,15 @@ func (tr TestRun) lightClientAmnesiaAttack( // See https://github.com/cometbft/cometbft/tree/main/spec/light-client/accountability // for more information about light client attacks. type lightClientLunaticAttackAction struct { - validator validatorID - chain chainID + Validator ValidatorID + Chain ChainID } func (tr TestRun) lightClientLunaticAttack( action lightClientLunaticAttackAction, verbose bool, ) { - tr.lightClientAttack(action.validator, action.chain, LightClientLunaticAttack) + tr.lightClientAttack(action.Validator, action.Chain, LightClientLunaticAttack) } type LightClientAttackType string @@ -1911,8 +1916,8 @@ const ( ) func (tr TestRun) lightClientAttack( - validator validatorID, - chain chainID, + validator ValidatorID, + chain ChainID, attackType LightClientAttackType, ) { if !tr.useCometmock { @@ -1930,18 +1935,18 @@ func (tr TestRun) lightClientAttack( } type assignConsumerPubKeyAction struct { - chain chainID - validator validatorID - consumerPubkey string - // reconfigureNode will change keys the node uses and restart - reconfigureNode bool + Chain ChainID + Validator ValidatorID + ConsumerPubkey string + // ReconfigureNode will change keys the node uses and restart + ReconfigureNode bool // executing the action should raise an error - expectError bool - expectedError string + ExpectError bool + ExpectedError string } func (tr TestRun) assignConsumerPubKey(action assignConsumerPubKeyAction, verbose bool) { - valCfg := tr.validatorConfigs[action.validator] + valCfg := tr.validatorConfigs[action.Validator] // Note: to get error response reported back from this command '--gas auto' needs to be set. gas := "auto" @@ -1951,19 +1956,19 @@ func (tr TestRun) assignConsumerPubKey(action assignConsumerPubKeyAction, verbos } assignKey := fmt.Sprintf( `%s tx provider assign-consensus-key %s '%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.consumerPubkey, - action.validator, - tr.chainConfigs[chainID("provi")].chainId, - tr.getValidatorHome(chainID("provi"), action.validator), - tr.getValidatorNode(chainID("provi"), action.validator), + tr.chainConfigs[ChainID("provi")].BinaryName, + string(tr.chainConfigs[action.Chain].ChainId), + action.ConsumerPubkey, + action.Validator, + tr.chainConfigs[ChainID("provi")].ChainId, + tr.getValidatorHome(ChainID("provi"), action.Validator), + tr.getValidatorNode(ChainID("provi"), action.Validator), gas, ) //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. cmd := exec.Command("docker", "exec", - tr.containerConfig.instanceName, + tr.containerConfig.InstanceName, "/bin/bash", "-c", assignKey, ) @@ -1973,13 +1978,13 @@ func (tr TestRun) assignConsumerPubKey(action assignConsumerPubKeyAction, verbos } bz, err := cmd.CombinedOutput() - if err != nil && !action.expectError { + if err != nil && !action.ExpectError { log.Fatalf("unexpected error during key assignment - output: %s, err: %s", string(bz), err) } - if action.expectError && !tr.useCometmock { // error report ony works with --gas auto, which does not work with CometMock, so ignore - if err == nil || !strings.Contains(string(bz), action.expectedError) { - log.Fatalf("expected error not raised: expected: '%s', got '%s'", action.expectedError, (bz)) + if action.ExpectError && !tr.useCometmock { // error report ony works with --gas auto, which does not work with CometMock, so ignore + if err == nil || !strings.Contains(string(bz), action.ExpectedError) { + log.Fatalf("expected error not raised: expected: '%s', got '%s'", action.ExpectedError, (bz)) } if verbose { @@ -1989,14 +1994,14 @@ func (tr TestRun) assignConsumerPubKey(action assignConsumerPubKeyAction, verbos // node was started with provider key // we swap the nodes's keys for consumer keys and restart it - if action.reconfigureNode { + if action.ReconfigureNode { //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - configureNodeCmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, "/bin/bash", - "/testnet-scripts/reconfigure-node.sh", tr.chainConfigs[action.chain].binaryName, - string(action.validator), string(action.chain), - tr.chainConfigs[action.chain].ipPrefix, valCfg.ipSuffix, - valCfg.consumerMnemonic, valCfg.consumerPrivValidatorKey, - valCfg.consumerNodeKey, + configureNodeCmd := exec.Command("docker", "exec", tr.containerConfig.InstanceName, "/bin/bash", + "/testnet-scripts/reconfigure-node.sh", tr.chainConfigs[action.Chain].BinaryName, + string(action.Validator), string(action.Chain), + tr.chainConfigs[action.Chain].IpPrefix, valCfg.IpSuffix, + valCfg.ConsumerMnemonic, valCfg.ConsumerPrivValidatorKey, + valCfg.ConsumerNodeKey, ) if verbose { @@ -2032,54 +2037,54 @@ func (tr TestRun) assignConsumerPubKey(action assignConsumerPubKeyAction, verbos // make the validator use consumer key // @POfftermatt I am currently using this for downtime slashing with cometmock // (I need to find the currently used validator key address)Í - valCfg.useConsumerKey = true - tr.validatorConfigs[action.validator] = valCfg + valCfg.UseConsumerKey = true + tr.validatorConfigs[action.Validator] = valCfg } // wait for inclusion in a block -> '--broadcast-mode block' is deprecated - tr.waitBlocks(chainID("provi"), 2, 30*time.Second) + tr.waitBlocks(ChainID("provi"), 2, 30*time.Second) } // slashThrottleDequeue polls slash queue sizes until nextQueueSize is achieved type slashThrottleDequeue struct { - chain chainID - currentQueueSize int - nextQueueSize int - // panic if timeout is exceeded - timeout time.Duration + Chain ChainID + CurrentQueueSize int + NextQueueSize int + // panic if Timeout is exceeded + Timeout time.Duration } func (tr TestRun) waitForSlashThrottleDequeue( action slashThrottleDequeue, verbose bool, ) { - timeout := time.Now().Add(action.timeout) + timeout := time.Now().Add(action.Timeout) initialGlobalQueueSize := int(tr.getGlobalSlashQueueSize()) - if initialGlobalQueueSize != action.currentQueueSize { - panic(fmt.Sprintf("wrong initial queue size: %d - expected global queue: %d\n", initialGlobalQueueSize, action.currentQueueSize)) + if initialGlobalQueueSize != action.CurrentQueueSize { + panic(fmt.Sprintf("wrong initial queue size: %d - expected global queue: %d\n", initialGlobalQueueSize, action.CurrentQueueSize)) } for { globalQueueSize := int(tr.getGlobalSlashQueueSize()) - chainQueueSize := int(tr.getConsumerChainPacketQueueSize(action.chain)) + chainQueueSize := int(tr.getConsumerChainPacketQueueSize(action.Chain)) if verbose { - fmt.Printf("waiting for packed queue size to reach: %d - current: %d\n", action.nextQueueSize, globalQueueSize) + fmt.Printf("waiting for packed queue size to reach: %d - current: %d\n", action.NextQueueSize, globalQueueSize) } // check if global queue size is equal to chain queue size - if globalQueueSize == chainQueueSize && globalQueueSize == action.nextQueueSize { //nolint:gocritic // this is the comparison that we want here. + if globalQueueSize == chainQueueSize && globalQueueSize == action.NextQueueSize { //nolint:gocritic // this is the comparison that we want here. break } if time.Now().After(timeout) { - panic(fmt.Sprintf("\n\n\nwaitForSlashThrottleDequeuemethod has timed out after: %s\n\n", action.timeout)) + panic(fmt.Sprintf("\n\n\nwaitForSlashThrottleDequeuemethod has timed out after: %s\n\n", action.Timeout)) } time.Sleep(500 * time.Millisecond) } // wair for 2 blocks to be created // allowing the jailing to be incorporated into voting power - tr.waitBlocks(action.chain, 2, time.Minute) + tr.waitBlocks(action.Chain, 2, time.Minute) } func uintPointer(i uint) *uint { @@ -2089,7 +2094,7 @@ func uintPointer(i uint) *uint { // GetPathNameForGorelayer returns the name of the path between two given chains used by Gorelayer. // Since paths are bidirectional, we need either chain to be able to be provided as first or second argument // and still return the same name, so we sort the chain names alphabetically. -func (tr TestRun) GetPathNameForGorelayer(chainA, chainB chainID) string { +func (tr TestRun) GetPathNameForGorelayer(chainA, chainB ChainID) string { var pathName string if string(chainA) < string(chainB) { pathName = string(chainA) + "-" + string(chainB) @@ -2121,7 +2126,7 @@ func (tr *TestRun) WaitTime(duration time.Duration) { } } -func (tr TestRun) AdvanceTimeForChain(chain chainID, duration time.Duration) { +func (tr TestRun) AdvanceTimeForChain(chain ChainID, duration time.Duration) { // cometmock avoids sleeping, and instead advances time for all chains method := "advance_time" params := fmt.Sprintf(`{"duration_in_seconds": "%d"}`, int(math.Ceil(duration.Seconds()))) diff --git a/tests/e2e/actions_sovereign_chain.go b/tests/e2e/actions_sovereign_chain.go index cf2d6288e8..88aa8bf03d 100644 --- a/tests/e2e/actions_sovereign_chain.go +++ b/tests/e2e/actions_sovereign_chain.go @@ -10,10 +10,10 @@ import ( ) type StartSovereignChainAction struct { - chain chainID - validators []StartChainValidator + Chain ChainID + Validators []StartChainValidator // Genesis changes specific to this action, appended to genesis changes defined in chain config - genesisChanges string + GenesisChanges string } // calls a simplified startup script (start-sovereign.sh) and runs a validator node @@ -38,20 +38,20 @@ func (tr TestRun) startSovereignChain( } var validators []jsonValAttrs - for _, val := range action.validators { + for _, val := range action.Validators { validators = append(validators, jsonValAttrs{ - Mnemonic: tr.validatorConfigs[val.id].mnemonic, - NodeKey: tr.validatorConfigs[val.id].nodeKey, - ValId: fmt.Sprint(val.id), - PrivValidatorKey: tr.validatorConfigs[val.id].privValidatorKey, - Allocation: fmt.Sprint(val.allocation) + "stake", - Stake: fmt.Sprint(val.stake) + "stake", - IpSuffix: tr.validatorConfigs[val.id].ipSuffix, - - ConsumerMnemonic: tr.validatorConfigs[val.id].consumerMnemonic, - ConsumerPrivValidatorKey: tr.validatorConfigs[val.id].consumerPrivValidatorKey, + Mnemonic: tr.validatorConfigs[val.Id].Mnemonic, + NodeKey: tr.validatorConfigs[val.Id].NodeKey, + ValId: fmt.Sprint(val.Id), + PrivValidatorKey: tr.validatorConfigs[val.Id].PrivValidatorKey, + Allocation: fmt.Sprint(val.Allocation) + "stake", + Stake: fmt.Sprint(val.Stake) + "stake", + IpSuffix: tr.validatorConfigs[val.Id].IpSuffix, + + ConsumerMnemonic: tr.validatorConfigs[val.Id].ConsumerMnemonic, + ConsumerPrivValidatorKey: tr.validatorConfigs[val.Id].ConsumerPrivValidatorKey, // if true node will be started with consumer key for each consumer chain - StartWithConsumerKey: tr.validatorConfigs[val.id].useConsumerKey, + StartWithConsumerKey: tr.validatorConfigs[val.Id].UseConsumerKey, }) } @@ -62,16 +62,16 @@ func (tr TestRun) startSovereignChain( // Concat genesis changes defined in chain config, with any custom genesis changes for this chain instantiation var genesisChanges string - if action.genesisChanges != "" { - genesisChanges = chainConfig.genesisChanges + " | " + action.genesisChanges + if action.GenesisChanges != "" { + genesisChanges = chainConfig.GenesisChanges + " | " + action.GenesisChanges } else { - genesisChanges = chainConfig.genesisChanges + genesisChanges = chainConfig.GenesisChanges } //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, "/bin/bash", - "/testnet-scripts/start-sovereign.sh", chainConfig.binaryName, string(vals), - string(chainConfig.chainId), chainConfig.ipPrefix, genesisChanges, + cmd := exec.Command("docker", "exec", tr.containerConfig.InstanceName, "/bin/bash", + "/testnet-scripts/start-sovereign.sh", chainConfig.BinaryName, string(vals), + string(chainConfig.ChainId), chainConfig.IpPrefix, genesisChanges, tr.tendermintConfigOverride, ) @@ -100,16 +100,16 @@ func (tr TestRun) startSovereignChain( log.Fatal(err) } tr.addChainToRelayer(addChainToRelayerAction{ - chain: action.chain, - validator: action.validators[0].id, + Chain: action.Chain, + Validator: action.Validators[0].Id, }, verbose) } type LegacyUpgradeProposalAction struct { - chainID chainID - upgradeTitle string - proposer validatorID - upgradeHeight uint64 + ChainID ChainID + UpgradeTitle string + Proposer ValidatorID + UpgradeHeight uint64 } func (tr *TestRun) submitLegacyUpgradeProposal(action LegacyUpgradeProposalAction, verbose bool) { @@ -128,18 +128,18 @@ func (tr *TestRun) submitLegacyUpgradeProposal(action LegacyUpgradeProposalActio --node %s \ --no-validate \ -y`, - tr.chainConfigs[chainID("sover")].binaryName, - action.upgradeTitle, - action.upgradeTitle, - fmt.Sprint(action.upgradeHeight), - action.proposer, - tr.chainConfigs[chainID("sover")].chainId, - tr.getValidatorHome(chainID("sover"), action.proposer), - tr.getValidatorNode(chainID("sover"), action.proposer), + tr.chainConfigs[ChainID("sover")].BinaryName, + action.UpgradeTitle, + action.UpgradeTitle, + fmt.Sprint(action.UpgradeHeight), + action.Proposer, + tr.chainConfigs[ChainID("sover")].ChainId, + tr.getValidatorHome(ChainID("sover"), action.Proposer), + tr.getValidatorNode(ChainID("sover"), action.Proposer), ) //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. cmd := exec.Command("docker", "exec", - tr.containerConfig.instanceName, + tr.containerConfig.InstanceName, "/bin/bash", "-c", submit, ) @@ -153,16 +153,16 @@ func (tr *TestRun) submitLegacyUpgradeProposal(action LegacyUpgradeProposalActio log.Fatal(err, "\n", string(bz)) } - tr.waitBlocks(action.chainID, 1, 15*time.Second) + tr.waitBlocks(action.ChainID, 1, 15*time.Second) } type waitUntilBlockAction struct { - block uint - chain chainID + Block uint + Chain ChainID } func (tr *TestRun) waitUntilBlockOnChain(action waitUntilBlockAction) { - fmt.Println("waitUntilBlockOnChain is waiting for block:", action.block) - tr.waitUntilBlock(action.chain, action.block, 120*time.Second) - fmt.Println("waitUntilBlockOnChain done waiting for block:", action.block) + fmt.Println("waitUntilBlockOnChain is waiting for block:", action.Block) + tr.waitUntilBlock(action.Chain, action.Block, 120*time.Second) + fmt.Println("waitUntilBlockOnChain done waiting for block:", action.Block) } diff --git a/tests/e2e/config.go b/tests/e2e/config.go index 373281162d..6726ab2304 100644 --- a/tests/e2e/config.go +++ b/tests/e2e/config.go @@ -8,55 +8,55 @@ import ( // TODO: Determine if user defined type (wrapping a primitive string) is desired in long run type ( - chainID string - validatorID string + ChainID string + ValidatorID string ) // Attributes that are unique to a validator. Allows us to map (part of) // the set of strings defined above to a set of viable validators type ValidatorConfig struct { - mnemonic string - delAddress string - valoperAddress string - valconsAddress string - privValidatorKey string - nodeKey string + Mnemonic string + DelAddress string + ValoperAddress string + ValconsAddress string + PrivValidatorKey string + NodeKey string // Must be an integer greater than 0 and less than 253 - ipSuffix string + IpSuffix string // consumer chain key assignment data // keys are used on a new node - consumerMnemonic string - consumerDelAddress string - consumerValoperAddress string - consumerValconsAddress string - consumerValPubKey string - consumerPrivValidatorKey string - consumerNodeKey string - useConsumerKey bool // if true the validator node will start with consumer key + ConsumerMnemonic string + ConsumerDelAddress string + ConsumerValoperAddress string + ConsumerValconsAddress string + ConsumerValPubKey string + ConsumerPrivValidatorKey string + ConsumerNodeKey string + UseConsumerKey bool // if true the validator node will start with consumer key } // Attributes that are unique to a chain. Allows us to map (part of) // the set of strings defined above to a set of viable chains type ChainConfig struct { - chainId chainID + ChainId ChainID // Must be unique per chain - ipPrefix string - votingWaitTime uint + IpPrefix string + VotingWaitTime uint // Any transformations to apply to the genesis file of all chains instantiated with this chain config, as a jq string. // Example: ".app_state.gov.params.voting_period = \"5s\" | .app_state.slashing.params.signed_blocks_window = \"2\" | .app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\"" - genesisChanges string - binaryName string + GenesisChanges string + BinaryName string // binary to use after upgrade height - upgradeBinary string + UpgradeBinary string } type ContainerConfig struct { - containerName string - instanceName string - ccvVersion string - now time.Time + ContainerName string + InstanceName string + CcvVersion string + Now time.Time } // TODO: Split out TestRun and system wide config like localsdkpath @@ -64,8 +64,8 @@ type TestRun struct { // These are the non altered values during a typical test run, where multiple test runs can exist // to validate different action sequences and corresponding state checks. containerConfig ContainerConfig - validatorConfigs map[validatorID]ValidatorConfig - chainConfigs map[chainID]ChainConfig + validatorConfigs map[ValidatorID]ValidatorConfig + chainConfigs map[ChainID]ChainConfig // override config.toml parameters // usually used to override timeout_commit // having shorter timeout_commit reduces the test runtime because blocks are produced faster @@ -77,7 +77,7 @@ type TestRun struct { useGorelayer bool // if false, Hermes is used as the relayer gaiaTag string // chains which are running, i.e. producing blocks, at the moment - runningChains map[chainID]bool + runningChains map[ChainID]bool // Used with CometMock. The time by which chains have been advanced. Used to keep chains in sync: when a new chain is started, advance its time by this value to keep chains in sync. timeOffset time.Duration @@ -86,67 +86,67 @@ type TestRun struct { // Initialize initializes the TestRun instance by setting the runningChains field to an empty map. func (tr *TestRun) Initialize() { - tr.runningChains = make(map[chainID]bool) + tr.runningChains = make(map[ChainID]bool) } -func getDefaultValidators() map[validatorID]ValidatorConfig { - return map[validatorID]ValidatorConfig{ - validatorID("alice"): { - mnemonic: "pave immune ethics wrap gain ceiling always holiday employ earth tumble real ice engage false unable carbon equal fresh sick tattoo nature pupil nuclear", - delAddress: "cosmos19pe9pg5dv9k5fzgzmsrgnw9rl9asf7ddwhu7lm", - valoperAddress: "cosmosvaloper19pe9pg5dv9k5fzgzmsrgnw9rl9asf7ddtrgtng", - valconsAddress: "cosmosvalcons1qmq08eruchr5sf5s3rwz7djpr5a25f7xw4mceq", - privValidatorKey: `{"address":"06C0F3E47CC5C748269088DC2F36411D3AAA27C6","pub_key":{"type":"tendermint/PubKeyEd25519","value":"RrclQz9bIhkIy/gfL485g3PYMeiIku4qeo495787X10="},"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"uX+ZpDMg89a6gtqs/+MQpCTSqlkZ0nJQJOhLlCJvwvdGtyVDP1siGQjL+B8vjzmDc9gx6IiS7ip6jj3nvztfXQ=="}}`, - nodeKey: `{"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"fjw4/DAhyRPnwKgXns5SV7QfswRSXMWJpHS7TyULDmJ8ofUc5poQP8dgr8bZRbCV5RV8cPqDq3FPdqwpmUbmdA=="}}`, - ipSuffix: "4", +func getDefaultValidators() map[ValidatorID]ValidatorConfig { + return map[ValidatorID]ValidatorConfig{ + ValidatorID("alice"): { + Mnemonic: "pave immune ethics wrap gain ceiling always holiday employ earth tumble real ice engage false unable carbon equal fresh sick tattoo nature pupil nuclear", + DelAddress: "cosmos19pe9pg5dv9k5fzgzmsrgnw9rl9asf7ddwhu7lm", + ValoperAddress: "cosmosvaloper19pe9pg5dv9k5fzgzmsrgnw9rl9asf7ddtrgtng", + ValconsAddress: "cosmosvalcons1qmq08eruchr5sf5s3rwz7djpr5a25f7xw4mceq", + PrivValidatorKey: `{"address":"06C0F3E47CC5C748269088DC2F36411D3AAA27C6","pub_key":{"type":"tendermint/PubKeyEd25519","value":"RrclQz9bIhkIy/gfL485g3PYMeiIku4qeo495787X10="},"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"uX+ZpDMg89a6gtqs/+MQpCTSqlkZ0nJQJOhLlCJvwvdGtyVDP1siGQjL+B8vjzmDc9gx6IiS7ip6jj3nvztfXQ=="}}`, + NodeKey: `{"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"fjw4/DAhyRPnwKgXns5SV7QfswRSXMWJpHS7TyULDmJ8ofUc5poQP8dgr8bZRbCV5RV8cPqDq3FPdqwpmUbmdA=="}}`, + IpSuffix: "4", // consumer chain assigned key - consumerMnemonic: "exile install vapor thing little toss immune notable lounge december final easy strike title end program interest quote cloth forget forward job october twenty", - consumerDelAddress: "cosmos1eeeggku6dzk3mv7wph3zq035rhtd890sjswszd", - consumerValoperAddress: "cosmosvaloper1eeeggku6dzk3mv7wph3zq035rhtd890shy69w7", - consumerValconsAddress: "cosmosvalcons1muys5jyqk4xd27e208nym85kn0t4zjcfeu63fe", - consumerValPubKey: `{"@type":"/cosmos.crypto.ed25519.PubKey","key":"ujY14AgopV907IYgPAk/5x8c9267S4fQf89nyeCPTes="}`, - consumerPrivValidatorKey: `{"address":"DF090A4880B54CD57B2A79E64D9E969BD7514B09","pub_key":{"type":"tendermint/PubKeyEd25519","value":"ujY14AgopV907IYgPAk/5x8c9267S4fQf89nyeCPTes="},"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"TRJgf7lkTjs/sj43pyweEOanyV7H7fhnVivOi0A4yjW6NjXgCCilX3TshiA8CT/nHxz3brtLh9B/z2fJ4I9N6w=="}}`, - consumerNodeKey: `{"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"F966RL9pi20aXRzEBe4D0xRQJtZt696Xxz44XUON52cFc83FMn1WXJbP6arvA2JPyn2LA3DLKCFHSgALrCGXGA=="}}`, - useConsumerKey: false, + ConsumerMnemonic: "exile install vapor thing little toss immune notable lounge december final easy strike title end program interest quote cloth forget forward job october twenty", + ConsumerDelAddress: "cosmos1eeeggku6dzk3mv7wph3zq035rhtd890sjswszd", + ConsumerValoperAddress: "cosmosvaloper1eeeggku6dzk3mv7wph3zq035rhtd890shy69w7", + ConsumerValconsAddress: "cosmosvalcons1muys5jyqk4xd27e208nym85kn0t4zjcfeu63fe", + ConsumerValPubKey: `{"@type":"/cosmos.crypto.ed25519.PubKey","key":"ujY14AgopV907IYgPAk/5x8c9267S4fQf89nyeCPTes="}`, + ConsumerPrivValidatorKey: `{"address":"DF090A4880B54CD57B2A79E64D9E969BD7514B09","pub_key":{"type":"tendermint/PubKeyEd25519","value":"ujY14AgopV907IYgPAk/5x8c9267S4fQf89nyeCPTes="},"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"TRJgf7lkTjs/sj43pyweEOanyV7H7fhnVivOi0A4yjW6NjXgCCilX3TshiA8CT/nHxz3brtLh9B/z2fJ4I9N6w=="}}`, + ConsumerNodeKey: `{"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"F966RL9pi20aXRzEBe4D0xRQJtZt696Xxz44XUON52cFc83FMn1WXJbP6arvA2JPyn2LA3DLKCFHSgALrCGXGA=="}}`, + UseConsumerKey: false, }, - validatorID("bob"): { - mnemonic: "glass trip produce surprise diamond spin excess gaze wash drum human solve dress minor artefact canoe hard ivory orange dinner hybrid moral potato jewel", - delAddress: "cosmos1dkas8mu4kyhl5jrh4nzvm65qz588hy9qcz08la", - valoperAddress: "cosmosvaloper1dkas8mu4kyhl5jrh4nzvm65qz588hy9qakmjnw", - valconsAddress: "cosmosvalcons1nx7n5uh0ztxsynn4sje6eyq2ud6rc6klc96w39", - privValidatorKey: `{"address":"99BD3A72EF12CD024E7584B3AC900AE3743C6ADF","pub_key":{"type":"tendermint/PubKeyEd25519","value":"mAN6RXYxSM4MNGSIriYiS7pHuwAcOHDQAy9/wnlSzOI="},"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"QePcwfWtOavNK7pBJrtoLMzarHKn6iBWfWPFeyV+IdmYA3pFdjFIzgw0ZIiuJiJLuke7ABw4cNADL3/CeVLM4g=="}}`, - nodeKey: `{"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"TQ4vHcO/vKdzGtWpelkX53WdMQd4kTsWGFrdcatdXFvWyO215Rewn5IRP0FszPLWr2DqPzmuH8WvxYGk5aeOXw=="}}`, - ipSuffix: "5", + ValidatorID("bob"): { + Mnemonic: "glass trip produce surprise diamond spin excess gaze wash drum human solve dress minor artefact canoe hard ivory orange dinner hybrid moral potato jewel", + DelAddress: "cosmos1dkas8mu4kyhl5jrh4nzvm65qz588hy9qcz08la", + ValoperAddress: "cosmosvaloper1dkas8mu4kyhl5jrh4nzvm65qz588hy9qakmjnw", + ValconsAddress: "cosmosvalcons1nx7n5uh0ztxsynn4sje6eyq2ud6rc6klc96w39", + PrivValidatorKey: `{"address":"99BD3A72EF12CD024E7584B3AC900AE3743C6ADF","pub_key":{"type":"tendermint/PubKeyEd25519","value":"mAN6RXYxSM4MNGSIriYiS7pHuwAcOHDQAy9/wnlSzOI="},"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"QePcwfWtOavNK7pBJrtoLMzarHKn6iBWfWPFeyV+IdmYA3pFdjFIzgw0ZIiuJiJLuke7ABw4cNADL3/CeVLM4g=="}}`, + NodeKey: `{"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"TQ4vHcO/vKdzGtWpelkX53WdMQd4kTsWGFrdcatdXFvWyO215Rewn5IRP0FszPLWr2DqPzmuH8WvxYGk5aeOXw=="}}`, + IpSuffix: "5", // consumer chain assigned key - consumerMnemonic: "grunt list hour endless observe better spoil penalty lab duck only layer vague fantasy satoshi record demise topple space shaft solar practice donor sphere", - consumerDelAddress: "cosmos1q90l6j6lzzgt460ehjj56azknlt5yrd4s38n97", - consumerValoperAddress: "cosmosvaloper1q90l6j6lzzgt460ehjj56azknlt5yrd449nxfd", - consumerValconsAddress: "cosmosvalcons1uuec3cjxajv5te08p220usrjhkfhg9wyvqn0tm", - consumerValPubKey: `{"@type":"/cosmos.crypto.ed25519.PubKey","key":"QlG+iYe6AyYpvY1z9RNJKCVlH14Q/qSz4EjGdGCru3o="}`, - consumerPrivValidatorKey: `{"address":"E73388E246EC9945E5E70A94FE4072BD937415C4","pub_key":{"type":"tendermint/PubKeyEd25519","value":"QlG+iYe6AyYpvY1z9RNJKCVlH14Q/qSz4EjGdGCru3o="},"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"OFR4w+FC6EMw5fAGTrHVexyPrjzQ7QfqgZOMgVf0izlCUb6Jh7oDJim9jXP1E0koJWUfXhD+pLPgSMZ0YKu7eg=="}}`, - consumerNodeKey: `{"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"uhPCqnL2KE8m/8OFNLQ5bN3CJr6mds+xfBi0E4umT/s2uWiJhet+vbYx88DHSdof3gGFNTIzAIxSppscBKX96w=="}}`, - useConsumerKey: false, + ConsumerMnemonic: "grunt list hour endless observe better spoil penalty lab duck only layer vague fantasy satoshi record demise topple space shaft solar practice donor sphere", + ConsumerDelAddress: "cosmos1q90l6j6lzzgt460ehjj56azknlt5yrd4s38n97", + ConsumerValoperAddress: "cosmosvaloper1q90l6j6lzzgt460ehjj56azknlt5yrd449nxfd", + ConsumerValconsAddress: "cosmosvalcons1uuec3cjxajv5te08p220usrjhkfhg9wyvqn0tm", + ConsumerValPubKey: `{"@type":"/cosmos.crypto.ed25519.PubKey","key":"QlG+iYe6AyYpvY1z9RNJKCVlH14Q/qSz4EjGdGCru3o="}`, + ConsumerPrivValidatorKey: `{"address":"E73388E246EC9945E5E70A94FE4072BD937415C4","pub_key":{"type":"tendermint/PubKeyEd25519","value":"QlG+iYe6AyYpvY1z9RNJKCVlH14Q/qSz4EjGdGCru3o="},"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"OFR4w+FC6EMw5fAGTrHVexyPrjzQ7QfqgZOMgVf0izlCUb6Jh7oDJim9jXP1E0koJWUfXhD+pLPgSMZ0YKu7eg=="}}`, + ConsumerNodeKey: `{"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"uhPCqnL2KE8m/8OFNLQ5bN3CJr6mds+xfBi0E4umT/s2uWiJhet+vbYx88DHSdof3gGFNTIzAIxSppscBKX96w=="}}`, + UseConsumerKey: false, }, - validatorID("carol"): { - mnemonic: "sight similar better jar bitter laptop solve fashion father jelly scissors chest uniform play unhappy convince silly clump another conduct behave reunion marble animal", - delAddress: "cosmos19hz4m226ztankqramvt4a7t0shejv4dc79gp9u", - valoperAddress: "cosmosvaloper19hz4m226ztankqramvt4a7t0shejv4dcm3u5f0", - valconsAddress: "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6", - privValidatorKey: `{"address":"C888306A908A217B9A943D1DAD8790044D0947A4","pub_key":{"type":"tendermint/PubKeyEd25519","value":"IHo4QEikWZfIKmM0X+N+BjKttz8HOzGs2npyjiba3Xk="},"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"z08bmSB91uFVpVmR3t2ewd/bDjZ/AzwQpe5rKjWiPG0gejhASKRZl8gqYzRf434GMq23Pwc7MazaenKOJtrdeQ=="}}`, - nodeKey: `{"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"WLTcHEjbwB24Wp3z5oBSYTvtGQonz/7IQabOFw85BN0UkkyY5HDf38o8oHlFxVI26f+DFVeICuLbe9aXKGnUeg=="}}`, - ipSuffix: "6", + ValidatorID("carol"): { + Mnemonic: "sight similar better jar bitter laptop solve fashion father jelly scissors chest uniform play unhappy convince silly clump another conduct behave reunion marble animal", + DelAddress: "cosmos19hz4m226ztankqramvt4a7t0shejv4dc79gp9u", + ValoperAddress: "cosmosvaloper19hz4m226ztankqramvt4a7t0shejv4dcm3u5f0", + ValconsAddress: "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6", + PrivValidatorKey: `{"address":"C888306A908A217B9A943D1DAD8790044D0947A4","pub_key":{"type":"tendermint/PubKeyEd25519","value":"IHo4QEikWZfIKmM0X+N+BjKttz8HOzGs2npyjiba3Xk="},"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"z08bmSB91uFVpVmR3t2ewd/bDjZ/AzwQpe5rKjWiPG0gejhASKRZl8gqYzRf434GMq23Pwc7MazaenKOJtrdeQ=="}}`, + NodeKey: `{"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"WLTcHEjbwB24Wp3z5oBSYTvtGQonz/7IQabOFw85BN0UkkyY5HDf38o8oHlFxVI26f+DFVeICuLbe9aXKGnUeg=="}}`, + IpSuffix: "6", // consumer chain assigned key - consumerMnemonic: "clip choose cake west range gun slam cry village receive juice galaxy lend ritual range provide ritual can since verify breeze vacant play dragon", - consumerDelAddress: "cosmos1sx6j9g2rh324a342a5f0rnx7me34r9nwgf0mc7", - consumerValoperAddress: "cosmosvaloper1sx6j9g2rh324a342a5f0rnx7me34r9nwdamw5d", - consumerValconsAddress: "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk", - consumerValPubKey: `{"@type":"/cosmos.crypto.ed25519.PubKey","key":"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is="}`, - consumerPrivValidatorKey: `{"address":"B41C3A40142963AA5B12DDD1C4E5890C0B3926B1","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is="},"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"3YaBAZLA+sl/E73lLfbFbG0u6DYm33ayr/0UpCt/vFBSLkZ/X6a1ZR0fy7fGWbN0ogP4Xc8rSx9dnvcZnqrqKw=="}}`, - consumerNodeKey: `{"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"rxBzFedtD3pqgfJQblbxGusKOr47oBfr8ba0Iz14gobtDRZQZlSZ/UGP4pSHkVf+4vtkrkO1vRHBYJobuiP+7A=="}}`, - useConsumerKey: true, + ConsumerMnemonic: "clip choose cake west range gun slam cry village receive juice galaxy lend ritual range provide ritual can since verify breeze vacant play dragon", + ConsumerDelAddress: "cosmos1sx6j9g2rh324a342a5f0rnx7me34r9nwgf0mc7", + ConsumerValoperAddress: "cosmosvaloper1sx6j9g2rh324a342a5f0rnx7me34r9nwdamw5d", + ConsumerValconsAddress: "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk", + ConsumerValPubKey: `{"@type":"/cosmos.crypto.ed25519.PubKey","key":"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is="}`, + ConsumerPrivValidatorKey: `{"address":"B41C3A40142963AA5B12DDD1C4E5890C0B3926B1","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is="},"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"3YaBAZLA+sl/E73lLfbFbG0u6DYm33ayr/0UpCt/vFBSLkZ/X6a1ZR0fy7fGWbN0ogP4Xc8rSx9dnvcZnqrqKw=="}}`, + ConsumerNodeKey: `{"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"rxBzFedtD3pqgfJQblbxGusKOr47oBfr8ba0Iz14gobtDRZQZlSZ/UGP4pSHkVf+4vtkrkO1vRHBYJobuiP+7A=="}}`, + UseConsumerKey: true, }, } } @@ -155,19 +155,19 @@ func SlashThrottleTestRun() TestRun { tr := TestRun{ name: "slash-throttling", containerConfig: ContainerConfig{ - containerName: "interchain-security-slash-container", - instanceName: "interchain-security-slash-instance", - ccvVersion: "1", - now: time.Now(), + ContainerName: "interchain-security-slash-container", + InstanceName: "interchain-security-slash-instance", + CcvVersion: "1", + Now: time.Now(), }, validatorConfigs: getDefaultValidators(), - chainConfigs: map[chainID]ChainConfig{ - chainID("provi"): { - chainId: chainID("provi"), - binaryName: "interchain-security-pd", - ipPrefix: "7.7.7", - votingWaitTime: 20, - genesisChanges: ".app_state.gov.params.voting_period = \"20s\" | " + + chainConfigs: map[ChainID]ChainConfig{ + ChainID("provi"): { + ChainId: ChainID("provi"), + BinaryName: "interchain-security-pd", + IpPrefix: "7.7.7", + VotingWaitTime: 20, + GenesisChanges: ".app_state.gov.params.voting_period = \"20s\" | " + // Custom slashing parameters for testing validator downtime functionality // See https://docs.cosmos.network/main/modules/slashing/04_begin_block.html#uptime-tracking ".app_state.slashing.params.signed_blocks_window = \"10\" | " + @@ -177,12 +177,12 @@ func SlashThrottleTestRun() TestRun { ".app_state.provider.params.slash_meter_replenish_fraction = \"0.10\" | " + ".app_state.provider.params.slash_meter_replenish_period = \"20s\"", }, - chainID("consu"): { - chainId: chainID("consu"), - binaryName: "interchain-security-cd", - ipPrefix: "7.7.8", - votingWaitTime: 20, - genesisChanges: ".app_state.gov.params.voting_period = \"20s\" | " + + ChainID("consu"): { + ChainId: ChainID("consu"), + BinaryName: "interchain-security-cd", + IpPrefix: "7.7.8", + VotingWaitTime: 20, + GenesisChanges: ".app_state.gov.params.voting_period = \"20s\" | " + ".app_state.slashing.params.signed_blocks_window = \"15\" | " + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + ".app_state.slashing.params.downtime_jail_duration = \"60s\" | " + @@ -200,19 +200,19 @@ func DefaultTestRun() TestRun { tr := TestRun{ name: "default", containerConfig: ContainerConfig{ - containerName: "interchain-security-container", - instanceName: "interchain-security-instance", - ccvVersion: "1", - now: time.Now(), + ContainerName: "interchain-security-container", + InstanceName: "interchain-security-instance", + CcvVersion: "1", + Now: time.Now(), }, validatorConfigs: getDefaultValidators(), - chainConfigs: map[chainID]ChainConfig{ - chainID("provi"): { - chainId: chainID("provi"), - binaryName: "interchain-security-pd", - ipPrefix: "7.7.7", - votingWaitTime: 20, - genesisChanges: ".app_state.gov.params.voting_period = \"20s\" | " + + chainConfigs: map[ChainID]ChainConfig{ + ChainID("provi"): { + ChainId: ChainID("provi"), + BinaryName: "interchain-security-pd", + IpPrefix: "7.7.7", + VotingWaitTime: 20, + GenesisChanges: ".app_state.gov.params.voting_period = \"20s\" | " + // Custom slashing parameters for testing validator downtime functionality // See https://docs.cosmos.network/main/modules/slashing/04_begin_block.html#uptime-tracking ".app_state.slashing.params.signed_blocks_window = \"10\" | " + @@ -222,12 +222,12 @@ func DefaultTestRun() TestRun { ".app_state.provider.params.slash_meter_replenish_fraction = \"1.0\" | " + // This disables slash packet throttling ".app_state.provider.params.slash_meter_replenish_period = \"3s\"", }, - chainID("consu"): { - chainId: chainID("consu"), - binaryName: "interchain-security-cd", - ipPrefix: "7.7.8", - votingWaitTime: 20, - genesisChanges: ".app_state.gov.params.voting_period = \"20s\" | " + + ChainID("consu"): { + ChainId: ChainID("consu"), + BinaryName: "interchain-security-cd", + IpPrefix: "7.7.8", + VotingWaitTime: 20, + GenesisChanges: ".app_state.gov.params.voting_period = \"20s\" | " + ".app_state.slashing.params.signed_blocks_window = \"15\" | " + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + ".app_state.slashing.params.downtime_jail_duration = \"60s\" | " + @@ -257,19 +257,19 @@ func DemocracyTestRun(allowReward bool) TestRun { tr := TestRun{ name: "democracy", containerConfig: ContainerConfig{ - containerName: "interchain-security-democ-container", - instanceName: "interchain-security-democ-instance", - ccvVersion: "1", - now: time.Now(), + ContainerName: "interchain-security-democ-container", + InstanceName: "interchain-security-democ-instance", + CcvVersion: "1", + Now: time.Now(), }, validatorConfigs: getDefaultValidators(), - chainConfigs: map[chainID]ChainConfig{ - chainID("provi"): { - chainId: chainID("provi"), - binaryName: "interchain-security-pd", - ipPrefix: "7.7.7", - votingWaitTime: 20, - genesisChanges: ".app_state.gov.params.voting_period = \"20s\" | " + + chainConfigs: map[ChainID]ChainConfig{ + ChainID("provi"): { + ChainId: ChainID("provi"), + BinaryName: "interchain-security-pd", + IpPrefix: "7.7.7", + VotingWaitTime: 20, + GenesisChanges: ".app_state.gov.params.voting_period = \"20s\" | " + // Custom slashing parameters for testing validator downtime functionality // See https://docs.cosmos.network/main/modules/slashing/04_begin_block.html#uptime-tracking ".app_state.slashing.params.signed_blocks_window = \"10\" | " + @@ -278,12 +278,12 @@ func DemocracyTestRun(allowReward bool) TestRun { ".app_state.slashing.params.slash_fraction_downtime = \"0.010000000000000000\" | " + ".app_state.provider.params.slash_meter_replenish_fraction = \"1.0\"", // This disables slash packet throttling }, - chainID("democ"): { - chainId: chainID("democ"), - binaryName: "interchain-security-cdd", - ipPrefix: "7.7.9", - votingWaitTime: 20, - genesisChanges: consumerGenChanges, + ChainID("democ"): { + ChainId: ChainID("democ"), + BinaryName: "interchain-security-cdd", + IpPrefix: "7.7.9", + VotingWaitTime: 20, + GenesisChanges: consumerGenChanges, }, }, tendermintConfigOverride: `s/timeout_commit = "5s"/timeout_commit = "1s"/;` + @@ -297,19 +297,19 @@ func MultiConsumerTestRun() TestRun { tr := TestRun{ name: "multi-consumer", containerConfig: ContainerConfig{ - containerName: "interchain-security-multic-container", - instanceName: "interchain-security-multic-instance", - ccvVersion: "1", - now: time.Now(), + ContainerName: "interchain-security-multic-container", + InstanceName: "interchain-security-multic-instance", + CcvVersion: "1", + Now: time.Now(), }, validatorConfigs: getDefaultValidators(), - chainConfigs: map[chainID]ChainConfig{ - chainID("provi"): { - chainId: chainID("provi"), - binaryName: "interchain-security-pd", - ipPrefix: "7.7.7", - votingWaitTime: 20, - genesisChanges: ".app_state.gov.params.voting_period = \"30s\" | " + + chainConfigs: map[ChainID]ChainConfig{ + ChainID("provi"): { + ChainId: ChainID("provi"), + BinaryName: "interchain-security-pd", + IpPrefix: "7.7.7", + VotingWaitTime: 20, + GenesisChanges: ".app_state.gov.params.voting_period = \"30s\" | " + // Custom slashing parameters for testing validator downtime functionality // See https://docs.cosmos.network/main/modules/slashing/04_begin_block.html#uptime-tracking ".app_state.slashing.params.signed_blocks_window = \"10\" | " + @@ -318,23 +318,23 @@ func MultiConsumerTestRun() TestRun { ".app_state.slashing.params.slash_fraction_downtime = \"0.010000000000000000\" | " + ".app_state.provider.params.slash_meter_replenish_fraction = \"1.0\"", // This disables slash packet throttling }, - chainID("consu"): { - chainId: chainID("consu"), - binaryName: "interchain-security-cd", - ipPrefix: "7.7.8", - votingWaitTime: 20, - genesisChanges: ".app_state.gov.params.voting_period = \"20s\" | " + + ChainID("consu"): { + ChainId: ChainID("consu"), + BinaryName: "interchain-security-cd", + IpPrefix: "7.7.8", + VotingWaitTime: 20, + GenesisChanges: ".app_state.gov.params.voting_period = \"20s\" | " + ".app_state.slashing.params.signed_blocks_window = \"10\" | " + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + ".app_state.slashing.params.downtime_jail_duration = \"60s\" | " + ".app_state.slashing.params.slash_fraction_downtime = \"0.010000000000000000\"", }, - chainID("densu"): { - chainId: chainID("densu"), - binaryName: "interchain-security-cd", - ipPrefix: "7.7.9", - votingWaitTime: 20, - genesisChanges: ".app_state.gov.params.voting_period = \"20s\" | " + + ChainID("densu"): { + ChainId: ChainID("densu"), + BinaryName: "interchain-security-cd", + IpPrefix: "7.7.9", + VotingWaitTime: 20, + GenesisChanges: ".app_state.gov.params.voting_period = \"20s\" | " + ".app_state.slashing.params.signed_blocks_window = \"10\" | " + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + ".app_state.slashing.params.downtime_jail_duration = \"60s\" | " + @@ -352,19 +352,19 @@ func ChangeoverTestRun() TestRun { tr := TestRun{ name: "changeover", containerConfig: ContainerConfig{ - containerName: "interchain-security-changeover-container", - instanceName: "interchain-security-changeover-instance", - ccvVersion: "1", - now: time.Now(), + ContainerName: "interchain-security-changeover-container", + InstanceName: "interchain-security-changeover-instance", + CcvVersion: "1", + Now: time.Now(), }, validatorConfigs: getDefaultValidators(), - chainConfigs: map[chainID]ChainConfig{ - chainID("provi"): { - chainId: chainID("provi"), - binaryName: "interchain-security-pd", - ipPrefix: "7.7.7", - votingWaitTime: 20, - genesisChanges: ".app_state.gov.params.voting_period = \"20s\" | " + + chainConfigs: map[ChainID]ChainConfig{ + ChainID("provi"): { + ChainId: ChainID("provi"), + BinaryName: "interchain-security-pd", + IpPrefix: "7.7.7", + VotingWaitTime: 20, + GenesisChanges: ".app_state.gov.params.voting_period = \"20s\" | " + // Custom slashing parameters for testing validator downtime functionality // See https://docs.cosmos.network/main/modules/slashing/04_begin_block.html#uptime-tracking ".app_state.slashing.params.signed_blocks_window = \"10\" | " + @@ -374,13 +374,13 @@ func ChangeoverTestRun() TestRun { ".app_state.provider.params.slash_meter_replenish_fraction = \"1.0\" | " + // This disables slash packet throttling ".app_state.provider.params.slash_meter_replenish_period = \"3s\"", }, - chainID("sover"): { - chainId: chainID("sover"), - binaryName: "interchain-security-sd", - upgradeBinary: "interchain-security-cdd", - ipPrefix: "7.7.8", - votingWaitTime: 20, - genesisChanges: ".app_state.gov.params.voting_period = \"20s\" | " + + ChainID("sover"): { + ChainId: ChainID("sover"), + BinaryName: "interchain-security-sd", + UpgradeBinary: "interchain-security-cdd", + IpPrefix: "7.7.8", + VotingWaitTime: 20, + GenesisChanges: ".app_state.gov.params.voting_period = \"20s\" | " + ".app_state.slashing.params.signed_blocks_window = \"15\" | " + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + ".app_state.slashing.params.downtime_jail_duration = \"60s\" | " + @@ -430,7 +430,7 @@ func (s *TestRun) validateStringLiterals() { panic("validator id string literal must be 5 char or less") } - ipSuffix, err := strconv.Atoi(valConfig.ipSuffix) + ipSuffix, err := strconv.Atoi(valConfig.IpSuffix) if err != nil { panic(fmt.Sprintf("ip suffix must be an int: %v\n", err)) } @@ -453,7 +453,7 @@ func (s *TestRun) validateStringLiterals() { panic("chain id string literal must be 5 char or less") } - if chainID != chainConfig.chainId { + if chainID != chainConfig.ChainId { panic("chain config is mapped to a chain id that is different than what's stored in the config") } } diff --git a/tests/e2e/main.go b/tests/e2e/main.go index baf2db05da..0a376664a0 100644 --- a/tests/e2e/main.go +++ b/tests/e2e/main.go @@ -65,8 +65,8 @@ since causing light client attacks is not implemented.`, }, "happy-path": {testRun: DefaultTestRun(), steps: happyPathSteps, description: "happy path tests"}, "changeover": {testRun: ChangeoverTestRun(), steps: changeoverSteps, description: "changeover tests"}, - "democracy-reward": {testRun: DemocracyTestRun(true), steps: democracySteps, description: "democracy tests allowing rewards"}, - "democracy": {testRun: DemocracyTestRun(false), steps: rewardDenomConsumerSteps, description: "democracy tests"}, + "democracy-reward": {testRun: DemocracyTestRun(true), steps: democracyRewardsSteps, description: "democracy tests allowing rewards"}, + "democracy": {testRun: DemocracyTestRun(false), steps: democracySteps, description: "democracy tests"}, "slash-throttle": {testRun: SlashThrottleTestRun(), steps: slashThrottleSteps, description: "slash throttle tests"}, "multiconsumer": {testRun: MultiConsumerTestRun(), steps: multipleConsumers, description: "multi consumer tests"}, } @@ -189,7 +189,7 @@ type testRunWithSteps struct { } func (tr *TestRun) runStep(step Step, verbose bool) { - switch action := step.action.(type) { + switch action := step.Action.(type) { case StartChainAction: tr.startChain(action, verbose) case StartSovereignChainAction: @@ -264,13 +264,13 @@ func (tr *TestRun) runStep(step Step, verbose bool) { log.Fatalf("unknown action in testRun %s: %#v", tr.name, action) } - modelState := step.state - actualState := tr.getState(step.state) + modelState := step.State + actualState := tr.getState(step.State) // Check state if !reflect.DeepEqual(actualState, modelState) { fmt.Printf("=============== %s FAILED ===============\n", tr.name) - fmt.Println("FAILED action", reflect.TypeOf(step.action).Name()) + fmt.Println("FAILED action", reflect.TypeOf(step.Action).Name()) pretty.Print("actual state", actualState) pretty.Print("model state", modelState) log.Fatal(`actual state (-) not equal to model state (+): ` + pretty.Compare(actualState, modelState)) @@ -285,7 +285,7 @@ func (tr *TestRun) executeSteps(steps []Step) { for i, step := range steps { // print something the show the test is alive fmt.Printf("running %s: step %d == %s \n", - tr.name, i+1, reflect.TypeOf(step.action).Name()) + tr.name, i+1, reflect.TypeOf(step.Action).Name()) tr.runStep(step, *verbose) } @@ -315,8 +315,8 @@ func (tr *TestRun) startDocker() { } scriptStr := fmt.Sprintf( "tests/e2e/testnet-scripts/start-docker.sh %s %s %s %s %s", - tr.containerConfig.containerName, - tr.containerConfig.instanceName, + tr.containerConfig.ContainerName, + tr.containerConfig.InstanceName, localSdk, useGaia, gaiaTag, @@ -359,7 +359,7 @@ func (tr *TestRun) startDocker() { func (tr *TestRun) teardownDocker() { fmt.Printf("=============== tearing down %s testRun ===============\n", tr.name) //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - cmd := exec.Command("docker", "kill", tr.containerConfig.instanceName) + cmd := exec.Command("docker", "kill", tr.containerConfig.InstanceName) bz, err := cmd.CombinedOutput() if err != nil { diff --git a/tests/e2e/state.go b/tests/e2e/state.go index 8cc343ef00..f6beb3445c 100644 --- a/tests/e2e/state.go +++ b/tests/e2e/state.go @@ -14,19 +14,19 @@ import ( "gopkg.in/yaml.v2" ) -type State map[chainID]ChainState +type State map[ChainID]ChainState type ChainState struct { - ValBalances *map[validatorID]uint + ValBalances *map[ValidatorID]uint Proposals *map[uint]Proposal - ValPowers *map[validatorID]uint - RepresentativePowers *map[validatorID]uint + ValPowers *map[ValidatorID]uint + RepresentativePowers *map[ValidatorID]uint Params *[]Param Rewards *Rewards - ConsumerChains *map[chainID]bool - AssignedKeys *map[validatorID]string - ProviderKeys *map[validatorID]string // validatorID: validator provider key - ConsumerChainQueueSizes *map[chainID]uint + ConsumerChains *map[ChainID]bool + AssignedKeys *map[ValidatorID]string + ProviderKeys *map[ValidatorID]string // validatorID: validator provider key + ConsumerChainQueueSizes *map[ChainID]uint GlobalSlashQueueSize *uint RegisteredConsumerRewardDenoms *[]string } @@ -45,7 +45,7 @@ func (p TextProposal) isProposal() {} type ConsumerAdditionProposal struct { Deposit uint - Chain chainID + Chain ChainID SpawnTime int InitialHeight clienttypes.Height Status string @@ -66,7 +66,7 @@ func (p ConsumerAdditionProposal) isProposal() {} type ConsumerRemovalProposal struct { Deposit uint - Chain chainID + Chain ChainID StopTime int Status string } @@ -84,7 +84,7 @@ type EquivocationProposal struct { func (p EquivocationProposal) isProposal() {} type Rewards struct { - IsRewarded map[validatorID]bool + IsRewarded map[ValidatorID]bool // if true it will calculate if the validator/delegator is rewarded between 2 successive blocks, // otherwise it will calculate if it received any rewards since the 1st block IsIncrementalReward bool @@ -119,7 +119,7 @@ func (tr TestRun) getState(modelState State) State { return systemState } -func (tr TestRun) getChainState(chain chainID, modelState ChainState) ChainState { +func (tr TestRun) getChainState(chain ChainID, modelState ChainState) ChainState { chainState := ChainState{} if modelState.ValBalances != nil { @@ -174,7 +174,7 @@ func (tr TestRun) getChainState(chain chainID, modelState ChainState) ChainState } if modelState.ConsumerChainQueueSizes != nil { - consumerChainQueueSizes := map[chainID]uint{} + consumerChainQueueSizes := map[ChainID]uint{} for c := range *modelState.ConsumerChainQueueSizes { consumerChainQueueSizes[c] = tr.getConsumerChainPacketQueueSize(c) } @@ -195,9 +195,9 @@ func (tr TestRun) getChainState(chain chainID, modelState ChainState) ChainState var blockHeightRegex = regexp.MustCompile(`block_height: "(\d+)"`) -func (tr TestRun) getBlockHeight(chain chainID) uint { +func (tr TestRun) getBlockHeight(chain ChainID) uint { //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - bz, err := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[chain].binaryName, + bz, err := exec.Command("docker", "exec", tr.containerConfig.InstanceName, tr.chainConfigs[chain].BinaryName, "query", "tendermint-validator-set", @@ -215,7 +215,7 @@ func (tr TestRun) getBlockHeight(chain chainID) uint { return uint(blockHeight) } -func (tr TestRun) waitBlocks(chain chainID, blocks uint, timeout time.Duration) { +func (tr TestRun) waitBlocks(chain ChainID, blocks uint, timeout time.Duration) { if tr.useCometmock { // call advance_blocks method on cometmock // curl -H 'Content-Type: application/json' -H 'Accept:application/json' --data '{"jsonrpc":"2.0","method":"advance_blocks","params":{"num_blocks": "36000000"},"id":1}' 127.0.0.1:22331 @@ -241,7 +241,7 @@ func (tr TestRun) waitBlocks(chain chainID, blocks uint, timeout time.Duration) } } -func (tr TestRun) waitUntilBlock(chain chainID, block uint, timeout time.Duration) { +func (tr TestRun) waitUntilBlock(chain ChainID, block uint, timeout time.Duration) { start := time.Now() for { thisBlock := tr.getBlockHeight(chain) @@ -255,8 +255,8 @@ func (tr TestRun) waitUntilBlock(chain chainID, block uint, timeout time.Duratio } } -func (tr TestRun) getBalances(chain chainID, modelState map[validatorID]uint) map[validatorID]uint { - actualState := map[validatorID]uint{} +func (tr TestRun) getBalances(chain ChainID, modelState map[ValidatorID]uint) map[ValidatorID]uint { + actualState := map[ValidatorID]uint{} for k := range modelState { actualState[k] = tr.getBalance(chain, k) } @@ -264,7 +264,7 @@ func (tr TestRun) getBalances(chain chainID, modelState map[validatorID]uint) ma return actualState } -func (tr TestRun) getProposals(chain chainID, modelState map[uint]Proposal) map[uint]Proposal { +func (tr TestRun) getProposals(chain ChainID, modelState map[uint]Proposal) map[uint]Proposal { actualState := map[uint]Proposal{} for k := range modelState { actualState[k] = tr.getProposal(chain, k) @@ -273,8 +273,8 @@ func (tr TestRun) getProposals(chain chainID, modelState map[uint]Proposal) map[ return actualState } -func (tr TestRun) getValPowers(chain chainID, modelState map[validatorID]uint) map[validatorID]uint { - actualState := map[validatorID]uint{} +func (tr TestRun) getValPowers(chain ChainID, modelState map[ValidatorID]uint) map[ValidatorID]uint { + actualState := map[ValidatorID]uint{} for k := range modelState { actualState[k] = tr.getValPower(chain, k) } @@ -282,8 +282,8 @@ func (tr TestRun) getValPowers(chain chainID, modelState map[validatorID]uint) m return actualState } -func (tr TestRun) getRepresentativePowers(chain chainID, modelState map[validatorID]uint) map[validatorID]uint { - actualState := map[validatorID]uint{} +func (tr TestRun) getRepresentativePowers(chain ChainID, modelState map[ValidatorID]uint) map[ValidatorID]uint { + actualState := map[ValidatorID]uint{} for k := range modelState { actualState[k] = tr.getRepresentativePower(chain, k) } @@ -291,7 +291,7 @@ func (tr TestRun) getRepresentativePowers(chain chainID, modelState map[validato return actualState } -func (tr TestRun) getParams(chain chainID, modelState []Param) []Param { +func (tr TestRun) getParams(chain ChainID, modelState []Param) []Param { actualState := []Param{} for _, p := range modelState { actualState = append(actualState, Param{Subspace: p.Subspace, Key: p.Key, Value: tr.getParam(chain, p)}) @@ -300,8 +300,8 @@ func (tr TestRun) getParams(chain chainID, modelState []Param) []Param { return actualState } -func (tr TestRun) getRewards(chain chainID, modelState Rewards) Rewards { - receivedRewards := map[validatorID]bool{} +func (tr TestRun) getRewards(chain ChainID, modelState Rewards) Rewards { + receivedRewards := map[ValidatorID]bool{} currentBlock := tr.getBlockHeight(chain) tr.waitBlocks(chain, 1, 10*time.Second) @@ -318,13 +318,13 @@ func (tr TestRun) getRewards(chain chainID, modelState Rewards) Rewards { return Rewards{IsRewarded: receivedRewards, IsIncrementalReward: modelState.IsIncrementalReward, IsNativeDenom: modelState.IsNativeDenom} } -func (tr TestRun) getReward(chain chainID, validator validatorID, blockHeight uint, isNativeDenom bool) float64 { - delAddresss := tr.validatorConfigs[validator].delAddress - if chain != chainID("provi") && tr.validatorConfigs[validator].useConsumerKey { - delAddresss = tr.validatorConfigs[validator].consumerDelAddress +func (tr TestRun) getReward(chain ChainID, validator ValidatorID, blockHeight uint, isNativeDenom bool) float64 { + delAddresss := tr.validatorConfigs[validator].DelAddress + if chain != ChainID("provi") && tr.validatorConfigs[validator].UseConsumerKey { + delAddresss = tr.validatorConfigs[validator].ConsumerDelAddress } //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - bz, err := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[chain].binaryName, + bz, err := exec.Command("docker", "exec", tr.containerConfig.InstanceName, tr.chainConfigs[chain].BinaryName, "query", "distribution", "rewards", delAddresss, @@ -345,15 +345,15 @@ func (tr TestRun) getReward(chain chainID, validator validatorID, blockHeight ui return gjson.Get(string(bz), denomCondition).Float() } -func (tr TestRun) getBalance(chain chainID, validator validatorID) uint { +func (tr TestRun) getBalance(chain ChainID, validator ValidatorID) uint { //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - valDelAddress := tr.validatorConfigs[validator].delAddress - if chain != chainID("provi") && tr.validatorConfigs[validator].useConsumerKey { - valDelAddress = tr.validatorConfigs[validator].consumerDelAddress + valDelAddress := tr.validatorConfigs[validator].DelAddress + if chain != ChainID("provi") && tr.validatorConfigs[validator].UseConsumerKey { + valDelAddress = tr.validatorConfigs[validator].ConsumerDelAddress } //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - bz, err := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[chain].binaryName, + bz, err := exec.Command("docker", "exec", tr.containerConfig.InstanceName, tr.chainConfigs[chain].BinaryName, "query", "bank", "balances", valDelAddress, @@ -373,9 +373,9 @@ func (tr TestRun) getBalance(chain chainID, validator validatorID) uint { var noProposalRegex = regexp.MustCompile(`doesn't exist: key not found`) // interchain-securityd query gov proposals -func (tr TestRun) getProposal(chain chainID, proposal uint) Proposal { +func (tr TestRun) getProposal(chain ChainID, proposal uint) Proposal { //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - bz, err := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[chain].binaryName, + bz, err := exec.Command("docker", "exec", tr.containerConfig.InstanceName, tr.chainConfigs[chain].BinaryName, "query", "gov", "proposal", fmt.Sprint(proposal), @@ -411,11 +411,11 @@ func (tr TestRun) getProposal(chain chainID, proposal uint) Proposal { } case "/interchain_security.ccv.provider.v1.ConsumerAdditionProposal": chainId := gjson.Get(string(bz), `messages.0.content.chain_id`).String() - spawnTime := gjson.Get(string(bz), `messages.0.content.spawn_time`).Time().Sub(tr.containerConfig.now) + spawnTime := gjson.Get(string(bz), `messages.0.content.spawn_time`).Time().Sub(tr.containerConfig.Now) - var chain chainID + var chain ChainID for i, conf := range tr.chainConfigs { - if string(conf.chainId) == chainId { + if string(conf.ChainId) == chainId { chain = i break } @@ -443,11 +443,11 @@ func (tr TestRun) getProposal(chain chainID, proposal uint) Proposal { } case "/interchain_security.ccv.provider.v1.ConsumerRemovalProposal": chainId := gjson.Get(string(bz), `messages.0.content.chain_id`).String() - stopTime := gjson.Get(string(bz), `messages.0.content.stop_time`).Time().Sub(tr.containerConfig.now) + stopTime := gjson.Get(string(bz), `messages.0.content.stop_time`).Time().Sub(tr.containerConfig.Now) - var chain chainID + var chain ChainID for i, conf := range tr.chainConfigs { - if string(conf.chainId) == chainId { + if string(conf.ChainId) == chainId { chain = i break } @@ -497,12 +497,12 @@ type ValPubKey struct { Value string `yaml:"value"` } -func (tr TestRun) getValPower(chain chainID, validator validatorID) uint { +func (tr TestRun) getValPower(chain ChainID, validator ValidatorID) uint { if *verbose { log.Println("getting validator power for chain: ", chain, " validator: ", validator) } //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - command := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[chain].binaryName, + command := exec.Command("docker", "exec", tr.containerConfig.InstanceName, tr.chainConfigs[chain].BinaryName, "query", "tendermint-validator-set", @@ -531,8 +531,8 @@ func (tr TestRun) getValPower(chain chainID, validator validatorID) uint { } for _, val := range valset.Validators { - if val.Address == tr.validatorConfigs[validator].valconsAddress || - val.Address == tr.validatorConfigs[validator].consumerValconsAddress { + if val.Address == tr.validatorConfigs[validator].ValconsAddress || + val.Address == tr.validatorConfigs[validator].ConsumerValconsAddress { votingPower, err := strconv.Atoi(val.VotingPower) if err != nil { @@ -547,12 +547,12 @@ func (tr TestRun) getValPower(chain chainID, validator validatorID) uint { return 0 } -func (tr TestRun) getRepresentativePower(chain chainID, validator validatorID) uint { +func (tr TestRun) getRepresentativePower(chain ChainID, validator ValidatorID) uint { //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - bz, err := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[chain].binaryName, + bz, err := exec.Command("docker", "exec", tr.containerConfig.InstanceName, tr.chainConfigs[chain].BinaryName, "query", "staking", "validator", - tr.validatorConfigs[validator].valoperAddress, + tr.validatorConfigs[validator].ValoperAddress, `--node`, tr.getQueryNode(chain), `-o`, `json`, @@ -566,9 +566,9 @@ func (tr TestRun) getRepresentativePower(chain chainID, validator validatorID) u return uint(amount.Uint()) } -func (tr TestRun) getParam(chain chainID, param Param) string { +func (tr TestRun) getParam(chain ChainID, param Param) string { //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - bz, err := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[chain].binaryName, + bz, err := exec.Command("docker", "exec", tr.containerConfig.InstanceName, tr.chainConfigs[chain].BinaryName, "query", "params", "subspace", param.Subspace, @@ -588,9 +588,9 @@ func (tr TestRun) getParam(chain chainID, param Param) string { // getConsumerChains returns a list of consumer chains that're being secured by the provider chain, // determined by querying the provider chain. -func (tr TestRun) getConsumerChains(chain chainID) map[chainID]bool { +func (tr TestRun) getConsumerChains(chain ChainID) map[ChainID]bool { //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[chain].binaryName, + cmd := exec.Command("docker", "exec", tr.containerConfig.InstanceName, tr.chainConfigs[chain].BinaryName, "query", "provider", "list-consumer-chains", `--node`, tr.getQueryNode(chain), @@ -603,17 +603,17 @@ func (tr TestRun) getConsumerChains(chain chainID) map[chainID]bool { } arr := gjson.Get(string(bz), "chains").Array() - chains := make(map[chainID]bool) + chains := make(map[ChainID]bool) for _, c := range arr { id := c.Get("chain_id").String() - chains[chainID(id)] = true + chains[ChainID(id)] = true } return chains } -func (tr TestRun) getConsumerAddresses(chain chainID, modelState map[validatorID]string) map[validatorID]string { - actualState := map[validatorID]string{} +func (tr TestRun) getConsumerAddresses(chain ChainID, modelState map[ValidatorID]string) map[ValidatorID]string { + actualState := map[ValidatorID]string{} for k := range modelState { actualState[k] = tr.getConsumerAddress(chain, k) } @@ -621,8 +621,8 @@ func (tr TestRun) getConsumerAddresses(chain chainID, modelState map[validatorID return actualState } -func (tr TestRun) getProviderAddresses(chain chainID, modelState map[validatorID]string) map[validatorID]string { - actualState := map[validatorID]string{} +func (tr TestRun) getProviderAddresses(chain ChainID, modelState map[ValidatorID]string) map[ValidatorID]string { + actualState := map[ValidatorID]string{} for k := range modelState { actualState[k] = tr.getProviderAddressFromConsumer(chain, k) } @@ -630,13 +630,13 @@ func (tr TestRun) getProviderAddresses(chain chainID, modelState map[validatorID return actualState } -func (tr TestRun) getConsumerAddress(consumerChain chainID, validator validatorID) string { +func (tr TestRun) getConsumerAddress(consumerChain ChainID, validator ValidatorID) string { //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[chainID("provi")].binaryName, + cmd := exec.Command("docker", "exec", tr.containerConfig.InstanceName, tr.chainConfigs[ChainID("provi")].BinaryName, "query", "provider", "validator-consumer-key", - string(consumerChain), tr.validatorConfigs[validator].valconsAddress, - `--node`, tr.getQueryNode(chainID("provi")), + string(consumerChain), tr.validatorConfigs[validator].ValconsAddress, + `--node`, tr.getQueryNode(ChainID("provi")), `-o`, `json`, ) bz, err := cmd.CombinedOutput() @@ -648,13 +648,13 @@ func (tr TestRun) getConsumerAddress(consumerChain chainID, validator validatorI return addr } -func (tr TestRun) getProviderAddressFromConsumer(consumerChain chainID, validator validatorID) string { +func (tr TestRun) getProviderAddressFromConsumer(consumerChain ChainID, validator ValidatorID) string { //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[chainID("provi")].binaryName, + cmd := exec.Command("docker", "exec", tr.containerConfig.InstanceName, tr.chainConfigs[ChainID("provi")].BinaryName, "query", "provider", "validator-provider-key", - string(consumerChain), tr.validatorConfigs[validator].consumerValconsAddress, - `--node`, tr.getQueryNode(chainID("provi")), + string(consumerChain), tr.validatorConfigs[validator].ConsumerValconsAddress, + `--node`, tr.getQueryNode(ChainID("provi")), `-o`, `json`, ) @@ -669,10 +669,10 @@ func (tr TestRun) getProviderAddressFromConsumer(consumerChain chainID, validato func (tr TestRun) getGlobalSlashQueueSize() uint { //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[chainID("provi")].binaryName, + cmd := exec.Command("docker", "exec", tr.containerConfig.InstanceName, tr.chainConfigs[ChainID("provi")].BinaryName, "query", "provider", "throttle-state", - `--node`, tr.getQueryNode(chainID("provi")), + `--node`, tr.getQueryNode(ChainID("provi")), `-o`, `json`, ) bz, err := cmd.CombinedOutput() @@ -684,13 +684,13 @@ func (tr TestRun) getGlobalSlashQueueSize() uint { return uint(len(packets)) } -func (tr TestRun) getConsumerChainPacketQueueSize(consumerChain chainID) uint { +func (tr TestRun) getConsumerChainPacketQueueSize(consumerChain ChainID) uint { //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[chainID("provi")].binaryName, + cmd := exec.Command("docker", "exec", tr.containerConfig.InstanceName, tr.chainConfigs[ChainID("provi")].BinaryName, "query", "provider", "throttled-consumer-packet-data", string(consumerChain), - `--node`, tr.getQueryNode(chainID("provi")), + `--node`, tr.getQueryNode(ChainID("provi")), `-o`, `json`, ) bz, err := cmd.CombinedOutput() @@ -702,9 +702,9 @@ func (tr TestRun) getConsumerChainPacketQueueSize(consumerChain chainID) uint { return uint(size) } -func (tr TestRun) getRegisteredConsumerRewardDenoms(chain chainID) []string { +func (tr TestRun) getRegisteredConsumerRewardDenoms(chain ChainID) []string { //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[chain].binaryName, + cmd := exec.Command("docker", "exec", tr.containerConfig.InstanceName, tr.chainConfigs[chain].BinaryName, "query", "provider", "registered-consumer-reward-denoms", `--node`, tr.getQueryNode(chain), @@ -724,7 +724,7 @@ func (tr TestRun) getRegisteredConsumerRewardDenoms(chain chainID) []string { return rewardDenoms } -func (tr TestRun) getValidatorNode(chain chainID, validator validatorID) string { +func (tr TestRun) getValidatorNode(chain ChainID, validator ValidatorID) string { // for CometMock, validatorNodes are all the same address as the query node (which is CometMocks address) if tr.useCometmock { return tr.getQueryNode(chain) @@ -733,41 +733,41 @@ func (tr TestRun) getValidatorNode(chain chainID, validator validatorID) string return "tcp://" + tr.getValidatorIP(chain, validator) + ":26658" } -func (tr TestRun) getValidatorIP(chain chainID, validator validatorID) string { - return tr.chainConfigs[chain].ipPrefix + "." + tr.validatorConfigs[validator].ipSuffix +func (tr TestRun) getValidatorIP(chain ChainID, validator ValidatorID) string { + return tr.chainConfigs[chain].IpPrefix + "." + tr.validatorConfigs[validator].IpSuffix } -func (tr TestRun) getValidatorHome(chain chainID, validator validatorID) string { - return `/` + string(tr.chainConfigs[chain].chainId) + `/validator` + fmt.Sprint(validator) +func (tr TestRun) getValidatorHome(chain ChainID, validator ValidatorID) string { + return `/` + string(tr.chainConfigs[chain].ChainId) + `/validator` + fmt.Sprint(validator) } // getQueryNode returns query node tcp address on chain. -func (tr TestRun) getQueryNode(chain chainID) string { +func (tr TestRun) getQueryNode(chain ChainID) string { return fmt.Sprintf("tcp://%s", tr.getQueryNodeRPCAddress(chain)) } -func (tr TestRun) getQueryNodeRPCAddress(chain chainID) string { +func (tr TestRun) getQueryNodeRPCAddress(chain ChainID) string { return fmt.Sprintf("%s:26658", tr.getQueryNodeIP(chain)) } // getQueryNodeIP returns query node IP for chain, // ipSuffix is hardcoded to be 253 on all query nodes // except for "sover" chain where there's only one node -func (tr TestRun) getQueryNodeIP(chain chainID) string { - if chain == chainID("sover") { +func (tr TestRun) getQueryNodeIP(chain ChainID) string { + if chain == ChainID("sover") { // return address of first and only validator return fmt.Sprintf("%s.%s", - tr.chainConfigs[chain].ipPrefix, - tr.validatorConfigs[validatorID("alice")].ipSuffix) + tr.chainConfigs[chain].IpPrefix, + tr.validatorConfigs[ValidatorID("alice")].IpSuffix) } - return fmt.Sprintf("%s.253", tr.chainConfigs[chain].ipPrefix) + return fmt.Sprintf("%s.253", tr.chainConfigs[chain].IpPrefix) } func (tr TestRun) curlJsonRPCRequest(method, params, address string) { cmd_template := `curl -H 'Content-Type: application/json' -H 'Accept:application/json' --data '{"jsonrpc":"2.0","method":"%s","params":%s,"id":1}' %s` //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, "bash", "-c", fmt.Sprintf(cmd_template, method, params, address)) + cmd := exec.Command("docker", "exec", tr.containerConfig.InstanceName, "bash", "-c", fmt.Sprintf(cmd_template, method, params, address)) verbosity := false executeCommandWithVerbosity(cmd, "curlJsonRPCRequest", verbosity) diff --git a/tests/e2e/step_delegation.go b/tests/e2e/step_delegation.go index b6e7c8ad76..fc3208dbac 100644 --- a/tests/e2e/step_delegation.go +++ b/tests/e2e/step_delegation.go @@ -4,76 +4,76 @@ package main func stepsDelegate(consumerName string) []Step { return []Step{ { - action: delegateTokensAction{ - chain: chainID("provi"), - from: validatorID("alice"), - to: validatorID("alice"), - amount: 11000000, - }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 500, - validatorID("carol"): 500, + Action: delegateTokensAction{ + Chain: ChainID("provi"), + From: ValidatorID("alice"), + To: ValidatorID("alice"), + Amount: 11000000, + }, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 500, - validatorID("bob"): 500, - validatorID("carol"): 500, + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 500, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, }, }, { - action: SendTokensAction{ - chain: chainID(consumerName), - from: validatorID("alice"), - to: validatorID("bob"), - amount: 1, - }, - state: State{ - chainID(consumerName): ChainState{ + Action: SendTokensAction{ + Chain: ChainID(consumerName), + From: ValidatorID("alice"), + To: ValidatorID("bob"), + Amount: 1, + }, + State: State{ + ChainID(consumerName): ChainState{ // Tx should not go through, ICS channel is not setup until first VSC packet has been relayed to consumer - ValBalances: &map[validatorID]uint{ - validatorID("alice"): 10000000000, - validatorID("bob"): 10000000000, + ValBalances: &map[ValidatorID]uint{ + ValidatorID("alice"): 10000000000, + ValidatorID("bob"): 10000000000, }, }, }, }, { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 0, - }, - state: State{ - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 500, - validatorID("carol"): 500, + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 0, + }, + State: State{ + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, }, }, { - action: SendTokensAction{ - chain: chainID(consumerName), - from: validatorID("alice"), - to: validatorID("bob"), - amount: 1, - }, - state: State{ - chainID(consumerName): ChainState{ + Action: SendTokensAction{ + Chain: ChainID(consumerName), + From: ValidatorID("alice"), + To: ValidatorID("bob"), + Amount: 1, + }, + State: State{ + ChainID(consumerName): ChainState{ // Now tx should execute - ValBalances: &map[validatorID]uint{ - validatorID("alice"): 9999999999, - validatorID("bob"): 10000000001, + ValBalances: &map[ValidatorID]uint{ + ValidatorID("alice"): 9999999999, + ValidatorID("bob"): 10000000001, }, }, }, @@ -85,43 +85,43 @@ func stepsDelegate(consumerName string) []Step { func stepsUnbond(consumerName string) []Step { return []Step{ { - action: unbondTokensAction{ - chain: chainID("provi"), - unbondFrom: validatorID("alice"), - sender: validatorID("alice"), - amount: 1000000, - }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 510, - validatorID("bob"): 500, - validatorID("carol"): 500, + Action: unbondTokensAction{ + Chain: ChainID("provi"), + UnbondFrom: ValidatorID("alice"), + Sender: ValidatorID("alice"), + Amount: 1000000, + }, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 510, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, - chainID("consu"): ChainState{ - ValPowers: &map[validatorID]uint{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ // Voting power on consumer should not be affected yet - validatorID("alice"): 511, - validatorID("bob"): 500, - validatorID("carol"): 500, + ValidatorID("alice"): 511, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, }, }, { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 0, - }, - state: State{ - chainID("consu"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 510, - validatorID("bob"): 500, - validatorID("carol"): 500, + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 0, + }, + State: State{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 510, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, }, @@ -134,85 +134,85 @@ func stepsUnbond(consumerName string) []Step { func stepsCancelUnbond(consumerName string) []Step { return []Step{ { - action: unbondTokensAction{ - chain: chainID("provi"), - unbondFrom: validatorID("alice"), - sender: validatorID("alice"), - amount: 1000000, - }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 500, + Action: unbondTokensAction{ + Chain: ChainID("provi"), + UnbondFrom: ValidatorID("alice"), + Sender: ValidatorID("alice"), + Amount: 1000000, + }, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, - chainID("consu"): ChainState{ - ValPowers: &map[validatorID]uint{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ // Voting power on consumer should not be affected yet - validatorID("alice"): 510, - validatorID("bob"): 500, - validatorID("carol"): 500, + ValidatorID("alice"): 510, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, }, }, { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 0, - }, - state: State{ - chainID("consu"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 500, + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 0, + }, + State: State{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, }, }, { - action: cancelUnbondTokensAction{ - chain: chainID("provi"), - delegator: validatorID("alice"), - validator: validatorID("alice"), - amount: 1000000, // cancel unbonding the full amount - }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 510, // power restored - validatorID("bob"): 500, - validatorID("carol"): 500, + Action: cancelUnbondTokensAction{ + Chain: ChainID("provi"), + Delegator: ValidatorID("alice"), + Validator: ValidatorID("alice"), + Amount: 1000000, // cancel unbonding the full amount + }, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 510, // power restored + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, - chainID("consu"): ChainState{ - ValPowers: &map[validatorID]uint{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ // Voting power on consumer should not be affected yet - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 500, + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, }, }, { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 0, - }, - state: State{ - chainID("consu"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 510, // power restored on consumer - validatorID("bob"): 500, - validatorID("carol"): 500, + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 0, + }, + State: State{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 510, // power restored on consumer + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, }, @@ -226,45 +226,45 @@ func stepsCancelUnbond(consumerName string) []Step { func stepsRedelegateForOptOut(consumerName string) []Step { return []Step{ { - action: redelegateTokensAction{ - chain: chainID("provi"), - src: validatorID("alice"), - dst: validatorID("carol"), - txSender: validatorID("alice"), - amount: 450000000, - }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 60, - validatorID("bob"): 500, - validatorID("carol"): 950, + Action: redelegateTokensAction{ + Chain: ChainID("provi"), + Src: ValidatorID("alice"), + Dst: ValidatorID("carol"), + TxSender: ValidatorID("alice"), + Amount: 450000000, + }, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 60, + ValidatorID("bob"): 500, + ValidatorID("carol"): 950, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ // Voting power changes not seen by consumer yet - validatorID("alice"): 510, - validatorID("bob"): 500, - validatorID("carol"): 500, + ValidatorID("alice"): 510, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, }, }, { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 0, - }, - state: State{ - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 0, + }, + State: State{ + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ // Now power changes are seen by consumer - validatorID("alice"): 60, - validatorID("bob"): 500, - validatorID("carol"): 950, + ValidatorID("alice"): 60, + ValidatorID("bob"): 500, + ValidatorID("carol"): 950, }, }, }, @@ -276,48 +276,48 @@ func stepsRedelegateForOptOut(consumerName string) []Step { func stepsRedelegate(consumerName string) []Step { return []Step{ { - action: redelegateTokensAction{ - chain: chainID("provi"), - src: validatorID("carol"), - dst: validatorID("alice"), - txSender: validatorID("carol"), + Action: redelegateTokensAction{ + Chain: ChainID("provi"), + Src: ValidatorID("carol"), + Dst: ValidatorID("alice"), + TxSender: ValidatorID("carol"), // redelegate s.t. alice has majority stake so non-faulty validators maintain more than // 2/3 voting power during downtime tests below, avoiding chain halt - amount: 449000000, + Amount: 449000000, }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, // carol always uses a consumer assigned key - validatorID("carol"): 501, + ValidatorID("carol"): 501, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ // Voting power changes not seen by consumer yet - validatorID("alice"): 60, - validatorID("bob"): 500, - validatorID("carol"): 950, + ValidatorID("alice"): 60, + ValidatorID("bob"): 500, + ValidatorID("carol"): 950, }, }, }, }, { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 0, - }, - state: State{ - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 0, + }, + State: State{ + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ // Now power changes are seen by consumer - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 501, + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 501, }, }, }, @@ -329,48 +329,48 @@ func stepsRedelegate(consumerName string) []Step { func stepsRedelegateShort(consumerName string) []Step { return []Step{ { - action: redelegateTokensAction{ - chain: chainID("provi"), - src: validatorID("alice"), - dst: validatorID("carol"), - txSender: validatorID("alice"), + Action: redelegateTokensAction{ + Chain: ChainID("provi"), + Src: ValidatorID("alice"), + Dst: ValidatorID("carol"), + TxSender: ValidatorID("alice"), // Leave alice with majority stake so non-faulty validators maintain more than // 2/3 voting power during downtime tests below, avoiding chain halt - amount: 1000000, + Amount: 1000000, }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, // carol always uses a consumer assigned key - validatorID("carol"): 501, + ValidatorID("carol"): 501, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ // Voting power changes not seen by consumer yet - validatorID("alice"): 510, - validatorID("bob"): 500, - validatorID("carol"): 500, + ValidatorID("alice"): 510, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, }, }, { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 0, - }, - state: State{ - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 0, + }, + State: State{ + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ // Now power changes are seen by consumer - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 501, + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 501, }, }, }, diff --git a/tests/e2e/steps.go b/tests/e2e/steps.go index 6fb284c07a..21db55e3b7 100644 --- a/tests/e2e/steps.go +++ b/tests/e2e/steps.go @@ -1,8 +1,8 @@ package main type Step struct { - action interface{} - state State + Action interface{} + State State } func concatSteps(steps ...[]Step) []Step { @@ -66,7 +66,7 @@ var slashThrottleSteps = concatSteps( stepsStopChain("consu", 2), ) -var democracySteps = concatSteps( +var democracyRewardsSteps = concatSteps( // democracySteps requires a transfer channel stepsStartChains([]string{"democ"}, true), // delegation needs to happen so the first VSC packet can be delivered @@ -74,7 +74,7 @@ var democracySteps = concatSteps( stepsDemocracy("democ"), ) -var rewardDenomConsumerSteps = concatSteps( +var democracySteps = concatSteps( // democracySteps requires a transfer channel stepsStartChains([]string{"democ"}, true), // delegation needs to happen so the first VSC packet can be delivered diff --git a/tests/e2e/steps_democracy.go b/tests/e2e/steps_democracy.go index 85e9e8cbd7..9779ce45bc 100644 --- a/tests/e2e/steps_democracy.go +++ b/tests/e2e/steps_democracy.go @@ -5,22 +5,22 @@ const consumerRewardDenom = "ibc/3C3D7B3BE4ECC85A0E5B52A3AEC3B7DFC2AA9CA47C37821 func stepsDemocracy(consumerName string) []Step { return []Step{ { - action: registerRepresentativeAction{ - chain: chainID(consumerName), - representatives: []validatorID{validatorID("alice"), validatorID("bob")}, - stakes: []uint{100000000, 40000000}, + Action: registerRepresentativeAction{ + Chain: ChainID(consumerName), + Representatives: []ValidatorID{ValidatorID("alice"), ValidatorID("bob")}, + Stakes: []uint{100000000, 40000000}, }, - state: State{ - chainID(consumerName): ChainState{ - RepresentativePowers: &map[validatorID]uint{ - validatorID("alice"): 100000000, - validatorID("bob"): 40000000, + State: State{ + ChainID(consumerName): ChainState{ + RepresentativePowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 100000000, + ValidatorID("bob"): 40000000, }, Rewards: &Rewards{ - IsRewarded: map[validatorID]bool{ - validatorID("alice"): true, - validatorID("bob"): true, - validatorID("carol"): false, + IsRewarded: map[ValidatorID]bool{ + ValidatorID("alice"): true, + ValidatorID("bob"): true, + ValidatorID("carol"): false, }, IsIncrementalReward: true, IsNativeDenom: true, @@ -29,31 +29,31 @@ func stepsDemocracy(consumerName string) []Step { }, }, { - action: delegateTokensAction{ - chain: chainID(consumerName), - from: validatorID("carol"), - to: validatorID("alice"), - amount: 500000, + Action: delegateTokensAction{ + Chain: ChainID(consumerName), + From: ValidatorID("carol"), + To: ValidatorID("alice"), + Amount: 500000, }, - state: State{ - chainID(consumerName): ChainState{ + State: State{ + ChainID(consumerName): ChainState{ // Check that delegators on gov-consumer chain can change representative powers - RepresentativePowers: &map[validatorID]uint{ - validatorID("alice"): 100500000, - validatorID("bob"): 40000000, + RepresentativePowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 100500000, + ValidatorID("bob"): 40000000, }, // Check that delegating on gov-consumer does not change validator powers - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 500, - validatorID("carol"): 500, + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, // Check that tokens are minted and distributed to representatives and their delegators Rewards: &Rewards{ - IsRewarded: map[validatorID]bool{ - validatorID("alice"): true, - validatorID("bob"): true, - validatorID("carol"): true, + IsRewarded: map[ValidatorID]bool{ + ValidatorID("alice"): true, + ValidatorID("bob"): true, + ValidatorID("carol"): true, }, IsIncrementalReward: true, IsNativeDenom: true, @@ -63,19 +63,19 @@ func stepsDemocracy(consumerName string) []Step { }, { // whitelisted legacy proposal can only handle ibctransfer.SendEnabled/ReceiveEnabled - action: submitParamChangeLegacyProposalAction{ - chain: chainID(consumerName), - from: validatorID("alice"), - deposit: 10000001, - subspace: "transfer", - key: "SendEnabled", - value: true, + Action: submitParamChangeLegacyProposalAction{ + Chain: ChainID(consumerName), + From: ValidatorID("alice"), + Deposit: 10000001, + Subspace: "transfer", + Key: "SendEnabled", + Value: true, }, - state: State{ - chainID(consumerName): ChainState{ - ValBalances: &map[validatorID]uint{ - validatorID("alice"): 9889999998, - validatorID("bob"): 9960000001, + State: State{ + ChainID(consumerName): ChainState{ + ValBalances: &map[ValidatorID]uint{ + ValidatorID("alice"): 9889999998, + ValidatorID("bob"): 9960000001, }, Proposals: &map[uint]Proposal{ 1: ParamsProposal{ @@ -91,17 +91,17 @@ func stepsDemocracy(consumerName string) []Step { }, { // Have accounts vote on something on the gov-consumer chain - action: voteGovProposalAction{ - chain: chainID(consumerName), - from: []validatorID{validatorID("alice"), validatorID("bob")}, - vote: []string{"yes", "no"}, - propNumber: 1, + Action: voteGovProposalAction{ + Chain: ChainID(consumerName), + From: []ValidatorID{ValidatorID("alice"), ValidatorID("bob")}, + Vote: []string{"yes", "no"}, + PropNumber: 1, }, - state: State{ - chainID(consumerName): ChainState{ - ValBalances: &map[validatorID]uint{ - validatorID("alice"): 9889999998, - validatorID("bob"): 9960000001, + State: State{ + ChainID(consumerName): ChainState{ + ValBalances: &map[ValidatorID]uint{ + ValidatorID("alice"): 9889999998, + ValidatorID("bob"): 9960000001, }, // Check that the parameter is changed on gov-consumer chain Params: &([]Param{{Subspace: "transfer", Key: "SendEnabled", Value: "true"}}), @@ -109,20 +109,20 @@ func stepsDemocracy(consumerName string) []Step { }, }, { - action: relayRewardPacketsToProviderAction{ - consumerChain: chainID(consumerName), - providerChain: chainID("provi"), - port: "transfer", - channel: 1, + Action: relayRewardPacketsToProviderAction{ + ConsumerChain: ChainID(consumerName), + ProviderChain: ChainID("provi"), + Port: "transfer", + Channel: 1, }, - state: State{ - chainID("provi"): ChainState{ + State: State{ + ChainID("provi"): ChainState{ // Check that tokens are not distributed before the denom has been registered Rewards: &Rewards{ - IsRewarded: map[validatorID]bool{ - validatorID("alice"): false, - validatorID("bob"): false, - validatorID("carol"): false, + IsRewarded: map[ValidatorID]bool{ + ValidatorID("alice"): false, + ValidatorID("bob"): false, + ValidatorID("carol"): false, }, IsIncrementalReward: false, IsNativeDenom: false, @@ -133,47 +133,47 @@ func stepsDemocracy(consumerName string) []Step { }, }, { - action: submitChangeRewardDenomsProposalAction{ - denom: consumerRewardDenom, - deposit: 10000001, - from: validatorID("bob"), + Action: submitChangeRewardDenomsProposalAction{ + Denom: consumerRewardDenom, + Deposit: 10000001, + From: ValidatorID("bob"), }, - state: State{ - chainID("provi"): ChainState{ + State: State{ + ChainID("provi"): ChainState{ // Denom not yet registered, gov prop needs to pass first RegisteredConsumerRewardDenoms: &[]string{}, }, }, }, { - action: voteGovProposalAction{ - chain: chainID("provi"), - from: []validatorID{validatorID("alice"), validatorID("bob"), validatorID("carol")}, - vote: []string{"yes", "yes", "yes"}, - propNumber: 2, + Action: voteGovProposalAction{ + Chain: ChainID("provi"), + From: []ValidatorID{ValidatorID("alice"), ValidatorID("bob"), ValidatorID("carol")}, + Vote: []string{"yes", "yes", "yes"}, + PropNumber: 2, }, - state: State{ - chainID("provi"): ChainState{ + State: State{ + ChainID("provi"): ChainState{ // Check that the denom is registered on provider chain RegisteredConsumerRewardDenoms: &[]string{consumerRewardDenom}, }, }, }, { - action: relayRewardPacketsToProviderAction{ - consumerChain: chainID(consumerName), - providerChain: chainID("provi"), - port: "transfer", - channel: 1, + Action: relayRewardPacketsToProviderAction{ + ConsumerChain: ChainID(consumerName), + ProviderChain: ChainID("provi"), + Port: "transfer", + Channel: 1, }, - state: State{ - chainID("provi"): ChainState{ + State: State{ + ChainID("provi"): ChainState{ // Check that tokens are minted and sent to provider chain and distributed to validators and their delegators on provider chain Rewards: &Rewards{ - IsRewarded: map[validatorID]bool{ - validatorID("alice"): true, - validatorID("bob"): true, - validatorID("carol"): true, + IsRewarded: map[ValidatorID]bool{ + ValidatorID("alice"): true, + ValidatorID("bob"): true, + ValidatorID("carol"): true, }, IsIncrementalReward: false, IsNativeDenom: false, @@ -182,49 +182,49 @@ func stepsDemocracy(consumerName string) []Step { }, }, { - action: downtimeSlashAction{ - chain: chainID(consumerName), - validator: validatorID("bob"), + Action: downtimeSlashAction{ + Chain: ChainID(consumerName), + Validator: ValidatorID("bob"), }, - state: State{ + State: State{ // validator should be slashed on consumer, powers not affected on either chain yet - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 500, - validatorID("carol"): 500, + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 500, - validatorID("carol"): 500, + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, }, }, { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 0, + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 0, }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, // Downtime jailing and corresponding voting power change are processed by provider - validatorID("bob"): 0, - validatorID("carol"): 500, + ValidatorID("bob"): 0, + ValidatorID("carol"): 500, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 500, - validatorID("carol"): 500, + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, }, @@ -232,63 +232,63 @@ func stepsDemocracy(consumerName string) []Step { // A block is incremented each action, hence why VSC is committed on provider, // and can now be relayed as packet to consumer { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 0, + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 0, }, - state: State{ - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, + State: State{ + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, // VSC now seen on consumer - validatorID("bob"): 0, - validatorID("carol"): 500, + ValidatorID("bob"): 0, + ValidatorID("carol"): 500, }, }, }, }, { - action: unjailValidatorAction{ - provider: chainID("provi"), - validator: validatorID("bob"), + Action: unjailValidatorAction{ + Provider: ChainID("provi"), + Validator: ValidatorID("bob"), }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 500, - validatorID("carol"): 500, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 0, - validatorID("carol"): 500, + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 0, + ValidatorID("carol"): 500, }, }, }, }, { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 0, + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 0, }, - state: State{ - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 500, - validatorID("carol"): 500, + State: State{ + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, // Check that slashing on the gov-consumer chain does not result in slashing for the representatives or their delegators - RepresentativePowers: &map[validatorID]uint{ - validatorID("alice"): 100500000, - validatorID("bob"): 40000000, + RepresentativePowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 100500000, + ValidatorID("bob"): 40000000, }, }, }, diff --git a/tests/e2e/steps_double_sign.go b/tests/e2e/steps_double_sign.go index c007fa5c1c..4d69569b29 100644 --- a/tests/e2e/steps_double_sign.go +++ b/tests/e2e/steps_double_sign.go @@ -5,49 +5,49 @@ func stepsDoubleSignOnProviderAndConsumer(consumerName string) []Step { return []Step{ { // provider double sign - action: doublesignSlashAction{ - chain: chainID("provi"), - validator: validatorID("carol"), + Action: doublesignSlashAction{ + Chain: ChainID("provi"), + Validator: ValidatorID("carol"), }, - state: State{ + State: State{ // slash on provider - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, // from 500 to 0 + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, // from 500 to 0 }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 495, // not tombstoned on consumerName yet + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 495, // not tombstoned on consumerName yet }, }, }, }, { // relay power change to consumerName - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 0, // consumerName channel + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 0, // consumerName channel }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, // tombstoning visible on consumerName + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, // tombstoning visible on consumerName }, }, }, @@ -56,72 +56,72 @@ func stepsDoubleSignOnProviderAndConsumer(consumerName string) []Step { // consumer double sign // provider will only log the double sign slash // stepsSubmitEquivocationProposal will cause the double sign slash to be executed - action: doublesignSlashAction{ - chain: chainID("consu"), - validator: validatorID("bob"), + Action: doublesignSlashAction{ + Chain: ChainID("consu"), + Validator: ValidatorID("bob"), }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, }, }, }, }, { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 0, + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 0, }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, // not tombstoned - validatorID("carol"): 0, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, // not tombstoned + ValidatorID("carol"): 0, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, // not tombstoned - validatorID("carol"): 0, + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, // not tombstoned + ValidatorID("carol"): 0, }, }, }, }, { // consumer learns about the double sign - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 0, + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 0, }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, // not tombstoned - validatorID("carol"): 0, + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, // not tombstoned + ValidatorID("carol"): 0, }, }, }, diff --git a/tests/e2e/steps_downtime.go b/tests/e2e/steps_downtime.go index e6d320bec1..08054f9089 100644 --- a/tests/e2e/steps_downtime.go +++ b/tests/e2e/steps_downtime.go @@ -15,49 +15,49 @@ import "time" func stepsDowntime(consumerName string) []Step { return []Step{ { - action: downtimeSlashAction{ - chain: chainID(consumerName), - validator: validatorID("bob"), + Action: downtimeSlashAction{ + Chain: ChainID(consumerName), + Validator: ValidatorID("bob"), }, - state: State{ + State: State{ // validator should be slashed on consumer, powers not affected on either chain yet - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 501, + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 501, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 501, + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 501, }, }, }, }, { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 0, - }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 0, + }, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, // Downtime jailing and corresponding voting power change are processed by provider - validatorID("bob"): 0, - validatorID("carol"): 501, + ValidatorID("bob"): 0, + ValidatorID("carol"): 501, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 501, + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 501, }, }, }, @@ -65,144 +65,144 @@ func stepsDowntime(consumerName string) []Step { // A block is incremented each action, hence why VSC is committed on provider, // and can now be relayed as packet to consumer { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 0, - }, - state: State{ - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 0, + }, + State: State{ + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, // VSC now seen on consumer - validatorID("bob"): 0, - validatorID("carol"): 501, + ValidatorID("bob"): 0, + ValidatorID("carol"): 501, }, }, }, }, { - action: unjailValidatorAction{ - provider: chainID("provi"), - validator: validatorID("bob"), - }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, + Action: unjailValidatorAction{ + Provider: ChainID("provi"), + Validator: ValidatorID("bob"), + }, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, // bob's stake should not be slashed // since the slash was initiated from consumer - validatorID("bob"): 500, - validatorID("carol"): 501, + ValidatorID("bob"): 500, + ValidatorID("carol"): 501, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 0, - validatorID("carol"): 501, + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 0, + ValidatorID("carol"): 501, }, }, }, }, { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 0, - }, - state: State{ - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 0, + }, + State: State{ + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, // bob's stake should not be slashed // since the slash was initiated from consumer - validatorID("bob"): 500, - validatorID("carol"): 501, + ValidatorID("bob"): 500, + ValidatorID("carol"): 501, }, }, }, }, // Now we test provider initiated downtime/slashing { - action: downtimeSlashAction{ - chain: chainID("provi"), - validator: validatorID("carol"), + Action: downtimeSlashAction{ + Chain: ChainID("provi"), + Validator: ValidatorID("carol"), }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ // Non faulty validators still maintain just above 2/3 power here - validatorID("alice"): 509, - validatorID("bob"): 500, + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, // Carol's stake should be slashed and jailed // downtime slash was initiated from provider - validatorID("carol"): 0, + ValidatorID("carol"): 0, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 501, + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 501, }, }, }, }, { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 0, - }, - state: State{ - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 0, + }, + State: State{ + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, }, }, }, }, { - action: unjailValidatorAction{ - provider: chainID("provi"), - validator: validatorID("carol"), + Action: unjailValidatorAction{ + Provider: ChainID("provi"), + Validator: ValidatorID("carol"), }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 495, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 495, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, }, }, }, }, { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 0, - }, - state: State{ - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 495, + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 0, + }, + State: State{ + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 495, }, }, }, @@ -217,49 +217,49 @@ func stepsDowntime(consumerName string) []Step { func stepsDowntimeWithOptOut(consumerName string) []Step { return []Step{ { - action: downtimeSlashAction{ - chain: chainID(consumerName), - validator: validatorID("alice"), + Action: downtimeSlashAction{ + Chain: ChainID(consumerName), + Validator: ValidatorID("alice"), }, - state: State{ + State: State{ // powers not affected on either chain - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 60, - validatorID("bob"): 500, - validatorID("carol"): 950, + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 60, + ValidatorID("bob"): 500, + ValidatorID("carol"): 950, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 60, - validatorID("bob"): 500, - validatorID("carol"): 950, + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 60, + ValidatorID("bob"): 500, + ValidatorID("carol"): 950, }, }, }, }, { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 0, - }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 0, + }, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ // alice is not slashed or jailed due to soft opt out - validatorID("alice"): 60, - validatorID("bob"): 500, - validatorID("carol"): 950, + ValidatorID("alice"): 60, + ValidatorID("bob"): 500, + ValidatorID("carol"): 950, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 60, - validatorID("bob"): 500, - validatorID("carol"): 950, + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 60, + ValidatorID("bob"): 500, + ValidatorID("carol"): 950, }, }, }, @@ -273,24 +273,24 @@ func stepsDowntimeWithOptOut(consumerName string) []Step { func stepsThrottledDowntime(consumerName string) []Step { return []Step{ { - action: downtimeSlashAction{ - chain: chainID(consumerName), - validator: validatorID("bob"), + Action: downtimeSlashAction{ + Chain: ChainID(consumerName), + Validator: ValidatorID("bob"), }, - state: State{ + State: State{ // slash packet queued on consumer, but powers not affected on either chain yet - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 500, - validatorID("carol"): 500, + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 500, - validatorID("carol"): 500, + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, }, @@ -299,115 +299,115 @@ func stepsThrottledDowntime(consumerName string) []Step { // and consumer receives ack that provider recv the downtime slash. // The latter is necessary for the consumer to send the second downtime slash. { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 0, - }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 0, // bob is jailed - validatorID("carol"): 500, + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 0, + }, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 0, // bob is jailed + ValidatorID("carol"): 500, }, // no provider throttling engaged yet GlobalSlashQueueSize: uintPointer(0), - ConsumerChainQueueSizes: &map[chainID]uint{ - chainID(consumerName): uint(0), + ConsumerChainQueueSizes: &map[ChainID]uint{ + ChainID(consumerName): uint(0), }, }, - chainID(consumerName): ChainState{ + ChainID(consumerName): ChainState{ // VSC packet applying jailing is not yet relayed to consumer - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 500, - validatorID("carol"): 500, + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, }, }, { - action: downtimeSlashAction{ - chain: chainID(consumerName), - validator: validatorID("carol"), + Action: downtimeSlashAction{ + Chain: ChainID(consumerName), + Validator: ValidatorID("carol"), }, - state: State{ + State: State{ // powers not affected on either chain yet - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 0, - validatorID("carol"): 500, + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 0, + ValidatorID("carol"): 500, }, }, - chainID(consumerName): ChainState{ + ChainID(consumerName): ChainState{ // VSC packet applying jailing is not yet relayed to consumer - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 500, - validatorID("carol"): 500, + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, }, }, { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 0, - }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 0, - validatorID("carol"): 500, // not slashed due to throttling + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 0, + }, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 0, + ValidatorID("carol"): 500, // not slashed due to throttling }, GlobalSlashQueueSize: uintPointer(1), // carol's slash request is throttled - ConsumerChainQueueSizes: &map[chainID]uint{ - chainID(consumerName): uint(1), + ConsumerChainQueueSizes: &map[ChainID]uint{ + ChainID(consumerName): uint(1), }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 0, - validatorID("carol"): 500, + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 0, + ValidatorID("carol"): 500, }, }, }, }, { - action: slashThrottleDequeue{ - chain: chainID(consumerName), - currentQueueSize: 1, - nextQueueSize: 0, + Action: slashThrottleDequeue{ + Chain: ChainID(consumerName), + CurrentQueueSize: 1, + NextQueueSize: 0, // Slash meter replenish fraction is set to 10%, replenish period is 20 seconds, see config.go // Meter is initially at 10%, decremented to -23% from bob being jailed. It'll then take three replenishments // for meter to become positive again. 3*20 = 60 seconds + buffer = 80 seconds - timeout: 80 * time.Second, + Timeout: 80 * time.Second, }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 0, - validatorID("carol"): 0, // Carol is jailed upon packet being handled on provider + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 0, + ValidatorID("carol"): 0, // Carol is jailed upon packet being handled on provider }, GlobalSlashQueueSize: uintPointer(0), // slash packets dequeued - ConsumerChainQueueSizes: &map[chainID]uint{ - chainID(consumerName): 0, + ConsumerChainQueueSizes: &map[ChainID]uint{ + ChainID(consumerName): 0, }, }, - chainID(consumerName): ChainState{ + ChainID(consumerName): ChainState{ // no updates received on consumer - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 0, - validatorID("carol"): 500, + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 0, + ValidatorID("carol"): 500, }, }, }, @@ -415,30 +415,30 @@ func stepsThrottledDowntime(consumerName string) []Step { // A block is incremented each action, hence why VSC is committed on provider, // and can now be relayed as packet to consumer { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 0, - }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 0, - validatorID("carol"): 0, + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 0, + }, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 0, + ValidatorID("carol"): 0, }, GlobalSlashQueueSize: uintPointer(0), - ConsumerChainQueueSizes: &map[chainID]uint{ - chainID(consumerName): 0, + ConsumerChainQueueSizes: &map[ChainID]uint{ + ChainID(consumerName): 0, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, // throttled update gets to consumer - validatorID("bob"): 0, - validatorID("carol"): 0, + ValidatorID("bob"): 0, + ValidatorID("carol"): 0, }, }, }, diff --git a/tests/e2e/steps_light_client_attack.go b/tests/e2e/steps_light_client_attack.go index f00d5f5bd6..284b3fafea 100644 --- a/tests/e2e/steps_light_client_attack.go +++ b/tests/e2e/steps_light_client_attack.go @@ -4,124 +4,124 @@ package main func stepsLightClientAttackOnProviderAndConsumer(consumerName string) []Step { return []Step{ { - // provider double sign - action: lightClientEquivocationAttackAction{ - chain: chainID("provi"), - validator: validatorID("carol"), + // Provider double sign + Action: lightClientEquivocationAttackAction{ + Chain: ChainID("provi"), + Validator: ValidatorID("carol"), }, - state: State{ - // slash on provider - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, // from 500 to 0 + State: State{ + // Slash on provider + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, // from 500 to 0 }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 495, // not tombstoned on consumerName yet + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 495, // not tombstoned on consumerName yet }, }, }, }, { - // relay power change to consumerName - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 0, // consumerName channel + // Relay power change to consumerName + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 0, // consumerName channel }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, // tombstoning visible on consumerName + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, // tombstoning visible on consumerName }, }, }, }, { - // consumer double sign - // provider will only log the double sign slash + // Consumer double sign + // Provider will only log the double sign slash // stepsSubmitEquivocationProposal will cause the double sign slash to be executed - action: lightClientEquivocationAttackAction{ - chain: chainID(consumerName), - validator: validatorID("bob"), + Action: lightClientEquivocationAttackAction{ + Chain: ChainID(consumerName), + Validator: ValidatorID("bob"), }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, }, }, }, }, { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 0, + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 0, }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, // not tombstoned - validatorID("carol"): 0, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, // not tombstoned + ValidatorID("carol"): 0, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, // not tombstoned - validatorID("carol"): 0, + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, // not tombstoned + ValidatorID("carol"): 0, }, }, }, }, { - // consumer learns about the double sign - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 0, + // Consumer learns about the double sign + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 0, }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, // not tombstoned - validatorID("carol"): 0, + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, // not tombstoned + ValidatorID("carol"): 0, }, }, }, diff --git a/tests/e2e/steps_multi_consumer_delegation.go b/tests/e2e/steps_multi_consumer_delegation.go index 45536c0679..67368e277c 100644 --- a/tests/e2e/steps_multi_consumer_delegation.go +++ b/tests/e2e/steps_multi_consumer_delegation.go @@ -5,96 +5,96 @@ func stepsMultiConsumerDelegate(consumer1, consumer2 string) []Step { return []Step{ { // changes not visible on any consumer - action: delegateTokensAction{ - chain: chainID("provi"), - from: validatorID("alice"), - to: validatorID("alice"), - amount: 11000000, + Action: delegateTokensAction{ + Chain: ChainID("provi"), + From: ValidatorID("alice"), + To: ValidatorID("alice"), + Amount: 11000000, }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, // this changes from 500 - validatorID("bob"): 500, - validatorID("carol"): 500, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, // this changes from 500 + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, - chainID(consumer1): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 500, - validatorID("bob"): 500, - validatorID("carol"): 500, + ChainID(consumer1): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 500, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, - chainID(consumer2): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 500, - validatorID("bob"): 500, - validatorID("carol"): 500, + ChainID(consumer2): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 500, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, }, }, { // relay changes to consumer1 - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumer1), - port: "provider", - channel: 0, // consumer1 channel + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumer1), + Port: "provider", + Channel: 0, // consumer1 Channel }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 500, - validatorID("carol"): 500, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, - chainID(consumer1): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, // changed - validatorID("bob"): 500, - validatorID("carol"): 500, + ChainID(consumer1): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, // changed + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, - chainID(consumer2): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 500, // unchanged - validatorID("bob"): 500, - validatorID("carol"): 500, + ChainID(consumer2): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 500, // unchanged + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, }, }, { // relay changes to consumer2 - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumer2), - port: "provider", - channel: 1, // consumer2 channel + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumer2), + Port: "provider", + Channel: 1, // consumer2 Channel }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 500, - validatorID("carol"): 500, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, - chainID(consumer1): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 500, - validatorID("carol"): 500, + ChainID(consumer1): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, - chainID(consumer2): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, // changed - validatorID("bob"): 500, - validatorID("carol"): 500, + ChainID(consumer2): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, // changed + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, }, @@ -107,96 +107,96 @@ func stepsMultiConsumerDelegate(consumer1, consumer2 string) []Step { func stepsMultiConsumerUnbond(consumer1, consumer2 string) []Step { return []Step{ { - action: unbondTokensAction{ - chain: chainID("provi"), - unbondFrom: validatorID("alice"), - sender: validatorID("alice"), - amount: 1000000, + Action: unbondTokensAction{ + Chain: ChainID("provi"), + UnbondFrom: ValidatorID("alice"), + Sender: ValidatorID("alice"), + Amount: 1000000, }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 510, // change from 511 - validatorID("bob"): 500, - validatorID("carol"): 500, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 510, // change from 511 + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, - chainID(consumer1): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, // no change - validatorID("bob"): 500, - validatorID("carol"): 500, + ChainID(consumer1): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, // no change + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, - chainID(consumer2): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, // no change - validatorID("bob"): 500, - validatorID("carol"): 500, + ChainID(consumer2): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, // no change + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, }, }, { // relay to consumer1 - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumer1), - port: "provider", - channel: 0, // consumer1 channel + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumer1), + Port: "provider", + Channel: 0, // consumer1 Channel }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 510, - validatorID("bob"): 500, - validatorID("carol"): 500, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 510, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, - chainID(consumer1): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 510, // change from 511 - validatorID("bob"): 500, - validatorID("carol"): 500, + ChainID(consumer1): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 510, // change from 511 + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, - chainID(consumer2): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, // no change - validatorID("bob"): 500, - validatorID("carol"): 500, + ChainID(consumer2): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, // no change + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, }, }, { // relay to consumer2 - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumer2), - port: "provider", - channel: 1, // consumer2 channel + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumer2), + Port: "provider", + Channel: 1, // consumer2 Channel }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 510, - validatorID("bob"): 500, - validatorID("carol"): 500, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 510, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, - chainID(consumer1): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 510, - validatorID("bob"): 500, - validatorID("carol"): 500, + ChainID(consumer1): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 510, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, - chainID(consumer2): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 510, // change from 511 - validatorID("bob"): 500, - validatorID("carol"): 500, + ChainID(consumer2): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 510, // change from 511 + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, }, @@ -209,35 +209,35 @@ func stepsMultiConsumerUnbond(consumer1, consumer2 string) []Step { func stepsMultiConsumerRedelegate(consumer1, consumer2 string) []Step { return []Step{ { - action: redelegateTokensAction{ - chain: chainID("provi"), - src: validatorID("alice"), - dst: validatorID("carol"), - txSender: validatorID("alice"), + Action: redelegateTokensAction{ + Chain: ChainID("provi"), + Src: ValidatorID("alice"), + Dst: ValidatorID("carol"), + TxSender: ValidatorID("alice"), // Leave alice with majority stake so non-faulty validators maintain more than // 2/3 voting power during downtime tests below, avoiding chain halt - amount: 1000000, + Amount: 1000000, }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 501, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 501, }, }, - chainID(consumer1): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 510, // no change - validatorID("bob"): 500, - validatorID("carol"): 500, + ChainID(consumer1): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 510, // no change + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, - chainID(consumer2): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 510, // no change - validatorID("bob"): 500, - validatorID("carol"): 500, + ChainID(consumer2): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 510, // no change + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, }, @@ -245,64 +245,64 @@ func stepsMultiConsumerRedelegate(consumer1, consumer2 string) []Step { { // relay to consumer1 - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumer1), - port: "provider", - channel: 0, // consumer1 channel + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumer1), + Port: "provider", + Channel: 0, // consumer1 Channel }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 501, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 501, }, }, - chainID(consumer1): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, // change from 510 - validatorID("bob"): 500, - validatorID("carol"): 501, // change from 500 + ChainID(consumer1): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, // change from 510 + ValidatorID("bob"): 500, + ValidatorID("carol"): 501, // change from 500 }, }, - chainID(consumer2): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 510, // no change - validatorID("bob"): 500, - validatorID("carol"): 500, // no change + ChainID(consumer2): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 510, // no change + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, // no change }, }, }, }, { // relay to consumer2 - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumer2), - port: "provider", - channel: 1, // consumer1 channel + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumer2), + Port: "provider", + Channel: 1, // consumer1 Channel }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 501, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 501, }, }, - chainID(consumer1): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 501, + ChainID(consumer1): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 501, }, }, - chainID(consumer2): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, // change from 510 - validatorID("bob"): 500, - validatorID("carol"): 501, // change from 500 + ChainID(consumer2): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, // change from 510 + ValidatorID("bob"): 500, + ValidatorID("carol"): 501, // change from 500 }, }, }, diff --git a/tests/e2e/steps_multi_consumer_double_sign.go b/tests/e2e/steps_multi_consumer_double_sign.go index d12eb37eff..5388ea5c75 100644 --- a/tests/e2e/steps_multi_consumer_double_sign.go +++ b/tests/e2e/steps_multi_consumer_double_sign.go @@ -13,95 +13,95 @@ func stepsMultiConsumerDoubleSign(consumer1, consumer2 string) []Step { return []Step{ { // provider double sign - action: doublesignSlashAction{ - chain: chainID("provi"), - validator: validatorID("carol"), + Action: doublesignSlashAction{ + Chain: ChainID("provi"), + Validator: ValidatorID("carol"), }, - state: State{ + State: State{ // slash on provider - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, // from 500 to 0 + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, // from 500 to 0 }, }, - chainID(consumer1): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 495, // not tombstoned on consumer1 yet + ChainID(consumer1): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 495, // not tombstoned on consumer1 yet }, }, - chainID(consumer2): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 495, // not tombstoned on consumer2 yet + ChainID(consumer2): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 495, // not tombstoned on consumer2 yet }, }, }, }, { // relay power change to consumer1 - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumer1), - port: "provider", - channel: 0, // consumer1 channel + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumer1), + Port: "provider", + Channel: 0, // consumer1 channel }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, }, }, - chainID(consumer1): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, // tombstoning visible on consumer1 + ChainID(consumer1): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, // tombstoning visible on consumer1 }, }, - chainID(consumer2): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 495, // tombstoning NOT YET visible on consumer2 + ChainID(consumer2): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 495, // tombstoning NOT YET visible on consumer2 }, }, }, }, { // relay power change to consumer2 - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumer2), - port: "provider", - channel: 1, // consumer2 channel + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumer2), + Port: "provider", + Channel: 1, // consumer2 channel }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, }, }, - chainID(consumer1): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, + ChainID(consumer1): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, }, }, - chainID(consumer2): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, // tombstoned on consumer2 + ChainID(consumer2): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, // tombstoned on consumer2 }, }, }, @@ -109,118 +109,118 @@ func stepsMultiConsumerDoubleSign(consumer1, consumer2 string) []Step { { // consumer double sign // nothing should happen - double sign from consumer is dropped - action: doublesignSlashAction{ - chain: chainID("consu"), - validator: validatorID("bob"), + Action: doublesignSlashAction{ + Chain: ChainID("consu"), + Validator: ValidatorID("bob"), }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, }, }, - chainID(consumer1): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, + ChainID(consumer1): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, }, }, - chainID(consumer2): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, + ChainID(consumer2): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, }, }, }, }, { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumer1), - port: "provider", - channel: 0, // consumer1 channel + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumer1), + Port: "provider", + Channel: 0, // consumer1 channel }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, // not tombstoned - validatorID("carol"): 0, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, // not tombstoned + ValidatorID("carol"): 0, }, }, - chainID(consumer1): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, // not tombstoned - validatorID("carol"): 0, + ChainID(consumer1): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, // not tombstoned + ValidatorID("carol"): 0, }, }, - chainID(consumer2): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, // not tombstoned - validatorID("carol"): 0, + ChainID(consumer2): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, // not tombstoned + ValidatorID("carol"): 0, }, }, }, }, { // consumer1 learns about the double sign - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumer1), - port: "provider", - channel: 0, // consumer1 channel + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumer1), + Port: "provider", + Channel: 0, // consumer1 channel }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, }, }, - chainID(consumer1): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, // not tombstoned - validatorID("carol"): 0, + ChainID(consumer1): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, // not tombstoned + ValidatorID("carol"): 0, }, }, - chainID(consumer2): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, // not tombstoned - validatorID("carol"): 0, + ChainID(consumer2): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, // not tombstoned + ValidatorID("carol"): 0, }, }, }, }, { // consumer2 learns about the double sign - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumer2), - port: "provider", - channel: 1, // consumer2 channel + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumer2), + Port: "provider", + Channel: 1, // consumer2 channel }, - state: State{ - chainID(consumer1): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, - }, - }, - chainID(consumer2): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, + State: State{ + ChainID(consumer1): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, + }, + }, + ChainID(consumer2): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, }, }, }, diff --git a/tests/e2e/steps_multi_consumer_downtime.go b/tests/e2e/steps_multi_consumer_downtime.go index ce6cbdff59..eba44ed361 100644 --- a/tests/e2e/steps_multi_consumer_downtime.go +++ b/tests/e2e/steps_multi_consumer_downtime.go @@ -7,31 +7,31 @@ package main func stepsMultiConsumerDowntimeFromConsumer(consumer1, consumer2 string) []Step { return []Step{ { - action: downtimeSlashAction{ - chain: chainID(consumer1), - validator: validatorID("bob"), + Action: downtimeSlashAction{ + Chain: ChainID(consumer1), + Validator: ValidatorID("bob"), }, - state: State{ + State: State{ // validator should be slashed on consumer, powers not affected on either chain yet - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 501, + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 501, }, }, - chainID(consumer1): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 501, + ChainID(consumer1): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 501, }, }, - chainID(consumer2): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 501, + ChainID(consumer2): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 501, }, }, }, @@ -39,32 +39,32 @@ func stepsMultiConsumerDowntimeFromConsumer(consumer1, consumer2 string) []Step { // Downtime jailing and corresponding voting power change are processed by provider // Validator powers are unchanged on consumer chains - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumer1), - port: "provider", - channel: 0, + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumer1), + Port: "provider", + Channel: 0, }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 0, - validatorID("carol"): 501, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 0, + ValidatorID("carol"): 501, }, }, - chainID(consumer1): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 501, + ChainID(consumer1): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 501, }, }, - chainID(consumer2): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 501, + ChainID(consumer2): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 501, }, }, }, @@ -73,149 +73,149 @@ func stepsMultiConsumerDowntimeFromConsumer(consumer1, consumer2 string) []Step // A block is incremented each action, hence why VSC is committed on provider, // and can now be relayed as packet to consumer // consumer1 will now see the validator power changes - consumer2 will not (had not been relayed) - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumer1), - port: "provider", - channel: 0, // consumer1 chan + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumer1), + Port: "provider", + Channel: 0, // consumer1 chan }, - state: State{ + State: State{ // change propagated to consumer1 - chainID(consumer1): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, + ChainID(consumer1): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, // VSC now seen on consumer1 - validatorID("bob"): 0, - validatorID("carol"): 501, + ValidatorID("bob"): 0, + ValidatorID("carol"): 501, }, }, - chainID(consumer2): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, + ChainID(consumer2): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, // VSC has not arrived to on consumer2 - validatorID("bob"): 500, - validatorID("carol"): 501, + ValidatorID("bob"): 500, + ValidatorID("carol"): 501, }, }, }, }, { // both consumer1 and consumer will now see the validator power changes - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumer2), - port: "provider", - channel: 1, // consumer2 chan + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumer2), + Port: "provider", + Channel: 1, // consumer2 chan }, - state: State{ - chainID(consumer1): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 0, // both consumers see the change - validatorID("carol"): 501, + State: State{ + ChainID(consumer1): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 0, // both consumers see the change + ValidatorID("carol"): 501, }, }, - chainID(consumer2): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 0, // both consumers see the change - validatorID("carol"): 501, + ChainID(consumer2): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 0, // both consumers see the change + ValidatorID("carol"): 501, }, }, }, }, { - action: unjailValidatorAction{ - provider: chainID("provi"), - validator: validatorID("bob"), + Action: unjailValidatorAction{ + Provider: ChainID("provi"), + Validator: ValidatorID("bob"), }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, // bob's stake should not be slashed since slash comes from consumer1 - validatorID("bob"): 500, - validatorID("carol"): 501, + ValidatorID("bob"): 500, + ValidatorID("carol"): 501, }, }, // change is not visible on consumer1 - chainID(consumer1): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 0, - validatorID("carol"): 501, + ChainID(consumer1): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 0, + ValidatorID("carol"): 501, }, }, // change is not visible on consumer2 - chainID(consumer2): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 0, - validatorID("carol"): 501, + ChainID(consumer2): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 0, + ValidatorID("carol"): 501, }, }, }, }, { // relay to consumer 1 - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumer1), - port: "provider", - channel: 0, + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumer1), + Port: "provider", + Channel: 0, }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 501, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 501, }, }, - chainID(consumer1): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, // change has arrived to consumer1 (no slashing) - validatorID("carol"): 501, + ChainID(consumer1): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, // change has arrived to consumer1 (no slashing) + ValidatorID("carol"): 501, }, }, - chainID(consumer2): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 0, // change has not arrived to consumer2 - validatorID("carol"): 501, + ChainID(consumer2): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 0, // change has not arrived to consumer2 + ValidatorID("carol"): 501, }, }, }, }, { // relay to consumer2 - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumer2), - port: "provider", - channel: 1, // consumer2 chan + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumer2), + Port: "provider", + Channel: 1, // consumer2 chan }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 501, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 501, }, }, - chainID(consumer1): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, // change has arrived to consumer1 (no slashing) - validatorID("carol"): 501, + ChainID(consumer1): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, // change has arrived to consumer1 (no slashing) + ValidatorID("carol"): 501, }, }, - chainID(consumer2): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, // change has arrived to consumer2 (no slashing) - validatorID("carol"): 501, + ChainID(consumer2): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, // change has arrived to consumer2 (no slashing) + ValidatorID("carol"): 501, }, }, }, @@ -229,190 +229,190 @@ func stepsMultiConsumerDowntimeFromProvider(consumer1, consumer2 string) []Step return []Step{ // Now we test provider initiated downtime/slashing { - action: downtimeSlashAction{ - chain: chainID("provi"), - validator: validatorID("carol"), + Action: downtimeSlashAction{ + Chain: ChainID("provi"), + Validator: ValidatorID("carol"), }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ // Non faulty validators still maintain just above 2/3 power here - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, }, }, - chainID(consumer1): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 501, + ChainID(consumer1): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 501, }, }, - chainID(consumer2): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 501, + ChainID(consumer2): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 501, }, }, }, }, { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumer1), - port: "provider", - channel: 0, // consumer 1 channel + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumer1), + Port: "provider", + Channel: 0, // consumer 1 channel }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ // Non faulty validators still maintain just above 2/3 power here - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, }, }, // powers now changed - chainID(consumer1): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, + ChainID(consumer1): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, }, }, // not relayed yet - powers unchanged - chainID(consumer2): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 501, + ChainID(consumer2): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 501, }, }, }, }, { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumer2), - port: "provider", - channel: 1, // consumer2 channel + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumer2), + Port: "provider", + Channel: 1, // consumer2 channel }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ // Non faulty validators still maintain just above 2/3 power here - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, }, }, - chainID(consumer1): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, + ChainID(consumer1): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, }, }, // powers now changed - chainID(consumer2): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, + ChainID(consumer2): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, }, }, }, }, { - action: unjailValidatorAction{ - provider: chainID("provi"), - validator: validatorID("carol"), + Action: unjailValidatorAction{ + Provider: ChainID("provi"), + Validator: ValidatorID("carol"), }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 495, // slashed because infraction was committed on provider + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 495, // slashed because infraction was committed on provider }, }, - chainID(consumer1): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, + ChainID(consumer1): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, }, }, - chainID(consumer2): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, + ChainID(consumer2): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, }, }, }, }, { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumer1), - port: "provider", - channel: 0, // consumer1 channel + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumer1), + Port: "provider", + Channel: 0, // consumer1 channel }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 495, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 495, }, }, - chainID(consumer1): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 495, + ChainID(consumer1): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 495, }, }, // not relayed yet - chainID(consumer2): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, + ChainID(consumer2): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, }, }, }, }, { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumer2), - port: "provider", - channel: 1, // consumer2 channel + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumer2), + Port: "provider", + Channel: 1, // consumer2 channel }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 495, - }, - }, - chainID(consumer1): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 495, - }, - }, - chainID(consumer2): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 495, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 495, + }, + }, + ChainID(consumer1): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 495, + }, + }, + ChainID(consumer2): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 495, }, }, }, diff --git a/tests/e2e/steps_reward_denom.go b/tests/e2e/steps_reward_denom.go index cc9934f3f8..125f3dd401 100644 --- a/tests/e2e/steps_reward_denom.go +++ b/tests/e2e/steps_reward_denom.go @@ -3,22 +3,22 @@ package main func stepsRewardDenomConsumer(consumerName string) []Step { return []Step{ { - action: registerRepresentativeAction{ - chain: chainID(consumerName), - representatives: []validatorID{validatorID("alice"), validatorID("bob")}, - stakes: []uint{100000000, 40000000}, + Action: registerRepresentativeAction{ + Chain: ChainID(consumerName), + Representatives: []ValidatorID{ValidatorID("alice"), ValidatorID("bob")}, + Stakes: []uint{100000000, 40000000}, }, - state: State{ - chainID(consumerName): ChainState{ - RepresentativePowers: &map[validatorID]uint{ - validatorID("alice"): 100000000, - validatorID("bob"): 40000000, + State: State{ + ChainID(consumerName): ChainState{ + RepresentativePowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 100000000, + ValidatorID("bob"): 40000000, }, Rewards: &Rewards{ - IsRewarded: map[validatorID]bool{ - validatorID("alice"): true, - validatorID("bob"): true, - validatorID("carol"): false, + IsRewarded: map[ValidatorID]bool{ + ValidatorID("alice"): true, + ValidatorID("bob"): true, + ValidatorID("carol"): false, }, IsIncrementalReward: true, IsNativeDenom: true, @@ -27,31 +27,31 @@ func stepsRewardDenomConsumer(consumerName string) []Step { }, }, { - action: delegateTokensAction{ - chain: chainID(consumerName), - from: validatorID("carol"), - to: validatorID("alice"), - amount: 500000, + Action: delegateTokensAction{ + Chain: ChainID(consumerName), + From: ValidatorID("carol"), + To: ValidatorID("alice"), + Amount: 500000, }, - state: State{ - chainID(consumerName): ChainState{ + State: State{ + ChainID(consumerName): ChainState{ // Check that delegators on gov-consumer chain can change representative powers - RepresentativePowers: &map[validatorID]uint{ - validatorID("alice"): 100500000, - validatorID("bob"): 40000000, + RepresentativePowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 100500000, + ValidatorID("bob"): 40000000, }, // Check that delegating on gov-consumer does not change validator powers - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 500, - validatorID("carol"): 500, + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, // Check that tokens are minted and distributed to representatives and their delegators Rewards: &Rewards{ - IsRewarded: map[validatorID]bool{ - validatorID("alice"): true, - validatorID("bob"): true, - validatorID("carol"): true, + IsRewarded: map[ValidatorID]bool{ + ValidatorID("alice"): true, + ValidatorID("bob"): true, + ValidatorID("carol"): true, }, IsIncrementalReward: true, IsNativeDenom: true, @@ -61,19 +61,19 @@ func stepsRewardDenomConsumer(consumerName string) []Step { }, { // whitelisted legacy proposal can only handle ibctransfer.SendEnabled/ReceiveEnabled - action: submitParamChangeLegacyProposalAction{ - chain: chainID(consumerName), - from: validatorID("alice"), - deposit: 10000001, - subspace: "transfer", - key: "SendEnabled", - value: true, + Action: submitParamChangeLegacyProposalAction{ + Chain: ChainID(consumerName), + From: ValidatorID("alice"), + Deposit: 10000001, + Subspace: "transfer", + Key: "SendEnabled", + Value: true, }, - state: State{ - chainID(consumerName): ChainState{ - ValBalances: &map[validatorID]uint{ - validatorID("alice"): 9889999998, - validatorID("bob"): 9960000001, + State: State{ + ChainID(consumerName): ChainState{ + ValBalances: &map[ValidatorID]uint{ + ValidatorID("alice"): 9889999998, + ValidatorID("bob"): 9960000001, }, Proposals: &map[uint]Proposal{ 1: ParamsProposal{ @@ -89,17 +89,17 @@ func stepsRewardDenomConsumer(consumerName string) []Step { }, { // Have accounts vote on something on the gov-consumer chain - action: voteGovProposalAction{ - chain: chainID(consumerName), - from: []validatorID{validatorID("alice"), validatorID("bob")}, - vote: []string{"yes", "no"}, - propNumber: 1, + Action: voteGovProposalAction{ + Chain: ChainID(consumerName), + From: []ValidatorID{ValidatorID("alice"), ValidatorID("bob")}, + Vote: []string{"yes", "no"}, + PropNumber: 1, }, - state: State{ - chainID(consumerName): ChainState{ - ValBalances: &map[validatorID]uint{ - validatorID("alice"): 9889999998, - validatorID("bob"): 9960000001, + State: State{ + ChainID(consumerName): ChainState{ + ValBalances: &map[ValidatorID]uint{ + ValidatorID("alice"): 9889999998, + ValidatorID("bob"): 9960000001, }, // Check that the parameter is changed on gov-consumer chain Params: &([]Param{{Subspace: "transfer", Key: "SendEnabled", Value: "true"}}), @@ -107,20 +107,20 @@ func stepsRewardDenomConsumer(consumerName string) []Step { }, }, { - action: relayRewardPacketsToProviderAction{ - consumerChain: chainID(consumerName), - providerChain: chainID("provi"), - port: "transfer", - channel: 1, + Action: relayRewardPacketsToProviderAction{ + ConsumerChain: ChainID(consumerName), + ProviderChain: ChainID("provi"), + Port: "transfer", + Channel: 1, }, - state: State{ - chainID("provi"): ChainState{ + State: State{ + ChainID("provi"): ChainState{ // Check that tokens are not distributed before the denom has been registered Rewards: &Rewards{ - IsRewarded: map[validatorID]bool{ - validatorID("alice"): false, - validatorID("bob"): false, - validatorID("carol"): false, + IsRewarded: map[ValidatorID]bool{ + ValidatorID("alice"): false, + ValidatorID("bob"): false, + ValidatorID("carol"): false, }, IsIncrementalReward: false, IsNativeDenom: false, @@ -131,47 +131,47 @@ func stepsRewardDenomConsumer(consumerName string) []Step { }, }, { - action: submitChangeRewardDenomsProposalAction{ - denom: "ibc/3C3D7B3BE4ECC85A0E5B52A3AEC3B7DFC2AA9CA47C37821E57020D6807043BE9", - deposit: 10000001, - from: validatorID("bob"), + Action: submitChangeRewardDenomsProposalAction{ + Denom: "ibc/3C3D7B3BE4ECC85A0E5B52A3AEC3B7DFC2AA9CA47C37821E57020D6807043BE9", + Deposit: 10000001, + From: ValidatorID("bob"), }, - state: State{ - chainID("provi"): ChainState{ + State: State{ + ChainID("provi"): ChainState{ // Denom not yet registered, gov prop needs to pass first RegisteredConsumerRewardDenoms: &[]string{}, }, }, }, { - action: voteGovProposalAction{ - chain: chainID("provi"), - from: []validatorID{validatorID("alice"), validatorID("bob"), validatorID("carol")}, - vote: []string{"yes", "yes", "yes"}, - propNumber: 2, + Action: voteGovProposalAction{ + Chain: ChainID("provi"), + From: []ValidatorID{ValidatorID("alice"), ValidatorID("bob"), ValidatorID("carol")}, + Vote: []string{"yes", "yes", "yes"}, + PropNumber: 2, }, - state: State{ - chainID("provi"): ChainState{ + State: State{ + ChainID("provi"): ChainState{ // Check that the denom is registered on provider chain RegisteredConsumerRewardDenoms: &[]string{"ibc/3C3D7B3BE4ECC85A0E5B52A3AEC3B7DFC2AA9CA47C37821E57020D6807043BE9"}, }, }, }, { - action: relayRewardPacketsToProviderAction{ - consumerChain: chainID(consumerName), - providerChain: chainID("provi"), - port: "transfer", - channel: 1, + Action: relayRewardPacketsToProviderAction{ + ConsumerChain: ChainID(consumerName), + ProviderChain: ChainID("provi"), + Port: "transfer", + Channel: 1, }, - state: State{ - chainID("provi"): ChainState{ + State: State{ + ChainID("provi"): ChainState{ // Check that tokens are not minted and sent to provider chain and distributed to validators and their delegators on provider chain Rewards: &Rewards{ - IsRewarded: map[validatorID]bool{ - validatorID("alice"): false, - validatorID("bob"): false, - validatorID("carol"): false, + IsRewarded: map[ValidatorID]bool{ + ValidatorID("alice"): false, + ValidatorID("bob"): false, + ValidatorID("carol"): false, }, IsIncrementalReward: false, IsNativeDenom: false, @@ -180,113 +180,113 @@ func stepsRewardDenomConsumer(consumerName string) []Step { }, }, { - action: downtimeSlashAction{ - chain: chainID(consumerName), - validator: validatorID("bob"), + Action: downtimeSlashAction{ + Chain: ChainID(consumerName), + Validator: ValidatorID("bob"), }, - state: State{ + State: State{ // validator should be slashed on consumer, powers not affected on either chain yet - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 500, - validatorID("carol"): 500, + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 500, - validatorID("carol"): 500, + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, }, }, { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 0, + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 0, }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, // Downtime jailing and corresponding voting power change are processed by provider - validatorID("bob"): 0, - validatorID("carol"): 500, + ValidatorID("bob"): 0, + ValidatorID("carol"): 500, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 500, - validatorID("carol"): 500, + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, }, }, - // A block is incremented each action, hence why VSC is committed on provider, + // A block is incremented each Action, hence why VSC is committed on provider, // and can now be relayed as packet to consumer { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 0, + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 0, }, - state: State{ - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, + State: State{ + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, // VSC now seen on consumer - validatorID("bob"): 0, - validatorID("carol"): 500, + ValidatorID("bob"): 0, + ValidatorID("carol"): 500, }, }, }, }, { - action: unjailValidatorAction{ - provider: chainID("provi"), - validator: validatorID("bob"), + Action: unjailValidatorAction{ + Provider: ChainID("provi"), + Validator: ValidatorID("bob"), }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 500, - validatorID("carol"): 500, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 0, - validatorID("carol"): 500, + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 0, + ValidatorID("carol"): 500, }, }, }, }, { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 0, + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 0, }, - state: State{ - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 500, - validatorID("carol"): 500, + State: State{ + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, // Check that slashing on the gov-consumer chain does not result in slashing for the representatives or their delegators - RepresentativePowers: &map[validatorID]uint{ - validatorID("alice"): 100500000, - validatorID("bob"): 40000000, + RepresentativePowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 100500000, + ValidatorID("bob"): 40000000, }, }, }, diff --git a/tests/e2e/steps_sovereign_changeover.go b/tests/e2e/steps_sovereign_changeover.go index c02b2c4d43..8c053299cc 100644 --- a/tests/e2e/steps_sovereign_changeover.go +++ b/tests/e2e/steps_sovereign_changeover.go @@ -10,24 +10,24 @@ import clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" func stepsSovereignTransferChan() []Step { return []Step{ { - action: createIbcClientsAction{ - chainA: chainID("sover"), - chainB: chainID("provi"), + Action: createIbcClientsAction{ + ChainA: ChainID("sover"), + ChainB: ChainID("provi"), }, - state: State{}, + State: State{}, }, { // this will create channel-0 connection end on both chain - action: addIbcChannelAction{ - chainA: chainID("sover"), - chainB: chainID("provi"), - connectionA: 0, - portA: "transfer", - portB: "transfer", - order: "unordered", - version: "ics20-1", + Action: addIbcChannelAction{ + ChainA: ChainID("sover"), + ChainB: ChainID("provi"), + ConnectionA: 0, + PortA: "transfer", + PortB: "transfer", + Order: "unordered", + Version: "ics20-1", }, - state: State{}, + State: State{}, }, } } @@ -36,29 +36,29 @@ func stepsSovereignTransferChan() []Step { func stepsChangeoverToConsumer(consumerName string) []Step { s := []Step{ { - action: submitConsumerAdditionProposalAction{ - preCCV: true, - chain: chainID("provi"), - from: validatorID("alice"), - deposit: 10000001, - consumerChain: chainID(consumerName), + Action: submitConsumerAdditionProposalAction{ + PreCCV: true, + Chain: ChainID("provi"), + From: ValidatorID("alice"), + Deposit: 10000001, + ConsumerChain: ChainID(consumerName), // chain-0 is the transfer channelID that gets created in stepsSovereignTransferChan // the consumer chain will use this channel to send rewards to the provider chain // there is no need to create a new channel for rewards distribution - distributionChannel: "channel-0", - spawnTime: 0, - initialHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: 111}, // 1 block after upgrade !important + DistributionChannel: "channel-0", + SpawnTime: 0, + InitialHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: 111}, // 1 block after upgrade !important }, - state: State{ - chainID("provi"): ChainState{ - ValBalances: &map[validatorID]uint{ - validatorID("alice"): 9489999999, - validatorID("bob"): 9500000000, + State: State{ + ChainID("provi"): ChainState{ + ValBalances: &map[ValidatorID]uint{ + ValidatorID("alice"): 9489999999, + ValidatorID("bob"): 9500000000, }, Proposals: &map[uint]Proposal{ 1: ConsumerAdditionProposal{ Deposit: 10000001, - Chain: chainID(consumerName), + Chain: ChainID(consumerName), SpawnTime: 0, InitialHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: 111}, Status: "PROPOSAL_STATUS_VOTING_PERIOD", @@ -68,78 +68,78 @@ func stepsChangeoverToConsumer(consumerName string) []Step { }, }, { - action: voteGovProposalAction{ - chain: chainID("provi"), - from: []validatorID{validatorID("alice"), validatorID("bob"), validatorID("carol")}, - vote: []string{"yes", "yes", "yes"}, - propNumber: 1, + Action: voteGovProposalAction{ + Chain: ChainID("provi"), + From: []ValidatorID{ValidatorID("alice"), ValidatorID("bob"), ValidatorID("carol")}, + Vote: []string{"yes", "yes", "yes"}, + PropNumber: 1, }, - state: State{ - chainID("provi"): ChainState{ + State: State{ + ChainID("provi"): ChainState{ Proposals: &map[uint]Proposal{ 1: ConsumerAdditionProposal{ Deposit: 10000001, - Chain: chainID(consumerName), + Chain: ChainID(consumerName), SpawnTime: 0, InitialHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: 111}, Status: "PROPOSAL_STATUS_PASSED", }, }, - ValBalances: &map[validatorID]uint{ - validatorID("alice"): 9500000000, - validatorID("bob"): 9500000000, + ValBalances: &map[ValidatorID]uint{ + ValidatorID("alice"): 9500000000, + ValidatorID("bob"): 9500000000, }, }, }, }, { - action: ChangeoverChainAction{ - sovereignChain: chainID(consumerName), - providerChain: chainID("provi"), - validators: []StartChainValidator{ - {id: validatorID("alice"), stake: 500000000, allocation: 10000000000}, - {id: validatorID("bob"), stake: 500000000, allocation: 10000000000}, - {id: validatorID("carol"), stake: 500000000, allocation: 10000000000}, + Action: ChangeoverChainAction{ + SovereignChain: ChainID(consumerName), + ProviderChain: ChainID("provi"), + Validators: []StartChainValidator{ + {Id: ValidatorID("alice"), Stake: 500000000, Allocation: 10000000000}, + {Id: ValidatorID("bob"), Stake: 500000000, Allocation: 10000000000}, + {Id: ValidatorID("carol"), Stake: 500000000, Allocation: 10000000000}, }, - genesisChanges: ".app_state.ccvconsumer.params.soft_opt_out_threshold = \"0.05\"", + GenesisChanges: ".app_state.ccvconsumer.params.soft_opt_out_threshold = \"0.05\"", }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 500, - validatorID("bob"): 500, - validatorID("carol"): 500, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 500, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ // uses val powers from consumer - validatorID("alice"): 500, - validatorID("bob"): 500, - validatorID("carol"): 500, + ValidatorID("alice"): 500, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, }, }, { - action: addIbcConnectionAction{ - chainA: chainID(consumerName), - chainB: chainID("provi"), - clientA: 1, - clientB: 1, + Action: addIbcConnectionAction{ + ChainA: ChainID(consumerName), + ChainB: ChainID("provi"), + ClientA: 1, + ClientB: 1, }, - state: State{}, + State: State{}, }, { - action: addIbcChannelAction{ - chainA: chainID(consumerName), - chainB: chainID("provi"), - connectionA: 1, - portA: "consumer", - portB: "provider", - order: "ordered", + Action: addIbcChannelAction{ + ChainA: ChainID(consumerName), + ChainB: ChainID("provi"), + ConnectionA: 1, + PortA: "consumer", + PortB: "provider", + Order: "ordered", }, - state: State{}, + State: State{}, }, } @@ -154,33 +154,33 @@ func stepsChangeoverToConsumer(consumerName string) []Step { func stepRunSovereignChain() []Step { return []Step{ { - action: StartSovereignChainAction{ - chain: chainID("sover"), - validators: []StartChainValidator{ - {id: validatorID("alice"), stake: 500000000, allocation: 10000000000}, + Action: StartSovereignChainAction{ + Chain: ChainID("sover"), + Validators: []StartChainValidator{ + {Id: ValidatorID("alice"), Stake: 500000000, Allocation: 10000000000}, }, }, - state: State{ - chainID("sover"): ChainState{ - ValBalances: &map[validatorID]uint{ - validatorID("alice"): 9500000000, + State: State{ + ChainID("sover"): ChainState{ + ValBalances: &map[ValidatorID]uint{ + ValidatorID("alice"): 9500000000, }, }, }, }, { - action: delegateTokensAction{ - chain: chainID("sover"), - from: validatorID("alice"), - to: validatorID("alice"), - amount: 11000000, + Action: delegateTokensAction{ + Chain: ChainID("sover"), + From: ValidatorID("alice"), + To: ValidatorID("alice"), + Amount: 11000000, }, - state: State{ - chainID("sover"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 0, // does not exist on pre-ccv sover - validatorID("carol"): 0, // does not exist on pre-ccv sover + State: State{ + ChainID("sover"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 0, // does not exist on pre-ccv sover + ValidatorID("carol"): 0, // does not exist on pre-ccv sover }, }, }, @@ -192,14 +192,14 @@ func stepRunSovereignChain() []Step { func stepsUpgradeChain() []Step { return []Step{ { - action: LegacyUpgradeProposalAction{ - chainID: chainID("sover"), - upgradeTitle: "sovereign-changeover", - proposer: validatorID("alice"), - upgradeHeight: 110, + Action: LegacyUpgradeProposalAction{ + ChainID: ChainID("sover"), + UpgradeTitle: "sovereign-changeover", + Proposer: ValidatorID("alice"), + UpgradeHeight: 110, }, - state: State{ - chainID("sover"): ChainState{ + State: State{ + ChainID("sover"): ChainState{ Proposals: &map[uint]Proposal{ 1: UpgradeProposal{ Title: "sovereign-changeover", @@ -213,14 +213,14 @@ func stepsUpgradeChain() []Step { }, }, { - action: voteGovProposalAction{ - chain: chainID("sover"), - from: []validatorID{validatorID("alice")}, - vote: []string{"yes"}, - propNumber: 1, + Action: voteGovProposalAction{ + Chain: ChainID("sover"), + From: []ValidatorID{ValidatorID("alice")}, + Vote: []string{"yes"}, + PropNumber: 1, }, - state: State{ - chainID("sover"): ChainState{ + State: State{ + ChainID("sover"): ChainState{ Proposals: &map[uint]Proposal{ 1: UpgradeProposal{ Deposit: 10000000, @@ -234,11 +234,11 @@ func stepsUpgradeChain() []Step { }, }, { - action: waitUntilBlockAction{ - chain: chainID("sover"), - block: 110, + Action: waitUntilBlockAction{ + Chain: ChainID("sover"), + Block: 110, }, - state: State{}, + State: State{}, }, } } @@ -249,116 +249,116 @@ func stepsUpgradeChain() []Step { func stepsPostChangeoverDelegate(consumerName string) []Step { return []Step{ { - action: SendTokensAction{ - chain: chainID(consumerName), - from: validatorID("alice"), - to: validatorID("bob"), - amount: 100, + Action: SendTokensAction{ + Chain: ChainID(consumerName), + From: ValidatorID("alice"), + To: ValidatorID("bob"), + Amount: 100, }, - state: State{ - chainID(consumerName): ChainState{ + State: State{ + ChainID(consumerName): ChainState{ // Tx should not go through, ICS channel is not setup until first VSC packet has been relayed to consumer - ValBalances: &map[validatorID]uint{ - validatorID("bob"): 0, + ValBalances: &map[ValidatorID]uint{ + ValidatorID("bob"): 0, }, }, }, }, { - action: delegateTokensAction{ - chain: chainID("provi"), - from: validatorID("alice"), - to: validatorID("alice"), - amount: 11000000, + Action: delegateTokensAction{ + Chain: ChainID("provi"), + From: ValidatorID("alice"), + To: ValidatorID("alice"), + Amount: 11000000, }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 500, - validatorID("carol"): 500, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 500, - validatorID("bob"): 500, - validatorID("carol"): 500, + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 500, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, }, }, { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 1, + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 1, }, - state: State{ - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 511, - validatorID("bob"): 500, - validatorID("carol"): 500, + State: State{ + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, }, }, { - action: SendTokensAction{ - chain: chainID(consumerName), - from: validatorID("alice"), - to: validatorID("bob"), - amount: 100, + Action: SendTokensAction{ + Chain: ChainID(consumerName), + From: ValidatorID("alice"), + To: ValidatorID("bob"), + Amount: 100, }, - state: State{ - chainID(consumerName): ChainState{ + State: State{ + ChainID(consumerName): ChainState{ // Tx should go through, ICS channel is setup - ValBalances: &map[validatorID]uint{ - validatorID("bob"): 100, + ValBalances: &map[ValidatorID]uint{ + ValidatorID("bob"): 100, }, }, }, }, { - action: unbondTokensAction{ - chain: chainID("provi"), - unbondFrom: validatorID("alice"), - sender: validatorID("alice"), - amount: 1000000, + Action: unbondTokensAction{ + Chain: ChainID("provi"), + UnbondFrom: ValidatorID("alice"), + Sender: ValidatorID("alice"), + Amount: 1000000, }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 510, - validatorID("bob"): 500, - validatorID("carol"): 500, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 510, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ // Voting power on consumer should not be affected yet - validatorID("alice"): 511, - validatorID("bob"): 500, - validatorID("carol"): 500, + ValidatorID("alice"): 511, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, }, }, { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 1, + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 1, }, - state: State{ - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 510, - validatorID("bob"): 500, - validatorID("carol"): 500, + State: State{ + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 510, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, }, diff --git a/tests/e2e/steps_start_chains.go b/tests/e2e/steps_start_chains.go index 6017a22641..ace3d6c255 100644 --- a/tests/e2e/steps_start_chains.go +++ b/tests/e2e/steps_start_chains.go @@ -7,20 +7,20 @@ import ( func stepStartProviderChain() []Step { return []Step{ { - action: StartChainAction{ - chain: chainID("provi"), - validators: []StartChainValidator{ - {id: validatorID("bob"), stake: 500000000, allocation: 10000000000}, - {id: validatorID("alice"), stake: 500000000, allocation: 10000000000}, - {id: validatorID("carol"), stake: 500000000, allocation: 10000000000}, + Action: StartChainAction{ + Chain: ChainID("provi"), + Validators: []StartChainValidator{ + {Id: ValidatorID("bob"), Stake: 500000000, Allocation: 10000000000}, + {Id: ValidatorID("alice"), Stake: 500000000, Allocation: 10000000000}, + {Id: ValidatorID("carol"), Stake: 500000000, Allocation: 10000000000}, }, }, - state: State{ - chainID("provi"): ChainState{ - ValBalances: &map[validatorID]uint{ - validatorID("alice"): 9500000000, - validatorID("bob"): 9500000000, - validatorID("carol"): 9500000000, + State: State{ + ChainID("provi"): ChainState{ + ValBalances: &map[ValidatorID]uint{ + ValidatorID("alice"): 9500000000, + ValidatorID("bob"): 9500000000, + ValidatorID("carol"): 9500000000, }, }, }, @@ -31,24 +31,24 @@ func stepStartProviderChain() []Step { func stepsStartConsumerChain(consumerName string, proposalIndex, chainIndex uint, setupTransferChans bool) []Step { s := []Step{ { - action: submitConsumerAdditionProposalAction{ - chain: chainID("provi"), - from: validatorID("alice"), - deposit: 10000001, - consumerChain: chainID(consumerName), - spawnTime: 0, - initialHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: 1}, + Action: submitConsumerAdditionProposalAction{ + Chain: ChainID("provi"), + From: ValidatorID("alice"), + Deposit: 10000001, + ConsumerChain: ChainID(consumerName), + SpawnTime: 0, + InitialHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: 1}, }, - state: State{ - chainID("provi"): ChainState{ - ValBalances: &map[validatorID]uint{ - validatorID("alice"): 9489999999, - validatorID("bob"): 9500000000, + State: State{ + ChainID("provi"): ChainState{ + ValBalances: &map[ValidatorID]uint{ + ValidatorID("alice"): 9489999999, + ValidatorID("bob"): 9500000000, }, Proposals: &map[uint]Proposal{ proposalIndex: ConsumerAdditionProposal{ Deposit: 10000001, - Chain: chainID(consumerName), + Chain: ChainID(consumerName), SpawnTime: 0, InitialHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: 1}, Status: "PROPOSAL_STATUS_VOTING_PERIOD", @@ -60,155 +60,155 @@ func stepsStartConsumerChain(consumerName string, proposalIndex, chainIndex uint // add a consumer key before the chain starts // the key will be present in consumer genesis initial_val_set { - action: assignConsumerPubKeyAction{ - chain: chainID(consumerName), - validator: validatorID("carol"), - consumerPubkey: `{"@type":"/cosmos.crypto.ed25519.PubKey","key":"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is="}`, + Action: assignConsumerPubKeyAction{ + Chain: ChainID(consumerName), + Validator: ValidatorID("carol"), + ConsumerPubkey: `{"@type":"/cosmos.crypto.ed25519.PubKey","key":"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is="}`, // consumer chain has not started // we don't need to reconfigure the node // since it will start with consumer key - reconfigureNode: false, + ReconfigureNode: false, }, - state: State{ - chainID(consumerName): ChainState{ - AssignedKeys: &map[validatorID]string{ - validatorID("carol"): "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk", + State: State{ + ChainID(consumerName): ChainState{ + AssignedKeys: &map[ValidatorID]string{ + ValidatorID("carol"): "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk", }, - ProviderKeys: &map[validatorID]string{ - validatorID("carol"): "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6", + ProviderKeys: &map[ValidatorID]string{ + ValidatorID("carol"): "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6", }, }, }, }, { // op should fail - key already assigned by the same validator - action: assignConsumerPubKeyAction{ - chain: chainID(consumerName), - validator: validatorID("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", + Action: assignConsumerPubKeyAction{ + Chain: ChainID(consumerName), + Validator: ValidatorID("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", }, - state: State{}, + State: State{}, }, { // op should fail - key already assigned by another validator - action: assignConsumerPubKeyAction{ - chain: chainID(consumerName), - validator: validatorID("bob"), + Action: assignConsumerPubKeyAction{ + Chain: ChainID(consumerName), + Validator: ValidatorID("bob"), // same pub key as 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", + 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", }, - state: State{ - chainID(consumerName): ChainState{ - AssignedKeys: &map[validatorID]string{ - validatorID("carol"): "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk", - validatorID("bob"): "", + State: State{ + ChainID(consumerName): ChainState{ + AssignedKeys: &map[ValidatorID]string{ + ValidatorID("carol"): "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk", + ValidatorID("bob"): "", }, - ProviderKeys: &map[validatorID]string{ - validatorID("carol"): "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6", + ProviderKeys: &map[ValidatorID]string{ + ValidatorID("carol"): "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6", }, }, }, }, { - action: voteGovProposalAction{ - chain: chainID("provi"), - from: []validatorID{validatorID("alice"), validatorID("bob"), validatorID("carol")}, - vote: []string{"yes", "yes", "yes"}, - propNumber: proposalIndex, + Action: voteGovProposalAction{ + Chain: ChainID("provi"), + From: []ValidatorID{ValidatorID("alice"), ValidatorID("bob"), ValidatorID("carol")}, + Vote: []string{"yes", "yes", "yes"}, + PropNumber: proposalIndex, }, - state: State{ - chainID("provi"): ChainState{ + State: State{ + ChainID("provi"): ChainState{ Proposals: &map[uint]Proposal{ proposalIndex: ConsumerAdditionProposal{ Deposit: 10000001, - Chain: chainID(consumerName), + Chain: ChainID(consumerName), SpawnTime: 0, InitialHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: 1}, Status: "PROPOSAL_STATUS_PASSED", }, }, - ValBalances: &map[validatorID]uint{ - validatorID("alice"): 9500000000, - validatorID("bob"): 9500000000, + ValBalances: &map[ValidatorID]uint{ + ValidatorID("alice"): 9500000000, + ValidatorID("bob"): 9500000000, }, }, }, }, { - action: startConsumerChainAction{ - consumerChain: chainID(consumerName), - providerChain: chainID("provi"), - validators: []StartChainValidator{ - {id: validatorID("bob"), stake: 500000000, allocation: 10000000000}, - {id: validatorID("alice"), stake: 500000000, allocation: 10000000000}, - {id: validatorID("carol"), stake: 500000000, allocation: 10000000000}, + Action: startConsumerChainAction{ + ConsumerChain: ChainID(consumerName), + ProviderChain: ChainID("provi"), + Validators: []StartChainValidator{ + {Id: ValidatorID("bob"), Stake: 500000000, Allocation: 10000000000}, + {Id: ValidatorID("alice"), Stake: 500000000, 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\"", + GenesisChanges: ".app_state.ccvconsumer.params.soft_opt_out_threshold = \"0.05\"", }, - state: State{ - chainID("provi"): ChainState{ - ValBalances: &map[validatorID]uint{ - validatorID("alice"): 9500000000, - validatorID("bob"): 9500000000, - validatorID("carol"): 9500000000, + State: State{ + ChainID("provi"): ChainState{ + ValBalances: &map[ValidatorID]uint{ + ValidatorID("alice"): 9500000000, + ValidatorID("bob"): 9500000000, + ValidatorID("carol"): 9500000000, }, }, - chainID(consumerName): ChainState{ - ValBalances: &map[validatorID]uint{ - validatorID("alice"): 10000000000, - validatorID("bob"): 10000000000, - validatorID("carol"): 10000000000, + ChainID(consumerName): ChainState{ + ValBalances: &map[ValidatorID]uint{ + ValidatorID("alice"): 10000000000, + ValidatorID("bob"): 10000000000, + ValidatorID("carol"): 10000000000, }, }, }, }, { - action: addIbcConnectionAction{ - chainA: chainID(consumerName), - chainB: chainID("provi"), - clientA: 0, - clientB: chainIndex, + Action: addIbcConnectionAction{ + ChainA: ChainID(consumerName), + ChainB: ChainID("provi"), + ClientA: 0, + ClientB: chainIndex, }, - state: State{}, + State: State{}, }, { - action: addIbcChannelAction{ - chainA: chainID(consumerName), - chainB: chainID("provi"), - connectionA: 0, - portA: "consumer", // TODO: check port mapping - portB: "provider", - order: "ordered", + Action: addIbcChannelAction{ + ChainA: ChainID(consumerName), + ChainB: ChainID("provi"), + ConnectionA: 0, + PortA: "consumer", // TODO: check port mapping + PortB: "provider", + Order: "ordered", }, - state: State{}, + State: State{}, }, } // currently only used in democracy tests if setupTransferChans { s = append(s, Step{ - action: transferChannelCompleteAction{ - chainA: chainID(consumerName), - chainB: chainID("provi"), - connectionA: 0, - portA: "transfer", - portB: "transfer", - order: "unordered", - channelA: 1, - channelB: 1, + Action: transferChannelCompleteAction{ + ChainA: ChainID(consumerName), + ChainB: ChainID("provi"), + ConnectionA: 0, + PortA: "transfer", + PortB: "transfer", + Order: "unordered", + ChannelA: 1, + ChannelB: 1, }, - state: State{}, + State: State{}, }) } return s @@ -228,75 +228,75 @@ func stepsStartChains(consumerNames []string, setupTransferChans bool) []Step { func stepsAssignConsumerKeyOnStartedChain(consumerName, validator string) []Step { return []Step{ { - action: assignConsumerPubKeyAction{ - chain: chainID(consumerName), - validator: validatorID("bob"), + Action: assignConsumerPubKeyAction{ + Chain: ChainID(consumerName), + Validator: ValidatorID("bob"), // reconfigure the node -> validator was using provider key // until this point -> key matches config.consumerValPubKey for "bob" - consumerPubkey: `{"@type":"/cosmos.crypto.ed25519.PubKey","key":"QlG+iYe6AyYpvY1z9RNJKCVlH14Q/qSz4EjGdGCru3o="}`, - reconfigureNode: true, + ConsumerPubkey: `{"@type":"/cosmos.crypto.ed25519.PubKey","key":"QlG+iYe6AyYpvY1z9RNJKCVlH14Q/qSz4EjGdGCru3o="}`, + ReconfigureNode: true, }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ // this happens after some delegations // so that the chain does not halt if 1/3 of power is offline - validatorID("alice"): 511, - validatorID("bob"): 500, - validatorID("carol"): 500, + ValidatorID("alice"): 511, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ // this happens after some delegations // so that the chain does not halt if 1/3 of power is offline - validatorID("alice"): 511, - validatorID("bob"): 500, - validatorID("carol"): 500, + ValidatorID("alice"): 511, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, - AssignedKeys: &map[validatorID]string{ - validatorID("bob"): "cosmosvalcons1uuec3cjxajv5te08p220usrjhkfhg9wyvqn0tm", - validatorID("carol"): "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk", + AssignedKeys: &map[ValidatorID]string{ + ValidatorID("bob"): "cosmosvalcons1uuec3cjxajv5te08p220usrjhkfhg9wyvqn0tm", + ValidatorID("carol"): "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk", }, - ProviderKeys: &map[validatorID]string{ - validatorID("bob"): "cosmosvalcons1nx7n5uh0ztxsynn4sje6eyq2ud6rc6klc96w39", - validatorID("carol"): "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6", + ProviderKeys: &map[ValidatorID]string{ + ValidatorID("bob"): "cosmosvalcons1nx7n5uh0ztxsynn4sje6eyq2ud6rc6klc96w39", + ValidatorID("carol"): "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6", }, }, }, }, { - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 0, + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 0, }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ // this happens after some delegations // so that the chain does not halt if 1/3 of power is offline - validatorID("alice"): 511, - validatorID("bob"): 500, - validatorID("carol"): 500, + ValidatorID("alice"): 511, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ // this happens after some delegations // so that the chain does not halt if 1/3 of power is offline - validatorID("alice"): 511, - validatorID("bob"): 500, - validatorID("carol"): 500, + ValidatorID("alice"): 511, + ValidatorID("bob"): 500, + ValidatorID("carol"): 500, }, - AssignedKeys: &map[validatorID]string{ - validatorID("bob"): "cosmosvalcons1uuec3cjxajv5te08p220usrjhkfhg9wyvqn0tm", - validatorID("carol"): "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk", + AssignedKeys: &map[ValidatorID]string{ + ValidatorID("bob"): "cosmosvalcons1uuec3cjxajv5te08p220usrjhkfhg9wyvqn0tm", + ValidatorID("carol"): "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk", }, - ProviderKeys: &map[validatorID]string{ - validatorID("bob"): "cosmosvalcons1nx7n5uh0ztxsynn4sje6eyq2ud6rc6klc96w39", - validatorID("carol"): "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6", + ProviderKeys: &map[ValidatorID]string{ + ValidatorID("bob"): "cosmosvalcons1nx7n5uh0ztxsynn4sje6eyq2ud6rc6klc96w39", + ValidatorID("carol"): "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6", }, }, }, diff --git a/tests/e2e/steps_stop_chain.go b/tests/e2e/steps_stop_chain.go index 9cef49a9ea..0841086417 100644 --- a/tests/e2e/steps_stop_chain.go +++ b/tests/e2e/steps_stop_chain.go @@ -6,8 +6,8 @@ import "time" func stepsStartRelayer() []Step { return []Step{ { - action: startRelayerAction{}, - state: State{}, + Action: startRelayerAction{}, + State: State{}, }, } } @@ -16,51 +16,51 @@ func stepsStartRelayer() []Step { func stepsStopChain(consumerName string, propNumber uint) []Step { s := []Step{ { - action: submitConsumerRemovalProposalAction{ - chain: chainID("provi"), - from: validatorID("bob"), - deposit: 10000001, - consumerChain: chainID(consumerName), - stopTimeOffset: 0 * time.Millisecond, + Action: submitConsumerRemovalProposalAction{ + Chain: ChainID("provi"), + From: ValidatorID("bob"), + Deposit: 10000001, + ConsumerChain: ChainID(consumerName), + StopTimeOffset: 0 * time.Millisecond, }, - state: State{ - chainID("provi"): ChainState{ - ValBalances: &map[validatorID]uint{ - validatorID("bob"): 9489999999, + State: State{ + ChainID("provi"): ChainState{ + ValBalances: &map[ValidatorID]uint{ + ValidatorID("bob"): 9489999999, }, Proposals: &map[uint]Proposal{ propNumber: ConsumerRemovalProposal{ Deposit: 10000001, - Chain: chainID(consumerName), + Chain: ChainID(consumerName), StopTime: 0, Status: "PROPOSAL_STATUS_VOTING_PERIOD", }, }, - ConsumerChains: &map[chainID]bool{"consu": true}, // consumer chain not yet removed + ConsumerChains: &map[ChainID]bool{"consu": true}, // consumer chain not yet removed }, }, }, { - action: voteGovProposalAction{ - chain: chainID("provi"), - from: []validatorID{validatorID("alice"), validatorID("bob"), validatorID("carol")}, - vote: []string{"yes", "yes", "yes"}, - propNumber: propNumber, + Action: voteGovProposalAction{ + Chain: ChainID("provi"), + From: []ValidatorID{ValidatorID("alice"), ValidatorID("bob"), ValidatorID("carol")}, + Vote: []string{"yes", "yes", "yes"}, + PropNumber: propNumber, }, - state: State{ - chainID("provi"): ChainState{ + State: State{ + ChainID("provi"): ChainState{ Proposals: &map[uint]Proposal{ propNumber: ConsumerRemovalProposal{ Deposit: 10000001, - Chain: chainID(consumerName), + Chain: ChainID(consumerName), StopTime: 0, Status: "PROPOSAL_STATUS_PASSED", }, }, - ValBalances: &map[validatorID]uint{ - validatorID("bob"): 9500000000, + ValBalances: &map[ValidatorID]uint{ + ValidatorID("bob"): 9500000000, }, - ConsumerChains: &map[chainID]bool{}, // Consumer chain is now removed + ConsumerChains: &map[ChainID]bool{}, // Consumer chain is now removed }, }, }, @@ -74,51 +74,51 @@ func stepsStopChain(consumerName string, propNumber uint) []Step { func stepsConsumerRemovalPropNotPassing(consumerName string, propNumber uint) []Step { s := []Step{ { - action: submitConsumerRemovalProposalAction{ - chain: chainID("provi"), - from: validatorID("bob"), - deposit: 10000001, - consumerChain: chainID(consumerName), - stopTimeOffset: 0 * time.Millisecond, + Action: submitConsumerRemovalProposalAction{ + Chain: ChainID("provi"), + From: ValidatorID("bob"), + Deposit: 10000001, + ConsumerChain: ChainID(consumerName), + StopTimeOffset: 0 * time.Millisecond, }, - state: State{ - chainID("provi"): ChainState{ - ValBalances: &map[validatorID]uint{ - validatorID("bob"): 9489999999, + State: State{ + ChainID("provi"): ChainState{ + ValBalances: &map[ValidatorID]uint{ + ValidatorID("bob"): 9489999999, }, Proposals: &map[uint]Proposal{ propNumber: ConsumerRemovalProposal{ Deposit: 10000001, - Chain: chainID(consumerName), + Chain: ChainID(consumerName), StopTime: 0, Status: "PROPOSAL_STATUS_VOTING_PERIOD", }, }, - ConsumerChains: &map[chainID]bool{"consu": true}, // consumer chain not removed + ConsumerChains: &map[ChainID]bool{"consu": true}, // consumer chain not removed }, }, }, { - action: voteGovProposalAction{ - chain: chainID("provi"), - from: []validatorID{validatorID("alice"), validatorID("bob"), validatorID("carol")}, - vote: []string{"no", "no", "no"}, - propNumber: propNumber, + Action: voteGovProposalAction{ + Chain: ChainID("provi"), + From: []ValidatorID{ValidatorID("alice"), ValidatorID("bob"), ValidatorID("carol")}, + Vote: []string{"no", "no", "no"}, + PropNumber: propNumber, }, - state: State{ - chainID("provi"): ChainState{ + State: State{ + ChainID("provi"): ChainState{ Proposals: &map[uint]Proposal{ propNumber: ConsumerRemovalProposal{ Deposit: 10000001, - Chain: chainID(consumerName), + Chain: ChainID(consumerName), StopTime: 0, Status: "PROPOSAL_STATUS_REJECTED", }, }, - ValBalances: &map[validatorID]uint{ - validatorID("bob"): 9500000000, + ValBalances: &map[ValidatorID]uint{ + ValidatorID("bob"): 9500000000, }, - ConsumerChains: &map[chainID]bool{"consu": true}, // consumer chain not removed + ConsumerChains: &map[ChainID]bool{"consu": true}, // consumer chain not removed }, }, }, diff --git a/tests/e2e/steps_submit_equivocation_proposal.go b/tests/e2e/steps_submit_equivocation_proposal.go index 8af1d2464d..243c01f04d 100644 --- a/tests/e2e/steps_submit_equivocation_proposal.go +++ b/tests/e2e/steps_submit_equivocation_proposal.go @@ -7,35 +7,35 @@ func stepsRejectEquivocationProposal(consumerName string, propNumber uint) []Ste return []Step{ { // bob submits a proposal to slash himself - action: submitEquivocationProposalAction{ - chain: chainID("consu"), - from: validatorID("bob"), - deposit: 10000001, - height: 10, - time: time.Now(), - power: 500, - validator: validatorID("bob"), + Action: submitEquivocationProposalAction{ + Chain: ChainID("consu"), + From: ValidatorID("bob"), + Deposit: 10000001, + Height: 10, + Time: time.Now(), + Power: 500, + Validator: ValidatorID("bob"), }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 495, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 495, }, - ValBalances: &map[validatorID]uint{ - validatorID("bob"): 9500000000, + ValBalances: &map[ValidatorID]uint{ + ValidatorID("bob"): 9500000000, }, Proposals: &map[uint]Proposal{ // proposal does not exist propNumber: TextProposal{}, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 495, + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 495, }, }, }, @@ -48,24 +48,24 @@ func stepsSubmitEquivocationProposal(consumerName string, propNumber uint) []Ste s := []Step{ { // bob submits a proposal to slash himself - action: submitEquivocationProposalAction{ - chain: chainID("consu"), - from: validatorID("bob"), - deposit: 10000001, - height: 10, - time: time.Now(), // not sure what time in equivocations means - power: 500, - validator: validatorID("bob"), + Action: submitEquivocationProposalAction{ + Chain: ChainID("consu"), + From: ValidatorID("bob"), + Deposit: 10000001, + Height: 10, + Time: time.Now(), // not sure what time in equivocations means + Power: 500, + Validator: ValidatorID("bob"), }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, }, - ValBalances: &map[validatorID]uint{ - validatorID("bob"): 9489999999, + ValBalances: &map[ValidatorID]uint{ + ValidatorID("bob"): 9489999999, }, Proposals: &map[uint]Proposal{ propNumber: EquivocationProposal{ @@ -77,28 +77,28 @@ func stepsSubmitEquivocationProposal(consumerName string, propNumber uint) []Ste }, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, - validatorID("carol"): 0, + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, }, }, }, }, { - action: voteGovProposalAction{ - chain: chainID("provi"), - from: []validatorID{validatorID("alice"), validatorID("bob"), validatorID("carol")}, - vote: []string{"yes", "yes", "yes"}, - propNumber: propNumber, + Action: voteGovProposalAction{ + Chain: ChainID("provi"), + From: []ValidatorID{ValidatorID("alice"), ValidatorID("bob"), ValidatorID("carol")}, + Vote: []string{"yes", "yes", "yes"}, + PropNumber: propNumber, }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 0, // bob is tombstoned after proposal passes - validatorID("carol"): 0, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 0, // bob is tombstoned after proposal passes + ValidatorID("carol"): 0, }, Proposals: &map[uint]Proposal{ propNumber: EquivocationProposal{ @@ -110,36 +110,36 @@ func stepsSubmitEquivocationProposal(consumerName string, propNumber uint) []Ste }, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 500, // slash not reflected in consumer chain - validatorID("carol"): 0, + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, // slash not reflected in consumer chain + ValidatorID("carol"): 0, }, }, }, }, { // relay power change to consumer1 - action: relayPacketsAction{ - chainA: chainID("provi"), - chainB: chainID(consumerName), - port: "provider", - channel: 0, + Action: relayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID(consumerName), + Port: "provider", + Channel: 0, }, - state: State{ - chainID("provi"): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 0, - validatorID("carol"): 0, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 0, + ValidatorID("carol"): 0, }, }, - chainID(consumerName): ChainState{ - ValPowers: &map[validatorID]uint{ - validatorID("alice"): 509, - validatorID("bob"): 0, // slash relayed to consumer chain - validatorID("carol"): 0, + ChainID(consumerName): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 0, // slash relayed to consumer chain + ValidatorID("carol"): 0, }, }, }, From cb6f856f1da105ad8f7e3f2803cd7a7dc49447fb Mon Sep 17 00:00:00 2001 From: Simon Noetzlin Date: Thu, 21 Sep 2023 19:05:12 +0200 Subject: [PATCH 122/134] doc: add changelog entry for v2.*-lsm releases (#1323) add changelog entry for v2.*-lsm releases --- CHANGELOG.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 29b6328e94..a238df4a44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,6 +68,19 @@ Interchain Security v3 uses SDK 0.47 and IBC 7. * `[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.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 From 3d4627b77bdfa809db0229b005c09c9f86f2a35a Mon Sep 17 00:00:00 2001 From: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Date: Mon, 25 Sep 2023 10:54:43 +0200 Subject: [PATCH 123/134] test: Add json marshal/unmarshal for test traces (#1314) * Add json marshal/unmarshal for test traces * Remove auto-generated trace files * Add an example trace to see the input format * Add comment in rapid test * Remove duplicated test case * Remove TODO in favor of comment * Reduce code duplication * Run go mod tidy and make format * Correct testdata directory in gitignore * Remove testdata directory * Remove testdata from gitignore * Add tracehandler_testdata * Remove example trace, since there are examples in the test data * Revert unintentional change to .gitignore * Remove propType field from generator * Add docstrings to action_rapid test and state_rapid_test to better explain what the files are doing * bite -> byte * Refactor: slashThrottleDequeue to slashThrottleDequeueAction * action name -> action type * use method name as first word in docstring * Simply remove simply * Clarify that WriteTrace overrides * Remove outdated comments * Add RegisteredConsumerRewardDenoms to rapid test * Add gen for submitChangeRewardDenomsProposalAction * Remove startChain steps * Marshal step files with indent * Add README that contains info about updates to trace format * Pull out the copied ChainState and Proposal types from methods * Use shadowing to avoid relisting chainstate fields * Make format * Remove log --- go.mod | 6 +- tests/e2e/README.md | 13 + tests/e2e/action_rapid_test.go | 501 ++++ tests/e2e/actions.go | 8 +- tests/e2e/json_marshal_test.go | 189 ++ tests/e2e/json_parser.go | 35 + tests/e2e/json_utils.go | 374 +++ tests/e2e/json_writer.go | 28 + tests/e2e/main.go | 2 +- tests/e2e/state_rapid_test.go | 250 ++ tests/e2e/step_rapid_test.go | 51 + tests/e2e/steps_downtime.go | 2 +- tests/e2e/trace_handlers_test.go | 229 ++ .../e2e/tracehandler_testdata/changeover.json | 603 +++++ .../e2e/tracehandler_testdata/democracy.json | 935 +++++++ .../democracyRewardsSteps.json | 935 +++++++ .../e2e/tracehandler_testdata/happyPath.json | 2007 ++++++++++++++ .../multipleConsumers.json | 2381 +++++++++++++++++ .../e2e/tracehandler_testdata/shorthappy.json | 1578 +++++++++++ .../tracehandler_testdata/slashThrottle.json | 807 ++++++ 20 files changed, 10925 insertions(+), 9 deletions(-) create mode 100644 tests/e2e/README.md create mode 100644 tests/e2e/action_rapid_test.go create mode 100644 tests/e2e/json_marshal_test.go create mode 100644 tests/e2e/json_parser.go create mode 100644 tests/e2e/json_utils.go create mode 100644 tests/e2e/json_writer.go create mode 100644 tests/e2e/state_rapid_test.go create mode 100644 tests/e2e/step_rapid_test.go create mode 100644 tests/e2e/trace_handlers_test.go create mode 100644 tests/e2e/tracehandler_testdata/changeover.json create mode 100644 tests/e2e/tracehandler_testdata/democracy.json create mode 100644 tests/e2e/tracehandler_testdata/democracyRewardsSteps.json create mode 100644 tests/e2e/tracehandler_testdata/happyPath.json create mode 100644 tests/e2e/tracehandler_testdata/multipleConsumers.json create mode 100644 tests/e2e/tracehandler_testdata/shorthappy.json create mode 100644 tests/e2e/tracehandler_testdata/slashThrottle.json diff --git a/go.mod b/go.mod index 1f05100cd2..5f869f97db 100644 --- a/go.mod +++ b/go.mod @@ -68,7 +68,7 @@ require ( github.com/cosmos/rosetta-sdk-go v0.10.0 // indirect github.com/creachadair/taskgroup v0.4.2 // indirect github.com/danieljoos/wincred v1.1.2 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davecgh/go-spew v1.1.1 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect github.com/dgraph-io/badger/v2 v2.2007.4 // indirect @@ -88,7 +88,7 @@ require ( github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/btree v1.1.2 // indirect - github.com/google/go-cmp v0.5.9 // indirect + github.com/google/go-cmp v0.5.9 github.com/google/orderedcode v0.0.1 // indirect github.com/google/uuid v1.3.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect @@ -161,7 +161,7 @@ require ( gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect nhooyr.io/websocket v1.8.6 // indirect - pgregory.net/rapid v0.5.5 // indirect + pgregory.net/rapid v0.5.5 sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/tests/e2e/README.md b/tests/e2e/README.md new file mode 100644 index 0000000000..ee9c962651 --- /dev/null +++ b/tests/e2e/README.md @@ -0,0 +1,13 @@ +## Updating the trace format and tests when adjusting the framework + +Some things in the test framework should stay consistent, in particular with respect to the trace format. +When adding or modifying actions, please follow these guidelines: +* Add a case for your action to `main.go` +* Add a case for your action to `json_utils.go/UnmarshalMapToActionType` +* Add a generator for your action to `action_rapid_test.go` and add the generator to `GetActionGen` + +If the chain state from `state.go` is modified, the `ChainStateWithProposalTypes` in `json_utils.go/MarshalJSON` should be updated. + +When adding a new proposal type: +* add a case for your proposal type to `json_utils.go/UnmarshalProposalWithType` +* add a generator for your proposal type in `state_rapid_test.go` and add it to the `GetProposalGen` function \ No newline at end of file diff --git a/tests/e2e/action_rapid_test.go b/tests/e2e/action_rapid_test.go new file mode 100644 index 0000000000..005f52610d --- /dev/null +++ b/tests/e2e/action_rapid_test.go @@ -0,0 +1,501 @@ +package main + +import ( + "encoding/json" + "fmt" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/stretchr/testify/require" + "pgregory.net/rapid" +) + +// This file contains tests for serialization/deserialization of actions. +// The tests are written using the rapid testing library, which allows us to +// generate arbitrary actions and test that they can be serialized and +// deserialized without error. +// The generators for the various actions are defined in this file, and +// essentially tell rapid how to build these actions. + +func TestActionMarshalling(t *testing.T) { + rapid.Check(t, func(t *rapid.T) { + action := GetActionGen().Draw(t, "Action") + err := MarshalAndUnmarshalAction(action) + if err != nil { + t.Fatalf("error marshalling and unmarshalling action: %v", err) + } + }) +} + +func MarshalAndUnmarshalAction(action interface{}) error { + // wraps the action with a step, since it needs custom unmarshalling that is called by the step unmarshaller + step := Step{ + Action: action, + } + jsonobj, err := json.Marshal(step) + if err != nil { + return fmt.Errorf("error marshalling action inside step: %v", err) + } + + var got Step + err = json.Unmarshal(jsonobj, &got) + if err != nil { + return fmt.Errorf("error unmarshalling action inside step: %v", err) + } + + diff := cmp.Diff(step, got) + if diff != "" { + return fmt.Errorf("got (-), want (+): %v", diff) + } + + return nil +} + +// This needs to be adjusted manually when new actions are added and should +// include generators for all actions that are mentioned in main.go/runStep. +func GetActionGen() *rapid.Generator[any] { + return rapid.OneOf( + GetStartSovereignChainActionGen().AsAny(), + GetSubmitLegacyUpgradeProposalActionGen().AsAny(), + GetWaitUntilBlockActionGen().AsAny(), + GetChangeoverChainActionGen().AsAny(), + GetSendTokensActionGen().AsAny(), + GetStartChainActionGen().AsAny(), + GetSubmitTextProposalActionGen().AsAny(), + GetSubmitConsumerAdditionProposalActionGen().AsAny(), + GetSubmitConsumerRemovalProposalActionGen().AsAny(), + GetSubmitParamChangeProposalActionGen().AsAny(), + GetSubmitEquivocationProposalActionGen().AsAny(), + GetVoteGovProposalActionGen().AsAny(), + GetStartConsumerChainActionGen().AsAny(), + GetAddChainToRelayerActionGen().AsAny(), + GetAddIbcConnectionActionGen().AsAny(), + GetAddIbcChannelActionGen().AsAny(), + GetStartRelayerActionGen().AsAny(), + GetTransferChannelCompleteActionGen().AsAny(), + GetRelayPacketsActionGen().AsAny(), + GetRelayRewardPacketsToProviderActionGen().AsAny(), + GetDelegateTokensActionGen().AsAny(), + GetUnbondTokensActionGen().AsAny(), + GetRedelegateTokensActionGen().AsAny(), + GetDowntimeSlashActionGen().AsAny(), + GetUnjailValidatorActionGen().AsAny(), + GetRegisterRepresentativeActionGen().AsAny(), + GetDoublesignSlashActionGen().AsAny(), + GetAssignConsumerPubKeyActionGen().AsAny(), + GetSlashThrottleDequeueActionGen().AsAny(), + GetCreateIbcClientsActionGen().AsAny(), + CreateCancelUnbondTokensActionGen().AsAny(), + CreateLightClientEquivocationAttackActionGen().AsAny(), + CreateLightClientAmnesiaAttackActionGen().AsAny(), + CreateLightClientLunaticAttackActionGen().AsAny(), + ) +} + +func CreateSubmitChangeRewardDenomsProposalActionGen() *rapid.Generator[submitChangeRewardDenomsProposalAction] { + return rapid.Custom(func(t *rapid.T) submitChangeRewardDenomsProposalAction { + return submitChangeRewardDenomsProposalAction{ + From: GetValidatorIDGen().Draw(t, "From"), + Deposit: rapid.Uint().Draw(t, "Deposit"), + Denom: rapid.String().Draw(t, "Denom"), + } + }) +} + +func CreateLightClientEquivocationAttackActionGen() *rapid.Generator[lightClientEquivocationAttackAction] { + return rapid.Custom(func(t *rapid.T) lightClientEquivocationAttackAction { + return lightClientEquivocationAttackAction{ + Validator: GetValidatorIDGen().Draw(t, "Validator"), + Chain: GetChainIDGen().Draw(t, "Chain"), + } + }) +} + +func CreateLightClientAmnesiaAttackActionGen() *rapid.Generator[lightClientAmnesiaAttackAction] { + return rapid.Custom(func(t *rapid.T) lightClientAmnesiaAttackAction { + return lightClientAmnesiaAttackAction{ + Validator: GetValidatorIDGen().Draw(t, "Validator"), + Chain: GetChainIDGen().Draw(t, "Chain"), + } + }) +} + +func CreateLightClientLunaticAttackActionGen() *rapid.Generator[lightClientLunaticAttackAction] { + return rapid.Custom(func(t *rapid.T) lightClientLunaticAttackAction { + return lightClientLunaticAttackAction{ + Validator: GetValidatorIDGen().Draw(t, "Validator"), + Chain: GetChainIDGen().Draw(t, "Chain"), + } + }) +} + +func CreateCancelUnbondTokensActionGen() *rapid.Generator[cancelUnbondTokensAction] { + return rapid.Custom(func(t *rapid.T) cancelUnbondTokensAction { + return cancelUnbondTokensAction{ + Chain: GetChainIDGen().Draw(t, "Chain"), + Amount: rapid.Uint().Draw(t, "Amount"), + Delegator: GetValidatorIDGen().Draw(t, "Delegator"), + Validator: GetValidatorIDGen().Draw(t, "Validator"), + } + }) +} + +func GetCreateIbcClientsActionGen() *rapid.Generator[createIbcClientsAction] { + return rapid.Custom(func(t *rapid.T) createIbcClientsAction { + return createIbcClientsAction{ + ChainA: GetChainIDGen().Draw(t, "ChainA"), + ChainB: GetChainIDGen().Draw(t, "ChainB"), + } + }) +} + +func GetStartSovereignChainActionGen() *rapid.Generator[StartSovereignChainAction] { + return rapid.Custom(func(t *rapid.T) StartSovereignChainAction { + return StartSovereignChainAction{ + Chain: GetChainIDGen().Draw(t, "Chain"), + Validators: GetStartChainValidatorsGen().Draw(t, "Validators"), + GenesisChanges: rapid.String().Draw(t, "GenesisChanges"), + } + }) +} + +func GetSubmitLegacyUpgradeProposalActionGen() *rapid.Generator[LegacyUpgradeProposalAction] { + return rapid.Custom(func(t *rapid.T) LegacyUpgradeProposalAction { + return LegacyUpgradeProposalAction{ + ChainID: GetChainIDGen().Draw(t, "ChainID"), + UpgradeTitle: rapid.String().Draw(t, "UpgradeTitle"), + Proposer: GetValidatorIDGen().Draw(t, "Proposer"), + UpgradeHeight: rapid.Uint64().Draw(t, "UpgradeHeight"), + } + }) +} + +func GetWaitUntilBlockActionGen() *rapid.Generator[waitUntilBlockAction] { + return rapid.Custom(func(t *rapid.T) waitUntilBlockAction { + return waitUntilBlockAction{ + Chain: GetChainIDGen().Draw(t, "Chain"), + Block: rapid.Uint().Draw(t, "Block"), + } + }) +} + +func GetChangeoverChainActionGen() *rapid.Generator[ChangeoverChainAction] { + return rapid.Custom(func(t *rapid.T) ChangeoverChainAction { + return ChangeoverChainAction{ + SovereignChain: GetChainIDGen().Draw(t, "SovereignChain"), + ProviderChain: GetChainIDGen().Draw(t, "ProviderChain"), + Validators: GetStartChainValidatorsGen().Draw(t, "Validators"), + GenesisChanges: rapid.String().Draw(t, "GenesisChanges"), + } + }) +} + +func GetSendTokensActionGen() *rapid.Generator[SendTokensAction] { + return rapid.Custom(func(t *rapid.T) SendTokensAction { + return SendTokensAction{ + Amount: rapid.Uint().Draw(t, "Amount"), + Chain: GetChainIDGen().Draw(t, "Chain"), + From: GetValidatorIDGen().Draw(t, "From"), + To: GetValidatorIDGen().Draw(t, "To"), + } + }) +} + +func GetStartChainActionGen() *rapid.Generator[StartChainAction] { + return rapid.Custom(func(t *rapid.T) StartChainAction { + return StartChainAction{ + Chain: GetChainIDGen().Draw(t, "Chain"), + Validators: GetStartChainValidatorsGen().Draw(t, "Validators"), + GenesisChanges: rapid.String().Draw(t, "GenesisChanges"), + SkipGentx: rapid.Bool().Draw(t, "SkipGentx"), + } + }) +} + +func GetStartChainValidatorsGen() *rapid.Generator[[]StartChainValidator] { + return rapid.Custom(func(t *rapid.T) []StartChainValidator { + return rapid.SliceOf(GetStartChainValidatorGen()).Draw(t, "StartChainValidators") + }) +} + +func GetStartChainValidatorGen() *rapid.Generator[StartChainValidator] { + return rapid.Custom(func(t *rapid.T) StartChainValidator { + return StartChainValidator{ + Id: GetValidatorIDGen().Draw(t, "Id"), + Allocation: rapid.Uint().Draw(t, "Allocation"), + Stake: rapid.Uint().Draw(t, "Stake"), + } + }) +} + +func GetSubmitTextProposalActionGen() *rapid.Generator[submitTextProposalAction] { + return rapid.Custom(func(t *rapid.T) submitTextProposalAction { + return submitTextProposalAction{ + Chain: GetChainIDGen().Draw(t, "Chain"), + From: GetValidatorIDGen().Draw(t, "From"), + Deposit: rapid.Uint().Draw(t, "Deposit"), + Title: rapid.String().Draw(t, "Title"), + Description: rapid.String().Draw(t, "Description"), + } + }) +} + +func GetSubmitConsumerAdditionProposalActionGen() *rapid.Generator[submitConsumerAdditionProposalAction] { + return rapid.Custom(func(t *rapid.T) submitConsumerAdditionProposalAction { + return submitConsumerAdditionProposalAction{ + Chain: GetChainIDGen().Draw(t, "Chain"), + From: GetValidatorIDGen().Draw(t, "From"), + Deposit: rapid.Uint().Draw(t, "Deposit"), + ConsumerChain: GetChainIDGen().Draw(t, "ConsumerChain"), + SpawnTime: rapid.Uint().Draw(t, "SpawnTime"), + InitialHeight: GetHeightGen().Draw(t, "InitialHeight"), + } + }) +} + +func GetSubmitConsumerRemovalProposalActionGen() *rapid.Generator[submitConsumerRemovalProposalAction] { + return rapid.Custom(func(t *rapid.T) submitConsumerRemovalProposalAction { + return submitConsumerRemovalProposalAction{ + Chain: GetChainIDGen().Draw(t, "Chain"), + From: GetValidatorIDGen().Draw(t, "From"), + Deposit: rapid.Uint().Draw(t, "Deposit"), + ConsumerChain: GetChainIDGen().Draw(t, "ConsumerChain"), + StopTimeOffset: time.Duration(rapid.Int64().Draw(t, "StopTimeOffset")), + } + }) +} + +func GetSubmitParamChangeProposalActionGen() *rapid.Generator[submitParamChangeLegacyProposalAction] { + return rapid.Custom(func(t *rapid.T) submitParamChangeLegacyProposalAction { + return submitParamChangeLegacyProposalAction{ + Chain: GetChainIDGen().Draw(t, "Chain"), + From: GetValidatorIDGen().Draw(t, "From"), + Deposit: rapid.Uint().Draw(t, "Deposit"), + Subspace: rapid.String().Draw(t, "Subspace"), + Key: rapid.String().Draw(t, "Key"), + Value: rapid.String().Draw(t, "Value"), // could make this more generic in the future, since Value takes interfaces + } + }) +} + +func GetSubmitEquivocationProposalActionGen() *rapid.Generator[submitEquivocationProposalAction] { + return rapid.Custom(func(t *rapid.T) submitEquivocationProposalAction { + return submitEquivocationProposalAction{ + Chain: GetChainIDGen().Draw(t, "Chain"), + From: GetValidatorIDGen().Draw(t, "From"), + Deposit: rapid.Uint().Draw(t, "Deposit"), + Height: rapid.Int64().Draw(t, "Height"), + Time: GetTimeGen().Draw(t, "Time"), + Power: rapid.Int64().Draw(t, "Power"), + } + }) +} + +func TestMarshalAndUnmarshalTime(t *testing.T) { + rapid.Check(t, func(t *rapid.T) { + time1 := GetTimeGen().Draw(t, "time") + data, err := time1.MarshalJSON() + require.NoError(t, err) + var time2 time.Time + err = time2.UnmarshalJSON(data) + require.NoError(t, err) + require.True(t, time1.Equal(time2)) + }) +} + +func GetTimeGen() *rapid.Generator[time.Time] { + return rapid.Custom(func(t *rapid.T) time.Time { + return time.Unix(rapid.Int64Range(-5.9959e+10, 1.5779e+11).Draw(t, "unix time"), 0).UTC() + }) +} + +func GetVoteGovProposalActionGen() *rapid.Generator[voteGovProposalAction] { + return rapid.Custom(func(t *rapid.T) voteGovProposalAction { + return voteGovProposalAction{ + Chain: GetChainIDGen().Draw(t, "Chain"), + From: rapid.SliceOf(GetValidatorIDGen()).Draw(t, "From"), + Vote: rapid.SliceOf(rapid.String()).Draw(t, "Vote"), + PropNumber: rapid.Uint().Draw(t, "PropNumber"), + } + }) +} + +func GetStartConsumerChainActionGen() *rapid.Generator[startConsumerChainAction] { + return rapid.Custom(func(t *rapid.T) startConsumerChainAction { + return startConsumerChainAction{ + ConsumerChain: GetChainIDGen().Draw(t, "ConsumerChain"), + ProviderChain: GetChainIDGen().Draw(t, "ProviderChain"), + Validators: GetStartChainValidatorsGen().Draw(t, "Validators"), + GenesisChanges: rapid.String().Draw(t, "GenesisChanges"), + } + }) +} + +func GetAddChainToRelayerActionGen() *rapid.Generator[addChainToRelayerAction] { + return rapid.Custom(func(t *rapid.T) addChainToRelayerAction { + return addChainToRelayerAction{ + Chain: GetChainIDGen().Draw(t, "Chain"), + Validator: GetValidatorIDGen().Draw(t, "Validator"), + } + }) +} + +func GetAddIbcConnectionActionGen() *rapid.Generator[addIbcConnectionAction] { + return rapid.Custom(func(t *rapid.T) addIbcConnectionAction { + return addIbcConnectionAction{ + ChainA: GetChainIDGen().Draw(t, "ChainA"), + ChainB: GetChainIDGen().Draw(t, "ChainB"), + ClientA: rapid.Uint().Draw(t, "ClientA"), + ClientB: rapid.Uint().Draw(t, "ClientB"), + } + }) +} + +func GetAddIbcChannelActionGen() *rapid.Generator[addIbcChannelAction] { + return rapid.Custom(func(t *rapid.T) addIbcChannelAction { + return addIbcChannelAction{ + ChainA: GetChainIDGen().Draw(t, "ChainA"), + ChainB: GetChainIDGen().Draw(t, "ChainB"), + ConnectionA: rapid.Uint().Draw(t, "ConnectionA"), + PortA: rapid.String().Draw(t, "PortA"), + PortB: rapid.String().Draw(t, "PortB"), + Order: rapid.String().Draw(t, "Order"), + } + }) +} + +func GetStartRelayerActionGen() *rapid.Generator[startRelayerAction] { + return rapid.Just(startRelayerAction{}) +} + +func GetTransferChannelCompleteActionGen() *rapid.Generator[transferChannelCompleteAction] { + return rapid.Custom(func(t *rapid.T) transferChannelCompleteAction { + return transferChannelCompleteAction{ + ChainA: GetChainIDGen().Draw(t, "ChainA"), + ChainB: GetChainIDGen().Draw(t, "ChainB"), + ConnectionA: rapid.Uint().Draw(t, "ConnectionA"), + PortA: rapid.String().Draw(t, "PortA"), + PortB: rapid.String().Draw(t, "PortB"), + Order: rapid.String().Draw(t, "Order"), + ChannelA: rapid.Uint().Draw(t, "ChannelA"), + ChannelB: rapid.Uint().Draw(t, "ChannelB"), + } + }) +} + +func GetRelayPacketsActionGen() *rapid.Generator[relayPacketsAction] { + return rapid.Custom(func(t *rapid.T) relayPacketsAction { + return relayPacketsAction{ + ChainA: GetChainIDGen().Draw(t, "Chain"), + ChainB: GetChainIDGen().Draw(t, "Chain"), + Port: rapid.String().Draw(t, "Port"), + Channel: rapid.Uint().Draw(t, "Channel"), + } + }) +} + +func GetRelayRewardPacketsToProviderActionGen() *rapid.Generator[relayRewardPacketsToProviderAction] { + return rapid.Custom(func(t *rapid.T) relayRewardPacketsToProviderAction { + return relayRewardPacketsToProviderAction{ + ConsumerChain: GetChainIDGen().Draw(t, "ConsumerChain"), + ProviderChain: GetChainIDGen().Draw(t, "ProviderChain"), + Port: rapid.String().Draw(t, "Port"), + Channel: rapid.Uint().Draw(t, "Channel"), + } + }) +} + +func GetDelegateTokensActionGen() *rapid.Generator[delegateTokensAction] { + return rapid.Custom(func(t *rapid.T) delegateTokensAction { + return delegateTokensAction{ + Chain: GetChainIDGen().Draw(t, "Chain"), + Amount: rapid.Uint().Draw(t, "Amount"), + From: GetValidatorIDGen().Draw(t, "From"), + To: GetValidatorIDGen().Draw(t, "To"), + } + }) +} + +func GetUnbondTokensActionGen() *rapid.Generator[unbondTokensAction] { + return rapid.Custom(func(t *rapid.T) unbondTokensAction { + return unbondTokensAction{ + Chain: GetChainIDGen().Draw(t, "Chain"), + Amount: rapid.Uint().Draw(t, "Amount"), + Sender: GetValidatorIDGen().Draw(t, "Sender"), + UnbondFrom: GetValidatorIDGen().Draw(t, "UnbondFrom"), + } + }) +} + +func GetRedelegateTokensActionGen() *rapid.Generator[redelegateTokensAction] { + return rapid.Custom(func(t *rapid.T) redelegateTokensAction { + return redelegateTokensAction{ + Chain: GetChainIDGen().Draw(t, "Chain"), + Amount: rapid.Uint().Draw(t, "Amount"), + Src: GetValidatorIDGen().Draw(t, "Src"), + Dst: GetValidatorIDGen().Draw(t, "Dst"), + TxSender: GetValidatorIDGen().Draw(t, "TxSender"), + } + }) +} + +func GetDowntimeSlashActionGen() *rapid.Generator[downtimeSlashAction] { + return rapid.Custom(func(t *rapid.T) downtimeSlashAction { + return downtimeSlashAction{ + Chain: GetChainIDGen().Draw(t, "Chain"), + Validator: GetValidatorIDGen().Draw(t, "Validator"), + } + }) +} + +func GetUnjailValidatorActionGen() *rapid.Generator[unjailValidatorAction] { + return rapid.Custom(func(t *rapid.T) unjailValidatorAction { + return unjailValidatorAction{ + Validator: GetValidatorIDGen().Draw(t, "Validator"), + Provider: GetChainIDGen().Draw(t, "Provider"), + } + }) +} + +func GetRegisterRepresentativeActionGen() *rapid.Generator[registerRepresentativeAction] { + return rapid.Custom(func(t *rapid.T) registerRepresentativeAction { + return registerRepresentativeAction{ + Chain: GetChainIDGen().Draw(t, "Chain"), + Representatives: rapid.SliceOf(GetValidatorIDGen()).Draw(t, "Representatives"), + Stakes: rapid.SliceOf(rapid.Uint()).Draw(t, "Stakes"), + } + }) +} + +func GetDoublesignSlashActionGen() *rapid.Generator[doublesignSlashAction] { + return rapid.Custom(func(t *rapid.T) doublesignSlashAction { + return doublesignSlashAction{ + Chain: GetChainIDGen().Draw(t, "Chain"), + Validator: GetValidatorIDGen().Draw(t, "Validator"), + } + }) +} + +func GetAssignConsumerPubKeyActionGen() *rapid.Generator[assignConsumerPubKeyAction] { + return rapid.Custom(func(t *rapid.T) assignConsumerPubKeyAction { + return assignConsumerPubKeyAction{ + Chain: GetChainIDGen().Draw(t, "Chain"), + Validator: GetValidatorIDGen().Draw(t, "Validator"), + ConsumerPubkey: rapid.String().Draw(t, "ConsumerPubkey"), + ReconfigureNode: rapid.Bool().Draw(t, "ReconfigureNode"), + ExpectError: rapid.Bool().Draw(t, "ExpectError"), + } + }) +} + +func GetSlashThrottleDequeueActionGen() *rapid.Generator[slashThrottleDequeueAction] { + return rapid.Custom(func(t *rapid.T) slashThrottleDequeueAction { + return slashThrottleDequeueAction{ + Chain: GetChainIDGen().Draw(t, "Chain"), + CurrentQueueSize: rapid.Int().Draw(t, "CurrentQueueSize"), + NextQueueSize: rapid.Int().Draw(t, "NextQueueSize"), + Timeout: time.Duration(rapid.Int().Draw(t, "Timeout")) * time.Millisecond, + } + }) +} diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index 36e0c47dd2..408c9066fc 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -2045,8 +2045,8 @@ func (tr TestRun) assignConsumerPubKey(action assignConsumerPubKeyAction, verbos tr.waitBlocks(ChainID("provi"), 2, 30*time.Second) } -// slashThrottleDequeue polls slash queue sizes until nextQueueSize is achieved -type slashThrottleDequeue struct { +// slashThrottleDequeueAction polls slash queue sizes until nextQueueSize is achieved +type slashThrottleDequeueAction struct { Chain ChainID CurrentQueueSize int NextQueueSize int @@ -2055,7 +2055,7 @@ type slashThrottleDequeue struct { } func (tr TestRun) waitForSlashThrottleDequeue( - action slashThrottleDequeue, + action slashThrottleDequeueAction, verbose bool, ) { timeout := time.Now().Add(action.Timeout) @@ -2077,7 +2077,7 @@ func (tr TestRun) waitForSlashThrottleDequeue( } if time.Now().After(timeout) { - panic(fmt.Sprintf("\n\n\nwaitForSlashThrottleDequeuemethod has timed out after: %s\n\n", action.Timeout)) + panic(fmt.Sprintf("\n\n\nwaitForSlashThrottleDequeue method has timed out after: %s\n\n", action.Timeout)) } time.Sleep(500 * time.Millisecond) diff --git a/tests/e2e/json_marshal_test.go b/tests/e2e/json_marshal_test.go new file mode 100644 index 0000000000..5ee91dcb66 --- /dev/null +++ b/tests/e2e/json_marshal_test.go @@ -0,0 +1,189 @@ +package main + +import ( + "encoding/json" + "reflect" + "strings" + "testing" + + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + "github.com/davecgh/go-spew/spew" +) + +func TestProposalUnmarshal(t *testing.T) { + proposalAndTypeString := `{ + "Type": "main.ConsumerAdditionProposal", + "RawProposal": { + "Deposit": 10000001, + "Chain": "consu", + "SpawnTime": 0, + "InitialHeight": { + "revision_height": 1 + }, + "Status": "PROPOSAL_STATUS_PASSED" + } + }` + + expectedProposal := ConsumerAdditionProposal{ + Deposit: 10000001, + Chain: ChainID("consu"), + SpawnTime: 0, + InitialHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: 1}, + Status: "PROPOSAL_STATUS_PASSED", + } + + type ProposalAndType struct { + RawProposal json.RawMessage + Type string + } + + propAndType := &ProposalAndType{} + err := json.Unmarshal([]byte(proposalAndTypeString), propAndType) + if err != nil { + t.Errorf("Unexpected error while unmarshalling: %v", err) + } + + actualProposal, err := UnmarshalProposalWithType(propAndType.RawProposal, propAndType.Type) + if err != nil { + t.Errorf("Unexpected error while unmarshalling\n error: %v\n Raw proposal: %v\n Type: %v", err, spew.Sdump(propAndType.RawProposal), propAndType.Type) + } + + if !reflect.DeepEqual(actualProposal, expectedProposal) { + t.Errorf("Expected proposal: %v, but got: %v", spew.Sdump(expectedProposal), spew.Sdump(actualProposal)) + } +} + +type ChainStateTestCase struct { + name string + jsonBytes []byte + chainState ChainState + expectedUnmarshalErrorText string +} + +var testCases = []ChainStateTestCase{ + { + name: "valid JSON with proposals", + jsonBytes: []byte(`{ + "ValBalances": { + "alice": 9500000000, + "bob": 9500000000, + "carol": 9500000000 + }, + "Proposals": { + "1": { + "Type": "main.ConsumerAdditionProposal", + "RawProposal": { + "Deposit": 10000001, + "Chain": "consu", + "SpawnTime": 0, + "InitialHeight": { + "revision_height": 1 + }, + "Status": "PROPOSAL_STATUS_PASSED" + } + } + } + }`), + chainState: ChainState{ + ValBalances: &map[ValidatorID]uint{ + ValidatorID("alice"): 9500000000, + ValidatorID("bob"): 9500000000, + ValidatorID("carol"): 9500000000, + }, + Proposals: &map[uint]Proposal{ + 1: ConsumerAdditionProposal{ + Deposit: 10000001, + Chain: ChainID("consu"), + SpawnTime: 0, + InitialHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: 1}, + Status: "PROPOSAL_STATUS_PASSED", + }, + }, + }, + expectedUnmarshalErrorText: "", + }, + { + name: "invalid JSON", + jsonBytes: []byte(`thisisnotagoodjsonstring`), + expectedUnmarshalErrorText: "invalid json", + }, + { + name: "unknown proposal type", + jsonBytes: []byte(`{ + "ValBalances": { + "alice": 9500000000, + "bob": 9500000000, + "carol": 9500000000 + }, + "Proposals": { + "1": { + "Type": "main.NotAProposalTypeProposal", + "RawProposal": { + "Deposit": 10000001, + "Chain": "consu", + "SpawnTime": 0, + "InitialHeight": { + "revision_height": 1 + }, + "Status": "PROPOSAL_STATUS_PASSED" + } + } + }, + }`), + expectedUnmarshalErrorText: "not a known proposal type", + }, +} + +func TestUnmarshalJSON(t *testing.T) { + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + var result ChainState + err := result.UnmarshalJSON(tc.jsonBytes) + if err != nil && tc.expectedUnmarshalErrorText == "" { + t.Errorf("Test case %v: Unexpected error: %v", tc.name, err) + } + + if err == nil && tc.expectedUnmarshalErrorText != "" { + t.Errorf("Test case %v: Expected error to contain: %v, but got no error", tc.name, tc.expectedUnmarshalErrorText) + } + + if err != nil && tc.expectedUnmarshalErrorText != "" && strings.Contains(err.Error(), tc.expectedUnmarshalErrorText) { + t.Errorf("Test case %v: Expected error to contain: %v, but got: %v", tc.name, tc.expectedUnmarshalErrorText, err) + } + + if !reflect.DeepEqual(result, tc.chainState) { + t.Errorf("Test case %v: Expected ChainState: %v, but got: %v", tc.name, tc.chainState, result) + } + }) + } +} + +func TestMarshalJSON(t *testing.T) { + // checks that marshalling and unmarshalling is the identity + // would optimally check that the marshalled JSON is the same as the expected JSON, + // but the marshalled JSON will specifically list null fields + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + result, err := tc.chainState.MarshalJSON() + if err != nil { + t.Errorf("Test case %v: Unexpected error while marshalling: %v", tc.name, err) + } + + if tc.expectedUnmarshalErrorText != "" { + // unmarshalling to compare does not make sense, since we expect it to + // fail, so just test that marshalling works and continue + return + } + + unmarshalledResult := ChainState{} + err = unmarshalledResult.UnmarshalJSON(result) + if err != nil { + t.Errorf("Test case %v: Unexpected error while unmarshalling: %v", tc.name, err) + } + + if !reflect.DeepEqual(unmarshalledResult, tc.chainState) { + t.Errorf("Test case %v: Expected: %v, but got: %v", tc.name, string(tc.jsonBytes), string(result)) + } + }) + } +} diff --git a/tests/e2e/json_parser.go b/tests/e2e/json_parser.go new file mode 100644 index 0000000000..3f85a23e30 --- /dev/null +++ b/tests/e2e/json_parser.go @@ -0,0 +1,35 @@ +package main + +import ( + "encoding/json" + "os" + "path/filepath" +) + +// TraceParser provides an interface for parsers that read sequences of Steps from files. +type TraceParser interface { + ReadTraceFromFile(filepath string) ([]Step, error) +} + +// JSONParser is a simple parser that reads steps by unmarshalling from a file. +type JSONParser struct{} + +var GlobalJSONParser = JSONParser{} + +func (parser JSONParser) ReadTraceFromFile(path string) ([]Step, error) { + // Open the JSON file and read into a byte array + jsonData, err := os.ReadFile(filepath.Clean(path)) + if err != nil { + return nil, err + } + + // Unmarshal the JSON into a slice of Step structs + var steps []Step + + err = json.Unmarshal(jsonData, &steps) + if err != nil { + return nil, err + } + + return steps, nil +} diff --git a/tests/e2e/json_utils.go b/tests/e2e/json_utils.go new file mode 100644 index 0000000000..692c34a14f --- /dev/null +++ b/tests/e2e/json_utils.go @@ -0,0 +1,374 @@ +package main + +import ( + "encoding/json" + "fmt" + "reflect" +) + +// stores a proposal as a raw json, together with its type +type ProposalAndType struct { + RawProposal json.RawMessage + Type string +} + +type ( + // to have a ChainState object that does not have the overridden Marshal/Unmarshal method + ChainStateCopy ChainState + + // duplicated from the ChainState with a minor change to the Proposals field + ChainStateWithProposalTypes struct { + ChainStateCopy + Proposals *map[uint]ProposalAndType // the only thing changed from the real ChainState + } +) + +// MarshalJSON marshals a step into JSON while including the type of the action. +func (step Step) MarshalJSON() ([]byte, error) { + actionType := reflect.TypeOf(step.Action) + + result := struct { + ActionType string + Action interface{} + State State + }{ + ActionType: actionType.String(), + Action: step.Action, + State: step.State, + } + + return json.Marshal(result) +} + +// UnmarshalJSON unmarshals a step from JSON while including the type of the action. +func (step *Step) UnmarshalJSON(data []byte) error { + var tmp struct { + ActionType string + Action json.RawMessage + State State + } + if err := json.Unmarshal(data, &tmp); err != nil { + return err + } + + action, err := UnmarshalMapToActionType(tmp.Action, tmp.ActionType) + if err != nil { + return err + } + + step.Action = action + step.State = tmp.State + return nil +} + +// UnmarshalMapToActionType takes a JSON object and an action type and marshals into an object of the corresponding action. +func UnmarshalMapToActionType(rawAction json.RawMessage, actionTypeString string) (interface{}, error) { + var err error + switch actionTypeString { + case "main.submitConsumerAdditionProposalAction": + var a submitConsumerAdditionProposalAction + err = json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.SendTokensAction": + var a SendTokensAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.StartChainAction": + var a StartChainAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.submitTextProposalAction": + var a submitTextProposalAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.submitConsumerRemovalProposalAction": + var a submitConsumerRemovalProposalAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.submitEquivocationProposalAction": + var a submitEquivocationProposalAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.submitParamChangeLegacyProposalAction": + var a submitParamChangeLegacyProposalAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.voteGovProposalAction": + var a voteGovProposalAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.startConsumerChainAction": + var a startConsumerChainAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.addChainToRelayerAction": + var a addChainToRelayerAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.addIbcConnectionAction": + var a addIbcConnectionAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.addIbcChannelAction": + var a addIbcChannelAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.transferChannelCompleteAction": + var a transferChannelCompleteAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.unjailValidatorAction": + var a unjailValidatorAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.assignConsumerPubKeyAction": + var a assignConsumerPubKeyAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.delegateTokensAction": + var a delegateTokensAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.relayPacketsAction": + var a relayPacketsAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.registerRepresentativeAction": + var a registerRepresentativeAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.relayRewardPacketsToProviderAction": + var a relayRewardPacketsToProviderAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.submitChangeRewardDenomsProposalAction": + var a submitChangeRewardDenomsProposalAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.downtimeSlashAction": + var a downtimeSlashAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.unbondTokensAction": + var a unbondTokensAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.cancelUnbondTokensAction": + var a cancelUnbondTokensAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.redelegateTokensAction": + var a redelegateTokensAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.doublesignSlashAction": + var a doublesignSlashAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.startRelayerAction": + var a startRelayerAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.slashThrottleDequeueAction": + var a slashThrottleDequeueAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.createIbcClientsAction": + var a createIbcClientsAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.LegacyUpgradeProposalAction": + var a LegacyUpgradeProposalAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.waitUntilBlockAction": + var a waitUntilBlockAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.ChangeoverChainAction": + var a ChangeoverChainAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.StartSovereignChainAction": + var a StartSovereignChainAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.lightClientEquivocationAttackAction": + var a lightClientEquivocationAttackAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.lightClientAmnesiaAttackAction": + var a lightClientAmnesiaAttackAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + case "main.lightClientLunaticAttackAction": + var a lightClientLunaticAttackAction + err := json.Unmarshal(rawAction, &a) + if err == nil { + return a, nil + } + default: + return nil, fmt.Errorf("unknown action type: %s", actionTypeString) + } + return nil, err +} + +// custom marshal and unmarshal functions for the chainstate that convert proposals to/from the auxiliary type with type info + +// MarshalJSON transforms the ChainState into a ChainStateWithProposalTypes by adding type info to the proposals +func (c ChainState) MarshalJSON() ([]byte, error) { + chainStateCopy := ChainStateCopy(c) + chainStateWithProposalTypes := ChainStateWithProposalTypes{chainStateCopy, nil} + if c.Proposals != nil { + proposalsWithTypes := make(map[uint]ProposalAndType) + for k, v := range *c.Proposals { + rawMessage, err := json.Marshal(v) + if err != nil { + return nil, err + } + proposalsWithTypes[k] = ProposalAndType{rawMessage, reflect.TypeOf(v).String()} + } + chainStateWithProposalTypes.Proposals = &proposalsWithTypes + } + return json.Marshal(chainStateWithProposalTypes) +} + +// UnmarshalJSON unmarshals the ChainStateWithProposalTypes into a ChainState by removing the type info from the proposals and getting back standard proposals +func (c *ChainState) UnmarshalJSON(data []byte) error { + chainStateWithProposalTypes := ChainStateWithProposalTypes{} + err := json.Unmarshal(data, &chainStateWithProposalTypes) + if err != nil { + return err + } + + chainState := ChainState(chainStateWithProposalTypes.ChainStateCopy) + *c = chainState + + if chainStateWithProposalTypes.Proposals != nil { + proposals := make(map[uint]Proposal) + for k, v := range *chainStateWithProposalTypes.Proposals { + proposal, err := UnmarshalProposalWithType(v.RawProposal, v.Type) + if err != nil { + return err + } + proposals[k] = proposal + } + c.Proposals = &proposals + } + return nil +} + +// UnmarshalProposalWithType takes a JSON object and a proposal type and marshals into an object of the corresponding proposal. +func UnmarshalProposalWithType(inputMap json.RawMessage, proposalType string) (Proposal, error) { + var err error + switch proposalType { + case "main.TextProposal": + prop := TextProposal{} + err := json.Unmarshal(inputMap, &prop) + if err == nil { + return prop, nil + } + case "main.ConsumerAdditionProposal": + prop := ConsumerAdditionProposal{} + err := json.Unmarshal(inputMap, &prop) + if err == nil { + return prop, nil + } + case "main.UpgradeProposal": + prop := UpgradeProposal{} + err := json.Unmarshal(inputMap, &prop) + if err == nil { + return prop, nil + } + case "main.ConsumerRemovalProposal": + prop := ConsumerRemovalProposal{} + err := json.Unmarshal(inputMap, &prop) + if err == nil { + return prop, nil + } + case "main.EquivocationProposal": + prop := EquivocationProposal{} + err := json.Unmarshal(inputMap, &prop) + if err == nil { + return prop, nil + } + case "main.ParamsProposal": + prop := ParamsProposal{} + err := json.Unmarshal(inputMap, &prop) + if err == nil { + return prop, nil + } + default: + return nil, fmt.Errorf("%s is not a known proposal type", proposalType) + } + + return nil, err +} diff --git a/tests/e2e/json_writer.go b/tests/e2e/json_writer.go new file mode 100644 index 0000000000..ea56d779dd --- /dev/null +++ b/tests/e2e/json_writer.go @@ -0,0 +1,28 @@ +package main + +import ( + "encoding/json" + "os" +) + +// TraceWriter is an interface for writers that write steps to files. +type TraceWriter interface { + // WriteTraceToFile writes a given trace to a file, overwriting the file if it already exists. + WriteTraceToFile(filepath string, trace []Step) error +} + +// JSONWriter is a simple writer that marshals the array of Step objects. +// To identify which type of action is being used, we add a field to the Step struct. +type JSONWriter struct{} + +var GlobalJSONWriter = JSONWriter{} + +func (writer JSONWriter) WriteTraceToFile(filepath string, trace []Step) error { + jsonobj, err := json.MarshalIndent(trace, "", " ") + if err != nil { + panic(err) + } + + err = os.WriteFile(filepath, jsonobj, 0o600) + return err +} diff --git a/tests/e2e/main.go b/tests/e2e/main.go index 0a376664a0..d24f42676a 100644 --- a/tests/e2e/main.go +++ b/tests/e2e/main.go @@ -254,7 +254,7 @@ func (tr *TestRun) runStep(step Step, verbose bool) { tr.registerRepresentative(action, verbose) case assignConsumerPubKeyAction: tr.assignConsumerPubKey(action, verbose) - case slashThrottleDequeue: + case slashThrottleDequeueAction: tr.waitForSlashThrottleDequeue(action, verbose) case startRelayerAction: tr.startRelayer(action, verbose) diff --git a/tests/e2e/state_rapid_test.go b/tests/e2e/state_rapid_test.go new file mode 100644 index 0000000000..6c82c2e7fb --- /dev/null +++ b/tests/e2e/state_rapid_test.go @@ -0,0 +1,250 @@ +package main + +import ( + "testing" + + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + "pgregory.net/rapid" +) + +// This file contains tests for serialization/deserialization of state. +// The tests are written using the rapid testing library, which allows us to +// generate arbitrary state structs and test that they can be serialized and +// deserialized without error. +// The generators for the various parts of the state are defined in this file, and +// essentially tell rapid how to build the state. + +func TestChainStateMarshalling(t *testing.T) { + rapid.Check(t, func(t *rapid.T) { + chainState := GetChainStateGen().Draw(t, "ChainState") + err := MarshalAndUnmarshalChainState(chainState) + if err != nil { + t.Fatalf("error marshalling and unmarshalling chain state: %v", err) + } + }) +} + +// Below this are utility functions for Rapid that define generators for the various structs that can appear in testing. +// These are used in the rapid tests and generate arbitrary test traces for fuzzing. +// These traces will not in general be useful to execute as e2e tests, since they are filled with essentially completely random values. +func GetStateGen() *rapid.Generator[State] { + return rapid.Custom(func(t *rapid.T) State { + return rapid.MapOf(GetChainIDGen(), GetChainStateGen()).Draw(t, "State") + }) +} + +func GetChainStateGen() *rapid.Generator[ChainState] { + return rapid.Custom( + func(t *rapid.T) ChainState { + valBalances := GetValBalancesGen().Draw(t, "ValBalances") + proposals := GetProposalsGen().Draw(t, "Proposals") + valPowers := GetValPowersGen().Draw(t, "ValPowers") + representativePowers := GetRepresentativePowersGen().Draw(t, "RepresentativePowers") + params := GetParamsGen().Draw(t, "Params") + rewards := GetRewardsGen().Draw(t, "Rewards") + consumerChains := GetConsumerChainsGen().Draw(t, "ConsumerChains") + assignedKeys := GetAssignedKeysGen().Draw(t, "AssignedKeys") + providerKeys := GetProviderKeysGen().Draw(t, "ProviderKeys") + consumerChainQueueSizes := GetConsumerChainQueueSizesGen().Draw(t, "ConsumerChainQueueSizes") + globalSlashQueueSize := rapid.Uint().Draw(t, "GlobalSlashQueueSize") + registeredConsumerRewardDenoms := GetRegisteredConsumerRewardDenomsGen().Draw(t, "RegisteredConsumerRewardDenoms") + + return ChainState{ + ValBalances: &valBalances, + Proposals: &proposals, + ValPowers: &valPowers, + RepresentativePowers: &representativePowers, + Params: ¶ms, + Rewards: &rewards, + ConsumerChains: &consumerChains, + AssignedKeys: &assignedKeys, + ProviderKeys: &providerKeys, + ConsumerChainQueueSizes: &consumerChainQueueSizes, + GlobalSlashQueueSize: &globalSlashQueueSize, + RegisteredConsumerRewardDenoms: ®isteredConsumerRewardDenoms, + } + }) +} + +func GetRegisteredConsumerRewardDenomsGen() *rapid.Generator[[]string] { + return rapid.Custom(func(t *rapid.T) []string { + return rapid.SliceOf(rapid.String()).Draw(t, "RegisteredConsumerRewardDenoms") + }) +} + +func GetConsumerChainQueueSizesGen() *rapid.Generator[map[ChainID]uint] { + return rapid.Custom(func(t *rapid.T) map[ChainID]uint { + return rapid.MapOf(GetChainIDGen(), rapid.Uint()).Draw(t, "ConsumerChainQueueSizes") + }) +} + +func GetProviderKeysGen() *rapid.Generator[map[ValidatorID]string] { + return rapid.Custom(func(t *rapid.T) map[ValidatorID]string { + return rapid.MapOf(GetValidatorIDGen(), rapid.String()).Draw(t, "ProviderKeys") + }) +} + +func GetAssignedKeysGen() *rapid.Generator[map[ValidatorID]string] { + return rapid.Custom(func(t *rapid.T) map[ValidatorID]string { + return rapid.MapOf(GetValidatorIDGen(), rapid.String()).Draw(t, "AssignedKeys") + }) +} + +func GetChainIDGen() *rapid.Generator[ChainID] { + return rapid.Custom(func(t *rapid.T) ChainID { + return ChainID(rapid.String().Draw(t, "ChainID")) + }) +} + +func GetConsumerChainsGen() *rapid.Generator[map[ChainID]bool] { + return rapid.Custom(func(t *rapid.T) map[ChainID]bool { + return rapid.MapOf(GetChainIDGen(), rapid.Bool()).Draw(t, "ConsumerChains") + }) +} + +func GetRewardsGen() *rapid.Generator[Rewards] { + return rapid.Custom(func(t *rapid.T) Rewards { + return Rewards{ + IsIncrementalReward: rapid.Bool().Draw(t, "IsIncrementalReward"), + IsNativeDenom: rapid.Bool().Draw(t, "IsNativeDenom"), + IsRewarded: rapid.MapOf(GetValidatorIDGen(), rapid.Bool()).Draw(t, "IsRewarded"), + } + }) +} + +func GetParamsGen() *rapid.Generator[[]Param] { + return rapid.Custom(func(t *rapid.T) []Param { + return rapid.SliceOf(GetParamGen()).Draw(t, "Params") + }) +} + +func GetParamGen() *rapid.Generator[Param] { + return rapid.Custom(func(t *rapid.T) Param { + return Param{ + Key: rapid.String().Draw(t, "Key"), + Value: rapid.String().Draw(t, "Value"), + } + }) +} + +func GetRepresentativePowersGen() *rapid.Generator[map[ValidatorID]uint] { + return rapid.Custom(func(t *rapid.T) map[ValidatorID]uint { + return rapid.MapOf( + GetValidatorIDGen(), + rapid.Uint(), + ).Draw(t, "RepresentativePowers") + }) +} + +func GetValPowersGen() *rapid.Generator[map[ValidatorID]uint] { + return rapid.Custom(func(t *rapid.T) map[ValidatorID]uint { + return rapid.MapOf( + GetValidatorIDGen(), + rapid.Uint(), + ).Draw(t, "ValPowers") + }) +} + +func GetValBalancesGen() *rapid.Generator[map[ValidatorID]uint] { + return rapid.Custom(func(t *rapid.T) map[ValidatorID]uint { + return rapid.MapOf( + GetValidatorIDGen(), + rapid.Uint(), + ).Draw(t, "ValBalances") + }) +} + +func GetValidatorIDGen() *rapid.Generator[ValidatorID] { + return rapid.Custom(func(t *rapid.T) ValidatorID { + return ValidatorID(rapid.String().Draw(t, "ValidatorID")) + }) +} + +func GetProposalsGen() *rapid.Generator[map[uint]Proposal] { + return rapid.Custom(func(t *rapid.T) map[uint]Proposal { + return rapid.MapOf( + rapid.Uint(), + GetProposalGen(), + ).Draw(t, "Proposals") + }) +} + +func GetProposalGen() *rapid.Generator[Proposal] { + return rapid.Custom(func(t *rapid.T) Proposal { + gen := rapid.OneOf( + GetConsumerAdditionProposalGen().AsAny(), + GetConsumerRemovalProposalGen().AsAny(), + GetEquivocationProposalGen().AsAny(), + GetTextProposalGen().AsAny(), + GetParamsProposalGen().AsAny(), + ) + return gen.Draw(t, "Proposal").(Proposal) + }) +} + +func GetConsumerAdditionProposalGen() *rapid.Generator[ConsumerAdditionProposal] { + return rapid.Custom(func(t *rapid.T) ConsumerAdditionProposal { + return ConsumerAdditionProposal{ + Deposit: rapid.Uint().Draw(t, "Deposit"), + Chain: GetChainIDGen().Draw(t, "Chain"), + SpawnTime: rapid.Int().Draw(t, "SpawnTime"), + InitialHeight: GetHeightGen().Draw(t, "InitialHeight"), + Status: rapid.String().Draw(t, "Status"), + } + }) +} + +func GetConsumerRemovalProposalGen() *rapid.Generator[ConsumerRemovalProposal] { + return rapid.Custom(func(t *rapid.T) ConsumerRemovalProposal { + return ConsumerRemovalProposal{ + Deposit: rapid.Uint().Draw(t, "Deposit"), + Chain: GetChainIDGen().Draw(t, "Chain"), + StopTime: rapid.Int().Draw(t, "StopTime"), + Status: rapid.String().Draw(t, "Status"), + } + }) +} + +func GetEquivocationProposalGen() *rapid.Generator[EquivocationProposal] { + return rapid.Custom(func(t *rapid.T) EquivocationProposal { + return EquivocationProposal{ + Power: rapid.Uint().Draw(t, "Power"), + Height: rapid.Uint().Draw(t, "Height"), + ConsensusAddress: rapid.String().Draw(t, "ConesnsuAddress"), + Deposit: rapid.Uint().Draw(t, "Deposit"), + Status: rapid.String().Draw(t, "Status"), + } + }) +} + +func GetTextProposalGen() *rapid.Generator[TextProposal] { + return rapid.Custom(func(t *rapid.T) TextProposal { + return TextProposal{ + Title: rapid.String().Draw(t, "Title"), + Description: rapid.String().Draw(t, "Description"), + Deposit: rapid.Uint().Draw(t, "Deposit"), + Status: rapid.String().Draw(t, "Status"), + } + }) +} + +func GetParamsProposalGen() *rapid.Generator[ParamsProposal] { + return rapid.Custom(func(t *rapid.T) ParamsProposal { + return ParamsProposal{ + Subspace: rapid.String().Draw(t, "Subspace"), + Key: rapid.String().Draw(t, "Key"), + Value: rapid.String().Draw(t, "Value"), + Deposit: rapid.Uint().Draw(t, "Deposit"), + Status: rapid.String().Draw(t, "Status"), + } + }) +} + +func GetHeightGen() *rapid.Generator[clienttypes.Height] { + return rapid.Custom(func(t *rapid.T) clienttypes.Height { + return clienttypes.Height{ + RevisionNumber: rapid.Uint64().Draw(t, "RevisionNumber"), + RevisionHeight: rapid.Uint64().Draw(t, "RevisionHeight"), + } + }) +} diff --git a/tests/e2e/step_rapid_test.go b/tests/e2e/step_rapid_test.go new file mode 100644 index 0000000000..dde5f2f465 --- /dev/null +++ b/tests/e2e/step_rapid_test.go @@ -0,0 +1,51 @@ +package main + +import ( + "log" + "os" + "path/filepath" + "testing" + + "pgregory.net/rapid" +) + +// TestReadAndWriteTrace uses rapid to do property based testing +// of reading and writing traces. +// It generates a random trace, writes it to a file, then reads it back. +// It then compares the original trace to the read trace. +// If the traces are not equal, rapid will generate a minimal example +// that causes the test to fail. +func TestReadAndWriteTrace(t *testing.T) { + parser := JSONParser{} + writer := JSONWriter{} + + dir, err := os.MkdirTemp("", "example") + if err != nil { + log.Fatal(err) + } + defer os.RemoveAll(dir) // clean up + + rapid.Check(t, func(t *rapid.T) { + trace := GetTraceGen().Draw(t, "Trace") + filename := filepath.Join(dir, "trace.json") + err := WriteAndReadTrace(parser, writer, trace, filename) + if err != nil { + t.Fatalf("error writing and reading trace: %v", err) + } + }) +} + +// This can be used to test writing and parsing traces, but does not make much sense +// for testing trace execution, since the generated traces are almost guaranteed to be nonsensical. +func GetTraceGen() *rapid.Generator[[]Step] { + return rapid.SliceOf(GetStepGen()) +} + +func GetStepGen() *rapid.Generator[Step] { + return rapid.Custom(func(t *rapid.T) Step { + return Step{ + Action: GetActionGen().Draw(t, "Action"), + State: GetStateGen().Draw(t, "State"), + } + }) +} diff --git a/tests/e2e/steps_downtime.go b/tests/e2e/steps_downtime.go index 08054f9089..7b4152023b 100644 --- a/tests/e2e/steps_downtime.go +++ b/tests/e2e/steps_downtime.go @@ -381,7 +381,7 @@ func stepsThrottledDowntime(consumerName string) []Step { }, }, { - Action: slashThrottleDequeue{ + Action: slashThrottleDequeueAction{ Chain: ChainID(consumerName), CurrentQueueSize: 1, NextQueueSize: 0, diff --git a/tests/e2e/trace_handlers_test.go b/tests/e2e/trace_handlers_test.go new file mode 100644 index 0000000000..725496c51f --- /dev/null +++ b/tests/e2e/trace_handlers_test.go @@ -0,0 +1,229 @@ +package main + +import ( + "encoding/json" + "fmt" + "log" + "os" + "path/filepath" + "testing" + + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + "github.com/google/go-cmp/cmp" +) + +// an isolated test case for a proposal submission +var proposalSubmissionSteps = []Step{ + {submitTextProposalAction{Title: "Proposal 1", Description: "Description 1"}, State{}}, +} + +// an isolated test case for a state check involving a proposal +var proposalInStateSteps = []Step{ + { + Action: submitConsumerRemovalProposalAction{}, + State: State{ + ChainID("provi"): ChainState{ + Proposals: &map[uint]Proposal{ + 1: ConsumerRemovalProposal{ + Deposit: 10000001, + Chain: ChainID("foo"), + StopTime: 0, + Status: "PROPOSAL_STATUS_VOTING_PERIOD", + }, + }, + }, + }, + }, +} + +// Checks that writing, then parsing a trace results in the same trace. +func TestWriterThenParser(t *testing.T) { + tests := map[string]struct { + trace []Step + }{ + "proposalSubmission": {proposalSubmissionSteps}, + "proposalInState": {proposalInStateSteps}, + "start_provider_chain": {stepStartProviderChain()}, + "happyPath": {happyPathSteps}, + "democracy": {democracySteps}, + "slashThrottle": {slashThrottleSteps}, + "multipleConsumers": {multipleConsumers}, + "shorthappy": {shortHappyPathSteps}, + "democracyRewardsSteps": {democracyRewardsSteps}, + "changeover": {changeoverSteps}, + } + + dir, err := os.MkdirTemp("", "example") + if err != nil { + log.Fatal(err) + } + defer os.RemoveAll(dir) // clean up + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + filename := filepath.Join(dir, "trace.json") + err := WriteAndReadTrace(GlobalJSONParser, GlobalJSONWriter, tc.trace, filename) + if err != nil { + log.Fatalf("got error for testcase %v: %s", name, err) + } + }) + } +} + +// Checks that writing a trace does not result in an error. +func TestWriteExamples(t *testing.T) { + tests := map[string]struct { + trace []Step + }{ + "happyPath": {happyPathSteps}, + "democracy": {democracySteps}, + "slashThrottle": {slashThrottleSteps}, + "multipleConsumers": {multipleConsumers}, + "shorthappy": {shortHappyPathSteps}, + "democracyRewardsSteps": {democracyRewardsSteps}, + "changeover": {changeoverSteps}, + } + + dir := "tracehandler_testdata" + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + filename := filepath.Join(dir, name+".json") + err := GlobalJSONWriter.WriteTraceToFile(filename, tc.trace) + if err != nil { + t.Fatalf("error writing trace to file: %v", err) + } + }) + } +} + +func TestMarshalAndUnmarshalChainState(t *testing.T) { + tests := map[string]struct { + chainState ChainState + }{ + "consumer addition proposal": {ChainState{ + ValBalances: &map[ValidatorID]uint{ + ValidatorID("alice"): 9489999999, + ValidatorID("bob"): 9500000000, + }, + Proposals: &map[uint]Proposal{ + 2: ConsumerAdditionProposal{ + Deposit: 10000001, + Chain: ChainID("test"), + SpawnTime: 0, + InitialHeight: clienttypes.Height{RevisionNumber: 5, RevisionHeight: 5}, + Status: "PROPOSAL_STATUS_VOTING_PERIOD", + }, + }, + }}, + "params-proposal": {ChainState{ + ValBalances: &map[ValidatorID]uint{ + ValidatorID("alice"): 9889999998, + ValidatorID("bob"): 9960000001, + }, + Proposals: &map[uint]Proposal{ + 1: ParamsProposal{ + Deposit: 10000001, + Status: "PROPOSAL_STATUS_VOTING_PERIOD", + Subspace: "staking", + Key: "MaxValidators", + Value: "105", + }, + }, + }}, + "consuemr removal proposal": {ChainState{ + Proposals: &map[uint]Proposal{ + 5: ConsumerRemovalProposal{ + Deposit: 10000001, + Chain: ChainID("test123"), + StopTime: 5000000000, + Status: "PROPOSAL_STATUS_PASSED", + }, + }, + ValBalances: &map[ValidatorID]uint{ + ValidatorID("bob"): 9500000000, + }, + ConsumerChains: &map[ChainID]bool{}, // Consumer chain is now removed + }}, + "text-proposal": {ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 495, + }, + ValBalances: &map[ValidatorID]uint{ + ValidatorID("bob"): 9500000000, + }, + Proposals: &map[uint]Proposal{ + // proposal does not exist + 10: TextProposal{}, + }, + }}, + "equivocation-proposal": {ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 509, + ValidatorID("bob"): 500, + ValidatorID("carol"): 0, + }, + ValBalances: &map[ValidatorID]uint{ + ValidatorID("bob"): 9489999999, + }, + Proposals: &map[uint]Proposal{ + 5: EquivocationProposal{ + Deposit: 10000001, + Status: "PROPOSAL_STATUS_VOTING_PERIOD", + ConsensusAddress: "cosmosvalcons1nx7n5uh0ztxsynn4sje6eyq2ud6rc6klc96w39", + Power: 500, + Height: 10, + }, + }, + }}, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + err := MarshalAndUnmarshalChainState(tc.chainState) + if err != nil { + t.Fatalf(err.Error()) + } + }) + } +} + +func MarshalAndUnmarshalChainState(chainState ChainState) error { + jsonobj, err := json.Marshal(chainState) + if err != nil { + return fmt.Errorf("error marshalling chain state: %v", err) + } + + var got *ChainState + err = json.Unmarshal(jsonobj, &got) + if err != nil { + return fmt.Errorf("error unmarshalling chain state: %v", err) + } + + diff := cmp.Diff(chainState, *got) + if diff != "" { + log.Print(string(jsonobj)) + return fmt.Errorf(diff) + } + + return nil +} + +func WriteAndReadTrace(parser TraceParser, writer TraceWriter, trace []Step, tmp_filepath string) error { + err := writer.WriteTraceToFile(tmp_filepath, trace) + if err != nil { + return fmt.Errorf("error writing trace to file: %v", err) + } + + got, err := GlobalJSONParser.ReadTraceFromFile(tmp_filepath) + if err != nil { + return fmt.Errorf("got error reading trace from file: %v", err) + } + diff := cmp.Diff(trace, got, cmp.AllowUnexported(Step{})) + if diff != "" { + return fmt.Errorf("Got a difference (-want +got):\n%s", diff) + } + return nil +} diff --git a/tests/e2e/tracehandler_testdata/changeover.json b/tests/e2e/tracehandler_testdata/changeover.json new file mode 100644 index 0000000000..42613462f8 --- /dev/null +++ b/tests/e2e/tracehandler_testdata/changeover.json @@ -0,0 +1,603 @@ +[ + { + "ActionType": "main.StartSovereignChainAction", + "Action": { + "Chain": "sover", + "Validators": [ + { + "Id": "alice", + "Allocation": 10000000000, + "Stake": 500000000 + } + ], + "GenesisChanges": "" + }, + "State": { + "sover": { + "ValBalances": { + "alice": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.delegateTokensAction", + "Action": { + "Chain": "sover", + "From": "alice", + "To": "alice", + "Amount": 11000000 + }, + "State": { + "sover": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 0, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.StartChainAction", + "Action": { + "Chain": "provi", + "Validators": [ + { + "Id": "bob", + "Allocation": 10000000000, + "Stake": 500000000 + }, + { + "Id": "alice", + "Allocation": 10000000000, + "Stake": 500000000 + }, + { + "Id": "carol", + "Allocation": 10000000000, + "Stake": 500000000 + } + ], + "GenesisChanges": "", + "SkipGentx": false + }, + "State": { + "provi": { + "ValBalances": { + "alice": 9500000000, + "bob": 9500000000, + "carol": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.createIbcClientsAction", + "Action": { + "ChainA": "sover", + "ChainB": "provi" + }, + "State": {} + }, + { + "ActionType": "main.addIbcChannelAction", + "Action": { + "ChainA": "sover", + "ChainB": "provi", + "ConnectionA": 0, + "PortA": "transfer", + "PortB": "transfer", + "Order": "unordered", + "Version": "ics20-1" + }, + "State": {} + }, + { + "ActionType": "main.LegacyUpgradeProposalAction", + "Action": { + "ChainID": "sover", + "UpgradeTitle": "sovereign-changeover", + "Proposer": "alice", + "UpgradeHeight": 110 + }, + "State": { + "sover": { + "ValBalances": null, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "1": { + "RawProposal": { + "Title": "sovereign-changeover", + "Description": "", + "UpgradeHeight": 110, + "Type": "/cosmos.upgrade.v1beta1.SoftwareUpgradeProposal", + "Deposit": 10000000, + "Status": "PROPOSAL_STATUS_VOTING_PERIOD" + }, + "Type": "main.UpgradeProposal" + } + } + } + } + }, + { + "ActionType": "main.voteGovProposalAction", + "Action": { + "Chain": "sover", + "From": [ + "alice" + ], + "Vote": [ + "yes" + ], + "PropNumber": 1 + }, + "State": { + "sover": { + "ValBalances": null, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "1": { + "RawProposal": { + "Title": "sovereign-changeover", + "Description": "", + "UpgradeHeight": 110, + "Type": "/cosmos.upgrade.v1beta1.SoftwareUpgradeProposal", + "Deposit": 10000000, + "Status": "PROPOSAL_STATUS_PASSED" + }, + "Type": "main.UpgradeProposal" + } + } + } + } + }, + { + "ActionType": "main.waitUntilBlockAction", + "Action": { + "Block": 110, + "Chain": "sover" + }, + "State": {} + }, + { + "ActionType": "main.submitConsumerAdditionProposalAction", + "Action": { + "PreCCV": true, + "Chain": "provi", + "From": "alice", + "Deposit": 10000001, + "ConsumerChain": "sover", + "SpawnTime": 0, + "InitialHeight": { + "revision_height": 111 + }, + "DistributionChannel": "channel-0" + }, + "State": { + "provi": { + "ValBalances": { + "alice": 9489999999, + "bob": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "1": { + "RawProposal": { + "Deposit": 10000001, + "Chain": "sover", + "SpawnTime": 0, + "InitialHeight": { + "revision_height": 111 + }, + "Status": "PROPOSAL_STATUS_VOTING_PERIOD" + }, + "Type": "main.ConsumerAdditionProposal" + } + } + } + } + }, + { + "ActionType": "main.voteGovProposalAction", + "Action": { + "Chain": "provi", + "From": [ + "alice", + "bob", + "carol" + ], + "Vote": [ + "yes", + "yes", + "yes" + ], + "PropNumber": 1 + }, + "State": { + "provi": { + "ValBalances": { + "alice": 9500000000, + "bob": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "1": { + "RawProposal": { + "Deposit": 10000001, + "Chain": "sover", + "SpawnTime": 0, + "InitialHeight": { + "revision_height": 111 + }, + "Status": "PROPOSAL_STATUS_PASSED" + }, + "Type": "main.ConsumerAdditionProposal" + } + } + } + } + }, + { + "ActionType": "main.ChangeoverChainAction", + "Action": { + "SovereignChain": "sover", + "ProviderChain": "provi", + "Validators": [ + { + "Id": "alice", + "Allocation": 10000000000, + "Stake": 500000000 + }, + { + "Id": "bob", + "Allocation": 10000000000, + "Stake": 500000000 + }, + { + "Id": "carol", + "Allocation": 10000000000, + "Stake": 500000000 + } + ], + "GenesisChanges": ".app_state.ccvconsumer.params.soft_opt_out_threshold = \"0.05\"" + }, + "State": { + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 500, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "sover": { + "ValBalances": null, + "ValPowers": { + "alice": 500, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.addIbcConnectionAction", + "Action": { + "ChainA": "sover", + "ChainB": "provi", + "ClientA": 1, + "ClientB": 1 + }, + "State": {} + }, + { + "ActionType": "main.addIbcChannelAction", + "Action": { + "ChainA": "sover", + "ChainB": "provi", + "ConnectionA": 1, + "PortA": "consumer", + "PortB": "provider", + "Order": "ordered", + "Version": "" + }, + "State": {} + }, + { + "ActionType": "main.SendTokensAction", + "Action": { + "Chain": "sover", + "From": "alice", + "To": "bob", + "Amount": 100 + }, + "State": { + "sover": { + "ValBalances": { + "bob": 0 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.delegateTokensAction", + "Action": { + "Chain": "provi", + "From": "alice", + "To": "alice", + "Amount": 11000000 + }, + "State": { + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "sover": { + "ValBalances": null, + "ValPowers": { + "alice": 500, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "sover", + "Port": "provider", + "Channel": 1 + }, + "State": { + "sover": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.SendTokensAction", + "Action": { + "Chain": "sover", + "From": "alice", + "To": "bob", + "Amount": 100 + }, + "State": { + "sover": { + "ValBalances": { + "bob": 100 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.unbondTokensAction", + "Action": { + "Chain": "provi", + "Sender": "alice", + "UnbondFrom": "alice", + "Amount": 1000000 + }, + "State": { + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 510, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "sover": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "sover", + "Port": "provider", + "Channel": 1 + }, + "State": { + "sover": { + "ValBalances": null, + "ValPowers": { + "alice": 510, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + } +] \ No newline at end of file diff --git a/tests/e2e/tracehandler_testdata/democracy.json b/tests/e2e/tracehandler_testdata/democracy.json new file mode 100644 index 0000000000..706eb944f5 --- /dev/null +++ b/tests/e2e/tracehandler_testdata/democracy.json @@ -0,0 +1,935 @@ +[ + { + "ActionType": "main.StartChainAction", + "Action": { + "Chain": "provi", + "Validators": [ + { + "Id": "bob", + "Allocation": 10000000000, + "Stake": 500000000 + }, + { + "Id": "alice", + "Allocation": 10000000000, + "Stake": 500000000 + }, + { + "Id": "carol", + "Allocation": 10000000000, + "Stake": 500000000 + } + ], + "GenesisChanges": "", + "SkipGentx": false + }, + "State": { + "provi": { + "ValBalances": { + "alice": 9500000000, + "bob": 9500000000, + "carol": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.submitConsumerAdditionProposalAction", + "Action": { + "PreCCV": false, + "Chain": "provi", + "From": "alice", + "Deposit": 10000001, + "ConsumerChain": "democ", + "SpawnTime": 0, + "InitialHeight": { + "revision_height": 1 + }, + "DistributionChannel": "" + }, + "State": { + "provi": { + "ValBalances": { + "alice": 9489999999, + "bob": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "1": { + "RawProposal": { + "Deposit": 10000001, + "Chain": "democ", + "SpawnTime": 0, + "InitialHeight": { + "revision_height": 1 + }, + "Status": "PROPOSAL_STATUS_VOTING_PERIOD" + }, + "Type": "main.ConsumerAdditionProposal" + } + } + } + } + }, + { + "ActionType": "main.assignConsumerPubKeyAction", + "Action": { + "Chain": "democ", + "Validator": "carol", + "ConsumerPubkey": "{\"@type\":\"/cosmos.crypto.ed25519.PubKey\",\"key\":\"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is=\"}", + "ReconfigureNode": false, + "ExpectError": false, + "ExpectedError": "" + }, + "State": { + "democ": { + "ValBalances": null, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": { + "carol": "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk" + }, + "ProviderKeys": { + "carol": "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6" + }, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.assignConsumerPubKeyAction", + "Action": { + "Chain": "democ", + "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" + }, + "State": {} + }, + { + "ActionType": "main.assignConsumerPubKeyAction", + "Action": { + "Chain": "democ", + "Validator": "bob", + "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" + }, + "State": { + "democ": { + "ValBalances": null, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": { + "bob": "", + "carol": "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk" + }, + "ProviderKeys": { + "carol": "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6" + }, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.voteGovProposalAction", + "Action": { + "Chain": "provi", + "From": [ + "alice", + "bob", + "carol" + ], + "Vote": [ + "yes", + "yes", + "yes" + ], + "PropNumber": 1 + }, + "State": { + "provi": { + "ValBalances": { + "alice": 9500000000, + "bob": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "1": { + "RawProposal": { + "Deposit": 10000001, + "Chain": "democ", + "SpawnTime": 0, + "InitialHeight": { + "revision_height": 1 + }, + "Status": "PROPOSAL_STATUS_PASSED" + }, + "Type": "main.ConsumerAdditionProposal" + } + } + } + } + }, + { + "ActionType": "main.startConsumerChainAction", + "Action": { + "ConsumerChain": "democ", + "ProviderChain": "provi", + "Validators": [ + { + "Id": "bob", + "Allocation": 10000000000, + "Stake": 500000000 + }, + { + "Id": "alice", + "Allocation": 10000000000, + "Stake": 500000000 + }, + { + "Id": "carol", + "Allocation": 10000000000, + "Stake": 500000000 + } + ], + "GenesisChanges": ".app_state.ccvconsumer.params.soft_opt_out_threshold = \"0.05\"" + }, + "State": { + "democ": { + "ValBalances": { + "alice": 10000000000, + "bob": 10000000000, + "carol": 10000000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": { + "alice": 9500000000, + "bob": 9500000000, + "carol": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.addIbcConnectionAction", + "Action": { + "ChainA": "democ", + "ChainB": "provi", + "ClientA": 0, + "ClientB": 0 + }, + "State": {} + }, + { + "ActionType": "main.addIbcChannelAction", + "Action": { + "ChainA": "democ", + "ChainB": "provi", + "ConnectionA": 0, + "PortA": "consumer", + "PortB": "provider", + "Order": "ordered", + "Version": "" + }, + "State": {} + }, + { + "ActionType": "main.transferChannelCompleteAction", + "Action": { + "ChainA": "democ", + "ChainB": "provi", + "ConnectionA": 0, + "PortA": "transfer", + "PortB": "transfer", + "Order": "unordered", + "ChannelA": 1, + "ChannelB": 1 + }, + "State": {} + }, + { + "ActionType": "main.delegateTokensAction", + "Action": { + "Chain": "provi", + "From": "alice", + "To": "alice", + "Amount": 11000000 + }, + "State": { + "democ": { + "ValBalances": null, + "ValPowers": { + "alice": 500, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.SendTokensAction", + "Action": { + "Chain": "democ", + "From": "alice", + "To": "bob", + "Amount": 1 + }, + "State": { + "democ": { + "ValBalances": { + "alice": 10000000000, + "bob": 10000000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "democ", + "Port": "provider", + "Channel": 0 + }, + "State": { + "democ": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.SendTokensAction", + "Action": { + "Chain": "democ", + "From": "alice", + "To": "bob", + "Amount": 1 + }, + "State": { + "democ": { + "ValBalances": { + "alice": 9999999999, + "bob": 10000000001 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.registerRepresentativeAction", + "Action": { + "Chain": "democ", + "Representatives": [ + "alice", + "bob" + ], + "Stakes": [ + 100000000, + 40000000 + ] + }, + "State": { + "democ": { + "ValBalances": null, + "ValPowers": null, + "RepresentativePowers": { + "alice": 100000000, + "bob": 40000000 + }, + "Params": null, + "Rewards": { + "IsRewarded": { + "alice": true, + "bob": true, + "carol": false + }, + "IsIncrementalReward": true, + "IsNativeDenom": true + }, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.delegateTokensAction", + "Action": { + "Chain": "democ", + "From": "carol", + "To": "alice", + "Amount": 500000 + }, + "State": { + "democ": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": { + "alice": 100500000, + "bob": 40000000 + }, + "Params": null, + "Rewards": { + "IsRewarded": { + "alice": true, + "bob": true, + "carol": true + }, + "IsIncrementalReward": true, + "IsNativeDenom": true + }, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.submitParamChangeLegacyProposalAction", + "Action": { + "Chain": "democ", + "From": "alice", + "Deposit": 10000001, + "Subspace": "transfer", + "Key": "SendEnabled", + "Value": true + }, + "State": { + "democ": { + "ValBalances": { + "alice": 9889999998, + "bob": 9960000001 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "1": { + "RawProposal": { + "Deposit": 10000001, + "Status": "PROPOSAL_STATUS_VOTING_PERIOD", + "Subspace": "transfer", + "Key": "SendEnabled", + "Value": "true" + }, + "Type": "main.ParamsProposal" + } + } + } + } + }, + { + "ActionType": "main.voteGovProposalAction", + "Action": { + "Chain": "democ", + "From": [ + "alice", + "bob" + ], + "Vote": [ + "yes", + "no" + ], + "PropNumber": 1 + }, + "State": { + "democ": { + "ValBalances": { + "alice": 9889999998, + "bob": 9960000001 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": [ + { + "Subspace": "transfer", + "Key": "SendEnabled", + "Value": "true" + } + ], + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayRewardPacketsToProviderAction", + "Action": { + "ConsumerChain": "democ", + "ProviderChain": "provi", + "Port": "transfer", + "Channel": 1 + }, + "State": { + "provi": { + "ValBalances": null, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": { + "IsRewarded": { + "alice": false, + "bob": false, + "carol": false + }, + "IsIncrementalReward": false, + "IsNativeDenom": false + }, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": [], + "Proposals": null + } + } + }, + { + "ActionType": "main.submitChangeRewardDenomsProposalAction", + "Action": { + "Denom": "ibc/3C3D7B3BE4ECC85A0E5B52A3AEC3B7DFC2AA9CA47C37821E57020D6807043BE9", + "Deposit": 10000001, + "From": "bob" + }, + "State": { + "provi": { + "ValBalances": null, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": [], + "Proposals": null + } + } + }, + { + "ActionType": "main.voteGovProposalAction", + "Action": { + "Chain": "provi", + "From": [ + "alice", + "bob", + "carol" + ], + "Vote": [ + "yes", + "yes", + "yes" + ], + "PropNumber": 2 + }, + "State": { + "provi": { + "ValBalances": null, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": [ + "ibc/3C3D7B3BE4ECC85A0E5B52A3AEC3B7DFC2AA9CA47C37821E57020D6807043BE9" + ], + "Proposals": null + } + } + }, + { + "ActionType": "main.relayRewardPacketsToProviderAction", + "Action": { + "ConsumerChain": "democ", + "ProviderChain": "provi", + "Port": "transfer", + "Channel": 1 + }, + "State": { + "provi": { + "ValBalances": null, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": { + "IsRewarded": { + "alice": false, + "bob": false, + "carol": false + }, + "IsIncrementalReward": false, + "IsNativeDenom": false + }, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.downtimeSlashAction", + "Action": { + "Chain": "democ", + "Validator": "bob" + }, + "State": { + "democ": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "democ", + "Port": "provider", + "Channel": 0 + }, + "State": { + "democ": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 0, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "democ", + "Port": "provider", + "Channel": 0 + }, + "State": { + "democ": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 0, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.unjailValidatorAction", + "Action": { + "Provider": "provi", + "Validator": "bob" + }, + "State": { + "democ": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 0, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "democ", + "Port": "provider", + "Channel": 0 + }, + "State": { + "democ": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": { + "alice": 100500000, + "bob": 40000000 + }, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + } +] \ No newline at end of file diff --git a/tests/e2e/tracehandler_testdata/democracyRewardsSteps.json b/tests/e2e/tracehandler_testdata/democracyRewardsSteps.json new file mode 100644 index 0000000000..cea7f937be --- /dev/null +++ b/tests/e2e/tracehandler_testdata/democracyRewardsSteps.json @@ -0,0 +1,935 @@ +[ + { + "ActionType": "main.StartChainAction", + "Action": { + "Chain": "provi", + "Validators": [ + { + "Id": "bob", + "Allocation": 10000000000, + "Stake": 500000000 + }, + { + "Id": "alice", + "Allocation": 10000000000, + "Stake": 500000000 + }, + { + "Id": "carol", + "Allocation": 10000000000, + "Stake": 500000000 + } + ], + "GenesisChanges": "", + "SkipGentx": false + }, + "State": { + "provi": { + "ValBalances": { + "alice": 9500000000, + "bob": 9500000000, + "carol": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.submitConsumerAdditionProposalAction", + "Action": { + "PreCCV": false, + "Chain": "provi", + "From": "alice", + "Deposit": 10000001, + "ConsumerChain": "democ", + "SpawnTime": 0, + "InitialHeight": { + "revision_height": 1 + }, + "DistributionChannel": "" + }, + "State": { + "provi": { + "ValBalances": { + "alice": 9489999999, + "bob": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "1": { + "RawProposal": { + "Deposit": 10000001, + "Chain": "democ", + "SpawnTime": 0, + "InitialHeight": { + "revision_height": 1 + }, + "Status": "PROPOSAL_STATUS_VOTING_PERIOD" + }, + "Type": "main.ConsumerAdditionProposal" + } + } + } + } + }, + { + "ActionType": "main.assignConsumerPubKeyAction", + "Action": { + "Chain": "democ", + "Validator": "carol", + "ConsumerPubkey": "{\"@type\":\"/cosmos.crypto.ed25519.PubKey\",\"key\":\"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is=\"}", + "ReconfigureNode": false, + "ExpectError": false, + "ExpectedError": "" + }, + "State": { + "democ": { + "ValBalances": null, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": { + "carol": "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk" + }, + "ProviderKeys": { + "carol": "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6" + }, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.assignConsumerPubKeyAction", + "Action": { + "Chain": "democ", + "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" + }, + "State": {} + }, + { + "ActionType": "main.assignConsumerPubKeyAction", + "Action": { + "Chain": "democ", + "Validator": "bob", + "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" + }, + "State": { + "democ": { + "ValBalances": null, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": { + "bob": "", + "carol": "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk" + }, + "ProviderKeys": { + "carol": "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6" + }, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.voteGovProposalAction", + "Action": { + "Chain": "provi", + "From": [ + "alice", + "bob", + "carol" + ], + "Vote": [ + "yes", + "yes", + "yes" + ], + "PropNumber": 1 + }, + "State": { + "provi": { + "ValBalances": { + "alice": 9500000000, + "bob": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "1": { + "RawProposal": { + "Deposit": 10000001, + "Chain": "democ", + "SpawnTime": 0, + "InitialHeight": { + "revision_height": 1 + }, + "Status": "PROPOSAL_STATUS_PASSED" + }, + "Type": "main.ConsumerAdditionProposal" + } + } + } + } + }, + { + "ActionType": "main.startConsumerChainAction", + "Action": { + "ConsumerChain": "democ", + "ProviderChain": "provi", + "Validators": [ + { + "Id": "bob", + "Allocation": 10000000000, + "Stake": 500000000 + }, + { + "Id": "alice", + "Allocation": 10000000000, + "Stake": 500000000 + }, + { + "Id": "carol", + "Allocation": 10000000000, + "Stake": 500000000 + } + ], + "GenesisChanges": ".app_state.ccvconsumer.params.soft_opt_out_threshold = \"0.05\"" + }, + "State": { + "democ": { + "ValBalances": { + "alice": 10000000000, + "bob": 10000000000, + "carol": 10000000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": { + "alice": 9500000000, + "bob": 9500000000, + "carol": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.addIbcConnectionAction", + "Action": { + "ChainA": "democ", + "ChainB": "provi", + "ClientA": 0, + "ClientB": 0 + }, + "State": {} + }, + { + "ActionType": "main.addIbcChannelAction", + "Action": { + "ChainA": "democ", + "ChainB": "provi", + "ConnectionA": 0, + "PortA": "consumer", + "PortB": "provider", + "Order": "ordered", + "Version": "" + }, + "State": {} + }, + { + "ActionType": "main.transferChannelCompleteAction", + "Action": { + "ChainA": "democ", + "ChainB": "provi", + "ConnectionA": 0, + "PortA": "transfer", + "PortB": "transfer", + "Order": "unordered", + "ChannelA": 1, + "ChannelB": 1 + }, + "State": {} + }, + { + "ActionType": "main.delegateTokensAction", + "Action": { + "Chain": "provi", + "From": "alice", + "To": "alice", + "Amount": 11000000 + }, + "State": { + "democ": { + "ValBalances": null, + "ValPowers": { + "alice": 500, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.SendTokensAction", + "Action": { + "Chain": "democ", + "From": "alice", + "To": "bob", + "Amount": 1 + }, + "State": { + "democ": { + "ValBalances": { + "alice": 10000000000, + "bob": 10000000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "democ", + "Port": "provider", + "Channel": 0 + }, + "State": { + "democ": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.SendTokensAction", + "Action": { + "Chain": "democ", + "From": "alice", + "To": "bob", + "Amount": 1 + }, + "State": { + "democ": { + "ValBalances": { + "alice": 9999999999, + "bob": 10000000001 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.registerRepresentativeAction", + "Action": { + "Chain": "democ", + "Representatives": [ + "alice", + "bob" + ], + "Stakes": [ + 100000000, + 40000000 + ] + }, + "State": { + "democ": { + "ValBalances": null, + "ValPowers": null, + "RepresentativePowers": { + "alice": 100000000, + "bob": 40000000 + }, + "Params": null, + "Rewards": { + "IsRewarded": { + "alice": true, + "bob": true, + "carol": false + }, + "IsIncrementalReward": true, + "IsNativeDenom": true + }, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.delegateTokensAction", + "Action": { + "Chain": "democ", + "From": "carol", + "To": "alice", + "Amount": 500000 + }, + "State": { + "democ": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": { + "alice": 100500000, + "bob": 40000000 + }, + "Params": null, + "Rewards": { + "IsRewarded": { + "alice": true, + "bob": true, + "carol": true + }, + "IsIncrementalReward": true, + "IsNativeDenom": true + }, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.submitParamChangeLegacyProposalAction", + "Action": { + "Chain": "democ", + "From": "alice", + "Deposit": 10000001, + "Subspace": "transfer", + "Key": "SendEnabled", + "Value": true + }, + "State": { + "democ": { + "ValBalances": { + "alice": 9889999998, + "bob": 9960000001 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "1": { + "RawProposal": { + "Deposit": 10000001, + "Status": "PROPOSAL_STATUS_VOTING_PERIOD", + "Subspace": "transfer", + "Key": "SendEnabled", + "Value": "true" + }, + "Type": "main.ParamsProposal" + } + } + } + } + }, + { + "ActionType": "main.voteGovProposalAction", + "Action": { + "Chain": "democ", + "From": [ + "alice", + "bob" + ], + "Vote": [ + "yes", + "no" + ], + "PropNumber": 1 + }, + "State": { + "democ": { + "ValBalances": { + "alice": 9889999998, + "bob": 9960000001 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": [ + { + "Subspace": "transfer", + "Key": "SendEnabled", + "Value": "true" + } + ], + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayRewardPacketsToProviderAction", + "Action": { + "ConsumerChain": "democ", + "ProviderChain": "provi", + "Port": "transfer", + "Channel": 1 + }, + "State": { + "provi": { + "ValBalances": null, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": { + "IsRewarded": { + "alice": false, + "bob": false, + "carol": false + }, + "IsIncrementalReward": false, + "IsNativeDenom": false + }, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": [], + "Proposals": null + } + } + }, + { + "ActionType": "main.submitChangeRewardDenomsProposalAction", + "Action": { + "Denom": "ibc/3C3D7B3BE4ECC85A0E5B52A3AEC3B7DFC2AA9CA47C37821E57020D6807043BE9", + "Deposit": 10000001, + "From": "bob" + }, + "State": { + "provi": { + "ValBalances": null, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": [], + "Proposals": null + } + } + }, + { + "ActionType": "main.voteGovProposalAction", + "Action": { + "Chain": "provi", + "From": [ + "alice", + "bob", + "carol" + ], + "Vote": [ + "yes", + "yes", + "yes" + ], + "PropNumber": 2 + }, + "State": { + "provi": { + "ValBalances": null, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": [ + "ibc/3C3D7B3BE4ECC85A0E5B52A3AEC3B7DFC2AA9CA47C37821E57020D6807043BE9" + ], + "Proposals": null + } + } + }, + { + "ActionType": "main.relayRewardPacketsToProviderAction", + "Action": { + "ConsumerChain": "democ", + "ProviderChain": "provi", + "Port": "transfer", + "Channel": 1 + }, + "State": { + "provi": { + "ValBalances": null, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": { + "IsRewarded": { + "alice": true, + "bob": true, + "carol": true + }, + "IsIncrementalReward": false, + "IsNativeDenom": false + }, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.downtimeSlashAction", + "Action": { + "Chain": "democ", + "Validator": "bob" + }, + "State": { + "democ": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "democ", + "Port": "provider", + "Channel": 0 + }, + "State": { + "democ": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 0, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "democ", + "Port": "provider", + "Channel": 0 + }, + "State": { + "democ": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 0, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.unjailValidatorAction", + "Action": { + "Provider": "provi", + "Validator": "bob" + }, + "State": { + "democ": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 0, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "democ", + "Port": "provider", + "Channel": 0 + }, + "State": { + "democ": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": { + "alice": 100500000, + "bob": 40000000 + }, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + } +] \ No newline at end of file diff --git a/tests/e2e/tracehandler_testdata/happyPath.json b/tests/e2e/tracehandler_testdata/happyPath.json new file mode 100644 index 0000000000..2ed4363c96 --- /dev/null +++ b/tests/e2e/tracehandler_testdata/happyPath.json @@ -0,0 +1,2007 @@ +[ + { + "ActionType": "main.StartChainAction", + "Action": { + "Chain": "provi", + "Validators": [ + { + "Id": "bob", + "Allocation": 10000000000, + "Stake": 500000000 + }, + { + "Id": "alice", + "Allocation": 10000000000, + "Stake": 500000000 + }, + { + "Id": "carol", + "Allocation": 10000000000, + "Stake": 500000000 + } + ], + "GenesisChanges": "", + "SkipGentx": false + }, + "State": { + "provi": { + "ValBalances": { + "alice": 9500000000, + "bob": 9500000000, + "carol": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.submitConsumerAdditionProposalAction", + "Action": { + "PreCCV": false, + "Chain": "provi", + "From": "alice", + "Deposit": 10000001, + "ConsumerChain": "consu", + "SpawnTime": 0, + "InitialHeight": { + "revision_height": 1 + }, + "DistributionChannel": "" + }, + "State": { + "provi": { + "ValBalances": { + "alice": 9489999999, + "bob": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "1": { + "RawProposal": { + "Deposit": 10000001, + "Chain": "consu", + "SpawnTime": 0, + "InitialHeight": { + "revision_height": 1 + }, + "Status": "PROPOSAL_STATUS_VOTING_PERIOD" + }, + "Type": "main.ConsumerAdditionProposal" + } + } + } + } + }, + { + "ActionType": "main.assignConsumerPubKeyAction", + "Action": { + "Chain": "consu", + "Validator": "carol", + "ConsumerPubkey": "{\"@type\":\"/cosmos.crypto.ed25519.PubKey\",\"key\":\"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is=\"}", + "ReconfigureNode": false, + "ExpectError": false, + "ExpectedError": "" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": { + "carol": "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk" + }, + "ProviderKeys": { + "carol": "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6" + }, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.assignConsumerPubKeyAction", + "Action": { + "Chain": "consu", + "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" + }, + "State": {} + }, + { + "ActionType": "main.assignConsumerPubKeyAction", + "Action": { + "Chain": "consu", + "Validator": "bob", + "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" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": { + "bob": "", + "carol": "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk" + }, + "ProviderKeys": { + "carol": "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6" + }, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.voteGovProposalAction", + "Action": { + "Chain": "provi", + "From": [ + "alice", + "bob", + "carol" + ], + "Vote": [ + "yes", + "yes", + "yes" + ], + "PropNumber": 1 + }, + "State": { + "provi": { + "ValBalances": { + "alice": 9500000000, + "bob": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "1": { + "RawProposal": { + "Deposit": 10000001, + "Chain": "consu", + "SpawnTime": 0, + "InitialHeight": { + "revision_height": 1 + }, + "Status": "PROPOSAL_STATUS_PASSED" + }, + "Type": "main.ConsumerAdditionProposal" + } + } + } + } + }, + { + "ActionType": "main.startConsumerChainAction", + "Action": { + "ConsumerChain": "consu", + "ProviderChain": "provi", + "Validators": [ + { + "Id": "bob", + "Allocation": 10000000000, + "Stake": 500000000 + }, + { + "Id": "alice", + "Allocation": 10000000000, + "Stake": 500000000 + }, + { + "Id": "carol", + "Allocation": 10000000000, + "Stake": 500000000 + } + ], + "GenesisChanges": ".app_state.ccvconsumer.params.soft_opt_out_threshold = \"0.05\"" + }, + "State": { + "consu": { + "ValBalances": { + "alice": 10000000000, + "bob": 10000000000, + "carol": 10000000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": { + "alice": 9500000000, + "bob": 9500000000, + "carol": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.addIbcConnectionAction", + "Action": { + "ChainA": "consu", + "ChainB": "provi", + "ClientA": 0, + "ClientB": 0 + }, + "State": {} + }, + { + "ActionType": "main.addIbcChannelAction", + "Action": { + "ChainA": "consu", + "ChainB": "provi", + "ConnectionA": 0, + "PortA": "consumer", + "PortB": "provider", + "Order": "ordered", + "Version": "" + }, + "State": {} + }, + { + "ActionType": "main.delegateTokensAction", + "Action": { + "Chain": "provi", + "From": "alice", + "To": "alice", + "Amount": 11000000 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 500, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.SendTokensAction", + "Action": { + "Chain": "consu", + "From": "alice", + "To": "bob", + "Amount": 1 + }, + "State": { + "consu": { + "ValBalances": { + "alice": 10000000000, + "bob": 10000000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.SendTokensAction", + "Action": { + "Chain": "consu", + "From": "alice", + "To": "bob", + "Amount": 1 + }, + "State": { + "consu": { + "ValBalances": { + "alice": 9999999999, + "bob": 10000000001 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.assignConsumerPubKeyAction", + "Action": { + "Chain": "consu", + "Validator": "bob", + "ConsumerPubkey": "{\"@type\":\"/cosmos.crypto.ed25519.PubKey\",\"key\":\"QlG+iYe6AyYpvY1z9RNJKCVlH14Q/qSz4EjGdGCru3o=\"}", + "ReconfigureNode": true, + "ExpectError": false, + "ExpectedError": "" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": { + "bob": "cosmosvalcons1uuec3cjxajv5te08p220usrjhkfhg9wyvqn0tm", + "carol": "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk" + }, + "ProviderKeys": { + "bob": "cosmosvalcons1nx7n5uh0ztxsynn4sje6eyq2ud6rc6klc96w39", + "carol": "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6" + }, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": { + "bob": "cosmosvalcons1uuec3cjxajv5te08p220usrjhkfhg9wyvqn0tm", + "carol": "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk" + }, + "ProviderKeys": { + "bob": "cosmosvalcons1nx7n5uh0ztxsynn4sje6eyq2ud6rc6klc96w39", + "carol": "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6" + }, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.unbondTokensAction", + "Action": { + "Chain": "provi", + "Sender": "alice", + "UnbondFrom": "alice", + "Amount": 1000000 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 510, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 510, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.unbondTokensAction", + "Action": { + "Chain": "provi", + "Sender": "alice", + "UnbondFrom": "alice", + "Amount": 1000000 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 510, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.cancelUnbondTokensAction", + "Action": { + "Chain": "provi", + "Delegator": "alice", + "Validator": "alice", + "Amount": 1000000 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 510, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 510, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.redelegateTokensAction", + "Action": { + "Chain": "provi", + "Src": "alice", + "Dst": "carol", + "TxSender": "alice", + "Amount": 450000000 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 510, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 60, + "bob": 500, + "carol": 950 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 60, + "bob": 500, + "carol": 950 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.downtimeSlashAction", + "Action": { + "Chain": "consu", + "Validator": "alice" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 60, + "bob": 500, + "carol": 950 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 60, + "bob": 500, + "carol": 950 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 60, + "bob": 500, + "carol": 950 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 60, + "bob": 500, + "carol": 950 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.redelegateTokensAction", + "Action": { + "Chain": "provi", + "Src": "carol", + "Dst": "alice", + "TxSender": "carol", + "Amount": 449000000 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 60, + "bob": 500, + "carol": 950 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.downtimeSlashAction", + "Action": { + "Chain": "consu", + "Validator": "bob" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 0, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 0, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.unjailValidatorAction", + "Action": { + "Provider": "provi", + "Validator": "bob" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 0, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.downtimeSlashAction", + "Action": { + "Chain": "provi", + "Validator": "carol" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.unjailValidatorAction", + "Action": { + "Provider": "provi", + "Validator": "carol" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 495 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 495 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.submitEquivocationProposalAction", + "Action": { + "Chain": "consu", + "Height": 10, + "Time": "2023-09-20T18:24:51.823193+02:00", + "Power": 500, + "Validator": "bob", + "Deposit": 10000001, + "From": "bob" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 495 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": { + "bob": 9500000000 + }, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 495 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "2": { + "RawProposal": { + "Title": "", + "Description": "", + "Deposit": 0, + "Status": "" + }, + "Type": "main.TextProposal" + } + } + } + } + }, + { + "ActionType": "main.doublesignSlashAction", + "Action": { + "Validator": "carol", + "Chain": "provi" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 495 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.doublesignSlashAction", + "Action": { + "Validator": "bob", + "Chain": "consu" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.submitEquivocationProposalAction", + "Action": { + "Chain": "consu", + "Height": 10, + "Time": "2023-09-20T18:24:51.823197+02:00", + "Power": 500, + "Validator": "bob", + "Deposit": 10000001, + "From": "bob" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": { + "bob": 9489999999 + }, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "2": { + "RawProposal": { + "Height": 10, + "Power": 500, + "ConsensusAddress": "cosmosvalcons1nx7n5uh0ztxsynn4sje6eyq2ud6rc6klc96w39", + "Deposit": 10000001, + "Status": "PROPOSAL_STATUS_VOTING_PERIOD" + }, + "Type": "main.EquivocationProposal" + } + } + } + } + }, + { + "ActionType": "main.voteGovProposalAction", + "Action": { + "Chain": "provi", + "From": [ + "alice", + "bob", + "carol" + ], + "Vote": [ + "yes", + "yes", + "yes" + ], + "PropNumber": 2 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 0, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "2": { + "RawProposal": { + "Height": 10, + "Power": 500, + "ConsensusAddress": "cosmosvalcons1nx7n5uh0ztxsynn4sje6eyq2ud6rc6klc96w39", + "Deposit": 10000001, + "Status": "PROPOSAL_STATUS_PASSED" + }, + "Type": "main.EquivocationProposal" + } + } + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 0, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 0, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.startRelayerAction", + "Action": {}, + "State": {} + }, + { + "ActionType": "main.submitConsumerRemovalProposalAction", + "Action": { + "Chain": "provi", + "From": "bob", + "Deposit": 10000001, + "ConsumerChain": "consu", + "StopTimeOffset": 0 + }, + "State": { + "provi": { + "ValBalances": { + "bob": 9489999999 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": { + "consu": true + }, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "3": { + "RawProposal": { + "Deposit": 10000001, + "Chain": "consu", + "StopTime": 0, + "Status": "PROPOSAL_STATUS_VOTING_PERIOD" + }, + "Type": "main.ConsumerRemovalProposal" + } + } + } + } + }, + { + "ActionType": "main.voteGovProposalAction", + "Action": { + "Chain": "provi", + "From": [ + "alice", + "bob", + "carol" + ], + "Vote": [ + "no", + "no", + "no" + ], + "PropNumber": 3 + }, + "State": { + "provi": { + "ValBalances": { + "bob": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": { + "consu": true + }, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "3": { + "RawProposal": { + "Deposit": 10000001, + "Chain": "consu", + "StopTime": 0, + "Status": "PROPOSAL_STATUS_REJECTED" + }, + "Type": "main.ConsumerRemovalProposal" + } + } + } + } + }, + { + "ActionType": "main.submitConsumerRemovalProposalAction", + "Action": { + "Chain": "provi", + "From": "bob", + "Deposit": 10000001, + "ConsumerChain": "consu", + "StopTimeOffset": 0 + }, + "State": { + "provi": { + "ValBalances": { + "bob": 9489999999 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": { + "consu": true + }, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "4": { + "RawProposal": { + "Deposit": 10000001, + "Chain": "consu", + "StopTime": 0, + "Status": "PROPOSAL_STATUS_VOTING_PERIOD" + }, + "Type": "main.ConsumerRemovalProposal" + } + } + } + } + }, + { + "ActionType": "main.voteGovProposalAction", + "Action": { + "Chain": "provi", + "From": [ + "alice", + "bob", + "carol" + ], + "Vote": [ + "yes", + "yes", + "yes" + ], + "PropNumber": 4 + }, + "State": { + "provi": { + "ValBalances": { + "bob": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": {}, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "4": { + "RawProposal": { + "Deposit": 10000001, + "Chain": "consu", + "StopTime": 0, + "Status": "PROPOSAL_STATUS_PASSED" + }, + "Type": "main.ConsumerRemovalProposal" + } + } + } + } + } +] \ No newline at end of file diff --git a/tests/e2e/tracehandler_testdata/multipleConsumers.json b/tests/e2e/tracehandler_testdata/multipleConsumers.json new file mode 100644 index 0000000000..0630749179 --- /dev/null +++ b/tests/e2e/tracehandler_testdata/multipleConsumers.json @@ -0,0 +1,2381 @@ +[ + { + "ActionType": "main.StartChainAction", + "Action": { + "Chain": "provi", + "Validators": [ + { + "Id": "bob", + "Allocation": 10000000000, + "Stake": 500000000 + }, + { + "Id": "alice", + "Allocation": 10000000000, + "Stake": 500000000 + }, + { + "Id": "carol", + "Allocation": 10000000000, + "Stake": 500000000 + } + ], + "GenesisChanges": "", + "SkipGentx": false + }, + "State": { + "provi": { + "ValBalances": { + "alice": 9500000000, + "bob": 9500000000, + "carol": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.submitConsumerAdditionProposalAction", + "Action": { + "PreCCV": false, + "Chain": "provi", + "From": "alice", + "Deposit": 10000001, + "ConsumerChain": "consu", + "SpawnTime": 0, + "InitialHeight": { + "revision_height": 1 + }, + "DistributionChannel": "" + }, + "State": { + "provi": { + "ValBalances": { + "alice": 9489999999, + "bob": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "1": { + "RawProposal": { + "Deposit": 10000001, + "Chain": "consu", + "SpawnTime": 0, + "InitialHeight": { + "revision_height": 1 + }, + "Status": "PROPOSAL_STATUS_VOTING_PERIOD" + }, + "Type": "main.ConsumerAdditionProposal" + } + } + } + } + }, + { + "ActionType": "main.assignConsumerPubKeyAction", + "Action": { + "Chain": "consu", + "Validator": "carol", + "ConsumerPubkey": "{\"@type\":\"/cosmos.crypto.ed25519.PubKey\",\"key\":\"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is=\"}", + "ReconfigureNode": false, + "ExpectError": false, + "ExpectedError": "" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": { + "carol": "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk" + }, + "ProviderKeys": { + "carol": "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6" + }, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.assignConsumerPubKeyAction", + "Action": { + "Chain": "consu", + "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" + }, + "State": {} + }, + { + "ActionType": "main.assignConsumerPubKeyAction", + "Action": { + "Chain": "consu", + "Validator": "bob", + "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" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": { + "bob": "", + "carol": "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk" + }, + "ProviderKeys": { + "carol": "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6" + }, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.voteGovProposalAction", + "Action": { + "Chain": "provi", + "From": [ + "alice", + "bob", + "carol" + ], + "Vote": [ + "yes", + "yes", + "yes" + ], + "PropNumber": 1 + }, + "State": { + "provi": { + "ValBalances": { + "alice": 9500000000, + "bob": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "1": { + "RawProposal": { + "Deposit": 10000001, + "Chain": "consu", + "SpawnTime": 0, + "InitialHeight": { + "revision_height": 1 + }, + "Status": "PROPOSAL_STATUS_PASSED" + }, + "Type": "main.ConsumerAdditionProposal" + } + } + } + } + }, + { + "ActionType": "main.startConsumerChainAction", + "Action": { + "ConsumerChain": "consu", + "ProviderChain": "provi", + "Validators": [ + { + "Id": "bob", + "Allocation": 10000000000, + "Stake": 500000000 + }, + { + "Id": "alice", + "Allocation": 10000000000, + "Stake": 500000000 + }, + { + "Id": "carol", + "Allocation": 10000000000, + "Stake": 500000000 + } + ], + "GenesisChanges": ".app_state.ccvconsumer.params.soft_opt_out_threshold = \"0.05\"" + }, + "State": { + "consu": { + "ValBalances": { + "alice": 10000000000, + "bob": 10000000000, + "carol": 10000000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": { + "alice": 9500000000, + "bob": 9500000000, + "carol": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.addIbcConnectionAction", + "Action": { + "ChainA": "consu", + "ChainB": "provi", + "ClientA": 0, + "ClientB": 0 + }, + "State": {} + }, + { + "ActionType": "main.addIbcChannelAction", + "Action": { + "ChainA": "consu", + "ChainB": "provi", + "ConnectionA": 0, + "PortA": "consumer", + "PortB": "provider", + "Order": "ordered", + "Version": "" + }, + "State": {} + }, + { + "ActionType": "main.submitConsumerAdditionProposalAction", + "Action": { + "PreCCV": false, + "Chain": "provi", + "From": "alice", + "Deposit": 10000001, + "ConsumerChain": "densu", + "SpawnTime": 0, + "InitialHeight": { + "revision_height": 1 + }, + "DistributionChannel": "" + }, + "State": { + "provi": { + "ValBalances": { + "alice": 9489999999, + "bob": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "2": { + "RawProposal": { + "Deposit": 10000001, + "Chain": "densu", + "SpawnTime": 0, + "InitialHeight": { + "revision_height": 1 + }, + "Status": "PROPOSAL_STATUS_VOTING_PERIOD" + }, + "Type": "main.ConsumerAdditionProposal" + } + } + } + } + }, + { + "ActionType": "main.assignConsumerPubKeyAction", + "Action": { + "Chain": "densu", + "Validator": "carol", + "ConsumerPubkey": "{\"@type\":\"/cosmos.crypto.ed25519.PubKey\",\"key\":\"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is=\"}", + "ReconfigureNode": false, + "ExpectError": false, + "ExpectedError": "" + }, + "State": { + "densu": { + "ValBalances": null, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": { + "carol": "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk" + }, + "ProviderKeys": { + "carol": "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6" + }, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.assignConsumerPubKeyAction", + "Action": { + "Chain": "densu", + "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" + }, + "State": {} + }, + { + "ActionType": "main.assignConsumerPubKeyAction", + "Action": { + "Chain": "densu", + "Validator": "bob", + "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" + }, + "State": { + "densu": { + "ValBalances": null, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": { + "bob": "", + "carol": "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk" + }, + "ProviderKeys": { + "carol": "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6" + }, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.voteGovProposalAction", + "Action": { + "Chain": "provi", + "From": [ + "alice", + "bob", + "carol" + ], + "Vote": [ + "yes", + "yes", + "yes" + ], + "PropNumber": 2 + }, + "State": { + "provi": { + "ValBalances": { + "alice": 9500000000, + "bob": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "2": { + "RawProposal": { + "Deposit": 10000001, + "Chain": "densu", + "SpawnTime": 0, + "InitialHeight": { + "revision_height": 1 + }, + "Status": "PROPOSAL_STATUS_PASSED" + }, + "Type": "main.ConsumerAdditionProposal" + } + } + } + } + }, + { + "ActionType": "main.startConsumerChainAction", + "Action": { + "ConsumerChain": "densu", + "ProviderChain": "provi", + "Validators": [ + { + "Id": "bob", + "Allocation": 10000000000, + "Stake": 500000000 + }, + { + "Id": "alice", + "Allocation": 10000000000, + "Stake": 500000000 + }, + { + "Id": "carol", + "Allocation": 10000000000, + "Stake": 500000000 + } + ], + "GenesisChanges": ".app_state.ccvconsumer.params.soft_opt_out_threshold = \"0.05\"" + }, + "State": { + "densu": { + "ValBalances": { + "alice": 10000000000, + "bob": 10000000000, + "carol": 10000000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": { + "alice": 9500000000, + "bob": 9500000000, + "carol": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.addIbcConnectionAction", + "Action": { + "ChainA": "densu", + "ChainB": "provi", + "ClientA": 0, + "ClientB": 1 + }, + "State": {} + }, + { + "ActionType": "main.addIbcChannelAction", + "Action": { + "ChainA": "densu", + "ChainB": "provi", + "ConnectionA": 0, + "PortA": "consumer", + "PortB": "provider", + "Order": "ordered", + "Version": "" + }, + "State": {} + }, + { + "ActionType": "main.delegateTokensAction", + "Action": { + "Chain": "provi", + "From": "alice", + "To": "alice", + "Amount": 11000000 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 500, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "densu": { + "ValBalances": null, + "ValPowers": { + "alice": 500, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "densu": { + "ValBalances": null, + "ValPowers": { + "alice": 500, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "densu", + "Port": "provider", + "Channel": 1 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "densu": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.unbondTokensAction", + "Action": { + "Chain": "provi", + "Sender": "alice", + "UnbondFrom": "alice", + "Amount": 1000000 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "densu": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 510, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 510, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "densu": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 510, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "densu", + "Port": "provider", + "Channel": 1 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 510, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "densu": { + "ValBalances": null, + "ValPowers": { + "alice": 510, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 510, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.redelegateTokensAction", + "Action": { + "Chain": "provi", + "Src": "alice", + "Dst": "carol", + "TxSender": "alice", + "Amount": 1000000 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 510, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "densu": { + "ValBalances": null, + "ValPowers": { + "alice": 510, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "densu": { + "ValBalances": null, + "ValPowers": { + "alice": 510, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "densu", + "Port": "provider", + "Channel": 1 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "densu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.downtimeSlashAction", + "Action": { + "Chain": "consu", + "Validator": "bob" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "densu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "densu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 0, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 0, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "densu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "densu", + "Port": "provider", + "Channel": 1 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 0, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "densu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 0, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.unjailValidatorAction", + "Action": { + "Provider": "provi", + "Validator": "bob" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 0, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "densu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 0, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "densu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 0, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "densu", + "Port": "provider", + "Channel": 1 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "densu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.downtimeSlashAction", + "Action": { + "Chain": "provi", + "Validator": "carol" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "densu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "densu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "densu", + "Port": "provider", + "Channel": 1 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "densu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.unjailValidatorAction", + "Action": { + "Provider": "provi", + "Validator": "carol" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "densu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 495 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 495 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "densu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 495 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "densu", + "Port": "provider", + "Channel": 1 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 495 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "densu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 495 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 495 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.doublesignSlashAction", + "Action": { + "Validator": "carol", + "Chain": "provi" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 495 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "densu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 495 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "densu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 495 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "densu", + "Port": "provider", + "Channel": 1 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "densu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.doublesignSlashAction", + "Action": { + "Validator": "bob", + "Chain": "consu" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "densu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "densu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "densu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "densu", + "Port": "provider", + "Channel": 1 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "densu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + } +] \ No newline at end of file diff --git a/tests/e2e/tracehandler_testdata/shorthappy.json b/tests/e2e/tracehandler_testdata/shorthappy.json new file mode 100644 index 0000000000..04827a04cf --- /dev/null +++ b/tests/e2e/tracehandler_testdata/shorthappy.json @@ -0,0 +1,1578 @@ +[ + { + "ActionType": "main.StartChainAction", + "Action": { + "Chain": "provi", + "Validators": [ + { + "Id": "bob", + "Allocation": 10000000000, + "Stake": 500000000 + }, + { + "Id": "alice", + "Allocation": 10000000000, + "Stake": 500000000 + }, + { + "Id": "carol", + "Allocation": 10000000000, + "Stake": 500000000 + } + ], + "GenesisChanges": "", + "SkipGentx": false + }, + "State": { + "provi": { + "ValBalances": { + "alice": 9500000000, + "bob": 9500000000, + "carol": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.submitConsumerAdditionProposalAction", + "Action": { + "PreCCV": false, + "Chain": "provi", + "From": "alice", + "Deposit": 10000001, + "ConsumerChain": "consu", + "SpawnTime": 0, + "InitialHeight": { + "revision_height": 1 + }, + "DistributionChannel": "" + }, + "State": { + "provi": { + "ValBalances": { + "alice": 9489999999, + "bob": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "1": { + "RawProposal": { + "Deposit": 10000001, + "Chain": "consu", + "SpawnTime": 0, + "InitialHeight": { + "revision_height": 1 + }, + "Status": "PROPOSAL_STATUS_VOTING_PERIOD" + }, + "Type": "main.ConsumerAdditionProposal" + } + } + } + } + }, + { + "ActionType": "main.assignConsumerPubKeyAction", + "Action": { + "Chain": "consu", + "Validator": "carol", + "ConsumerPubkey": "{\"@type\":\"/cosmos.crypto.ed25519.PubKey\",\"key\":\"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is=\"}", + "ReconfigureNode": false, + "ExpectError": false, + "ExpectedError": "" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": { + "carol": "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk" + }, + "ProviderKeys": { + "carol": "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6" + }, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.assignConsumerPubKeyAction", + "Action": { + "Chain": "consu", + "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" + }, + "State": {} + }, + { + "ActionType": "main.assignConsumerPubKeyAction", + "Action": { + "Chain": "consu", + "Validator": "bob", + "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" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": { + "bob": "", + "carol": "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk" + }, + "ProviderKeys": { + "carol": "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6" + }, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.voteGovProposalAction", + "Action": { + "Chain": "provi", + "From": [ + "alice", + "bob", + "carol" + ], + "Vote": [ + "yes", + "yes", + "yes" + ], + "PropNumber": 1 + }, + "State": { + "provi": { + "ValBalances": { + "alice": 9500000000, + "bob": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "1": { + "RawProposal": { + "Deposit": 10000001, + "Chain": "consu", + "SpawnTime": 0, + "InitialHeight": { + "revision_height": 1 + }, + "Status": "PROPOSAL_STATUS_PASSED" + }, + "Type": "main.ConsumerAdditionProposal" + } + } + } + } + }, + { + "ActionType": "main.startConsumerChainAction", + "Action": { + "ConsumerChain": "consu", + "ProviderChain": "provi", + "Validators": [ + { + "Id": "bob", + "Allocation": 10000000000, + "Stake": 500000000 + }, + { + "Id": "alice", + "Allocation": 10000000000, + "Stake": 500000000 + }, + { + "Id": "carol", + "Allocation": 10000000000, + "Stake": 500000000 + } + ], + "GenesisChanges": ".app_state.ccvconsumer.params.soft_opt_out_threshold = \"0.05\"" + }, + "State": { + "consu": { + "ValBalances": { + "alice": 10000000000, + "bob": 10000000000, + "carol": 10000000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": { + "alice": 9500000000, + "bob": 9500000000, + "carol": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.addIbcConnectionAction", + "Action": { + "ChainA": "consu", + "ChainB": "provi", + "ClientA": 0, + "ClientB": 0 + }, + "State": {} + }, + { + "ActionType": "main.addIbcChannelAction", + "Action": { + "ChainA": "consu", + "ChainB": "provi", + "ConnectionA": 0, + "PortA": "consumer", + "PortB": "provider", + "Order": "ordered", + "Version": "" + }, + "State": {} + }, + { + "ActionType": "main.delegateTokensAction", + "Action": { + "Chain": "provi", + "From": "alice", + "To": "alice", + "Amount": 11000000 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 500, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.SendTokensAction", + "Action": { + "Chain": "consu", + "From": "alice", + "To": "bob", + "Amount": 1 + }, + "State": { + "consu": { + "ValBalances": { + "alice": 10000000000, + "bob": 10000000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.SendTokensAction", + "Action": { + "Chain": "consu", + "From": "alice", + "To": "bob", + "Amount": 1 + }, + "State": { + "consu": { + "ValBalances": { + "alice": 9999999999, + "bob": 10000000001 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.unbondTokensAction", + "Action": { + "Chain": "provi", + "Sender": "alice", + "UnbondFrom": "alice", + "Amount": 1000000 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 510, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 510, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.redelegateTokensAction", + "Action": { + "Chain": "provi", + "Src": "alice", + "Dst": "carol", + "TxSender": "alice", + "Amount": 1000000 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 510, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.downtimeSlashAction", + "Action": { + "Chain": "consu", + "Validator": "bob" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 0, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 0, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.unjailValidatorAction", + "Action": { + "Provider": "provi", + "Validator": "bob" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 0, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.downtimeSlashAction", + "Action": { + "Chain": "provi", + "Validator": "carol" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 501 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.unjailValidatorAction", + "Action": { + "Provider": "provi", + "Validator": "carol" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 495 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 495 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.submitEquivocationProposalAction", + "Action": { + "Chain": "consu", + "Height": 10, + "Time": "2023-09-20T18:24:51.823231+02:00", + "Power": 500, + "Validator": "bob", + "Deposit": 10000001, + "From": "bob" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 495 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": { + "bob": 9500000000 + }, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 495 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "2": { + "RawProposal": { + "Title": "", + "Description": "", + "Deposit": 0, + "Status": "" + }, + "Type": "main.TextProposal" + } + } + } + } + }, + { + "ActionType": "main.doublesignSlashAction", + "Action": { + "Validator": "carol", + "Chain": "provi" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 495 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.doublesignSlashAction", + "Action": { + "Validator": "bob", + "Chain": "consu" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.submitEquivocationProposalAction", + "Action": { + "Chain": "consu", + "Height": 10, + "Time": "2023-09-20T18:24:51.823235+02:00", + "Power": 500, + "Validator": "bob", + "Deposit": 10000001, + "From": "bob" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": { + "bob": 9489999999 + }, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "2": { + "RawProposal": { + "Height": 10, + "Power": 500, + "ConsensusAddress": "cosmosvalcons1nx7n5uh0ztxsynn4sje6eyq2ud6rc6klc96w39", + "Deposit": 10000001, + "Status": "PROPOSAL_STATUS_VOTING_PERIOD" + }, + "Type": "main.EquivocationProposal" + } + } + } + } + }, + { + "ActionType": "main.voteGovProposalAction", + "Action": { + "Chain": "provi", + "From": [ + "alice", + "bob", + "carol" + ], + "Vote": [ + "yes", + "yes", + "yes" + ], + "PropNumber": 2 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 500, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 0, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "2": { + "RawProposal": { + "Height": 10, + "Power": 500, + "ConsensusAddress": "cosmosvalcons1nx7n5uh0ztxsynn4sje6eyq2ud6rc6klc96w39", + "Deposit": 10000001, + "Status": "PROPOSAL_STATUS_PASSED" + }, + "Type": "main.EquivocationProposal" + } + } + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 0, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 509, + "bob": 0, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.startRelayerAction", + "Action": {}, + "State": {} + }, + { + "ActionType": "main.submitConsumerRemovalProposalAction", + "Action": { + "Chain": "provi", + "From": "bob", + "Deposit": 10000001, + "ConsumerChain": "consu", + "StopTimeOffset": 0 + }, + "State": { + "provi": { + "ValBalances": { + "bob": 9489999999 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": { + "consu": true + }, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "3": { + "RawProposal": { + "Deposit": 10000001, + "Chain": "consu", + "StopTime": 0, + "Status": "PROPOSAL_STATUS_VOTING_PERIOD" + }, + "Type": "main.ConsumerRemovalProposal" + } + } + } + } + }, + { + "ActionType": "main.voteGovProposalAction", + "Action": { + "Chain": "provi", + "From": [ + "alice", + "bob", + "carol" + ], + "Vote": [ + "no", + "no", + "no" + ], + "PropNumber": 3 + }, + "State": { + "provi": { + "ValBalances": { + "bob": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": { + "consu": true + }, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "3": { + "RawProposal": { + "Deposit": 10000001, + "Chain": "consu", + "StopTime": 0, + "Status": "PROPOSAL_STATUS_REJECTED" + }, + "Type": "main.ConsumerRemovalProposal" + } + } + } + } + }, + { + "ActionType": "main.submitConsumerRemovalProposalAction", + "Action": { + "Chain": "provi", + "From": "bob", + "Deposit": 10000001, + "ConsumerChain": "consu", + "StopTimeOffset": 0 + }, + "State": { + "provi": { + "ValBalances": { + "bob": 9489999999 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": { + "consu": true + }, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "4": { + "RawProposal": { + "Deposit": 10000001, + "Chain": "consu", + "StopTime": 0, + "Status": "PROPOSAL_STATUS_VOTING_PERIOD" + }, + "Type": "main.ConsumerRemovalProposal" + } + } + } + } + }, + { + "ActionType": "main.voteGovProposalAction", + "Action": { + "Chain": "provi", + "From": [ + "alice", + "bob", + "carol" + ], + "Vote": [ + "yes", + "yes", + "yes" + ], + "PropNumber": 4 + }, + "State": { + "provi": { + "ValBalances": { + "bob": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": {}, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "4": { + "RawProposal": { + "Deposit": 10000001, + "Chain": "consu", + "StopTime": 0, + "Status": "PROPOSAL_STATUS_PASSED" + }, + "Type": "main.ConsumerRemovalProposal" + } + } + } + } + } +] \ No newline at end of file diff --git a/tests/e2e/tracehandler_testdata/slashThrottle.json b/tests/e2e/tracehandler_testdata/slashThrottle.json new file mode 100644 index 0000000000..dc25e590b0 --- /dev/null +++ b/tests/e2e/tracehandler_testdata/slashThrottle.json @@ -0,0 +1,807 @@ +[ + { + "ActionType": "main.StartChainAction", + "Action": { + "Chain": "provi", + "Validators": [ + { + "Id": "bob", + "Allocation": 10000000000, + "Stake": 500000000 + }, + { + "Id": "alice", + "Allocation": 10000000000, + "Stake": 500000000 + }, + { + "Id": "carol", + "Allocation": 10000000000, + "Stake": 500000000 + } + ], + "GenesisChanges": "", + "SkipGentx": false + }, + "State": { + "provi": { + "ValBalances": { + "alice": 9500000000, + "bob": 9500000000, + "carol": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.submitConsumerAdditionProposalAction", + "Action": { + "PreCCV": false, + "Chain": "provi", + "From": "alice", + "Deposit": 10000001, + "ConsumerChain": "consu", + "SpawnTime": 0, + "InitialHeight": { + "revision_height": 1 + }, + "DistributionChannel": "" + }, + "State": { + "provi": { + "ValBalances": { + "alice": 9489999999, + "bob": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "1": { + "RawProposal": { + "Deposit": 10000001, + "Chain": "consu", + "SpawnTime": 0, + "InitialHeight": { + "revision_height": 1 + }, + "Status": "PROPOSAL_STATUS_VOTING_PERIOD" + }, + "Type": "main.ConsumerAdditionProposal" + } + } + } + } + }, + { + "ActionType": "main.assignConsumerPubKeyAction", + "Action": { + "Chain": "consu", + "Validator": "carol", + "ConsumerPubkey": "{\"@type\":\"/cosmos.crypto.ed25519.PubKey\",\"key\":\"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is=\"}", + "ReconfigureNode": false, + "ExpectError": false, + "ExpectedError": "" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": { + "carol": "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk" + }, + "ProviderKeys": { + "carol": "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6" + }, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.assignConsumerPubKeyAction", + "Action": { + "Chain": "consu", + "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" + }, + "State": {} + }, + { + "ActionType": "main.assignConsumerPubKeyAction", + "Action": { + "Chain": "consu", + "Validator": "bob", + "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" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": { + "bob": "", + "carol": "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk" + }, + "ProviderKeys": { + "carol": "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6" + }, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.voteGovProposalAction", + "Action": { + "Chain": "provi", + "From": [ + "alice", + "bob", + "carol" + ], + "Vote": [ + "yes", + "yes", + "yes" + ], + "PropNumber": 1 + }, + "State": { + "provi": { + "ValBalances": { + "alice": 9500000000, + "bob": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "1": { + "RawProposal": { + "Deposit": 10000001, + "Chain": "consu", + "SpawnTime": 0, + "InitialHeight": { + "revision_height": 1 + }, + "Status": "PROPOSAL_STATUS_PASSED" + }, + "Type": "main.ConsumerAdditionProposal" + } + } + } + } + }, + { + "ActionType": "main.startConsumerChainAction", + "Action": { + "ConsumerChain": "consu", + "ProviderChain": "provi", + "Validators": [ + { + "Id": "bob", + "Allocation": 10000000000, + "Stake": 500000000 + }, + { + "Id": "alice", + "Allocation": 10000000000, + "Stake": 500000000 + }, + { + "Id": "carol", + "Allocation": 10000000000, + "Stake": 500000000 + } + ], + "GenesisChanges": ".app_state.ccvconsumer.params.soft_opt_out_threshold = \"0.05\"" + }, + "State": { + "consu": { + "ValBalances": { + "alice": 10000000000, + "bob": 10000000000, + "carol": 10000000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": { + "alice": 9500000000, + "bob": 9500000000, + "carol": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.addIbcConnectionAction", + "Action": { + "ChainA": "consu", + "ChainB": "provi", + "ClientA": 0, + "ClientB": 0 + }, + "State": {} + }, + { + "ActionType": "main.addIbcChannelAction", + "Action": { + "ChainA": "consu", + "ChainB": "provi", + "ConnectionA": 0, + "PortA": "consumer", + "PortB": "provider", + "Order": "ordered", + "Version": "" + }, + "State": {} + }, + { + "ActionType": "main.delegateTokensAction", + "Action": { + "Chain": "provi", + "From": "alice", + "To": "alice", + "Amount": 11000000 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 500, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.SendTokensAction", + "Action": { + "Chain": "consu", + "From": "alice", + "To": "bob", + "Amount": 1 + }, + "State": { + "consu": { + "ValBalances": { + "alice": 10000000000, + "bob": 10000000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.SendTokensAction", + "Action": { + "Chain": "consu", + "From": "alice", + "To": "bob", + "Amount": 1 + }, + "State": { + "consu": { + "ValBalances": { + "alice": 9999999999, + "bob": 10000000001 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.downtimeSlashAction", + "Action": { + "Chain": "consu", + "Validator": "bob" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 0, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": { + "consu": 0 + }, + "GlobalSlashQueueSize": 0, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.downtimeSlashAction", + "Action": { + "Chain": "consu", + "Validator": "carol" + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 500, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 0, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 0, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 0, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": { + "consu": 1 + }, + "GlobalSlashQueueSize": 1, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.slashThrottleDequeueAction", + "Action": { + "Chain": "consu", + "CurrentQueueSize": 1, + "NextQueueSize": 0, + "Timeout": 80000000000 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 0, + "carol": 500 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 0, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": { + "consu": 0 + }, + "GlobalSlashQueueSize": 0, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.relayPacketsAction", + "Action": { + "ChainA": "provi", + "ChainB": "consu", + "Port": "provider", + "Channel": 0 + }, + "State": { + "consu": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 0, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + }, + "provi": { + "ValBalances": null, + "ValPowers": { + "alice": 511, + "bob": 0, + "carol": 0 + }, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": null, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": { + "consu": 0 + }, + "GlobalSlashQueueSize": 0, + "RegisteredConsumerRewardDenoms": null, + "Proposals": null + } + } + }, + { + "ActionType": "main.submitConsumerRemovalProposalAction", + "Action": { + "Chain": "provi", + "From": "bob", + "Deposit": 10000001, + "ConsumerChain": "consu", + "StopTimeOffset": 0 + }, + "State": { + "provi": { + "ValBalances": { + "bob": 9489999999 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": { + "consu": true + }, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "2": { + "RawProposal": { + "Deposit": 10000001, + "Chain": "consu", + "StopTime": 0, + "Status": "PROPOSAL_STATUS_VOTING_PERIOD" + }, + "Type": "main.ConsumerRemovalProposal" + } + } + } + } + }, + { + "ActionType": "main.voteGovProposalAction", + "Action": { + "Chain": "provi", + "From": [ + "alice", + "bob", + "carol" + ], + "Vote": [ + "yes", + "yes", + "yes" + ], + "PropNumber": 2 + }, + "State": { + "provi": { + "ValBalances": { + "bob": 9500000000 + }, + "ValPowers": null, + "RepresentativePowers": null, + "Params": null, + "Rewards": null, + "ConsumerChains": {}, + "AssignedKeys": null, + "ProviderKeys": null, + "ConsumerChainQueueSizes": null, + "GlobalSlashQueueSize": null, + "RegisteredConsumerRewardDenoms": null, + "Proposals": { + "2": { + "RawProposal": { + "Deposit": 10000001, + "Chain": "consu", + "StopTime": 0, + "Status": "PROPOSAL_STATUS_PASSED" + }, + "Type": "main.ConsumerRemovalProposal" + } + } + } + } + } +] \ No newline at end of file From 5e3c3529dd32061e00942812dd05fb2ee82f5209 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Sep 2023 08:48:48 +0200 Subject: [PATCH 124/134] build(deps): bump pgregory.net/rapid from 0.5.5 to 1.1.0 (#1327) Bumps [pgregory.net/rapid](https://github.com/flyingmutant/rapid) from 0.5.5 to 1.1.0. - [Release notes](https://github.com/flyingmutant/rapid/releases) - [Commits](https://github.com/flyingmutant/rapid/compare/v0.5.5...v1.1.0) --- updated-dependencies: - dependency-name: pgregory.net/rapid dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 5f869f97db..1fa2e45293 100644 --- a/go.mod +++ b/go.mod @@ -161,7 +161,7 @@ require ( gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect nhooyr.io/websocket v1.8.6 // indirect - pgregory.net/rapid v0.5.5 + pgregory.net/rapid v1.1.0 sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index 2246f9decf..feeba1fcc4 100644 --- a/go.sum +++ b/go.sum @@ -1882,8 +1882,8 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= -pgregory.net/rapid v0.5.5 h1:jkgx1TjbQPD/feRoK+S/mXw9e1uj6WilpHrXJowi6oA= -pgregory.net/rapid v0.5.5/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= +pgregory.net/rapid v1.1.0 h1:CMa0sjHSru3puNx+J0MIAuiiEV4N0qj8/cMWGBBCsjw= +pgregory.net/rapid v1.1.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= From 147e435ed82cf8d5d7748d223877cab878377c90 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Sep 2023 08:50:22 +0200 Subject: [PATCH 125/134] build(deps): bump google.golang.org/grpc from 1.58.1 to 1.58.2 (#1328) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.58.1 to 1.58.2. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.58.1...v1.58.2) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 1fa2e45293..18dd967eef 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( golang.org/x/net v0.12.0 // indirect golang.org/x/sys v0.11.0 // indirect google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 // indirect - google.golang.org/grpc v1.58.1 + google.golang.org/grpc v1.58.2 google.golang.org/protobuf v1.31.0 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index feeba1fcc4..d9c4afc2f7 100644 --- a/go.sum +++ b/go.sum @@ -1813,8 +1813,8 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.58.1 h1:OL+Vz23DTtrrldqHK49FUOPHyY75rvFqJfXC84NYW58= -google.golang.org/grpc v1.58.1/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I= +google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= From 811675e267cd535126e5e9780c6325e7b8583db3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Sep 2023 08:50:38 +0200 Subject: [PATCH 126/134] build(deps): bump github.com/tidwall/gjson from 1.16.0 to 1.17.0 (#1326) Bumps [github.com/tidwall/gjson](https://github.com/tidwall/gjson) from 1.16.0 to 1.17.0. - [Commits](https://github.com/tidwall/gjson/compare/v1.16.0...v1.17.0) --- updated-dependencies: - dependency-name: github.com/tidwall/gjson dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 18dd967eef..8483e0a097 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/spf13/cast v1.5.1 github.com/spf13/cobra v1.7.0 github.com/stretchr/testify v1.8.4 - github.com/tidwall/gjson v1.16.0 + github.com/tidwall/gjson v1.17.0 golang.org/x/crypto v0.11.0 // indirect golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb golang.org/x/net v0.12.0 // indirect diff --git a/go.sum b/go.sum index d9c4afc2f7..b062a13dc2 100644 --- a/go.sum +++ b/go.sum @@ -1124,8 +1124,8 @@ github.com/tidwall/btree v1.6.0 h1:LDZfKfQIBHGHWSwckhXI0RPSXzlo+KYdjK7FWSqOzzg= github.com/tidwall/btree v1.6.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.14.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.16.0 h1:SyXa+dsSPpUlcwEDuKuEBJEz5vzTvOea+9rjyYodQFg= -github.com/tidwall/gjson v1.16.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM= +github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= From 04ca9a1001c75144cbfbd9053458714cca4d624d Mon Sep 17 00:00:00 2001 From: Simon Noetzlin Date: Thu, 28 Sep 2023 11:12:09 +0200 Subject: [PATCH 127/134] fix e2e happy-path-short test --- Dockerfile | 2 +- tests/e2e/testnet-scripts/start-chain.sh | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index 583a1e8009..6ed877a242 100644 --- a/Dockerfile +++ b/Dockerfile @@ -43,7 +43,7 @@ FROM ghcr.io/informalsystems/cometmock:v0.37.x as cometmock-builder # Get GoRelayer FROM ghcr.io/informalsystems/relayer-no-gas-sim:v2.3.0-rc4-no-gas-sim AS gorelayer-builder -FROM --platform=linux/amd64 fedora:36 +FROM --platform=linux/arm64 fedora:36 RUN dnf update -y RUN dnf install -y which iproute iputils procps-ng vim-minimal tmux net-tools htop jq USER root diff --git a/tests/e2e/testnet-scripts/start-chain.sh b/tests/e2e/testnet-scripts/start-chain.sh index 6dbce7d524..e1e7a5c95a 100644 --- a/tests/e2e/testnet-scripts/start-chain.sh +++ b/tests/e2e/testnet-scripts/start-chain.sh @@ -367,11 +367,7 @@ NODE_HOMES=${NODE_HOMES%?} # CometMock takes the role of the query node if [[ "$USE_COMETMOCK" == "true" ]]; then sleep 2 -<<<<<<< HEAD - ip netns exec $QUERY_NET_NAMESPACE_NAME cometmock $NODE_LISTEN_ADDR_STR /$CHAIN_ID/genesis.json tcp://$CHAIN_IP_PREFIX.$QUERY_IP_SUFFIX:26658 $NODE_HOMES &> cometmock_${CHAIN_ID}_out.log & -======= ip netns exec $QUERY_NET_NAMESPACE_NAME cometmock $NODE_LISTEN_ADDR_STR /$CHAIN_ID/genesis.json tcp://$CHAIN_IP_PREFIX.$QUERY_IP_SUFFIX:26658 $NODE_HOMES grpc &> cometmock_${CHAIN_ID}_out.log & ->>>>>>> main sleep 3 fi From 8163735675bde71e57abd029f61ae9a6815e9e70 Mon Sep 17 00:00:00 2001 From: Simon Noetzlin Date: Thu, 28 Sep 2023 15:21:28 +0200 Subject: [PATCH 128/134] make consumer misbehaviour and double signing tests pass --- tests/e2e/actions.go | 5 +++-- tests/e2e/config.go | 14 ++++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index 551f1100c2..d1e015f755 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -172,8 +172,9 @@ func (tr *TestRun) startChain( } tr.addChainToRelayer(addChainToRelayerAction{ - Chain: action.Chain, - Validator: action.Validators[0].Id, + Chain: action.Chain, + Validator: action.Validators[0].Id, + IsConsumer: action.IsConsumer, }, verbose) // store the fact that we started the chain diff --git a/tests/e2e/config.go b/tests/e2e/config.go index 08c2981284..89e951c400 100644 --- a/tests/e2e/config.go +++ b/tests/e2e/config.go @@ -396,7 +396,7 @@ func ChangeoverTestRun() TestRun { } func ConsumerMisbehaviourTestRun() TestRun { - return TestRun{ + tr := TestRun{ name: "misbehaviour", containerConfig: ContainerConfig{ ContainerName: "interchain-security-container", @@ -450,12 +450,12 @@ func ConsumerMisbehaviourTestRun() TestRun { BinaryName: "interchain-security-pd", IpPrefix: "7.7.7", VotingWaitTime: 20, - GenesisChanges: ".app_state.gov.voting_params.voting_period = \"20s\" | " + + GenesisChanges: ".app_state.gov.params.voting_period = \"20s\" | " + // Custom slashing parameters for testing validator downtime functionality // See https://docs.cosmos.network/main/modules/slashing/04_begin_block.html#uptime-tracking ".app_state.slashing.params.signed_blocks_window = \"10\" | " + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + - ".app_state.slashing.params.downtime_jail_duration = \"2s\" | " + + ".app_state.slashing.params.downtime_jail_duration = \"60s\" | " + ".app_state.slashing.params.slash_fraction_downtime = \"0.010000000000000000\" | " + ".app_state.provider.params.slash_meter_replenish_fraction = \"1.0\" | " + // This disables slash packet throttling ".app_state.provider.params.slash_meter_replenish_period = \"3s\"", @@ -465,18 +465,20 @@ func ConsumerMisbehaviourTestRun() TestRun { BinaryName: "interchain-security-cd", IpPrefix: "7.7.8", VotingWaitTime: 20, - GenesisChanges: ".app_state.gov.voting_params.voting_period = \"20s\" | " + + GenesisChanges: ".app_state.gov.params.voting_period = \"20s\" | " + ".app_state.slashing.params.signed_blocks_window = \"15\" | " + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + - ".app_state.slashing.params.downtime_jail_duration = \"2s\" | " + + ".app_state.slashing.params.downtime_jail_duration = \"60s\" | " + ".app_state.slashing.params.slash_fraction_downtime = \"0.010000000000000000\"", }, }, tendermintConfigOverride: `s/timeout_commit = "5s"/timeout_commit = "1s"/;` + `s/peer_gossip_sleep_duration = "100ms"/peer_gossip_sleep_duration = "50ms"/;` + // Required to start consumer chain by running a single big validator - `s/fast_sync = true/fast_sync = false/;`, + `s/block_sync = true/block_sync = false/;`, } + tr.Initialize() + return tr } func (s *TestRun) SetDockerConfig(localSdkPath string, useGaia bool, gaiaTag string) { From ac9f3ff299d06d20cbceee181d09ebaa492fbf4c Mon Sep 17 00:00:00 2001 From: Simon Noetzlin Date: Fri, 29 Sep 2023 12:10:25 +0200 Subject: [PATCH 129/134] currently debugging democracy-reward --- app/sovereign/app.go | 5 + .../testnet-scripts/sovereign-genesis.json | 281 ------------------ 2 files changed, 5 insertions(+), 281 deletions(-) diff --git a/app/sovereign/app.go b/app/sovereign/app.go index 959fa4ed5b..c6ffb0e853 100644 --- a/app/sovereign/app.go +++ b/app/sovereign/app.go @@ -126,6 +126,10 @@ var ( ModuleBasics = module.NewBasicManager( auth.AppModuleBasic{}, genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator), + bank.AppModuleBasic{}, + capability.AppModuleBasic{}, + sdkstaking.AppModuleBasic{}, + mint.AppModuleBasic{}, sdkdistr.AppModuleBasic{}, sdkgov.NewAppModuleBasic( []govclient.ProposalHandler{ @@ -136,6 +140,7 @@ var ( ), params.AppModuleBasic{}, crisis.AppModuleBasic{}, + slashing.AppModuleBasic{}, feegrantmodule.AppModuleBasic{}, authzmodule.AppModuleBasic{}, ibc.AppModuleBasic{}, diff --git a/tests/e2e/testnet-scripts/sovereign-genesis.json b/tests/e2e/testnet-scripts/sovereign-genesis.json index a2691569ef..2ab953b162 100644 --- a/tests/e2e/testnet-scripts/sovereign-genesis.json +++ b/tests/e2e/testnet-scripts/sovereign-genesis.json @@ -1,284 +1,4 @@ { -<<<<<<< HEAD - "genesis_time": "2023-06-13T11:19:05.998449459Z", - "chain_id": "sover", - "initial_height": "1", - "consensus_params": { - "block": { - "max_bytes": "22020096", - "max_gas": "-1", - "time_iota_ms": "1000" - }, - "evidence": { - "max_age_num_blocks": "100000", - "max_age_duration": "172800000000000", - "max_bytes": "1048576" - }, - "validator": { - "pub_key_types": [ - "ed25519" - ] - }, - "version": {} - }, - "app_hash": "", - "app_state": { - "auth": { - "params": { - "max_memo_characters": "256", - "tx_sig_limit": "7", - "tx_size_cost_per_byte": "10", - "sig_verify_cost_ed25519": "590", - "sig_verify_cost_secp256k1": "1000" - }, - "accounts": [ - { - "@type": "/cosmos.auth.v1beta1.BaseAccount", - "address": "cosmos19pe9pg5dv9k5fzgzmsrgnw9rl9asf7ddwhu7lm", - "pub_key": null, - "account_number": "0", - "sequence": "0" - } - ] - }, - "authz": { - "authorization": [] - }, - "bank": { - "params": { - "send_enabled": [], - "default_send_enabled": true - }, - "balances": [ - { - "address": "cosmos19pe9pg5dv9k5fzgzmsrgnw9rl9asf7ddwhu7lm", - "coins": [ - { - "denom": "stake", - "amount": "10000000000" - } - ] - } - ], - "supply": [ - { - "denom": "stake", - "amount": "10000000000" - } - ], - "denom_metadata": [] - }, - "capability": { - "index": "1", - "owners": [] - }, - "crisis": { - "constant_fee": { - "denom": "stake", - "amount": "1000" - } - }, - "distribution": { - "params": { - "community_tax": "0.020000000000000000", - "base_proposer_reward": "0.010000000000000000", - "bonus_proposer_reward": "0.040000000000000000", - "withdraw_addr_enabled": true - }, - "fee_pool": { - "community_pool": [] - }, - "delegator_withdraw_infos": [], - "previous_proposer": "", - "outstanding_rewards": [], - "validator_accumulated_commissions": [], - "validator_historical_rewards": [], - "validator_current_rewards": [], - "delegator_starting_infos": [], - "validator_slash_events": [] - }, - "evidence": { - "evidence": [] - }, - "feegrant": { - "allowances": [] - }, - "genutil": { - "gen_txs": [ - { - "body": { - "messages": [ - { - "@type": "/cosmos.staking.v1beta1.MsgCreateValidator", - "description": { - "moniker": "validatoralice", - "identity": "", - "website": "", - "security_contact": "", - "details": "" - }, - "commission": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "min_self_delegation": "1", - "delegator_address": "cosmos19pe9pg5dv9k5fzgzmsrgnw9rl9asf7ddwhu7lm", - "validator_address": "cosmosvaloper19pe9pg5dv9k5fzgzmsrgnw9rl9asf7ddtrgtng", - "pubkey": { - "@type": "/cosmos.crypto.ed25519.PubKey", - "key": "RrclQz9bIhkIy/gfL485g3PYMeiIku4qeo495787X10=" - }, - "value": { - "denom": "stake", - "amount": "500000000" - } - } - ], - "memo": "8339e14baab81c2a2350e261962263397a8d7fb0@7.7.8.254:26656", - "timeout_height": "0", - "extension_options": [], - "non_critical_extension_options": [] - }, - "auth_info": { - "signer_infos": [ - { - "public_key": { - "@type": "/cosmos.crypto.secp256k1.PubKey", - "key": "AsFC8tmbGGQSHthsVStbsQ13/+Yza9IT8KCSXXEN7y9f" - }, - "mode_info": { - "single": { - "mode": "SIGN_MODE_DIRECT" - } - }, - "sequence": "0" - } - ], - "fee": { - "amount": [], - "gas_limit": "200000", - "payer": "", - "granter": "" - } - }, - "signatures": [ - "rZuml3RLgrrZkUoNHw90FuHF/Orxzs0uiwflCkUOcvoA4bzohisjdQhkPWCn5aRw30mqZJGj1IxgXS15XleMvQ==" - ] - } - ] - }, - "gov": { - "starting_proposal_id": "1", - "deposits": [], - "votes": [], - "proposals": [], - "deposit_params": { - "min_deposit": [ - { - "denom": "stake", - "amount": "10000000" - } - ], - "max_deposit_period": "172800s" - }, - "voting_params": { - "voting_period": "20s" - }, - "tally_params": { - "quorum": "0.334000000000000000", - "threshold": "0.500000000000000000", - "veto_threshold": "0.334000000000000000" - } - }, - "ibc": { - "client_genesis": { - "clients": [], - "clients_consensus": [], - "clients_metadata": [], - "params": { - "allowed_clients": [ - "06-solomachine", - "07-tendermint" - ] - }, - "create_localhost": false, - "next_client_sequence": "0" - }, - "connection_genesis": { - "connections": [], - "client_connection_paths": [], - "next_connection_sequence": "0", - "params": { - "max_expected_time_per_block": "30000000000" - } - }, - "channel_genesis": { - "channels": [], - "acknowledgements": [], - "commitments": [], - "receipts": [], - "send_sequences": [], - "recv_sequences": [], - "ack_sequences": [], - "next_channel_sequence": "0" - } - }, - "mint": { - "minter": { - "inflation": "0.130000000000000000", - "annual_provisions": "0.000000000000000000" - }, - "params": { - "mint_denom": "stake", - "inflation_rate_change": "0.130000000000000000", - "inflation_max": "0.200000000000000000", - "inflation_min": "0.070000000000000000", - "goal_bonded": "0.670000000000000000", - "blocks_per_year": "6311520" - } - }, - "params": null, - "slashing": { - "params": { - "signed_blocks_window": "15", - "min_signed_per_window": "0.500000000000000000", - "downtime_jail_duration": "2s", - "slash_fraction_double_sign": "0.050000000000000000", - "slash_fraction_downtime": "0.010000000000000000" - }, - "signing_infos": [], - "missed_blocks": [] - }, - "staking": { - "params": { - "unbonding_time": "1814400s", - "max_validators": 100, - "max_entries": 7, - "historical_entries": 10000, - "bond_denom": "stake" - }, - "last_total_power": "0", - "last_validator_powers": [], - "validators": [], - "delegations": [], - "unbonding_delegations": [], - "redelegations": [], - "exported": false - }, - "transfer": { - "port_id": "transfer", - "denom_traces": [], - "params": { - "send_enabled": true, - "receive_enabled": true - } - }, - "upgrade": {}, - "vesting": {} - } - } -======= "genesis_time": "2023-06-22T15:55:00.982713586Z", "chain_id": "sover", "initial_height": "1", @@ -573,4 +293,3 @@ "vesting": {} } } ->>>>>>> main From 1fbaf09134056828fe70744e7ecc8068036b69c3 Mon Sep 17 00:00:00 2001 From: Simon Noetzlin Date: Fri, 29 Sep 2023 17:25:02 +0200 Subject: [PATCH 130/134] fix e2e democ test --- tests/e2e/actions.go | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index d1e015f755..8c7698b5c7 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -1747,6 +1747,7 @@ func (tr TestRun) registerRepresentative( `--commission-rate`, "0.1", `--commission-max-rate`, "0.2", `--commission-max-change-rate`, "0.01", + `--min-self-delegation`, "1", `--from`, `validator`+fmt.Sprint(val), `--chain-id`, string(tr.chainConfigs[action.Chain].ChainId), `--home`, tr.getValidatorHome(action.Chain, val), From dddcd1bbb3d8842726603056472134c721b18eed Mon Sep 17 00:00:00 2001 From: Simon Noetzlin Date: Mon, 2 Oct 2023 10:44:14 +0200 Subject: [PATCH 131/134] add equivo removal failing tests --- app/provider/app.go | 22 +- docs/docs/features/proposals.md | 58 -- docs/docs/features/slashing.md | 31 +- docs/docs/introduction/overview.md | 4 - docs/docs/validators/overview.md | 2 +- .../ccv/provider/v1/provider.proto | 14 - tests/e2e/action_rapid_test.go | 14 - tests/e2e/actions.go | 74 --- tests/e2e/config.go | 2 +- tests/e2e/json_utils.go | 12 - tests/e2e/main.go | 2 - tests/e2e/state.go | 20 - tests/e2e/state_rapid_test.go | 13 - tests/e2e/steps.go | 14 +- tests/e2e/steps_double_sign.go | 78 +-- tests/e2e/steps_light_client_attack.go | 1 - .../e2e/steps_submit_equivocation_proposal.go | 150 ----- tests/e2e/trace_handlers_test.go | 19 - testutil/keeper/mocks.go | 102 ++-- testutil/keeper/unit_test_helpers.go | 3 - x/ccv/provider/client/proposal_handler.go | 125 +--- x/ccv/provider/keeper/keeper.go | 17 +- x/ccv/provider/keeper/proposal.go | 12 - x/ccv/provider/keeper/proposal_test.go | 61 -- x/ccv/provider/proposal_handler.go | 4 +- x/ccv/provider/proposal_handler_test.go | 26 +- x/ccv/provider/types/codec.go | 5 - x/ccv/provider/types/proposal.go | 38 -- x/ccv/provider/types/proposal_test.go | 57 -- x/ccv/provider/types/provider.pb.go | 560 +++++------------- x/ccv/types/expected_keepers.go | 5 - 31 files changed, 201 insertions(+), 1344 deletions(-) delete mode 100644 tests/e2e/steps_submit_equivocation_proposal.go diff --git a/app/provider/app.go b/app/provider/app.go index 4550ec77d2..5680f254b5 100644 --- a/app/provider/app.go +++ b/app/provider/app.go @@ -25,6 +25,7 @@ import ( autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" + evidencekeeper "github.com/cosmos/cosmos-sdk/x/evidence/keeper" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" @@ -66,7 +67,6 @@ import ( distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" "github.com/cosmos/cosmos-sdk/x/evidence" - evidencekeeper "github.com/cosmos/cosmos-sdk/x/evidence/keeper" evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" "github.com/cosmos/cosmos-sdk/x/genutil" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" @@ -140,7 +140,6 @@ var ( ibcclientclient.UpgradeProposalHandler, ibcproviderclient.ConsumerAdditionProposalHandler, ibcproviderclient.ConsumerRemovalProposalHandler, - ibcproviderclient.EquivocationProposalHandler, ibcproviderclient.ChangeRewardDenomsProposalHandler, }, ), @@ -404,14 +403,6 @@ func New( scopedIBCKeeper, ) - // create evidence keeper with router - app.EvidenceKeeper = *evidencekeeper.NewKeeper( - appCodec, - keys[evidencetypes.StoreKey], - app.StakingKeeper, - app.SlashingKeeper, - ) - app.ProviderKeeper = ibcproviderkeeper.NewKeeper( appCodec, keys[providertypes.StoreKey], @@ -424,7 +415,6 @@ func New( app.StakingKeeper, app.SlashingKeeper, app.AccountKeeper, - app.EvidenceKeeper, app.DistrKeeper, app.BankKeeper, authtypes.FeeCollectorName, @@ -477,6 +467,16 @@ func New( ibcRouter.AddRoute(providertypes.ModuleName, providerModule) app.IBCKeeper.SetRouter(ibcRouter) + // create evidence keeper with router + evidenceKeeper := evidencekeeper.NewKeeper( + appCodec, + keys[evidencetypes.StoreKey], + app.StakingKeeper, + app.SlashingKeeper, + ) + + app.EvidenceKeeper = *evidenceKeeper + skipGenesisInvariants := cast.ToBool(appOpts.Get(crisis.FlagSkipGenesisInvariants)) // NOTE: Any module instantiated in the module manager that is later modified diff --git a/docs/docs/features/proposals.md b/docs/docs/features/proposals.md index de4f2dc421..70077944ea 100644 --- a/docs/docs/features/proposals.md +++ b/docs/docs/features/proposals.md @@ -74,37 +74,6 @@ Minimal example: } ``` -## `EquivocationProposal` -:::tip -`EquivocationProposal` will only be accepted on the provider chain if at least one of the consumer chains submits equivocation evidence to the provider. -Sending equivocation evidence to the provider is handled automatically by the interchain security protocol when an equivocation infraction is detected on the consumer chain. -::: - -Proposal type used to suggest slashing a validator for double signing on consumer chain. -When proposals of this type are passed, the validator in question will be slashed for equivocation on the provider chain. - -:::warning -Take note that an equivocation slash causes a validator to be tombstoned (can never re-enter the active set). -Tombstoning a validator on the provider chain will remove the validator from the validator set of all consumer chains. -::: - -Minimal example: -```js -{ - "title": "Validator-1 double signed on consumerchain-1", - "description": "Here is more information about the infraction so you can verify it yourself", - // the list of equivocations that will be processed - "equivocations": [ - { - "height": 14444680, - "time": "2023-02-28T20:40:00.000000Z", - "power": 5500000, - "consensus_address": "" - } - ] -} -``` - ## ChangeRewardDenomProposal :::tip `ChangeRewardDenomProposal` will only be accepted on the provider chain if at least one of the denomsToAdd or denomsToRemove fields is populated with at least one denom. Also, a denom cannot be repeated in both sets. @@ -121,30 +90,3 @@ Minimal example: "denomsToRemove": [] } ``` - -### Notes -When submitting equivocation evidence through an `EquivocationProposal` please take note that you need to use the consensus address (`valcons`) of the offending validator on the **provider chain**. -Besides that, the `height` and the `time` fields should be mapped to the **provider chain** to avoid your evidence being rejected. - -Before submitting the proposal please check that the evidence is not outdated by comparing the infraction height with the `max_age_duration` and `max_age_num_blocks` consensus parameters of the **provider chain**. - -### Gaia example: -``` -➜ ~ cat genesis.json | jq ".consensus_params" -{ - "block": { - ... - }, - "evidence": { - "max_age_duration": "172800000000000", - "max_age_num_blocks": "1000000", - "max_bytes": "50000" - }, - "validator": { - ... - }, - "version": {} -} -``` - -Any `EquivocationProposal` transactions that submit evidence with `height` older than `max_age_num_blocks` and `time` older than `max_age_duration` will be considered invalid. diff --git a/docs/docs/features/slashing.md b/docs/docs/features/slashing.md index ee01b93ce3..09ceeefd0b 100644 --- a/docs/docs/features/slashing.md +++ b/docs/docs/features/slashing.md @@ -20,33 +20,10 @@ Instead of slashing, the provider will only jail offending validator for the dur Slash throttling (sometimes called jail throttling) mechanism ensures that only a fraction of the validator set can be jailed at any one time to prevent malicious consumer chains from harming the provider. ::: -## Double-signing (equivocation) -infractions are not acted upon immediately. +# Cryptographic verification of equivocation and slashing +The Cryptographic verification of equivocation allows external agents to submit evidences of light client and double signing attack observed on a consumer chain. When a valid evidence is received, the malicious validators will be slashed, jailed, and tombstoned on the provider. -Upon receiving double signing evidence, the provider chain will take note of the evidence and allow for `EquivocationProposal` to be submitted to slash the offending validator. -Any `EquivocationProposal`s to slash a validator that has not double signed on any of the consumer chains will be automatically rejected by the provider chain. - -:::info -The offending validator will only be slashed (and tombstoned) if an `EquivocationProposal` is accepted and passed through governance. - -The offending validator will effectively get slashed and tombstoned on all consumer chains. -::: - - -You can find instructions on creating `EquivocationProposal`s [here](./proposals#equivocationproposal). - -# Cryptographic verification of equivocation -The Cryptographic verification of equivocation allows external agents to submit evidences of light client and double signing attack observed on a consumer chain. When a valid evidence is received, the malicious validators will be permanently jailed on the provider. - -The feature is outlined in this [ADR-005](../adrs/adr-005-cryptographic-equivocation-verification.md) +The feature is outlined in [ADR-005](../adrs/adr-005-cryptographic-equivocation-verification.md) and [ADR-013](../adrs/adr-013-equivocation-slashing.md). By sending a `MsgSubmitConsumerMisbehaviour` or a `MsgSubmitConsumerDoubleVoting` transaction, the provider will - verify the reported equivocation and, if successful, jail the malicious validator. - -:::info -Note that this feature can only lead to the jailing of the validators responsible for an attack on a consumer chain. However, an [equivocation proposal](#double-signing-equivocation) can still be submitted to execute the slashing and the tombstoning of the a malicious validator afterwards. -::: - - - - + verify the reported equivocation and, if successful, slash, jail, and tombstone the malicious validator. \ No newline at end of file diff --git a/docs/docs/introduction/overview.md b/docs/docs/introduction/overview.md index f61fe4d209..aba31751e1 100644 --- a/docs/docs/introduction/overview.md +++ b/docs/docs/introduction/overview.md @@ -30,10 +30,6 @@ To ensure the security of the consumer chain, provider delegators cannot unbond If downtime is initiated by a validator on a consumer chain, a downtime packet will be relayed to the provider to jail that validator for a set amount of time. The validator who committed downtime will then miss out on staking rewards for the configured jailing period. -### Equivocation (Double Sign) Slashing - -Evidence of equivocation must be submitted to provider governance and be voted on. This behavior is an extra safeguard before a validator is slashed, and may be replaced by a more automated system in the future. - ### Tokenomics and Rewards Consumer chains are free to create their own native token which can be used for fees, and can be created on the consumer chain in the form of inflationary rewards. These rewards can be used to incentivize user behavior, for example, LPing or staking. A portion of these fees and rewards will be sent to provider chain stakers, but that proportion is completely customizable by the developers, and subject to governance. diff --git a/docs/docs/validators/overview.md b/docs/docs/validators/overview.md index 35ce56cdb3..4d764703be 100644 --- a/docs/docs/validators/overview.md +++ b/docs/docs/validators/overview.md @@ -91,7 +91,7 @@ More information is available in [Downtime Slashing documentation](../features/s ::: ## Double-signing Infractions -To learn more about equivocation handling in replicated security check out the [Slashing](../features/slashing.md#double-signing-equivocation) and [EquivocationProposal](../features/proposals.md#equivocationproposal) documentation sections +To learn more about equivocation handling in replicated security check out the [Slashing](../features/slashing.md) documentation section. ## Key assignment Validators can use different consensus keys on the provider and each of the consumer chains. The consumer chain consensus key must be registered on the provider before use. diff --git a/proto/interchain_security/ccv/provider/v1/provider.proto b/proto/interchain_security/ccv/provider/v1/provider.proto index b0de16097b..229c4af0b3 100644 --- a/proto/interchain_security/ccv/provider/v1/provider.proto +++ b/proto/interchain_security/ccv/provider/v1/provider.proto @@ -12,7 +12,6 @@ import "google/protobuf/duration.proto"; import "ibc/core/client/v1/client.proto"; import "ibc/lightclients/tendermint/v1/tendermint.proto"; import "tendermint/crypto/keys.proto"; -import "cosmos/evidence/v1beta1/evidence.proto"; import "cosmos/base/v1beta1/coin.proto"; // @@ -103,19 +102,6 @@ message ConsumerRemovalProposal { [ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ]; } -// EquivocationProposal is a governance proposal on the provider chain to -// punish a validator for equivocation on a consumer chain. -// -// This type is only used internally to the consumer CCV module. -message EquivocationProposal { - // the title of the proposal - string title = 1; - // the description of the proposal - string description = 2; - // the list of equivocations that will be processed - repeated cosmos.evidence.v1beta1.Equivocation equivocations = 3; -} - // ChangeRewardDenomsProposal is a governance proposal on the provider chain to // mutate the set of denoms accepted by the provider as rewards. message ChangeRewardDenomsProposal { diff --git a/tests/e2e/action_rapid_test.go b/tests/e2e/action_rapid_test.go index ddef903d35..2ab4bd9af1 100644 --- a/tests/e2e/action_rapid_test.go +++ b/tests/e2e/action_rapid_test.go @@ -66,7 +66,6 @@ func GetActionGen() *rapid.Generator[any] { GetSubmitConsumerAdditionProposalActionGen().AsAny(), GetSubmitConsumerRemovalProposalActionGen().AsAny(), GetSubmitParamChangeProposalActionGen().AsAny(), - GetSubmitEquivocationProposalActionGen().AsAny(), GetVoteGovProposalActionGen().AsAny(), GetStartConsumerChainActionGen().AsAny(), GetAddChainToRelayerActionGen().AsAny(), @@ -279,19 +278,6 @@ func GetSubmitParamChangeProposalActionGen() *rapid.Generator[submitParamChangeL }) } -func GetSubmitEquivocationProposalActionGen() *rapid.Generator[submitEquivocationProposalAction] { - return rapid.Custom(func(t *rapid.T) submitEquivocationProposalAction { - return submitEquivocationProposalAction{ - Chain: GetChainIDGen().Draw(t, "Chain"), - From: GetValidatorIDGen().Draw(t, "From"), - Deposit: rapid.Uint().Draw(t, "Deposit"), - Height: rapid.Int64().Draw(t, "Height"), - Time: GetTimeGen().Draw(t, "Time"), - Power: rapid.Int64().Draw(t, "Power"), - } - }) -} - func TestMarshalAndUnmarshalTime(t *testing.T) { rapid.Check(t, func(t *rapid.T) { time1 := GetTimeGen().Draw(t, "time") diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index 8c7698b5c7..5c4ab5636c 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -15,8 +15,6 @@ import ( clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" "github.com/tidwall/gjson" - evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" - "github.com/cosmos/interchain-security/v3/x/ccv/provider/client" "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" @@ -432,78 +430,6 @@ func (tr TestRun) submitParamChangeProposal( tr.waitBlocks(action.Chain, 2, 60*time.Second) } -type submitEquivocationProposalAction struct { - Chain ChainID - Height int64 - Time time.Time - Power int64 - Validator ValidatorID - Deposit uint - From ValidatorID -} - -func (tr TestRun) submitEquivocationProposal(action submitEquivocationProposalAction, verbose bool) { - val := tr.validatorConfigs[action.Validator] - providerChain := tr.chainConfigs[ChainID("provi")] - - prop := client.EquivocationProposalJSON{ - Summary: "Validator equivocation!", - EquivocationProposal: types.EquivocationProposal{ - Title: "Validator equivocation!", - Description: fmt.Sprintf("Validator: %s has committed an equivocation infraction on ChainID: %s", action.Validator, action.Chain), - Equivocations: []*evidencetypes.Equivocation{ - { - Height: action.Height, - Time: action.Time, - Power: action.Power, - ConsensusAddress: val.ValconsAddress, - }, - }, - }, - Deposit: fmt.Sprint(action.Deposit) + `stake`, - } - - bz, err := json.Marshal(prop) - if err != nil { - log.Fatal(err) - } - - jsonStr := string(bz) - if strings.Contains(jsonStr, "'") { - log.Fatal("prop json contains single quote") - } - - //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - bz, err = exec.Command("docker", "exec", tr.containerConfig.InstanceName, - "/bin/bash", "-c", fmt.Sprintf(`echo '%s' > %s`, jsonStr, "/equivocation-proposal.json")).CombinedOutput() - - if err != nil { - log.Fatal(err, "\n", string(bz)) - } - - //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - // EQUIVOCATION PROPOSAL - bz, err = exec.Command("docker", "exec", tr.containerConfig.InstanceName, providerChain.BinaryName, - - "tx", "gov", "submit-legacy-proposal", "equivocation", "/equivocation-proposal.json", - - `--from`, `validator`+fmt.Sprint(action.From), - `--chain-id`, string(providerChain.ChainId), - `--home`, tr.getValidatorHome(providerChain.ChainId, action.From), - `--node`, tr.getValidatorNode(providerChain.ChainId, action.From), - `--gas`, "9000000", - `--keyring-backend`, `test`, - `-y`, - ).CombinedOutput() - - if err != nil { - log.Fatal(err, "\n", string(bz)) - } - - // wait for inclusion in a block -> '--broadcast-mode block' is deprecated - tr.waitBlocks(ChainID("provi"), 2, 30*time.Second) -} - type voteGovProposalAction struct { Chain ChainID From []ValidatorID diff --git a/tests/e2e/config.go b/tests/e2e/config.go index 89e951c400..301d2347bb 100644 --- a/tests/e2e/config.go +++ b/tests/e2e/config.go @@ -243,7 +243,7 @@ func DefaultTestRun() TestRun { func DemocracyTestRun(allowReward bool) TestRun { consumerGenChanges := ".app_state.ccvconsumer.params.blocks_per_distribution_transmission = \"20\" | " + - ".app_state.gov.voting_params.voting_period = \"10s\" | " + + ".app_state.gov.params.voting_period = \"10s\" | " + ".app_state.slashing.params.signed_blocks_window = \"10\" | " + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + ".app_state.slashing.params.downtime_jail_duration = \"60s\" | " + diff --git a/tests/e2e/json_utils.go b/tests/e2e/json_utils.go index 692c34a14f..37c463cdc4 100644 --- a/tests/e2e/json_utils.go +++ b/tests/e2e/json_utils.go @@ -95,12 +95,6 @@ func UnmarshalMapToActionType(rawAction json.RawMessage, actionTypeString string if err == nil { return a, nil } - case "main.submitEquivocationProposalAction": - var a submitEquivocationProposalAction - err := json.Unmarshal(rawAction, &a) - if err == nil { - return a, nil - } case "main.submitParamChangeLegacyProposalAction": var a submitParamChangeLegacyProposalAction err := json.Unmarshal(rawAction, &a) @@ -354,12 +348,6 @@ func UnmarshalProposalWithType(inputMap json.RawMessage, proposalType string) (P if err == nil { return prop, nil } - case "main.EquivocationProposal": - prop := EquivocationProposal{} - err := json.Unmarshal(inputMap, &prop) - if err == nil { - return prop, nil - } case "main.ParamsProposal": prop := ParamsProposal{} err := json.Unmarshal(inputMap, &prop) diff --git a/tests/e2e/main.go b/tests/e2e/main.go index 56cb25a8d1..7e45dfd764 100644 --- a/tests/e2e/main.go +++ b/tests/e2e/main.go @@ -210,8 +210,6 @@ func (tr *TestRun) runStep(step Step, verbose bool) { tr.submitConsumerAdditionProposal(action, verbose) case submitConsumerRemovalProposalAction: tr.submitConsumerRemovalProposal(action, verbose) - case submitEquivocationProposalAction: - tr.submitEquivocationProposal(action, verbose) case submitParamChangeLegacyProposalAction: tr.submitParamChangeProposal(action, verbose) case voteGovProposalAction: diff --git a/tests/e2e/state.go b/tests/e2e/state.go index 7e210552c7..4d0cc9c979 100644 --- a/tests/e2e/state.go +++ b/tests/e2e/state.go @@ -75,16 +75,6 @@ type ConsumerRemovalProposal struct { func (p ConsumerRemovalProposal) isProposal() {} -type EquivocationProposal struct { - Height uint - Power uint - ConsensusAddress string - Deposit uint - Status string -} - -func (p EquivocationProposal) isProposal() {} - type Rewards struct { IsRewarded map[ValidatorID]bool // if true it will calculate if the validator/delegator is rewarded between 2 successive blocks, @@ -469,16 +459,6 @@ func (tr TestRun) getProposal(chain ChainID, proposal uint) Proposal { Chain: chain, StopTime: int(stopTime.Milliseconds()), } - - case "/interchain_security.ccv.provider.v1.EquivocationProposal": - return EquivocationProposal{ - Deposit: uint(deposit), - Status: status, - Height: uint(gjson.Get(string(bz), `messages.0.content.equivocations.0.height`).Uint()), - Power: uint(gjson.Get(string(bz), `messages.0.content.equivocations.0.power`).Uint()), - ConsensusAddress: gjson.Get(string(bz), `messages.0.content.equivocations.0.consensus_address`).String(), - } - case "/cosmos.params.v1beta1.ParameterChangeProposal": return ParamsProposal{ Deposit: uint(deposit), diff --git a/tests/e2e/state_rapid_test.go b/tests/e2e/state_rapid_test.go index 6c82c2e7fb..9cf3c09894 100644 --- a/tests/e2e/state_rapid_test.go +++ b/tests/e2e/state_rapid_test.go @@ -174,7 +174,6 @@ func GetProposalGen() *rapid.Generator[Proposal] { gen := rapid.OneOf( GetConsumerAdditionProposalGen().AsAny(), GetConsumerRemovalProposalGen().AsAny(), - GetEquivocationProposalGen().AsAny(), GetTextProposalGen().AsAny(), GetParamsProposalGen().AsAny(), ) @@ -205,18 +204,6 @@ func GetConsumerRemovalProposalGen() *rapid.Generator[ConsumerRemovalProposal] { }) } -func GetEquivocationProposalGen() *rapid.Generator[EquivocationProposal] { - return rapid.Custom(func(t *rapid.T) EquivocationProposal { - return EquivocationProposal{ - Power: rapid.Uint().Draw(t, "Power"), - Height: rapid.Uint().Draw(t, "Height"), - ConsensusAddress: rapid.String().Draw(t, "ConesnsuAddress"), - Deposit: rapid.Uint().Draw(t, "Deposit"), - Status: rapid.String().Draw(t, "Status"), - } - }) -} - func GetTextProposalGen() *rapid.Generator[TextProposal] { return rapid.Custom(func(t *rapid.T) TextProposal { return TextProposal{ diff --git a/tests/e2e/steps.go b/tests/e2e/steps.go index 5eb5cd734b..68417f667c 100644 --- a/tests/e2e/steps.go +++ b/tests/e2e/steps.go @@ -23,12 +23,10 @@ var happyPathSteps = concatSteps( stepsDowntimeWithOptOut("consu"), stepsRedelegate("consu"), stepsDowntime("consu"), - stepsRejectEquivocationProposal("consu", 2), // prop to tombstone bob is rejected - stepsDoubleSignOnProviderAndConsumer("consu"), // carol double signs on provider, bob double signs on consumer - stepsSubmitEquivocationProposal("consu", 2), // now prop to tombstone bob is submitted and accepted + stepsDoubleSignOnProvider("consu"), // carol double signs on provider stepsStartRelayer(), - stepsConsumerRemovalPropNotPassing("consu", 3), // submit removal prop but vote no on it - chain should stay - stepsStopChain("consu", 4), // stop chain + stepsConsumerRemovalPropNotPassing("consu", 2), // submit removal prop but vote no on it - chain should stay + stepsStopChain("consu", 3), // stop chain ) var shortHappyPathSteps = concatSteps( @@ -37,9 +35,7 @@ var shortHappyPathSteps = concatSteps( stepsUnbond("consu"), stepsRedelegateShort("consu"), stepsDowntime("consu"), - stepsRejectEquivocationProposal("consu", 2), // prop to tombstone bob is rejected - stepsDoubleSignOnProviderAndConsumer("consu"), // carol double signs on provider, bob double signs on consumer - stepsSubmitEquivocationProposal("consu", 2), // now prop to tombstone bob is submitted and accepted + stepsDoubleSignOnProvider("consu"), // carol double signs on provider, bob double signs on consumer stepsStartRelayer(), stepsConsumerRemovalPropNotPassing("consu", 3), // submit removal prop but vote no on it - chain should stay stepsStopChain("consu", 4), // stop chain @@ -51,9 +47,7 @@ var lightClientAttackSteps = concatSteps( stepsUnbond("consu"), stepsRedelegateShort("consu"), stepsDowntime("consu"), - stepsRejectEquivocationProposal("consu", 2), // prop to tombstone bob is rejected stepsLightClientAttackOnProviderAndConsumer("consu"), // carol double signs on provider, bob double signs on consumer - stepsSubmitEquivocationProposal("consu", 2), // now prop to tombstone bob is submitted and accepted stepsStartRelayer(), stepsConsumerRemovalPropNotPassing("consu", 3), // submit removal prop but vote no on it - chain should stay stepsStopChain("consu", 4), // stop chain diff --git a/tests/e2e/steps_double_sign.go b/tests/e2e/steps_double_sign.go index 7e3c20a022..9d6e3c73b7 100644 --- a/tests/e2e/steps_double_sign.go +++ b/tests/e2e/steps_double_sign.go @@ -1,7 +1,7 @@ package main -// Steps that make carol double sign on the provider, and bob double sign on a single consumer -func stepsDoubleSignOnProviderAndConsumer(consumerName string) []Step { +// Steps that make carol double sign on the provider, and this power change propagates to consumer chain `consumerName` +func stepsDoubleSignOnProvider(consumerName string) []Step { return []Step{ { // provider double sign @@ -52,80 +52,6 @@ func stepsDoubleSignOnProviderAndConsumer(consumerName string) []Step { }, }, }, - { - // consumer double sign - // provider will only log the double sign slash - // stepsSubmitEquivocationProposal will cause the double sign slash to be executed - Action: doublesignSlashAction{ - Chain: ChainID("consu"), - Validator: ValidatorID("bob"), - }, - State: State{ - ChainID("provi"): ChainState{ - ValPowers: &map[ValidatorID]uint{ - ValidatorID("alice"): 509, - ValidatorID("bob"): 500, - ValidatorID("carol"): 0, - }, - }, - ChainID(consumerName): ChainState{ - ValPowers: &map[ValidatorID]uint{ - ValidatorID("alice"): 509, - ValidatorID("bob"): 500, - ValidatorID("carol"): 0, - }, - }, - }, - }, - { - Action: relayPacketsAction{ - ChainA: ChainID("provi"), - ChainB: ChainID(consumerName), - Port: "provider", - Channel: 0, - }, - State: State{ - ChainID("provi"): ChainState{ - ValPowers: &map[ValidatorID]uint{ - ValidatorID("alice"): 509, - ValidatorID("bob"): 500, // not tombstoned - ValidatorID("carol"): 0, - }, - }, - ChainID(consumerName): ChainState{ - ValPowers: &map[ValidatorID]uint{ - ValidatorID("alice"): 509, - ValidatorID("bob"): 500, // not tombstoned - ValidatorID("carol"): 0, - }, - }, - }, - }, - { - // consumer learns about the double sign - Action: relayPacketsAction{ - ChainA: ChainID("provi"), - ChainB: ChainID(consumerName), - Port: "provider", - Channel: 0, - }, - State: State{ - ChainID("provi"): ChainState{ - ValPowers: &map[ValidatorID]uint{ - ValidatorID("alice"): 509, - ValidatorID("bob"): 500, - ValidatorID("carol"): 0, - }, - }, - ChainID(consumerName): ChainState{ - ValPowers: &map[ValidatorID]uint{ - ValidatorID("alice"): 509, - ValidatorID("bob"): 500, // not tombstoned - ValidatorID("carol"): 0, - }, - }, - }, - }, } } diff --git a/tests/e2e/steps_light_client_attack.go b/tests/e2e/steps_light_client_attack.go index 284b3fafea..1d9f484b5c 100644 --- a/tests/e2e/steps_light_client_attack.go +++ b/tests/e2e/steps_light_client_attack.go @@ -55,7 +55,6 @@ func stepsLightClientAttackOnProviderAndConsumer(consumerName string) []Step { { // Consumer double sign // Provider will only log the double sign slash - // stepsSubmitEquivocationProposal will cause the double sign slash to be executed Action: lightClientEquivocationAttackAction{ Chain: ChainID(consumerName), Validator: ValidatorID("bob"), diff --git a/tests/e2e/steps_submit_equivocation_proposal.go b/tests/e2e/steps_submit_equivocation_proposal.go deleted file mode 100644 index 243c01f04d..0000000000 --- a/tests/e2e/steps_submit_equivocation_proposal.go +++ /dev/null @@ -1,150 +0,0 @@ -package main - -import "time" - -// submits an invalid equivocation proposal which should be rejected -func stepsRejectEquivocationProposal(consumerName string, propNumber uint) []Step { - return []Step{ - { - // bob submits a proposal to slash himself - Action: submitEquivocationProposalAction{ - Chain: ChainID("consu"), - From: ValidatorID("bob"), - Deposit: 10000001, - Height: 10, - Time: time.Now(), - Power: 500, - Validator: ValidatorID("bob"), - }, - State: State{ - ChainID("provi"): ChainState{ - ValPowers: &map[ValidatorID]uint{ - ValidatorID("alice"): 509, - ValidatorID("bob"): 500, - ValidatorID("carol"): 495, - }, - ValBalances: &map[ValidatorID]uint{ - ValidatorID("bob"): 9500000000, - }, - Proposals: &map[uint]Proposal{ - // proposal does not exist - propNumber: TextProposal{}, - }, - }, - ChainID(consumerName): ChainState{ - ValPowers: &map[ValidatorID]uint{ - ValidatorID("alice"): 509, - ValidatorID("bob"): 500, - ValidatorID("carol"): 495, - }, - }, - }, - }, - } -} - -// submits an equivocation proposal, votes on it, and tomstones the equivocating validator -func stepsSubmitEquivocationProposal(consumerName string, propNumber uint) []Step { - s := []Step{ - { - // bob submits a proposal to slash himself - Action: submitEquivocationProposalAction{ - Chain: ChainID("consu"), - From: ValidatorID("bob"), - Deposit: 10000001, - Height: 10, - Time: time.Now(), // not sure what time in equivocations means - Power: 500, - Validator: ValidatorID("bob"), - }, - State: State{ - ChainID("provi"): ChainState{ - ValPowers: &map[ValidatorID]uint{ - ValidatorID("alice"): 509, - ValidatorID("bob"): 500, - ValidatorID("carol"): 0, - }, - ValBalances: &map[ValidatorID]uint{ - ValidatorID("bob"): 9489999999, - }, - Proposals: &map[uint]Proposal{ - propNumber: EquivocationProposal{ - Deposit: 10000001, - Status: "PROPOSAL_STATUS_VOTING_PERIOD", - ConsensusAddress: "cosmosvalcons1nx7n5uh0ztxsynn4sje6eyq2ud6rc6klc96w39", - Power: 500, - Height: 10, - }, - }, - }, - ChainID(consumerName): ChainState{ - ValPowers: &map[ValidatorID]uint{ - ValidatorID("alice"): 509, - ValidatorID("bob"): 500, - ValidatorID("carol"): 0, - }, - }, - }, - }, - { - Action: voteGovProposalAction{ - Chain: ChainID("provi"), - From: []ValidatorID{ValidatorID("alice"), ValidatorID("bob"), ValidatorID("carol")}, - Vote: []string{"yes", "yes", "yes"}, - PropNumber: propNumber, - }, - State: State{ - ChainID("provi"): ChainState{ - ValPowers: &map[ValidatorID]uint{ - ValidatorID("alice"): 509, - ValidatorID("bob"): 0, // bob is tombstoned after proposal passes - ValidatorID("carol"): 0, - }, - Proposals: &map[uint]Proposal{ - propNumber: EquivocationProposal{ - Deposit: 10000001, - Status: "PROPOSAL_STATUS_PASSED", - ConsensusAddress: "cosmosvalcons1nx7n5uh0ztxsynn4sje6eyq2ud6rc6klc96w39", - Power: 500, - Height: 10, - }, - }, - }, - ChainID(consumerName): ChainState{ - ValPowers: &map[ValidatorID]uint{ - ValidatorID("alice"): 509, - ValidatorID("bob"): 500, // slash not reflected in consumer chain - ValidatorID("carol"): 0, - }, - }, - }, - }, - { - // relay power change to consumer1 - Action: relayPacketsAction{ - ChainA: ChainID("provi"), - ChainB: ChainID(consumerName), - Port: "provider", - Channel: 0, - }, - State: State{ - ChainID("provi"): ChainState{ - ValPowers: &map[ValidatorID]uint{ - ValidatorID("alice"): 509, - ValidatorID("bob"): 0, - ValidatorID("carol"): 0, - }, - }, - ChainID(consumerName): ChainState{ - ValPowers: &map[ValidatorID]uint{ - ValidatorID("alice"): 509, - ValidatorID("bob"): 0, // slash relayed to consumer chain - ValidatorID("carol"): 0, - }, - }, - }, - }, - } - - return s -} diff --git a/tests/e2e/trace_handlers_test.go b/tests/e2e/trace_handlers_test.go index 725496c51f..439b68ccad 100644 --- a/tests/e2e/trace_handlers_test.go +++ b/tests/e2e/trace_handlers_test.go @@ -159,25 +159,6 @@ func TestMarshalAndUnmarshalChainState(t *testing.T) { 10: TextProposal{}, }, }}, - "equivocation-proposal": {ChainState{ - ValPowers: &map[ValidatorID]uint{ - ValidatorID("alice"): 509, - ValidatorID("bob"): 500, - ValidatorID("carol"): 0, - }, - ValBalances: &map[ValidatorID]uint{ - ValidatorID("bob"): 9489999999, - }, - Proposals: &map[uint]Proposal{ - 5: EquivocationProposal{ - Deposit: 10000001, - Status: "PROPOSAL_STATUS_VOTING_PERIOD", - ConsensusAddress: "cosmosvalcons1nx7n5uh0ztxsynn4sje6eyq2ud6rc6klc96w39", - Power: 500, - Height: 10, - }, - }, - }}, } for name, tc := range tests { diff --git a/testutil/keeper/mocks.go b/testutil/keeper/mocks.go index 7279a5cb91..0311873349 100644 --- a/testutil/keeper/mocks.go +++ b/testutil/keeper/mocks.go @@ -14,13 +14,12 @@ 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/evidence/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" + 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" exported "github.com/cosmos/ibc-go/v7/modules/core/exported" gomock "github.com/golang/mock/gomock" ) @@ -63,10 +62,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) types5.DelegationI { +func (m *MockStakingKeeper) Delegation(ctx types0.Context, addr types0.AccAddress, valAddr types0.ValAddress) types4.DelegationI { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Delegation", ctx, addr, valAddr) - ret0, _ := ret[0].(types5.DelegationI) + ret0, _ := ret[0].(types4.DelegationI) return ret0 } @@ -105,10 +104,10 @@ func (mr *MockStakingKeeperMockRecorder) GetLastValidatorPower(ctx, operator int } // GetLastValidators mocks base method. -func (m *MockStakingKeeper) GetLastValidators(ctx types0.Context) []types5.Validator { +func (m *MockStakingKeeper) GetLastValidators(ctx types0.Context) []types4.Validator { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetLastValidators", ctx) - ret0, _ := ret[0].([]types5.Validator) + ret0, _ := ret[0].([]types4.Validator) return ret0 } @@ -119,10 +118,10 @@ func (mr *MockStakingKeeperMockRecorder) GetLastValidators(ctx interface{}) *gom } // GetUnbondingType mocks base method. -func (m *MockStakingKeeper) GetUnbondingType(ctx types0.Context, id uint64) (types5.UnbondingType, bool) { +func (m *MockStakingKeeper) GetUnbondingType(ctx types0.Context, id uint64) (types4.UnbondingType, bool) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetUnbondingType", ctx, id) - ret0, _ := ret[0].(types5.UnbondingType) + ret0, _ := ret[0].(types4.UnbondingType) ret1, _ := ret[1].(bool) return ret0, ret1 } @@ -134,10 +133,10 @@ func (mr *MockStakingKeeperMockRecorder) GetUnbondingType(ctx, id interface{}) * } // GetValidator mocks base method. -func (m *MockStakingKeeper) GetValidator(ctx types0.Context, addr types0.ValAddress) (types5.Validator, bool) { +func (m *MockStakingKeeper) GetValidator(ctx types0.Context, addr types0.ValAddress) (types4.Validator, bool) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetValidator", ctx, addr) - ret0, _ := ret[0].(types5.Validator) + ret0, _ := ret[0].(types4.Validator) ret1, _ := ret[1].(bool) return ret0, ret1 } @@ -149,10 +148,10 @@ func (mr *MockStakingKeeperMockRecorder) GetValidator(ctx, addr interface{}) *go } // GetValidatorByConsAddr mocks base method. -func (m *MockStakingKeeper) GetValidatorByConsAddr(ctx types0.Context, consAddr types0.ConsAddress) (types5.Validator, bool) { +func (m *MockStakingKeeper) GetValidatorByConsAddr(ctx types0.Context, consAddr types0.ConsAddress) (types4.Validator, bool) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetValidatorByConsAddr", ctx, consAddr) - ret0, _ := ret[0].(types5.Validator) + ret0, _ := ret[0].(types4.Validator) ret1, _ := ret[1].(bool) return ret0, ret1 } @@ -204,7 +203,7 @@ func (mr *MockStakingKeeperMockRecorder) IterateLastValidatorPowers(ctx, cb inte } // IterateValidators mocks base method. -func (m *MockStakingKeeper) IterateValidators(ctx types0.Context, f func(int64, types5.ValidatorI) bool) { +func (m *MockStakingKeeper) IterateValidators(ctx types0.Context, f func(int64, types4.ValidatorI) bool) { m.ctrl.T.Helper() m.ctrl.Call(m, "IterateValidators", ctx, f) } @@ -284,7 +283,7 @@ func (mr *MockStakingKeeperMockRecorder) Slash(arg0, arg1, arg2, arg3, arg4 inte } // SlashWithInfractionReason mocks base method. -func (m *MockStakingKeeper) SlashWithInfractionReason(arg0 types0.Context, arg1 types0.ConsAddress, arg2, arg3 int64, arg4 types0.Dec, arg5 types5.Infraction) math.Int { +func (m *MockStakingKeeper) SlashWithInfractionReason(arg0 types0.Context, arg1 types0.ConsAddress, arg2, arg3 int64, arg4 types0.Dec, arg5 types4.Infraction) math.Int { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SlashWithInfractionReason", arg0, arg1, arg2, arg3, arg4, arg5) ret0, _ := ret[0].(math.Int) @@ -338,10 +337,10 @@ func (mr *MockStakingKeeperMockRecorder) Unjail(ctx, addr interface{}) *gomock.C } // Validator mocks base method. -func (m *MockStakingKeeper) Validator(ctx types0.Context, addr types0.ValAddress) types5.ValidatorI { +func (m *MockStakingKeeper) Validator(ctx types0.Context, addr types0.ValAddress) types4.ValidatorI { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Validator", ctx, addr) - ret0, _ := ret[0].(types5.ValidatorI) + ret0, _ := ret[0].(types4.ValidatorI) return ret0 } @@ -352,10 +351,10 @@ func (mr *MockStakingKeeperMockRecorder) Validator(ctx, addr interface{}) *gomoc } // ValidatorByConsAddr mocks base method. -func (m *MockStakingKeeper) ValidatorByConsAddr(ctx types0.Context, consAddr types0.ConsAddress) types5.ValidatorI { +func (m *MockStakingKeeper) ValidatorByConsAddr(ctx types0.Context, consAddr types0.ConsAddress) types4.ValidatorI { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ValidatorByConsAddr", ctx, consAddr) - ret0, _ := ret[0].(types5.ValidatorI) + ret0, _ := ret[0].(types4.ValidatorI) return ret0 } @@ -365,41 +364,6 @@ func (mr *MockStakingKeeperMockRecorder) ValidatorByConsAddr(ctx, consAddr inter return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidatorByConsAddr", reflect.TypeOf((*MockStakingKeeper)(nil).ValidatorByConsAddr), ctx, consAddr) } -// MockEvidenceKeeper is a mock of EvidenceKeeper interface. -type MockEvidenceKeeper struct { - ctrl *gomock.Controller - recorder *MockEvidenceKeeperMockRecorder -} - -// MockEvidenceKeeperMockRecorder is the mock recorder for MockEvidenceKeeper. -type MockEvidenceKeeperMockRecorder struct { - mock *MockEvidenceKeeper -} - -// NewMockEvidenceKeeper creates a new mock instance. -func NewMockEvidenceKeeper(ctrl *gomock.Controller) *MockEvidenceKeeper { - mock := &MockEvidenceKeeper{ctrl: ctrl} - mock.recorder = &MockEvidenceKeeperMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockEvidenceKeeper) EXPECT() *MockEvidenceKeeperMockRecorder { - return m.recorder -} - -// HandleEquivocationEvidence mocks base method. -func (m *MockEvidenceKeeper) HandleEquivocationEvidence(ctx types0.Context, evidence *types3.Equivocation) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "HandleEquivocationEvidence", ctx, evidence) -} - -// HandleEquivocationEvidence indicates an expected call of HandleEquivocationEvidence. -func (mr *MockEvidenceKeeperMockRecorder) HandleEquivocationEvidence(ctx, evidence interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandleEquivocationEvidence", reflect.TypeOf((*MockEvidenceKeeper)(nil).HandleEquivocationEvidence), ctx, evidence) -} - // MockSlashingKeeper is a mock of SlashingKeeper interface. type MockSlashingKeeper struct { ctrl *gomock.Controller @@ -438,10 +402,10 @@ func (mr *MockSlashingKeeperMockRecorder) DowntimeJailDuration(arg0 interface{}) } // GetValidatorSigningInfo mocks base method. -func (m *MockSlashingKeeper) GetValidatorSigningInfo(ctx types0.Context, address types0.ConsAddress) (types4.ValidatorSigningInfo, bool) { +func (m *MockSlashingKeeper) GetValidatorSigningInfo(ctx types0.Context, address types0.ConsAddress) (types3.ValidatorSigningInfo, bool) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetValidatorSigningInfo", ctx, address) - ret0, _ := ret[0].(types4.ValidatorSigningInfo) + ret0, _ := ret[0].(types3.ValidatorSigningInfo) ret1, _ := ret[1].(bool) return ret0, ret1 } @@ -556,10 +520,10 @@ func (mr *MockChannelKeeperMockRecorder) ChanCloseInit(ctx, portID, channelID, c } // GetChannel mocks base method. -func (m *MockChannelKeeper) GetChannel(ctx types0.Context, srcPort, srcChan string) (types9.Channel, bool) { +func (m *MockChannelKeeper) GetChannel(ctx types0.Context, srcPort, srcChan string) (types8.Channel, bool) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetChannel", ctx, srcPort, srcChan) - ret0, _ := ret[0].(types9.Channel) + ret0, _ := ret[0].(types8.Channel) ret1, _ := ret[1].(bool) return ret0, ret1 } @@ -602,7 +566,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 types7.Height, timeoutTimestamp uint64, data []byte) (uint64, error) { +func (m *MockChannelKeeper) SendPacket(ctx types0.Context, chanCap *types2.Capability, sourcePort, sourceChannel string, timeoutHeight types6.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) @@ -691,10 +655,10 @@ func (m *MockConnectionKeeper) EXPECT() *MockConnectionKeeperMockRecorder { } // GetConnection mocks base method. -func (m *MockConnectionKeeper) GetConnection(ctx types0.Context, connectionID string) (types8.ConnectionEnd, bool) { +func (m *MockConnectionKeeper) GetConnection(ctx types0.Context, connectionID string) (types7.ConnectionEnd, bool) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetConnection", ctx, connectionID) - ret0, _ := ret[0].(types8.ConnectionEnd) + ret0, _ := ret[0].(types7.ConnectionEnd) ret1, _ := ret[1].(bool) return ret0, ret1 } @@ -1029,10 +993,10 @@ func (m *MockIBCTransferKeeper) EXPECT() *MockIBCTransferKeeperMockRecorder { } // Transfer mocks base method. -func (m *MockIBCTransferKeeper) Transfer(arg0 context.Context, arg1 *types6.MsgTransfer) (*types6.MsgTransferResponse, error) { +func (m *MockIBCTransferKeeper) Transfer(arg0 context.Context, arg1 *types5.MsgTransfer) (*types5.MsgTransferResponse, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Transfer", arg0, arg1) - ret0, _ := ret[0].(*types6.MsgTransferResponse) + ret0, _ := ret[0].(*types5.MsgTransferResponse) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -1067,10 +1031,10 @@ func (m *MockIBCCoreKeeper) EXPECT() *MockIBCCoreKeeperMockRecorder { } // ChannelOpenInit mocks base method. -func (m *MockIBCCoreKeeper) ChannelOpenInit(goCtx context.Context, msg *types9.MsgChannelOpenInit) (*types9.MsgChannelOpenInitResponse, error) { +func (m *MockIBCCoreKeeper) ChannelOpenInit(goCtx context.Context, msg *types8.MsgChannelOpenInit) (*types8.MsgChannelOpenInitResponse, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ChannelOpenInit", goCtx, msg) - ret0, _ := ret[0].(*types9.MsgChannelOpenInitResponse) + ret0, _ := ret[0].(*types8.MsgChannelOpenInitResponse) ret1, _ := ret[1].(error) return ret0, ret1 } diff --git a/testutil/keeper/unit_test_helpers.go b/testutil/keeper/unit_test_helpers.go index b58d6d2471..e35b02b4f8 100644 --- a/testutil/keeper/unit_test_helpers.go +++ b/testutil/keeper/unit_test_helpers.go @@ -87,7 +87,6 @@ type MockedKeepers struct { *MockBankKeeper *MockIBCTransferKeeper *MockIBCCoreKeeper - *MockEvidenceKeeper *MockDistributionKeeper } @@ -105,7 +104,6 @@ func NewMockedKeepers(ctrl *gomock.Controller) MockedKeepers { MockBankKeeper: NewMockBankKeeper(ctrl), MockIBCTransferKeeper: NewMockIBCTransferKeeper(ctrl), MockIBCCoreKeeper: NewMockIBCCoreKeeper(ctrl), - MockEvidenceKeeper: NewMockEvidenceKeeper(ctrl), MockDistributionKeeper: NewMockDistributionKeeper(ctrl), } } @@ -124,7 +122,6 @@ func NewInMemProviderKeeper(params InMemKeeperParams, mocks MockedKeepers) provi mocks.MockStakingKeeper, mocks.MockSlashingKeeper, mocks.MockAccountKeeper, - mocks.MockEvidenceKeeper, mocks.MockDistributionKeeper, mocks.MockBankKeeper, authtypes.FeeCollectorName, diff --git a/x/ccv/provider/client/proposal_handler.go b/x/ccv/provider/client/proposal_handler.go index 2b28c63466..0e18048bce 100644 --- a/x/ccv/provider/client/proposal_handler.go +++ b/x/ccv/provider/client/proposal_handler.go @@ -26,7 +26,6 @@ import ( var ( ConsumerAdditionProposalHandler = govclient.NewProposalHandler(SubmitConsumerAdditionPropTxCmd) ConsumerRemovalProposalHandler = govclient.NewProposalHandler(SubmitConsumerRemovalProposalTxCmd) - EquivocationProposalHandler = govclient.NewProposalHandler(SubmitEquivocationProposalTxCmd) ChangeRewardDenomsProposalHandler = govclient.NewProposalHandler(SubmitChangeRewardDenomsProposalTxCmd) ) @@ -167,69 +166,6 @@ Where proposal.json contains: } } -// SubmitEquivocationProposalTxCmd returns a CLI command handler for submitting -// a equivocation proposal via a transaction. -func SubmitEquivocationProposalTxCmd() *cobra.Command { - return &cobra.Command{ - Use: "equivocation [proposal-file]", - Args: cobra.ExactArgs(1), - Short: "Submit an equivocation proposal", - Long: fmt.Sprintf(`Submit an equivocation proposal along with an initial deposit. -The proposal details must be supplied via a JSON file. - -Example: -$ tx gov submit-legacy-proposal equivocation --from= - -Where proposal.json contains: -{ - "title": "Equivoque Foo validator", - "summary": "He double-signs on the Foobar consumer chain", - "equivocations": [ - { - "height": 10420042, - "time": "2023-01-27T15:59:50.121607-08:00", - "power": 10, - "consensus_address": "%s1s5afhd6gxevu37mkqcvvsj8qeylhn0rz46zdlq" - } - ], - "deposit": "10000stake" -} -`, sdk.GetConfig().GetBech32ConsensusAddrPrefix()), - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - proposal, err := ParseEquivocationProposalJSON(args[0]) - if err != nil { - return err - } - - content := types.NewEquivocationProposal(proposal.Title, proposal.Summary, proposal.Equivocations) - - from := clientCtx.GetFromAddress() - - msgContent, err := govv1.NewLegacyContent(content, authtypes.NewModuleAddress(govtypes.ModuleName).String()) - if err != nil { - return err - } - - deposit, err := sdk.ParseCoinsNormalized(proposal.Deposit) - if err != nil { - return err - } - - msg, err := govv1.NewMsgSubmitProposal([]sdk.Msg{msgContent}, deposit, from.String(), "", content.GetTitle(), proposal.Summary) - if err != nil { - return err - } - - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) - }, - } -} - // SubmitChangeRewardDenomsProposalTxCmd returns a CLI command handler for submitting // a change reward denoms proposal via a transaction. func SubmitChangeRewardDenomsProposalTxCmd() *cobra.Command { @@ -378,38 +314,6 @@ func ParseConsumerRemovalProposalJSON(proposalFile string) (ConsumerRemovalPropo return proposal, nil } -type EquivocationProposalJSON struct { - // evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" - Summary string `json:"summary"` - types.EquivocationProposal - - Deposit string `json:"deposit"` -} - -type EquivocationProposalReq struct { - Proposer sdk.AccAddress `json:"proposer"` - - // evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" - types.EquivocationProposal - - Deposit sdk.Coins `json:"deposit"` -} - -func ParseEquivocationProposalJSON(proposalFile string) (EquivocationProposalJSON, error) { - proposal := EquivocationProposalJSON{} - - contents, err := os.ReadFile(filepath.Clean(proposalFile)) - if err != nil { - return proposal, err - } - - if err := json.Unmarshal(contents, &proposal); err != nil { - return proposal, err - } - - return proposal, nil -} - type ChangeRewardDenomsProposalJSON struct { Summary string `json:"summary"` types.ChangeRewardDenomsProposal @@ -536,33 +440,8 @@ func postConsumerRemovalProposalHandlerFn(clientCtx client.Context) http.Handler } } -func postEquivocationProposalHandlerFn(clientCtx client.Context) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - var req EquivocationProposalReq - if !rest.ReadRESTReq(w, r, clientCtx.LegacyAmino, &req) { - return - } - - req.BaseReq = req.BaseReq.Sanitize() - if !req.BaseReq.ValidateBasic(w) { - return - } - - content := types.NewEquivocationProposal(req.Title, req.Description, req.Equivocations) - - msg, err := govtypes.NewMsgSubmitProposal(content, req.Deposit, req.Proposer) - if rest.CheckBadRequestError(w, err) { - return - } - - if rest.CheckBadRequestError(w, msg.ValidateBasic()) { - return - } - - tx.WriteGeneratedTxResponse(clientCtx, w, req.BaseReq, msg) - } -} - +func CheckPropUnbondingPeriod(clientCtx client.Context, propUnbondingPeriod time.Duration) { + queryClient := stakingtypes.NewQueryClient(clientCtx) */ diff --git a/x/ccv/provider/keeper/keeper.go b/x/ccv/provider/keeper/keeper.go index e9bb1d1bd0..428f8a0f8d 100644 --- a/x/ccv/provider/keeper/keeper.go +++ b/x/ccv/provider/keeper/keeper.go @@ -41,7 +41,6 @@ type Keeper struct { clientKeeper ccv.ClientKeeper stakingKeeper ccv.StakingKeeper slashingKeeper ccv.SlashingKeeper - evidenceKeeper ccv.EvidenceKeeper distributionKeeper ccv.DistributionKeeper bankKeeper ccv.BankKeeper feeCollectorName string @@ -53,8 +52,8 @@ func NewKeeper( channelKeeper ccv.ChannelKeeper, portKeeper ccv.PortKeeper, connectionKeeper ccv.ConnectionKeeper, clientKeeper ccv.ClientKeeper, stakingKeeper ccv.StakingKeeper, slashingKeeper ccv.SlashingKeeper, - accountKeeper ccv.AccountKeeper, evidenceKeeper ccv.EvidenceKeeper, - distributionKeeper ccv.DistributionKeeper, bankKeeper ccv.BankKeeper, + accountKeeper ccv.AccountKeeper, distributionKeeper ccv.DistributionKeeper, + bankKeeper ccv.BankKeeper, feeCollectorName string, ) Keeper { // set KeyTable if it has not already been set @@ -74,7 +73,6 @@ func NewKeeper( stakingKeeper: stakingKeeper, slashingKeeper: slashingKeeper, accountKeeper: accountKeeper, - evidenceKeeper: evidenceKeeper, distributionKeeper: distributionKeeper, bankKeeper: bankKeeper, feeCollectorName: feeCollectorName, @@ -94,8 +92,8 @@ func (k *Keeper) SetParamSpace(ctx sdk.Context, ps paramtypes.Subspace) { // non-nil values for all its fields. Otherwise this method will panic. func (k Keeper) mustValidateFields() { // Ensures no fields are missed in this validation - if reflect.ValueOf(k).NumField() != 15 { - panic("number of fields in provider keeper is not 15") + if reflect.ValueOf(k).NumField() != 14 { + panic("number of fields in provider keeper is not 14") } ccv.PanicIfZeroOrNil(k.cdc, "cdc") // 1 @@ -109,10 +107,9 @@ func (k Keeper) mustValidateFields() { ccv.PanicIfZeroOrNil(k.clientKeeper, "clientKeeper") // 9 ccv.PanicIfZeroOrNil(k.stakingKeeper, "stakingKeeper") // 10 ccv.PanicIfZeroOrNil(k.slashingKeeper, "slashingKeeper") // 11 - ccv.PanicIfZeroOrNil(k.evidenceKeeper, "evidenceKeeper") // 12 - ccv.PanicIfZeroOrNil(k.distributionKeeper, "distributionKeeper") // 13 - ccv.PanicIfZeroOrNil(k.bankKeeper, "bankKeeper") // 14 - ccv.PanicIfZeroOrNil(k.feeCollectorName, "feeCollectorName") // 15 + ccv.PanicIfZeroOrNil(k.distributionKeeper, "distributionKeeper") // 12 + ccv.PanicIfZeroOrNil(k.bankKeeper, "bankKeeper") // 13 + ccv.PanicIfZeroOrNil(k.feeCollectorName, "feeCollectorName") // 14 } // Logger returns a module-specific logger. diff --git a/x/ccv/provider/keeper/proposal.go b/x/ccv/provider/keeper/proposal.go index 7ea7433770..a903372056 100644 --- a/x/ccv/provider/keeper/proposal.go +++ b/x/ccv/provider/keeper/proposal.go @@ -605,18 +605,6 @@ func (k Keeper) StopConsumerChainInCachedCtx(ctx sdk.Context, p types.ConsumerRe return } -// HandleEquivocationProposal handles an equivocation proposal. -// Proposal will be accepted if a record in the SlashLog exists for a given validator address. -func (k Keeper) HandleEquivocationProposal(ctx sdk.Context, p *types.EquivocationProposal) error { - for _, ev := range p.Equivocations { - if !k.GetSlashLog(ctx, types.NewProviderConsAddress(ev.GetConsensusAddress())) { - return fmt.Errorf("no equivocation record found for validator %s", ev.GetConsensusAddress().String()) - } - k.evidenceKeeper.HandleEquivocationEvidence(ctx, ev) - } - return nil -} - func (k Keeper) HandleConsumerRewardDenomProposal(ctx sdk.Context, p *types.ChangeRewardDenomsProposal) error { for _, denomToAdd := range p.DenomsToAdd { // Log error and move on if one of the denoms is already registered diff --git a/x/ccv/provider/keeper/proposal_test.go b/x/ccv/provider/keeper/proposal_test.go index 135e16eaae..e6986ebf21 100644 --- a/x/ccv/provider/keeper/proposal_test.go +++ b/x/ccv/provider/keeper/proposal_test.go @@ -14,7 +14,6 @@ import ( "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" - evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" abci "github.com/cometbft/cometbft/abci/types" @@ -1094,63 +1093,3 @@ func TestBeginBlockCCR(t *testing.T) { ctx, invalidProp.ChainId, invalidProp.StopTime) require.False(t, found) } - -func TestHandleEquivocationProposal(t *testing.T) { - equivocations := []*evidencetypes.Equivocation{ - { - Time: time.Now(), - Height: 1, - Power: 1, - ConsensusAddress: "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk", - }, - { - Time: time.Now(), - Height: 1, - Power: 1, - ConsensusAddress: "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6", - }, - } - - prop := &providertypes.EquivocationProposal{ - Equivocations: []*evidencetypes.Equivocation{equivocations[0], equivocations[1]}, - } - - testCases := []struct { - name string - setSlashLogs bool - expectEquivsHandled bool - expectErr bool - }{ - {name: "slash logs not set", setSlashLogs: false, expectEquivsHandled: false, expectErr: true}, - {name: "slash logs set", setSlashLogs: true, expectEquivsHandled: true, expectErr: false}, - } - for _, tc := range testCases { - - keeperParams := testkeeper.NewInMemKeeperParams(t) - keeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, keeperParams) - - if tc.setSlashLogs { - // Set slash logs according to cons addrs in equivocations - consAddr := equivocations[0].GetConsensusAddress() - require.NotNil(t, consAddr, "consensus address could not be parsed") - keeper.SetSlashLog(ctx, providertypes.NewProviderConsAddress(consAddr)) - consAddr = equivocations[1].GetConsensusAddress() - require.NotNil(t, consAddr, "consensus address could not be parsed") - keeper.SetSlashLog(ctx, providertypes.NewProviderConsAddress(consAddr)) - } - - if tc.expectEquivsHandled { - mocks.MockEvidenceKeeper.EXPECT().HandleEquivocationEvidence(ctx, equivocations[0]) - mocks.MockEvidenceKeeper.EXPECT().HandleEquivocationEvidence(ctx, equivocations[1]) - } - - err := keeper.HandleEquivocationProposal(ctx, prop) - - if tc.expectErr { - require.Error(t, err) - } else { - require.NoError(t, err) - } - ctrl.Finish() - } -} diff --git a/x/ccv/provider/proposal_handler.go b/x/ccv/provider/proposal_handler.go index 7af7ec4e5f..b5bd4a6597 100644 --- a/x/ccv/provider/proposal_handler.go +++ b/x/ccv/provider/proposal_handler.go @@ -12,7 +12,7 @@ import ( ) // NewProviderProposalHandler defines the handler for consumer addition, -// consumer removal and equivocation proposals. +// consumer removal, and consumer reward denom proposals. // Passed proposals are executed during EndBlock. func NewProviderProposalHandler(k keeper.Keeper) govv1beta1.Handler { return func(ctx sdk.Context, content govv1beta1.Content) error { @@ -21,8 +21,6 @@ func NewProviderProposalHandler(k keeper.Keeper) govv1beta1.Handler { return k.HandleConsumerAdditionProposal(ctx, c) case *types.ConsumerRemovalProposal: return k.HandleConsumerRemovalProposal(ctx, c) - case *types.EquivocationProposal: - return k.HandleEquivocationProposal(ctx, c) case *types.ChangeRewardDenomsProposal: return k.HandleConsumerRewardDenomProposal(ctx, c) default: diff --git a/x/ccv/provider/proposal_handler_test.go b/x/ccv/provider/proposal_handler_test.go index 8f1322b3d2..7e4d586097 100644 --- a/x/ccv/provider/proposal_handler_test.go +++ b/x/ccv/provider/proposal_handler_test.go @@ -10,7 +10,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" - evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" @@ -19,12 +18,11 @@ import ( ) // TestProviderProposalHandler tests the highest level handler for proposals -// concerning creating, stopping consumer chains and submitting equivocations. +// concerning creating, stopping consumer chains and changing reward denom. func TestProviderProposalHandler(t *testing.T) { // Snapshot times asserted in tests now := time.Now().UTC() hourFromNow := now.Add(time.Hour).UTC() - equivocation := &evidencetypes.Equivocation{Height: 42} testCases := []struct { name string @@ -32,7 +30,6 @@ func TestProviderProposalHandler(t *testing.T) { blockTime time.Time expValidConsumerAddition bool expValidConsumerRemoval bool - expValidEquivocation bool expValidChangeRewardDenom bool }{ { @@ -58,21 +55,6 @@ func TestProviderProposalHandler(t *testing.T) { blockTime: hourFromNow, expValidConsumerRemoval: true, }, - { - // no slash log for equivocation - name: "invalid equivocation proposal", - content: providertypes.NewEquivocationProposal( - "title", "description", []*evidencetypes.Equivocation{equivocation}), - blockTime: hourFromNow, - expValidEquivocation: false, - }, - { - name: "valid equivocation proposal", - content: providertypes.NewEquivocationProposal( - "title", "description", []*evidencetypes.Equivocation{equivocation}), - blockTime: hourFromNow, - expValidEquivocation: true, - }, { name: "valid change reward denoms proposal", content: providertypes.NewChangeRewardDenomsProposal( @@ -118,10 +100,6 @@ func TestProviderProposalHandler(t *testing.T) { // assert mocks for expected calls to `StopConsumerChain` when closing the underlying channel gomock.InOrder(testkeeper.GetMocksForStopConsumerChainWithCloseChannel(ctx, &mocks)...) - - case tc.expValidEquivocation: - providerKeeper.SetSlashLog(ctx, providertypes.NewProviderConsAddress(equivocation.GetConsensusAddress())) - mocks.MockEvidenceKeeper.EXPECT().HandleEquivocationEvidence(ctx, equivocation) case tc.expValidChangeRewardDenom: // Nothing to mock } @@ -131,7 +109,7 @@ func TestProviderProposalHandler(t *testing.T) { err := proposalHandler(ctx, tc.content) if tc.expValidConsumerAddition || tc.expValidConsumerRemoval || - tc.expValidEquivocation || tc.expValidChangeRewardDenom { + tc.expValidChangeRewardDenom { require.NoError(t, err) } else { require.Error(t, err) diff --git a/x/ccv/provider/types/codec.go b/x/ccv/provider/types/codec.go index 8208fd68c5..59f3d51ee6 100644 --- a/x/ccv/provider/types/codec.go +++ b/x/ccv/provider/types/codec.go @@ -27,11 +27,6 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { (*sdk.Msg)(nil), &MsgAssignConsumerKey{}, ) - registry.RegisterImplementations( - (*govv1beta1.Content)(nil), - &EquivocationProposal{}, - ) - registry.RegisterImplementations( (*sdk.Msg)(nil), &MsgSubmitConsumerMisbehaviour{}, diff --git a/x/ccv/provider/types/proposal.go b/x/ccv/provider/types/proposal.go index b2286d4adf..fb954d83aa 100644 --- a/x/ccv/provider/types/proposal.go +++ b/x/ccv/provider/types/proposal.go @@ -1,7 +1,6 @@ package types import ( - "errors" "fmt" "strings" time "time" @@ -11,7 +10,6 @@ import ( errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" - 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/v3/x/ccv/types" @@ -20,21 +18,18 @@ import ( const ( ProposalTypeConsumerAddition = "ConsumerAddition" ProposalTypeConsumerRemoval = "ConsumerRemoval" - ProposalTypeEquivocation = "Equivocation" ProposalTypeChangeRewardDenoms = "ChangeRewardDenoms" ) var ( _ govv1beta1.Content = &ConsumerAdditionProposal{} _ govv1beta1.Content = &ConsumerRemovalProposal{} - _ govv1beta1.Content = &EquivocationProposal{} _ govv1beta1.Content = &ChangeRewardDenomsProposal{} ) func init() { govv1beta1.RegisterProposalType(ProposalTypeConsumerAddition) govv1beta1.RegisterProposalType(ProposalTypeConsumerRemoval) - govv1beta1.RegisterProposalType(ProposalTypeEquivocation) govv1beta1.RegisterProposalType(ProposalTypeChangeRewardDenoms) } @@ -203,39 +198,6 @@ func (sccp *ConsumerRemovalProposal) ValidateBasic() error { return nil } -// NewEquivocationProposal creates a new equivocation proposal. -func NewEquivocationProposal(title, description string, equivocations []*evidencetypes.Equivocation) govv1beta1.Content { - return &EquivocationProposal{ - Title: title, - Description: description, - Equivocations: equivocations, - } -} - -// ProposalRoute returns the routing key of an equivocation proposal. -func (sp *EquivocationProposal) ProposalRoute() string { return RouterKey } - -// ProposalType returns the type of a equivocation proposal. -func (sp *EquivocationProposal) ProposalType() string { - return ProposalTypeEquivocation -} - -// ValidateBasic runs basic stateless validity checks -func (sp *EquivocationProposal) ValidateBasic() error { - if err := govv1beta1.ValidateAbstract(sp); err != nil { - return err - } - if len(sp.Equivocations) == 0 { - return errors.New("invalid equivocation proposal: empty equivocations") - } - for i := 0; i < len(sp.Equivocations); i++ { - if err := sp.Equivocations[i].ValidateBasic(); err != nil { - return err - } - } - return nil -} - func NewChangeRewardDenomsProposal(title, description string, denomsToAdd, denomsToRemove []string, ) govv1beta1.Content { diff --git a/x/ccv/provider/types/proposal_test.go b/x/ccv/provider/types/proposal_test.go index 357c555d0e..d8f10766dd 100644 --- a/x/ccv/provider/types/proposal_test.go +++ b/x/ccv/provider/types/proposal_test.go @@ -12,7 +12,6 @@ import ( "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" - evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" @@ -307,62 +306,6 @@ func TestConsumerAdditionProposalString(t *testing.T) { require.Equal(t, expect, proposal.String(), "string method for ConsumerAdditionProposal returned unexpected string") } -func TestEquivocationProposalValidateBasic(t *testing.T) { - tests := []struct { - name string - proposal govv1beta1.Content - expectedError string - }{ - { - name: "fail: validate abstract - empty title", - proposal: types.NewEquivocationProposal("", "", nil), - expectedError: "proposal title cannot be blank: invalid proposal content", - }, - { - name: "fail: equivocations is empty", - proposal: types.NewEquivocationProposal("title", "desc", nil), - expectedError: "invalid equivocation proposal: empty equivocations", - }, - { - name: "fail: invalid equivocation", - proposal: types.NewEquivocationProposal("title", "desc", - []*evidencetypes.Equivocation{ - { - Time: time.Now(), - Height: 1, - Power: 1, - ConsensusAddress: "addr", - }, - {}, // invalid one - }), - expectedError: "invalid equivocation time: 0001-01-01 00:00:00 +0000 UTC", - }, - { - name: "ok", - proposal: types.NewEquivocationProposal("title", "desc", - []*evidencetypes.Equivocation{ - { - Time: time.Now(), - Height: 1, - Power: 1, - ConsensusAddress: "addr", - }, - }), - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := tt.proposal.ValidateBasic() - - if tt.expectedError != "" { - require.EqualError(t, err, tt.expectedError) - return - } - require.NoError(t, err) - }) - } -} - func TestChangeRewardDenomsProposalValidateBasic(t *testing.T) { tcs := []struct { name string diff --git a/x/ccv/provider/types/provider.pb.go b/x/ccv/provider/types/provider.pb.go index ef0aa6e5e1..3bdf4a537e 100644 --- a/x/ccv/provider/types/provider.pb.go +++ b/x/ccv/provider/types/provider.pb.go @@ -6,14 +6,13 @@ package types import ( fmt "fmt" crypto "github.com/cometbft/cometbft/proto/tendermint/crypto" - types2 "github.com/cosmos/cosmos-sdk/types" - types1 "github.com/cosmos/cosmos-sdk/x/evidence/types" + types1 "github.com/cosmos/cosmos-sdk/types" _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/cosmos/gogoproto/proto" 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/v3/x/ccv/types" + types2 "github.com/cosmos/interchain-security/v3/x/ccv/types" _ "google.golang.org/protobuf/types/known/durationpb" _ "google.golang.org/protobuf/types/known/timestamppb" io "io" @@ -201,73 +200,6 @@ func (m *ConsumerRemovalProposal) GetStopTime() time.Time { return time.Time{} } -// EquivocationProposal is a governance proposal on the provider chain to -// punish a validator for equivocation on a consumer chain. -// -// This type is only used internally to the consumer CCV module. -type EquivocationProposal struct { - // the title of the proposal - Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` - // the description of the proposal - Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` - // the list of equivocations that will be processed - Equivocations []*types1.Equivocation `protobuf:"bytes,3,rep,name=equivocations,proto3" json:"equivocations,omitempty"` -} - -func (m *EquivocationProposal) Reset() { *m = EquivocationProposal{} } -func (m *EquivocationProposal) String() string { return proto.CompactTextString(m) } -func (*EquivocationProposal) ProtoMessage() {} -func (*EquivocationProposal) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{2} -} -func (m *EquivocationProposal) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *EquivocationProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_EquivocationProposal.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 *EquivocationProposal) XXX_Merge(src proto.Message) { - xxx_messageInfo_EquivocationProposal.Merge(m, src) -} -func (m *EquivocationProposal) XXX_Size() int { - return m.Size() -} -func (m *EquivocationProposal) XXX_DiscardUnknown() { - xxx_messageInfo_EquivocationProposal.DiscardUnknown(m) -} - -var xxx_messageInfo_EquivocationProposal proto.InternalMessageInfo - -func (m *EquivocationProposal) GetTitle() string { - if m != nil { - return m.Title - } - return "" -} - -func (m *EquivocationProposal) GetDescription() string { - if m != nil { - return m.Description - } - return "" -} - -func (m *EquivocationProposal) GetEquivocations() []*types1.Equivocation { - if m != nil { - return m.Equivocations - } - return nil -} - // ChangeRewardDenomsProposal is a governance proposal on the provider chain to // mutate the set of denoms accepted by the provider as rewards. type ChangeRewardDenomsProposal struct { @@ -285,7 +217,7 @@ func (m *ChangeRewardDenomsProposal) Reset() { *m = ChangeRewardDenomsPr func (m *ChangeRewardDenomsProposal) String() string { return proto.CompactTextString(m) } func (*ChangeRewardDenomsProposal) ProtoMessage() {} func (*ChangeRewardDenomsProposal) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{3} + return fileDescriptor_f22ec409a72b7b72, []int{2} } func (m *ChangeRewardDenomsProposal) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -366,7 +298,7 @@ func (m *GlobalSlashEntry) Reset() { *m = GlobalSlashEntry{} } func (m *GlobalSlashEntry) String() string { return proto.CompactTextString(m) } func (*GlobalSlashEntry) ProtoMessage() {} func (*GlobalSlashEntry) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{4} + return fileDescriptor_f22ec409a72b7b72, []int{3} } func (m *GlobalSlashEntry) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -449,14 +381,14 @@ type Params struct { // that can be queued for a single consumer before the provider chain halts. MaxThrottledPackets int64 `protobuf:"varint,8,opt,name=max_throttled_packets,json=maxThrottledPackets,proto3" json:"max_throttled_packets,omitempty"` // The fee required to be paid to add a reward denom - ConsumerRewardDenomRegistrationFee types2.Coin `protobuf:"bytes,9,opt,name=consumer_reward_denom_registration_fee,json=consumerRewardDenomRegistrationFee,proto3" json:"consumer_reward_denom_registration_fee"` + ConsumerRewardDenomRegistrationFee types1.Coin `protobuf:"bytes,9,opt,name=consumer_reward_denom_registration_fee,json=consumerRewardDenomRegistrationFee,proto3" json:"consumer_reward_denom_registration_fee"` } func (m *Params) Reset() { *m = Params{} } func (m *Params) String() string { return proto.CompactTextString(m) } func (*Params) ProtoMessage() {} func (*Params) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{5} + return fileDescriptor_f22ec409a72b7b72, []int{4} } func (m *Params) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -541,11 +473,11 @@ func (m *Params) GetMaxThrottledPackets() int64 { return 0 } -func (m *Params) GetConsumerRewardDenomRegistrationFee() types2.Coin { +func (m *Params) GetConsumerRewardDenomRegistrationFee() types1.Coin { if m != nil { return m.ConsumerRewardDenomRegistrationFee } - return types2.Coin{} + return types1.Coin{} } // SlashAcks contains cons addresses of consumer chain validators @@ -558,7 +490,7 @@ func (m *SlashAcks) Reset() { *m = SlashAcks{} } func (m *SlashAcks) String() string { return proto.CompactTextString(m) } func (*SlashAcks) ProtoMessage() {} func (*SlashAcks) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{6} + return fileDescriptor_f22ec409a72b7b72, []int{5} } func (m *SlashAcks) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -605,7 +537,7 @@ func (m *ConsumerAdditionProposals) Reset() { *m = ConsumerAdditionPropo func (m *ConsumerAdditionProposals) String() string { return proto.CompactTextString(m) } func (*ConsumerAdditionProposals) ProtoMessage() {} func (*ConsumerAdditionProposals) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{7} + return fileDescriptor_f22ec409a72b7b72, []int{6} } func (m *ConsumerAdditionProposals) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -652,7 +584,7 @@ func (m *ConsumerRemovalProposals) Reset() { *m = ConsumerRemovalProposa func (m *ConsumerRemovalProposals) String() string { return proto.CompactTextString(m) } func (*ConsumerRemovalProposals) ProtoMessage() {} func (*ConsumerRemovalProposals) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{8} + return fileDescriptor_f22ec409a72b7b72, []int{7} } func (m *ConsumerRemovalProposals) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -697,7 +629,7 @@ func (m *AddressList) Reset() { *m = AddressList{} } func (m *AddressList) String() string { return proto.CompactTextString(m) } func (*AddressList) ProtoMessage() {} func (*AddressList) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{9} + return fileDescriptor_f22ec409a72b7b72, []int{8} } func (m *AddressList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -742,7 +674,7 @@ func (m *ChannelToChain) Reset() { *m = ChannelToChain{} } func (m *ChannelToChain) String() string { return proto.CompactTextString(m) } func (*ChannelToChain) ProtoMessage() {} func (*ChannelToChain) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{10} + return fileDescriptor_f22ec409a72b7b72, []int{9} } func (m *ChannelToChain) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -796,7 +728,7 @@ func (m *VscUnbondingOps) Reset() { *m = VscUnbondingOps{} } func (m *VscUnbondingOps) String() string { return proto.CompactTextString(m) } func (*VscUnbondingOps) ProtoMessage() {} func (*VscUnbondingOps) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{11} + return fileDescriptor_f22ec409a72b7b72, []int{10} } func (m *VscUnbondingOps) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -851,7 +783,7 @@ func (m *UnbondingOp) Reset() { *m = UnbondingOp{} } func (m *UnbondingOp) String() string { return proto.CompactTextString(m) } func (*UnbondingOp) ProtoMessage() {} func (*UnbondingOp) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{12} + return fileDescriptor_f22ec409a72b7b72, []int{11} } func (m *UnbondingOp) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -903,7 +835,7 @@ func (m *InitTimeoutTimestamp) Reset() { *m = InitTimeoutTimestamp{} } func (m *InitTimeoutTimestamp) String() string { return proto.CompactTextString(m) } func (*InitTimeoutTimestamp) ProtoMessage() {} func (*InitTimeoutTimestamp) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{13} + return fileDescriptor_f22ec409a72b7b72, []int{12} } func (m *InitTimeoutTimestamp) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -955,7 +887,7 @@ func (m *VscSendTimestamp) Reset() { *m = VscSendTimestamp{} } func (m *VscSendTimestamp) String() string { return proto.CompactTextString(m) } func (*VscSendTimestamp) ProtoMessage() {} func (*VscSendTimestamp) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{14} + return fileDescriptor_f22ec409a72b7b72, []int{13} } func (m *VscSendTimestamp) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1000,14 +932,14 @@ func (m *VscSendTimestamp) GetTimestamp() time.Time { // ValidatorSetChangePackets is a pb list of ccv.ValidatorSetChangePacketData. type ValidatorSetChangePackets struct { - List []types3.ValidatorSetChangePacketData `protobuf:"bytes,1,rep,name=list,proto3" json:"list"` + List []types2.ValidatorSetChangePacketData `protobuf:"bytes,1,rep,name=list,proto3" json:"list"` } func (m *ValidatorSetChangePackets) Reset() { *m = ValidatorSetChangePackets{} } func (m *ValidatorSetChangePackets) String() string { return proto.CompactTextString(m) } func (*ValidatorSetChangePackets) ProtoMessage() {} func (*ValidatorSetChangePackets) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{15} + return fileDescriptor_f22ec409a72b7b72, []int{14} } func (m *ValidatorSetChangePackets) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1036,7 +968,7 @@ func (m *ValidatorSetChangePackets) XXX_DiscardUnknown() { var xxx_messageInfo_ValidatorSetChangePackets proto.InternalMessageInfo -func (m *ValidatorSetChangePackets) GetList() []types3.ValidatorSetChangePacketData { +func (m *ValidatorSetChangePackets) GetList() []types2.ValidatorSetChangePacketData { if m != nil { return m.List } @@ -1053,7 +985,7 @@ func (m *MaturedUnbondingOps) Reset() { *m = MaturedUnbondingOps{} } func (m *MaturedUnbondingOps) String() string { return proto.CompactTextString(m) } func (*MaturedUnbondingOps) ProtoMessage() {} func (*MaturedUnbondingOps) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{16} + return fileDescriptor_f22ec409a72b7b72, []int{15} } func (m *MaturedUnbondingOps) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1099,7 +1031,7 @@ func (m *ExportedVscSendTimestamp) Reset() { *m = ExportedVscSendTimesta func (m *ExportedVscSendTimestamp) String() string { return proto.CompactTextString(m) } func (*ExportedVscSendTimestamp) ProtoMessage() {} func (*ExportedVscSendTimestamp) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{17} + return fileDescriptor_f22ec409a72b7b72, []int{16} } func (m *ExportedVscSendTimestamp) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1152,7 +1084,7 @@ func (m *KeyAssignmentReplacement) Reset() { *m = KeyAssignmentReplaceme func (m *KeyAssignmentReplacement) String() string { return proto.CompactTextString(m) } func (*KeyAssignmentReplacement) ProtoMessage() {} func (*KeyAssignmentReplacement) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{18} + return fileDescriptor_f22ec409a72b7b72, []int{17} } func (m *KeyAssignmentReplacement) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1215,7 +1147,7 @@ func (m *ValidatorConsumerPubKey) Reset() { *m = ValidatorConsumerPubKey func (m *ValidatorConsumerPubKey) String() string { return proto.CompactTextString(m) } func (*ValidatorConsumerPubKey) ProtoMessage() {} func (*ValidatorConsumerPubKey) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{19} + return fileDescriptor_f22ec409a72b7b72, []int{18} } func (m *ValidatorConsumerPubKey) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1278,7 +1210,7 @@ func (m *ValidatorByConsumerAddr) Reset() { *m = ValidatorByConsumerAddr func (m *ValidatorByConsumerAddr) String() string { return proto.CompactTextString(m) } func (*ValidatorByConsumerAddr) ProtoMessage() {} func (*ValidatorByConsumerAddr) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{20} + return fileDescriptor_f22ec409a72b7b72, []int{19} } func (m *ValidatorByConsumerAddr) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1340,7 +1272,7 @@ func (m *ConsumerAddrsToPrune) Reset() { *m = ConsumerAddrsToPrune{} } func (m *ConsumerAddrsToPrune) String() string { return proto.CompactTextString(m) } func (*ConsumerAddrsToPrune) ProtoMessage() {} func (*ConsumerAddrsToPrune) Descriptor() ([]byte, []int) { - return fileDescriptor_f22ec409a72b7b72, []int{21} + return fileDescriptor_f22ec409a72b7b72, []int{20} } func (m *ConsumerAddrsToPrune) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1393,7 +1325,6 @@ func (m *ConsumerAddrsToPrune) GetConsumerAddrs() *AddressList { func init() { proto.RegisterType((*ConsumerAdditionProposal)(nil), "interchain_security.ccv.provider.v1.ConsumerAdditionProposal") proto.RegisterType((*ConsumerRemovalProposal)(nil), "interchain_security.ccv.provider.v1.ConsumerRemovalProposal") - proto.RegisterType((*EquivocationProposal)(nil), "interchain_security.ccv.provider.v1.EquivocationProposal") proto.RegisterType((*ChangeRewardDenomsProposal)(nil), "interchain_security.ccv.provider.v1.ChangeRewardDenomsProposal") proto.RegisterType((*GlobalSlashEntry)(nil), "interchain_security.ccv.provider.v1.GlobalSlashEntry") proto.RegisterType((*Params)(nil), "interchain_security.ccv.provider.v1.Params") @@ -1420,115 +1351,112 @@ func init() { } var fileDescriptor_f22ec409a72b7b72 = []byte{ - // 1723 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0x4b, 0x73, 0x1b, 0xc7, - 0x11, 0xe6, 0x12, 0x20, 0x45, 0x34, 0xf8, 0xd2, 0x92, 0xb2, 0x40, 0x85, 0x01, 0xa9, 0x75, 0xec, - 0x30, 0xe5, 0xf2, 0xc2, 0xa4, 0x2a, 0x55, 0x2e, 0x55, 0x5c, 0x2e, 0x12, 0x94, 0x2d, 0x9a, 0xb1, - 0x45, 0x2f, 0x19, 0xaa, 0x92, 0x1c, 0xb6, 0x06, 0x33, 0x23, 0x60, 0x8a, 0xbb, 0x3b, 0xab, 0x99, - 0xc1, 0x4a, 0xb8, 0xe4, 0x9c, 0xa3, 0x73, 0x73, 0x25, 0x17, 0x27, 0x7f, 0x20, 0x7f, 0xc3, 0x47, - 0x1f, 0x73, 0xb2, 0x53, 0xd2, 0x21, 0x87, 0xfc, 0x89, 0xd4, 0xcc, 0x3e, 0x01, 0x3e, 0x02, 0x95, - 0x93, 0xdb, 0xa2, 0xa7, 0xfb, 0xeb, 0x9e, 0x7e, 0x7c, 0x3d, 0x24, 0xec, 0xb1, 0x48, 0x51, 0x81, - 0x07, 0x88, 0x45, 0xbe, 0xa4, 0x78, 0x28, 0x98, 0x1a, 0x75, 0x30, 0x4e, 0x3a, 0xb1, 0xe0, 0x09, - 0x23, 0x54, 0x74, 0x92, 0xdd, 0xe2, 0xdb, 0x8d, 0x05, 0x57, 0xdc, 0x7e, 0xfb, 0x0a, 0x1b, 0x17, - 0xe3, 0xc4, 0x2d, 0xf4, 0x92, 0xdd, 0x7b, 0x1f, 0x5c, 0x07, 0x9c, 0xec, 0x76, 0xe4, 0x00, 0x09, - 0x4a, 0x7c, 0xcc, 0x23, 0x39, 0x0c, 0x73, 0xd8, 0x7b, 0xef, 0xdc, 0x60, 0xf1, 0x82, 0x09, 0x9a, - 0xa9, 0xad, 0xf7, 0x79, 0x9f, 0x9b, 0xcf, 0x8e, 0xfe, 0xca, 0xa4, 0x5b, 0x7d, 0xce, 0xfb, 0x01, - 0xed, 0x98, 0x5f, 0xbd, 0xe1, 0xb3, 0x8e, 0x62, 0x21, 0x95, 0x0a, 0x85, 0x71, 0xa6, 0xd0, 0x9e, - 0x54, 0x20, 0x43, 0x81, 0x14, 0xe3, 0x51, 0x0e, 0xc0, 0x7a, 0xb8, 0x83, 0xb9, 0xa0, 0x1d, 0x1c, - 0x30, 0x1a, 0x29, 0xed, 0x35, 0xfd, 0xca, 0x14, 0x3a, 0x5a, 0x21, 0x60, 0xfd, 0x81, 0x4a, 0xc5, - 0xb2, 0xa3, 0x68, 0x44, 0xa8, 0x08, 0x59, 0xaa, 0x5c, 0xfe, 0xca, 0x0c, 0x36, 0x2b, 0xe7, 0x58, - 0x8c, 0x62, 0xc5, 0x3b, 0x17, 0x74, 0x24, 0xb3, 0xd3, 0x77, 0x31, 0x97, 0x21, 0x97, 0x1d, 0xaa, - 0x33, 0x16, 0x61, 0xda, 0x49, 0x76, 0x7b, 0x54, 0xa1, 0xdd, 0x42, 0x90, 0xc7, 0x9d, 0xe9, 0xf5, - 0x90, 0x2c, 0x75, 0x30, 0x67, 0x59, 0xdc, 0xce, 0x0f, 0xf3, 0xd0, 0xea, 0x66, 0x89, 0xdc, 0x27, - 0x84, 0xe9, 0x2b, 0x9d, 0x08, 0x1e, 0x73, 0x89, 0x02, 0x7b, 0x1d, 0xe6, 0x14, 0x53, 0x01, 0x6d, - 0x59, 0xdb, 0xd6, 0x4e, 0xc3, 0x4b, 0x7f, 0xd8, 0xdb, 0xd0, 0x24, 0x54, 0x62, 0xc1, 0x62, 0xad, - 0xdc, 0x9a, 0x35, 0x67, 0x55, 0x91, 0xbd, 0x01, 0x0b, 0x69, 0x1d, 0x18, 0x69, 0xd5, 0xcc, 0xf1, - 0x2d, 0xf3, 0xfb, 0x88, 0xd8, 0x9f, 0xc2, 0x32, 0x8b, 0x98, 0x62, 0x28, 0xf0, 0x07, 0x54, 0x67, - 0xa3, 0x55, 0xdf, 0xb6, 0x76, 0x9a, 0x7b, 0xf7, 0x5c, 0xd6, 0xc3, 0xae, 0x4e, 0xa0, 0x9b, 0xa5, - 0x2d, 0xd9, 0x75, 0x1f, 0x1b, 0x8d, 0x83, 0xfa, 0xb7, 0xdf, 0x6f, 0xcd, 0x78, 0x4b, 0x99, 0x5d, - 0x2a, 0xb4, 0xef, 0xc3, 0x62, 0x9f, 0x46, 0x54, 0x32, 0xe9, 0x0f, 0x90, 0x1c, 0xb4, 0xe6, 0xb6, - 0xad, 0x9d, 0x45, 0xaf, 0x99, 0xc9, 0x1e, 0x23, 0x39, 0xb0, 0xb7, 0xa0, 0xd9, 0x63, 0x11, 0x12, - 0xa3, 0x54, 0x63, 0xde, 0x68, 0x40, 0x2a, 0x32, 0x0a, 0x5d, 0x00, 0x19, 0xa3, 0x17, 0x91, 0xaf, - 0xab, 0xdd, 0xba, 0x95, 0x05, 0x92, 0x56, 0xda, 0xcd, 0x2b, 0xed, 0x9e, 0xe5, 0xad, 0x70, 0xb0, - 0xa0, 0x03, 0xf9, 0xea, 0x87, 0x2d, 0xcb, 0x6b, 0x18, 0x3b, 0x7d, 0x62, 0x7f, 0x01, 0xab, 0xc3, - 0xa8, 0xc7, 0x23, 0xc2, 0xa2, 0xbe, 0x1f, 0x53, 0xc1, 0x38, 0x69, 0x2d, 0x18, 0xa8, 0x8d, 0x4b, - 0x50, 0x87, 0x59, 0xd3, 0xa4, 0x48, 0x5f, 0x6b, 0xa4, 0x95, 0xc2, 0xf8, 0xc4, 0xd8, 0xda, 0x5f, - 0x82, 0x8d, 0x71, 0x62, 0x42, 0xe2, 0x43, 0x95, 0x23, 0x36, 0xa6, 0x47, 0x5c, 0xc5, 0x38, 0x39, - 0x4b, 0xad, 0x33, 0xc8, 0xdf, 0xc3, 0x5d, 0x25, 0x50, 0x24, 0x9f, 0x51, 0x31, 0x89, 0x0b, 0xd3, - 0xe3, 0xde, 0xc9, 0x31, 0xc6, 0xc1, 0x1f, 0xc3, 0x76, 0x3e, 0x89, 0xbe, 0xa0, 0x84, 0x49, 0x25, - 0x58, 0x6f, 0xa8, 0x6d, 0xfd, 0x67, 0x02, 0x61, 0xd3, 0x23, 0x4d, 0xd3, 0x04, 0xed, 0x5c, 0xcf, - 0x1b, 0x53, 0xfb, 0x24, 0xd3, 0xb2, 0x9f, 0xc0, 0xcf, 0x7a, 0x01, 0xc7, 0x17, 0x52, 0x07, 0xe7, - 0x8f, 0x21, 0x19, 0xd7, 0x21, 0x93, 0x52, 0xa3, 0x2d, 0x6e, 0x5b, 0x3b, 0x35, 0xef, 0x7e, 0xaa, - 0x7b, 0x42, 0xc5, 0x61, 0x45, 0xf3, 0xac, 0xa2, 0x68, 0xbf, 0x0f, 0xf6, 0x80, 0x49, 0xc5, 0x05, - 0xc3, 0x28, 0xf0, 0x69, 0xa4, 0x04, 0xa3, 0xb2, 0xb5, 0x64, 0xcc, 0x6f, 0x97, 0x27, 0x8f, 0xd2, - 0x03, 0xfb, 0x33, 0xb8, 0x7f, 0xad, 0x53, 0x1f, 0x0f, 0x50, 0x14, 0xd1, 0xa0, 0xb5, 0x6c, 0xae, - 0xb2, 0x45, 0xae, 0xf1, 0xd9, 0x4d, 0xd5, 0x1e, 0x2e, 0xfc, 0xf1, 0x9b, 0xad, 0x99, 0xaf, 0xbf, - 0xd9, 0x9a, 0x71, 0xfe, 0x6e, 0xc1, 0xdd, 0x6e, 0x71, 0xf1, 0x90, 0x27, 0x28, 0xf8, 0x7f, 0x0e, - 0xd8, 0x3e, 0x34, 0xa4, 0xe2, 0x71, 0xda, 0xd2, 0xf5, 0x37, 0x68, 0xe9, 0x05, 0x6d, 0xa6, 0x0f, - 0x9c, 0xbf, 0x58, 0xb0, 0xfe, 0xe8, 0xf9, 0x90, 0x25, 0x1c, 0xa3, 0xff, 0x09, 0x1f, 0x1c, 0xc3, - 0x12, 0xad, 0xe0, 0xc9, 0x56, 0x6d, 0xbb, 0xb6, 0xd3, 0xdc, 0x7b, 0xc7, 0x4d, 0xc9, 0xc9, 0x2d, - 0x38, 0x2b, 0x23, 0x28, 0xb7, 0xea, 0xdd, 0x1b, 0xb7, 0x75, 0xfe, 0x66, 0xc1, 0x3d, 0x9d, 0xe5, - 0x3e, 0xf5, 0xe8, 0x0b, 0x24, 0xc8, 0x21, 0x8d, 0x78, 0x28, 0x7f, 0x74, 0x8c, 0x0e, 0x2c, 0x11, - 0x83, 0xe4, 0x2b, 0xee, 0x23, 0x42, 0x4c, 0x8c, 0x46, 0x47, 0x0b, 0xcf, 0xf8, 0x3e, 0x21, 0xf6, - 0x0e, 0xac, 0x96, 0x3a, 0x42, 0xd7, 0x52, 0xa7, 0x58, 0xab, 0x2d, 0xe7, 0x6a, 0xa6, 0xc2, 0xd4, - 0xf9, 0xb7, 0x05, 0xab, 0x9f, 0x06, 0xbc, 0x87, 0x82, 0xd3, 0x00, 0xc9, 0x81, 0xee, 0xb0, 0x91, - 0x2e, 0x8d, 0xa0, 0xd9, 0x68, 0x9b, 0xf0, 0xa6, 0x2e, 0x8d, 0x36, 0x33, 0x64, 0xf3, 0x31, 0xdc, - 0x2e, 0x86, 0xad, 0xe8, 0x00, 0x73, 0x9b, 0x83, 0xb5, 0x57, 0xdf, 0x6f, 0xad, 0xe4, 0x8d, 0xd6, - 0x35, 0xdd, 0x70, 0xe8, 0xad, 0xe0, 0x31, 0x01, 0xb1, 0xdb, 0xd0, 0x64, 0x3d, 0xec, 0x4b, 0xfa, - 0xdc, 0x8f, 0x86, 0xa1, 0x69, 0x9e, 0xba, 0xd7, 0x60, 0x3d, 0x7c, 0x4a, 0x9f, 0x7f, 0x31, 0x0c, - 0xed, 0x07, 0xf0, 0x56, 0xbe, 0x86, 0xfd, 0x04, 0x05, 0x66, 0xc9, 0xea, 0x74, 0x08, 0xd3, 0x4b, - 0x8b, 0xde, 0x5a, 0x7e, 0x7a, 0x8e, 0x02, 0xed, 0x6c, 0x9f, 0x10, 0xe1, 0xfc, 0x6b, 0x0e, 0xe6, - 0x4f, 0x90, 0x40, 0xa1, 0xb4, 0xcf, 0x60, 0x45, 0xd1, 0x30, 0x0e, 0x90, 0xa2, 0x7e, 0x4a, 0xe4, - 0xd9, 0x4d, 0xdf, 0x33, 0x04, 0x5f, 0x5d, 0x80, 0x6e, 0x65, 0xe5, 0x25, 0xbb, 0x6e, 0xd7, 0x48, - 0x4f, 0x15, 0x52, 0xd4, 0x5b, 0xce, 0x31, 0x52, 0xa1, 0xfd, 0x21, 0xb4, 0x94, 0x18, 0x4a, 0x55, - 0x52, 0x6c, 0xc9, 0x2d, 0x69, 0x2d, 0xdf, 0xca, 0xcf, 0x53, 0x56, 0x2a, 0x38, 0xe5, 0x6a, 0x36, - 0xad, 0xfd, 0x18, 0x36, 0x3d, 0x85, 0x35, 0xbd, 0x8a, 0x26, 0x31, 0xeb, 0xd3, 0x63, 0xde, 0xd6, - 0xf6, 0xe3, 0xa0, 0x5f, 0x82, 0x9d, 0x48, 0x3c, 0x89, 0x39, 0xf7, 0x06, 0x71, 0x26, 0x12, 0x8f, - 0x43, 0x12, 0xd8, 0x94, 0xba, 0xf9, 0xfc, 0x90, 0x2a, 0xc3, 0xcd, 0x71, 0x40, 0x23, 0x26, 0x07, - 0x39, 0xf8, 0xfc, 0xf4, 0xe0, 0x1b, 0x06, 0xe8, 0x73, 0x8d, 0xe3, 0xe5, 0x30, 0x99, 0x97, 0x2e, - 0xb4, 0xaf, 0xf6, 0x52, 0x14, 0xe8, 0x96, 0x29, 0xd0, 0x4f, 0xae, 0x80, 0x28, 0xaa, 0xb4, 0x07, - 0x77, 0x42, 0xf4, 0xd2, 0x57, 0x03, 0xc1, 0x95, 0x0a, 0x28, 0xf1, 0x63, 0x84, 0x2f, 0xa8, 0x92, - 0x66, 0x91, 0xd6, 0xbc, 0xb5, 0x10, 0xbd, 0x3c, 0xcb, 0xcf, 0x4e, 0xd2, 0x23, 0x5b, 0xc2, 0xbb, - 0x95, 0xbd, 0xa3, 0x99, 0xc0, 0x37, 0x43, 0xe8, 0x0b, 0xda, 0xd7, 0xe4, 0x8c, 0xd2, 0x15, 0x44, - 0x69, 0xb1, 0x3b, 0x33, 0xb6, 0xd1, 0x4f, 0xa1, 0x82, 0x69, 0xba, 0x9c, 0x45, 0xd9, 0x03, 0xc3, - 0x29, 0xd7, 0x53, 0xc1, 0x2b, 0x5e, 0x05, 0xeb, 0x13, 0x4a, 0x9d, 0x5f, 0x40, 0xc3, 0x0c, 0xf4, - 0x3e, 0xbe, 0x90, 0xf6, 0x26, 0x34, 0xf4, 0x64, 0x50, 0x29, 0xa9, 0x6c, 0x59, 0x86, 0x07, 0x4a, - 0x81, 0xa3, 0x60, 0xe3, 0xba, 0x87, 0x95, 0xb4, 0x9f, 0xc2, 0xad, 0x98, 0x9a, 0xad, 0x6f, 0x0c, - 0x9b, 0x7b, 0x1f, 0xb9, 0x53, 0xbc, 0x8a, 0xdd, 0xeb, 0x00, 0xbd, 0x1c, 0xcd, 0x11, 0xe5, 0x73, - 0x6e, 0x62, 0xd9, 0x48, 0xfb, 0x7c, 0xd2, 0xe9, 0xaf, 0xde, 0xc8, 0xe9, 0x04, 0x5e, 0xe9, 0xf3, - 0x3d, 0x68, 0xee, 0xa7, 0xd7, 0xfe, 0x35, 0x93, 0xea, 0x72, 0x5a, 0x16, 0xab, 0x69, 0xf9, 0x0c, - 0x96, 0xb3, 0x1d, 0x79, 0xc6, 0x0d, 0x29, 0xd9, 0x3f, 0x05, 0xc8, 0x96, 0xab, 0x26, 0xb3, 0x94, - 0xb6, 0x1b, 0x99, 0xe4, 0x88, 0x8c, 0xed, 0xba, 0xd9, 0xb1, 0x5d, 0xe7, 0x78, 0xb0, 0x72, 0x2e, - 0xf1, 0x6f, 0xf2, 0x07, 0xd4, 0x93, 0x58, 0xda, 0x77, 0x60, 0x5e, 0xcf, 0x51, 0x06, 0x54, 0xf7, - 0xe6, 0x12, 0x89, 0x8f, 0x0c, 0x73, 0x97, 0x8f, 0x34, 0x1e, 0xfb, 0x8c, 0xc8, 0xd6, 0xec, 0x76, - 0x6d, 0xa7, 0xee, 0x2d, 0x0f, 0x4b, 0xf3, 0x23, 0x22, 0x9d, 0xdf, 0x42, 0xb3, 0x02, 0x68, 0x2f, - 0xc3, 0x6c, 0x81, 0x35, 0xcb, 0x88, 0xfd, 0x10, 0x36, 0x4a, 0xa0, 0x71, 0x2a, 0x4e, 0x11, 0x1b, - 0xde, 0xdd, 0x42, 0x61, 0x8c, 0x8d, 0xa5, 0xf3, 0x04, 0xd6, 0x8f, 0xca, 0xc1, 0x2f, 0x88, 0x7e, - 0xec, 0x86, 0xd6, 0xf8, 0x36, 0xdf, 0x84, 0x46, 0xf1, 0x97, 0x88, 0xb9, 0x7d, 0xdd, 0x2b, 0x05, - 0x4e, 0x08, 0xab, 0xe7, 0x12, 0x9f, 0xd2, 0x88, 0x94, 0x60, 0xd7, 0x24, 0xe0, 0x60, 0x12, 0x68, - 0xea, 0x97, 0x6e, 0xe9, 0x8e, 0xc3, 0xc6, 0x39, 0x0a, 0x18, 0x41, 0x8a, 0x8b, 0x53, 0xaa, 0xd2, - 0x25, 0x9c, 0x8f, 0xa3, 0x07, 0xf5, 0x80, 0x49, 0x95, 0x75, 0xd6, 0x87, 0xd7, 0x76, 0x56, 0xb2, - 0xeb, 0x5e, 0x07, 0x72, 0x88, 0x14, 0xca, 0x66, 0xd1, 0x60, 0x39, 0x3f, 0x87, 0xb5, 0xcf, 0x91, - 0x1a, 0x0a, 0x4a, 0xc6, 0x6a, 0xbc, 0x0a, 0x35, 0x5d, 0x3f, 0xcb, 0xd4, 0x4f, 0x7f, 0xea, 0x37, - 0x41, 0xeb, 0xd1, 0xcb, 0x98, 0x0b, 0x45, 0xc9, 0xa5, 0x8c, 0xdc, 0x90, 0xde, 0x0b, 0x58, 0xd3, - 0xc9, 0x92, 0x34, 0x22, 0x7e, 0x71, 0xcf, 0xb4, 0x8e, 0xcd, 0xbd, 0x5f, 0x4e, 0x35, 0x1d, 0x93, - 0xee, 0xb2, 0x0b, 0xdc, 0x4e, 0x26, 0xe4, 0xd2, 0xf9, 0x93, 0x05, 0xad, 0x63, 0x3a, 0xda, 0x97, - 0x92, 0xf5, 0xa3, 0x90, 0x46, 0x4a, 0xf3, 0x20, 0xc2, 0x54, 0x7f, 0xda, 0x6f, 0xc3, 0x52, 0xb1, - 0x77, 0xcd, 0xba, 0xb5, 0xcc, 0xba, 0x5d, 0xcc, 0x85, 0x7a, 0xc0, 0xec, 0x87, 0x00, 0xb1, 0xa0, - 0x89, 0x8f, 0xfd, 0x0b, 0x3a, 0xca, 0xaa, 0xb8, 0x59, 0x5d, 0xa3, 0xe9, 0xdf, 0x89, 0xee, 0xc9, - 0xb0, 0x17, 0x30, 0x7c, 0x4c, 0x47, 0xde, 0x82, 0xd6, 0xef, 0x1e, 0xd3, 0x91, 0x7e, 0x17, 0xc5, - 0xfc, 0x05, 0x15, 0x66, 0xf7, 0xd5, 0xbc, 0xf4, 0x87, 0xf3, 0x67, 0x0b, 0xee, 0x16, 0xe5, 0xc8, - 0xdb, 0xf5, 0x64, 0xd8, 0xd3, 0x16, 0x37, 0xe4, 0xed, 0x52, 0xb4, 0xb3, 0x57, 0x44, 0xfb, 0x31, - 0x2c, 0x16, 0x03, 0xa2, 0xe3, 0xad, 0x4d, 0x11, 0x6f, 0x33, 0xb7, 0x38, 0xa6, 0x23, 0xe7, 0x0f, - 0x95, 0xd8, 0x0e, 0x46, 0x15, 0xee, 0x13, 0xff, 0x25, 0xb6, 0xc2, 0x6d, 0x35, 0x36, 0x5c, 0xb5, - 0xbf, 0x74, 0x81, 0xda, 0xe5, 0x0b, 0x38, 0x7f, 0xb5, 0x60, 0xbd, 0xea, 0x55, 0x9e, 0xf1, 0x13, - 0x31, 0x8c, 0xe8, 0x4d, 0xde, 0xcb, 0xf1, 0x9b, 0xad, 0x8e, 0xdf, 0x53, 0x58, 0x1e, 0x0b, 0x4a, - 0x66, 0xd9, 0xf8, 0x60, 0xaa, 0x1e, 0xab, 0xb0, 0xab, 0xb7, 0x54, 0xbd, 0x87, 0x3c, 0x78, 0xfa, - 0xed, 0xab, 0xb6, 0xf5, 0xdd, 0xab, 0xb6, 0xf5, 0xcf, 0x57, 0x6d, 0xeb, 0xab, 0xd7, 0xed, 0x99, - 0xef, 0x5e, 0xb7, 0x67, 0xfe, 0xf1, 0xba, 0x3d, 0xf3, 0xbb, 0x8f, 0xfa, 0x4c, 0x0d, 0x86, 0x3d, - 0x17, 0xf3, 0xb0, 0x93, 0xfd, 0x13, 0xa0, 0xf4, 0xf5, 0x7e, 0xf1, 0x1f, 0x92, 0xe4, 0x41, 0xe7, - 0xe5, 0xf8, 0x7f, 0x6c, 0xd4, 0x28, 0xa6, 0xb2, 0x37, 0x6f, 0x58, 0xe1, 0xc1, 0x7f, 0x02, 0x00, - 0x00, 0xff, 0xff, 0x47, 0xa2, 0xef, 0x46, 0xe2, 0x11, 0x00, 0x00, + // 1668 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0xcb, 0x6f, 0x1b, 0xc7, + 0x19, 0xd7, 0x8a, 0x94, 0x2c, 0x7e, 0xd4, 0xcb, 0x2b, 0x3b, 0xa6, 0x5c, 0x95, 0x92, 0x37, 0x7d, + 0xa8, 0x08, 0xb2, 0x1b, 0xc9, 0x28, 0x10, 0x18, 0x0d, 0x02, 0x89, 0x4a, 0x62, 0xc5, 0x4d, 0xac, + 0xac, 0x54, 0x19, 0x6d, 0x0f, 0x8b, 0xe1, 0xcc, 0x98, 0x1c, 0x68, 0x77, 0x67, 0x33, 0x33, 0x5c, + 0x9b, 0x97, 0x9e, 0x7b, 0x4c, 0x6f, 0x41, 0x4f, 0x69, 0xff, 0x81, 0xfe, 0x1b, 0x39, 0xe6, 0xd8, + 0x53, 0x52, 0xd8, 0x87, 0x1e, 0xfa, 0x4f, 0x14, 0x33, 0xfb, 0x24, 0xf5, 0x28, 0x8d, 0xa0, 0xb7, + 0xd9, 0x6f, 0xbe, 0xef, 0xf7, 0xbd, 0xe6, 0x7b, 0x90, 0xb0, 0xcf, 0x62, 0x45, 0x05, 0x1e, 0x22, + 0x16, 0x07, 0x92, 0xe2, 0x91, 0x60, 0x6a, 0xec, 0x61, 0x9c, 0x7a, 0x89, 0xe0, 0x29, 0x23, 0x54, + 0x78, 0xe9, 0x5e, 0x79, 0x76, 0x13, 0xc1, 0x15, 0xb7, 0xdf, 0xbe, 0x42, 0xc6, 0xc5, 0x38, 0x75, + 0x4b, 0xbe, 0x74, 0xef, 0xfe, 0x7b, 0xd7, 0x01, 0xa7, 0x7b, 0x9e, 0x1c, 0x22, 0x41, 0x49, 0x80, + 0x79, 0x2c, 0x47, 0x51, 0x01, 0x7b, 0xff, 0xe7, 0x37, 0x48, 0xbc, 0x60, 0x82, 0xe6, 0x6c, 0x77, + 0x06, 0x7c, 0xc0, 0xcd, 0xd1, 0xd3, 0xa7, 0x9c, 0xba, 0x3d, 0xe0, 0x7c, 0x10, 0x52, 0xcf, 0x7c, + 0xf5, 0x47, 0xcf, 0x3d, 0xc5, 0x22, 0x2a, 0x15, 0x8a, 0x92, 0x9c, 0xa1, 0x3b, 0xcd, 0x40, 0x46, + 0x02, 0x29, 0xc6, 0xe3, 0x02, 0x80, 0xf5, 0xb1, 0x87, 0xb9, 0xa0, 0x1e, 0x0e, 0x19, 0x8d, 0x95, + 0xd6, 0x9a, 0x9d, 0x72, 0x06, 0x4f, 0x33, 0x84, 0x6c, 0x30, 0x54, 0x19, 0x59, 0x7a, 0x8a, 0xc6, + 0x84, 0x8a, 0x88, 0x65, 0xcc, 0xd5, 0x57, 0x2e, 0xb0, 0x55, 0xbb, 0xc7, 0x62, 0x9c, 0x28, 0xee, + 0x5d, 0xd0, 0xb1, 0x2c, 0xec, 0xc1, 0x5c, 0x46, 0x5c, 0x7a, 0x7d, 0x24, 0xa9, 0x97, 0xee, 0xf5, + 0xa9, 0x42, 0x7b, 0x1e, 0xe6, 0x2c, 0xb7, 0xc7, 0xf9, 0x61, 0x11, 0x3a, 0xbd, 0x3c, 0x40, 0x07, + 0x84, 0x30, 0x6d, 0xea, 0x89, 0xe0, 0x09, 0x97, 0x28, 0xb4, 0xef, 0xc0, 0x82, 0x62, 0x2a, 0xa4, + 0x1d, 0x6b, 0xc7, 0xda, 0x6d, 0xf9, 0xd9, 0x87, 0xbd, 0x03, 0x6d, 0x42, 0x25, 0x16, 0x2c, 0xd1, + 0xcc, 0x9d, 0x79, 0x73, 0x57, 0x27, 0xd9, 0x9b, 0xb0, 0x94, 0xc5, 0x97, 0x91, 0x4e, 0xc3, 0x5c, + 0xdf, 0x32, 0xdf, 0xc7, 0xc4, 0xfe, 0x04, 0x56, 0x59, 0xcc, 0x14, 0x43, 0x61, 0x30, 0xa4, 0xda, + 0xcb, 0x4e, 0x73, 0xc7, 0xda, 0x6d, 0xef, 0xdf, 0x77, 0x59, 0x1f, 0xbb, 0x3a, 0x30, 0x6e, 0x1e, + 0x8e, 0x74, 0xcf, 0x7d, 0x6c, 0x38, 0x0e, 0x9b, 0xdf, 0x7e, 0xbf, 0x3d, 0xe7, 0xaf, 0xe4, 0x72, + 0x19, 0xd1, 0x7e, 0x00, 0xcb, 0x03, 0x1a, 0x53, 0xc9, 0x64, 0x30, 0x44, 0x72, 0xd8, 0x59, 0xd8, + 0xb1, 0x76, 0x97, 0xfd, 0x76, 0x4e, 0x7b, 0x8c, 0xe4, 0xd0, 0xde, 0x86, 0x76, 0x9f, 0xc5, 0x48, + 0x8c, 0x33, 0x8e, 0x45, 0xc3, 0x01, 0x19, 0xc9, 0x30, 0xf4, 0x00, 0x64, 0x82, 0x5e, 0xc4, 0x81, + 0xce, 0x62, 0xe7, 0x56, 0x6e, 0x48, 0x96, 0x41, 0xb7, 0xc8, 0xa0, 0x7b, 0x56, 0xa4, 0xf8, 0x70, + 0x49, 0x1b, 0xf2, 0xd5, 0x0f, 0xdb, 0x96, 0xdf, 0x32, 0x72, 0xfa, 0xc6, 0xfe, 0x1c, 0xd6, 0x47, + 0x71, 0x9f, 0xc7, 0x84, 0xc5, 0x83, 0x20, 0xa1, 0x82, 0x71, 0xd2, 0x59, 0x32, 0x50, 0x9b, 0x97, + 0xa0, 0x8e, 0xf2, 0xc7, 0x90, 0x21, 0x7d, 0xad, 0x91, 0xd6, 0x4a, 0xe1, 0x13, 0x23, 0x6b, 0x7f, + 0x01, 0x36, 0xc6, 0xa9, 0x31, 0x89, 0x8f, 0x54, 0x81, 0xd8, 0x9a, 0x1d, 0x71, 0x1d, 0xe3, 0xf4, + 0x2c, 0x93, 0xce, 0x21, 0xff, 0x08, 0xf7, 0x94, 0x40, 0xb1, 0x7c, 0x4e, 0xc5, 0x34, 0x2e, 0xcc, + 0x8e, 0x7b, 0xb7, 0xc0, 0x98, 0x04, 0x7f, 0x0c, 0x3b, 0x45, 0x85, 0x05, 0x82, 0x12, 0x26, 0x95, + 0x60, 0xfd, 0x91, 0x96, 0x0d, 0x9e, 0x0b, 0x84, 0xcd, 0x1b, 0x69, 0x9b, 0x47, 0xd0, 0x2d, 0xf8, + 0xfc, 0x09, 0xb6, 0x8f, 0x73, 0x2e, 0xfb, 0x29, 0xfc, 0xac, 0x1f, 0x72, 0x7c, 0x21, 0xb5, 0x71, + 0xc1, 0x04, 0x92, 0x51, 0x1d, 0x31, 0x29, 0x35, 0xda, 0xf2, 0x8e, 0xb5, 0xdb, 0xf0, 0x1f, 0x64, + 0xbc, 0x27, 0x54, 0x1c, 0xd5, 0x38, 0xcf, 0x6a, 0x8c, 0xf6, 0xbb, 0x60, 0x0f, 0x99, 0x54, 0x5c, + 0x30, 0x8c, 0xc2, 0x80, 0xc6, 0x4a, 0x30, 0x2a, 0x3b, 0x2b, 0x46, 0xfc, 0x76, 0x75, 0xf3, 0x51, + 0x76, 0x61, 0x7f, 0x0a, 0x0f, 0xae, 0x55, 0x1a, 0xe0, 0x21, 0x8a, 0x63, 0x1a, 0x76, 0x56, 0x8d, + 0x2b, 0xdb, 0xe4, 0x1a, 0x9d, 0xbd, 0x8c, 0xed, 0xd1, 0xd2, 0x9f, 0xbf, 0xd9, 0x9e, 0xfb, 0xfa, + 0x9b, 0xed, 0x39, 0xe7, 0x1f, 0x16, 0xdc, 0xeb, 0x95, 0x8e, 0x47, 0x3c, 0x45, 0xe1, 0xff, 0xb3, + 0xc0, 0x0e, 0xa0, 0x25, 0x15, 0x4f, 0xb2, 0x27, 0xdd, 0x7c, 0x83, 0x27, 0xbd, 0xa4, 0xc5, 0xf4, + 0x85, 0xf3, 0x77, 0x0b, 0xee, 0x6b, 0x3f, 0x06, 0xd4, 0xa7, 0x2f, 0x90, 0x20, 0x47, 0x34, 0xe6, + 0x91, 0xfc, 0xd1, 0x46, 0x3b, 0xb0, 0x42, 0x0c, 0x52, 0xa0, 0x78, 0x80, 0x88, 0xb6, 0xbc, 0x91, + 0xf1, 0x68, 0xe2, 0x19, 0x3f, 0x20, 0xc4, 0xde, 0x85, 0xf5, 0x8a, 0x47, 0xe8, 0x68, 0x69, 0x27, + 0x34, 0xdb, 0x6a, 0xc1, 0x66, 0x62, 0x48, 0x9d, 0xff, 0x58, 0xb0, 0xfe, 0x49, 0xc8, 0xfb, 0x28, + 0x3c, 0x0d, 0x91, 0x1c, 0xea, 0x1c, 0x8e, 0xb5, 0xf3, 0x82, 0xe6, 0xc5, 0x63, 0xcc, 0x9b, 0xd9, + 0x79, 0x2d, 0x66, 0xca, 0xf9, 0x43, 0xb8, 0x5d, 0x3e, 0xe7, 0x32, 0xc6, 0xc6, 0x9b, 0xc3, 0x8d, + 0x57, 0xdf, 0x6f, 0xaf, 0x15, 0xa9, 0xec, 0x99, 0x78, 0x1f, 0xf9, 0x6b, 0x78, 0x82, 0x40, 0xec, + 0x2e, 0xb4, 0x59, 0x1f, 0x07, 0x92, 0x7e, 0x19, 0xc4, 0xa3, 0xc8, 0xa4, 0xa7, 0xe9, 0xb7, 0x58, + 0x1f, 0x9f, 0xd2, 0x2f, 0x3f, 0x1f, 0x45, 0xf6, 0x43, 0x78, 0xab, 0x18, 0x60, 0x41, 0x8a, 0x42, + 0x33, 0x9e, 0x74, 0x38, 0x84, 0xc9, 0xd6, 0xb2, 0xbf, 0x51, 0xdc, 0x9e, 0xa3, 0x50, 0x2b, 0x3b, + 0x20, 0x44, 0x38, 0xff, 0x5e, 0x80, 0xc5, 0x13, 0x24, 0x50, 0x24, 0xed, 0x33, 0x58, 0x53, 0x34, + 0x4a, 0x42, 0xa4, 0x68, 0x90, 0xb5, 0xca, 0xdc, 0xd3, 0x77, 0x4c, 0x0b, 0xad, 0x8f, 0x0e, 0xb7, + 0x36, 0x2c, 0xd2, 0x3d, 0xb7, 0x67, 0xa8, 0xa7, 0x0a, 0x29, 0xea, 0xaf, 0x16, 0x18, 0x19, 0xd1, + 0x7e, 0x1f, 0x3a, 0x4a, 0x8c, 0xa4, 0xaa, 0x9a, 0x58, 0x55, 0xbd, 0x59, 0x2e, 0xdf, 0x2a, 0xee, + 0xb3, 0xba, 0x2f, 0xab, 0xf6, 0xea, 0x7e, 0xd5, 0xf8, 0x31, 0xfd, 0xea, 0x14, 0x36, 0x74, 0xb3, + 0x9f, 0xc6, 0x6c, 0xce, 0x8e, 0x79, 0x5b, 0xcb, 0x4f, 0x82, 0x7e, 0x01, 0x76, 0x2a, 0xf1, 0x34, + 0xe6, 0xc2, 0x1b, 0xd8, 0x99, 0x4a, 0x3c, 0x09, 0x49, 0x60, 0x4b, 0xea, 0xc7, 0x17, 0x44, 0x54, + 0x99, 0xee, 0x97, 0x84, 0x34, 0x66, 0x72, 0x58, 0x80, 0x2f, 0xce, 0x0e, 0xbe, 0x69, 0x80, 0x3e, + 0xd3, 0x38, 0x7e, 0x01, 0x93, 0x6b, 0xe9, 0x41, 0xf7, 0x6a, 0x2d, 0x65, 0x82, 0x6e, 0x99, 0x04, + 0xfd, 0xe4, 0x0a, 0x88, 0x32, 0x4b, 0xfb, 0x70, 0x37, 0x42, 0x2f, 0x03, 0x35, 0x14, 0x5c, 0xa9, + 0x90, 0x92, 0x20, 0x41, 0xf8, 0x82, 0x2a, 0x69, 0x46, 0x55, 0xc3, 0xdf, 0x88, 0xd0, 0xcb, 0xb3, + 0xe2, 0xee, 0x24, 0xbb, 0xb2, 0x25, 0xfc, 0xa2, 0xd6, 0xd9, 0x75, 0x27, 0x08, 0x4c, 0x11, 0x06, + 0x82, 0x0e, 0x74, 0xfb, 0x43, 0x59, 0x93, 0xa7, 0xb4, 0x9c, 0x4e, 0xd9, 0xb2, 0xe1, 0xea, 0x65, + 0xc3, 0xcd, 0x97, 0x0d, 0xb7, 0xc7, 0x59, 0x9c, 0x8f, 0x70, 0xa7, 0x1a, 0x00, 0x65, 0x5f, 0xf1, + 0x6b, 0x58, 0x1f, 0x53, 0xea, 0xfc, 0x0a, 0x5a, 0xa6, 0xa0, 0x0f, 0xf0, 0x85, 0xb4, 0xb7, 0xa0, + 0xa5, 0x2b, 0x83, 0x4a, 0x49, 0x65, 0xc7, 0x32, 0x7d, 0xa0, 0x22, 0x38, 0x0a, 0x36, 0xaf, 0x5b, + 0x5d, 0xa4, 0xfd, 0x0c, 0x6e, 0x25, 0xd4, 0xcc, 0x55, 0x23, 0xd8, 0xde, 0xff, 0xc0, 0x9d, 0x61, + 0x9f, 0x74, 0xaf, 0x03, 0xf4, 0x0b, 0x34, 0x47, 0x54, 0x0b, 0xd3, 0x54, 0x3b, 0x97, 0xf6, 0xf9, + 0xb4, 0xd2, 0xdf, 0xbc, 0x91, 0xd2, 0x29, 0xbc, 0x4a, 0xe7, 0x3b, 0xd0, 0x3e, 0xc8, 0xdc, 0xfe, + 0x2d, 0x93, 0xea, 0x72, 0x58, 0x96, 0xeb, 0x61, 0xf9, 0x14, 0x56, 0xf3, 0x29, 0x74, 0xc6, 0x4d, + 0x53, 0xb2, 0x7f, 0x0a, 0x90, 0x8f, 0x2f, 0xdd, 0xcc, 0xb2, 0xb6, 0xdd, 0xca, 0x29, 0xc7, 0x64, + 0x62, 0x9a, 0xcc, 0x4f, 0x4c, 0x13, 0xc7, 0x87, 0xb5, 0x73, 0x89, 0x7f, 0x57, 0xac, 0x28, 0x4f, + 0x13, 0x69, 0xdf, 0x85, 0x45, 0x5d, 0x47, 0x39, 0x50, 0xd3, 0x5f, 0x48, 0x25, 0x3e, 0x36, 0x9d, + 0xbb, 0x5a, 0x83, 0x78, 0x12, 0x30, 0x22, 0x3b, 0xf3, 0x3b, 0x8d, 0xdd, 0xa6, 0xbf, 0x3a, 0xaa, + 0xc4, 0x8f, 0x89, 0x74, 0x7e, 0x0f, 0xed, 0x1a, 0xa0, 0xbd, 0x0a, 0xf3, 0x25, 0xd6, 0x3c, 0x23, + 0xf6, 0x23, 0xd8, 0xac, 0x80, 0x26, 0x5b, 0x71, 0x86, 0xd8, 0xf2, 0xef, 0x95, 0x0c, 0x13, 0xdd, + 0x58, 0x3a, 0x4f, 0xe1, 0xce, 0x71, 0x55, 0xf8, 0x65, 0xa3, 0x9f, 0xf0, 0xd0, 0x9a, 0x9c, 0x97, + 0x5b, 0xd0, 0x2a, 0x77, 0x78, 0xe3, 0x7d, 0xd3, 0xaf, 0x08, 0x4e, 0x04, 0xeb, 0xe7, 0x12, 0x9f, + 0xd2, 0x98, 0x54, 0x60, 0xd7, 0x04, 0xe0, 0x70, 0x1a, 0x68, 0xe6, 0x5d, 0xb2, 0x52, 0xc7, 0x61, + 0xf3, 0x1c, 0x85, 0x8c, 0x20, 0xc5, 0xc5, 0x29, 0x55, 0xd9, 0x10, 0x2e, 0xca, 0xd1, 0x87, 0x66, + 0xc8, 0xa4, 0xca, 0x5f, 0xd6, 0xfb, 0xd7, 0xbe, 0xac, 0x74, 0xcf, 0xbd, 0x0e, 0xe4, 0x08, 0x29, + 0x94, 0xd7, 0xa2, 0xc1, 0x72, 0x7e, 0x09, 0x1b, 0x9f, 0x21, 0x35, 0x12, 0x94, 0x4c, 0xe4, 0x78, + 0x1d, 0x1a, 0x3a, 0x7f, 0x96, 0xc9, 0x9f, 0x3e, 0xea, 0x9d, 0xa0, 0xf3, 0xd1, 0xcb, 0x84, 0x0b, + 0x45, 0xc9, 0xa5, 0x88, 0xdc, 0x10, 0xde, 0x0b, 0xd8, 0xd0, 0xc1, 0x92, 0x34, 0x26, 0x41, 0xe9, + 0x67, 0x96, 0xc7, 0xf6, 0xfe, 0xaf, 0x67, 0xaa, 0x8e, 0x69, 0x75, 0xb9, 0x03, 0xb7, 0xd3, 0x29, + 0xba, 0x74, 0xfe, 0x62, 0x41, 0xe7, 0x09, 0x1d, 0x1f, 0x48, 0xc9, 0x06, 0x71, 0x44, 0x63, 0xa5, + 0xfb, 0x20, 0xc2, 0x54, 0x1f, 0xed, 0xb7, 0x61, 0xa5, 0x9c, 0xbb, 0x66, 0xdc, 0x5a, 0x66, 0xdc, + 0x2e, 0x17, 0x44, 0x5d, 0x60, 0xf6, 0x23, 0x80, 0x44, 0xd0, 0x34, 0xc0, 0xc1, 0x05, 0x1d, 0xe7, + 0x59, 0xdc, 0xaa, 0x8f, 0xd1, 0xec, 0x17, 0x96, 0x7b, 0x32, 0xea, 0x87, 0x0c, 0x3f, 0xa1, 0x63, + 0x7f, 0x49, 0xf3, 0xf7, 0x9e, 0xd0, 0xb1, 0xde, 0x8b, 0x12, 0xfe, 0x82, 0x0a, 0x33, 0xfb, 0x1a, + 0x7e, 0xf6, 0xe1, 0xfc, 0xd5, 0x82, 0x7b, 0x65, 0x3a, 0x8a, 0xe7, 0x7a, 0x32, 0xea, 0x6b, 0x89, + 0x1b, 0xe2, 0x76, 0xc9, 0xda, 0xf9, 0x2b, 0xac, 0xfd, 0x10, 0x96, 0xcb, 0x02, 0xd1, 0xf6, 0x36, + 0x66, 0xb0, 0xb7, 0x5d, 0x48, 0x3c, 0xa1, 0x63, 0xe7, 0x4f, 0x35, 0xdb, 0x0e, 0xc7, 0xb5, 0xde, + 0x27, 0xfe, 0x87, 0x6d, 0xa5, 0xda, 0xba, 0x6d, 0xb8, 0x2e, 0x7f, 0xc9, 0x81, 0xc6, 0x65, 0x07, + 0x9c, 0xbf, 0x59, 0x70, 0xa7, 0xae, 0x55, 0x9e, 0xf1, 0x13, 0x31, 0x8a, 0xe9, 0x4d, 0xda, 0xab, + 0xf2, 0x9b, 0xaf, 0x97, 0xdf, 0x33, 0x58, 0x9d, 0x30, 0x4a, 0xe6, 0xd1, 0x78, 0x6f, 0xa6, 0x37, + 0x56, 0xeb, 0xae, 0xfe, 0x4a, 0xdd, 0x0f, 0x79, 0xf8, 0xec, 0xdb, 0x57, 0x5d, 0xeb, 0xbb, 0x57, + 0x5d, 0xeb, 0x5f, 0xaf, 0xba, 0xd6, 0x57, 0xaf, 0xbb, 0x73, 0xdf, 0xbd, 0xee, 0xce, 0xfd, 0xf3, + 0x75, 0x77, 0xee, 0x0f, 0x1f, 0x0c, 0x98, 0x1a, 0x8e, 0xfa, 0x2e, 0xe6, 0x91, 0x97, 0xff, 0xcc, + 0xae, 0x74, 0xbd, 0x5b, 0xfe, 0xb7, 0x90, 0x3e, 0xf4, 0x5e, 0x4e, 0xfe, 0xd7, 0xa1, 0xc6, 0x09, + 0x95, 0xfd, 0x45, 0xd3, 0x15, 0x1e, 0xfe, 0x37, 0x00, 0x00, 0xff, 0xff, 0xd5, 0x67, 0x5a, 0xbb, + 0x1c, 0x11, 0x00, 0x00, } func (m *ConsumerAdditionProposal) Marshal() (dAtA []byte, err error) { @@ -1707,57 +1635,6 @@ func (m *ConsumerRemovalProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) return len(dAtA) - i, nil } -func (m *EquivocationProposal) 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 *EquivocationProposal) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *EquivocationProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Equivocations) > 0 { - for iNdEx := len(m.Equivocations) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Equivocations[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintProvider(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - } - } - if len(m.Description) > 0 { - i -= len(m.Description) - copy(dAtA[i:], m.Description) - i = encodeVarintProvider(dAtA, i, uint64(len(m.Description))) - i-- - dAtA[i] = 0x12 - } - if len(m.Title) > 0 { - i -= len(m.Title) - copy(dAtA[i:], m.Title) - i = encodeVarintProvider(dAtA, i, uint64(len(m.Title))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - func (m *ChangeRewardDenomsProposal) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -2684,29 +2561,6 @@ func (m *ConsumerRemovalProposal) Size() (n int) { return n } -func (m *EquivocationProposal) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Title) - if l > 0 { - n += 1 + l + sovProvider(uint64(l)) - } - l = len(m.Description) - if l > 0 { - n += 1 + l + sovProvider(uint64(l)) - } - if len(m.Equivocations) > 0 { - for _, e := range m.Equivocations { - l = e.Size() - n += 1 + l + sovProvider(uint64(l)) - } - } - return n -} - func (m *ChangeRewardDenomsProposal) Size() (n int) { if m == nil { return 0 @@ -3734,154 +3588,6 @@ func (m *ConsumerRemovalProposal) Unmarshal(dAtA []byte) error { } return nil } -func (m *EquivocationProposal) 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: EquivocationProposal: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: EquivocationProposal: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Title", 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.Title = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Description", 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.Description = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Equivocations", 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.Equivocations = append(m.Equivocations, &types1.Equivocation{}) - if err := m.Equivocations[len(m.Equivocations)-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 (m *ChangeRewardDenomsProposal) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -5515,7 +5221,7 @@ func (m *ValidatorSetChangePackets) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.List = append(m.List, types3.ValidatorSetChangePacketData{}) + m.List = append(m.List, types2.ValidatorSetChangePacketData{}) if err := m.List[len(m.List)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } diff --git a/x/ccv/types/expected_keepers.go b/x/ccv/types/expected_keepers.go index 3e2ff14c75..ac11c5dce5 100644 --- a/x/ccv/types/expected_keepers.go +++ b/x/ccv/types/expected_keepers.go @@ -15,7 +15,6 @@ import ( 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" - evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" @@ -52,10 +51,6 @@ type StakingKeeper interface { BondDenom(ctx sdk.Context) (res string) } -type EvidenceKeeper interface { - HandleEquivocationEvidence(ctx sdk.Context, evidence *evidencetypes.Equivocation) -} - // SlashingKeeper defines the contract expected to perform ccv slashing type SlashingKeeper interface { JailUntil(sdk.Context, sdk.ConsAddress, time.Time) // called from provider keeper only From d9903a2ea4b69e22f06f338838f2a9692f426a1a Mon Sep 17 00:00:00 2001 From: Simon Noetzlin Date: Mon, 2 Oct 2023 12:05:51 +0200 Subject: [PATCH 132/134] fix democ e2e tests --- tests/e2e/actions.go | 8 ++++++++ tests/e2e/state.go | 9 +++++++++ tests/e2e/steps.go | 8 +++++--- tests/e2e/steps_democracy.go | 2 +- tests/e2e/steps_reward_denom.go | 2 +- 5 files changed, 24 insertions(+), 5 deletions(-) diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index 5c4ab5636c..bcfff03483 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -1260,6 +1260,11 @@ func (tr TestRun) relayPacketsHermes( ) { // hermes clear packets ibc0 transfer channel-13 //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + fmt.Println("hermes", "clear", "packets", + "--chain", string(tr.chainConfigs[action.ChainA].ChainId), + "--port", action.Port, + "--channel", "channel-"+fmt.Sprint(action.Channel)) + cmd := exec.Command("docker", "exec", tr.containerConfig.InstanceName, "hermes", "clear", "packets", "--chain", string(tr.chainConfigs[action.ChainA].ChainId), "--port", action.Port, @@ -1291,6 +1296,9 @@ func (tr TestRun) relayRewardPacketsToProvider( ) { blockPerDistribution, _ := strconv.ParseUint(strings.Trim(tr.getParam(action.ConsumerChain, Param{Subspace: "ccvconsumer", Key: "BlocksPerDistributionTransmission"}), "\""), 10, 64) currentBlock := uint64(tr.getBlockHeight(action.ConsumerChain)) + fmt.Println("blockPerDistribution", blockPerDistribution) + fmt.Println("currentBlock", currentBlock) + if currentBlock <= blockPerDistribution { tr.waitBlocks(action.ConsumerChain, uint(blockPerDistribution-currentBlock+1), 60*time.Second) } diff --git a/tests/e2e/state.go b/tests/e2e/state.go index 4d0cc9c979..61f7410283 100644 --- a/tests/e2e/state.go +++ b/tests/e2e/state.go @@ -319,10 +319,19 @@ func (tr TestRun) getRewards(chain ChainID, modelState Rewards) Rewards { } func (tr TestRun) getReward(chain ChainID, validator ValidatorID, blockHeight uint, isNativeDenom bool) float64 { + delAddresss := tr.validatorConfigs[validator].DelAddress if chain != ChainID("provi") && tr.validatorConfigs[validator].UseConsumerKey { delAddresss = tr.validatorConfigs[validator].ConsumerDelAddress } + + fmt.Println("getReward", tr.containerConfig.InstanceName, tr.chainConfigs[chain].BinaryName, + "query", "distribution", "rewards", + delAddresss, + + `--height`, fmt.Sprint(blockHeight), + `--node`, tr.getQueryNode(chain), + `-o`, `json`) //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. bz, err := exec.Command("docker", "exec", tr.containerConfig.InstanceName, tr.chainConfigs[chain].BinaryName, diff --git a/tests/e2e/steps.go b/tests/e2e/steps.go index 68417f667c..498516bea8 100644 --- a/tests/e2e/steps.go +++ b/tests/e2e/steps.go @@ -24,6 +24,7 @@ var happyPathSteps = concatSteps( stepsRedelegate("consu"), stepsDowntime("consu"), stepsDoubleSignOnProvider("consu"), // carol double signs on provider + // TODO: add double sign on consumer stepsStartRelayer(), stepsConsumerRemovalPropNotPassing("consu", 2), // submit removal prop but vote no on it - chain should stay stepsStopChain("consu", 3), // stop chain @@ -35,10 +36,11 @@ var shortHappyPathSteps = concatSteps( stepsUnbond("consu"), stepsRedelegateShort("consu"), stepsDowntime("consu"), - stepsDoubleSignOnProvider("consu"), // carol double signs on provider, bob double signs on consumer + stepsDoubleSignOnProvider("consu"), // carol double signs on provider + // TODO: add double sign on consumer stepsStartRelayer(), - stepsConsumerRemovalPropNotPassing("consu", 3), // submit removal prop but vote no on it - chain should stay - stepsStopChain("consu", 4), // stop chain + stepsConsumerRemovalPropNotPassing("consu", 2), // submit removal prop but vote no on it - chain should stay + stepsStopChain("consu", 3), // stop chain ) var lightClientAttackSteps = concatSteps( diff --git a/tests/e2e/steps_democracy.go b/tests/e2e/steps_democracy.go index 9779ce45bc..7877f719c0 100644 --- a/tests/e2e/steps_democracy.go +++ b/tests/e2e/steps_democracy.go @@ -100,7 +100,7 @@ func stepsDemocracy(consumerName string) []Step { State: State{ ChainID(consumerName): ChainState{ ValBalances: &map[ValidatorID]uint{ - ValidatorID("alice"): 9889999998, + ValidatorID("alice"): 9899999999, ValidatorID("bob"): 9960000001, }, // Check that the parameter is changed on gov-consumer chain diff --git a/tests/e2e/steps_reward_denom.go b/tests/e2e/steps_reward_denom.go index 125f3dd401..1a2d4af6a3 100644 --- a/tests/e2e/steps_reward_denom.go +++ b/tests/e2e/steps_reward_denom.go @@ -98,7 +98,7 @@ func stepsRewardDenomConsumer(consumerName string) []Step { State: State{ ChainID(consumerName): ChainState{ ValBalances: &map[ValidatorID]uint{ - ValidatorID("alice"): 9889999998, + ValidatorID("alice"): 9899999999, ValidatorID("bob"): 9960000001, }, // Check that the parameter is changed on gov-consumer chain From 67b8c3170aad76d82b695ea8280f366442012187 Mon Sep 17 00:00:00 2001 From: insumity Date: Wed, 27 Sep 2023 15:26:51 +0200 Subject: [PATCH 133/134] make mem tests pass --- tests/e2e/steps_consumer_misbehaviour.go | 10 + tests/e2e/steps_double_sign.go | 19 +- tests/integration/double_vote.go | 134 ++++++- tests/integration/misbehaviour.go | 12 +- testutil/integration/debug_test.go | 2 +- testutil/keeper/mocks.go | 56 +++ x/ccv/provider/keeper/double_vote.go | 8 +- x/ccv/provider/keeper/misbehaviour.go | 24 +- x/ccv/provider/keeper/punish_validator.go | 100 ++++- .../provider/keeper/punish_validator_test.go | 359 +++++++++++++++++- x/ccv/types/expected_keepers.go | 8 +- 11 files changed, 694 insertions(+), 38 deletions(-) diff --git a/tests/e2e/steps_consumer_misbehaviour.go b/tests/e2e/steps_consumer_misbehaviour.go index 84b504541e..560dfd069c 100644 --- a/tests/e2e/steps_consumer_misbehaviour.go +++ b/tests/e2e/steps_consumer_misbehaviour.go @@ -230,6 +230,10 @@ func stepsCauseConsumerMisbehaviour(consumerName string) []Step { ValidatorID("alice"): 511, ValidatorID("bob"): 20, }, + RepresentativePowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 511000000, + ValidatorID("bob"): 20000000, + }, }, ChainID(consumerName): ChainState{ ValPowers: &map[ValidatorID]uint{ @@ -255,6 +259,12 @@ func stepsCauseConsumerMisbehaviour(consumerName string) []Step { ValidatorID("alice"): 0, ValidatorID("bob"): 20, }, + // "alice" should be slashed on the provider, hence representative + // power is 511000000 - 0.05 * 511000000 = 485450000 + RepresentativePowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 485450000, + ValidatorID("bob"): 20000000, + }, // The consumer light client should be frozen on the provider ClientsFrozenHeights: &map[string]clienttypes.Height{ consumerClientID: { diff --git a/tests/e2e/steps_double_sign.go b/tests/e2e/steps_double_sign.go index 9d6e3c73b7..6d228274c3 100644 --- a/tests/e2e/steps_double_sign.go +++ b/tests/e2e/steps_double_sign.go @@ -70,6 +70,11 @@ func stepsCauseDoubleSignOnConsumer(consumerName, providerName string) []Step { ValidatorID("bob"): 500, ValidatorID("carol"): 500, }, + RepresentativePowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 500000000, + ValidatorID("bob"): 500000000, + ValidatorID("carol"): 500000000, + }, }, ChainID(consumerName): ChainState{ ValPowers: &map[ValidatorID]uint{ @@ -81,7 +86,7 @@ func stepsCauseDoubleSignOnConsumer(consumerName, providerName string) []Step { }, }, // detect the double voting infraction - // and jail bob on the provider + // and jail and slashing of bob on the provider { Action: startConsumerEvidenceDetectorAction{ Chain: ChainID(consumerName), @@ -93,6 +98,13 @@ func stepsCauseDoubleSignOnConsumer(consumerName, providerName string) []Step { ValidatorID("bob"): 0, ValidatorID("carol"): 500, }, + // "bob" gets slashed on the provider chain, hence representative + // power is 500000000 - 0.05 * 500000000 = 475000000 + RepresentativePowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 500000000, + ValidatorID("bob"): 475000000, + ValidatorID("carol"): 500000000, + }, }, ChainID(consumerName): ChainState{ ValPowers: &map[ValidatorID]uint{ @@ -118,6 +130,11 @@ func stepsCauseDoubleSignOnConsumer(consumerName, providerName string) []Step { ValidatorID("bob"): 0, ValidatorID("carol"): 500, }, + RepresentativePowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 500000000, + ValidatorID("bob"): 475000000, + ValidatorID("carol"): 500000000, + }, }, ChainID(consumerName): ChainState{ ValPowers: &map[ValidatorID]uint{ diff --git a/tests/integration/double_vote.go b/tests/integration/double_vote.go index 457be3ebc9..679a7c664b 100644 --- a/tests/integration/double_vote.go +++ b/tests/integration/double_vote.go @@ -10,7 +10,7 @@ import ( ) // TestHandleConsumerDoubleVoting verifies that handling a double voting evidence -// of a consumer chain results in the expected jailing of the malicious validator +// of a consumer chain results in the expected tombstoning and jailing the misbehaved validator func (s *CCVTestSuite) TestHandleConsumerDoubleVoting() { s.SetupCCVChannel(s.path) // required to have the consumer client revision height greater than 0 @@ -24,11 +24,11 @@ func (s *CCVTestSuite) TestHandleConsumerDoubleVoting() { consuValSet, err := tmtypes.ValidatorSetFromProto(s.consumerChain.LastHeader.ValidatorSet) s.Require().NoError(err) consuVal := consuValSet.Validators[0] - s.Require().NoError(err) consuSigner := s.consumerChain.Signers[consuVal.Address.String()] provValSet, err := tmtypes.ValidatorSetFromProto(s.providerChain.LastHeader.ValidatorSet) s.Require().NoError(err) + provVal := provValSet.Validators[0] provSigner := s.providerChain.Signers[provVal.Address.String()] @@ -156,13 +156,16 @@ func (s *CCVTestSuite) TestHandleConsumerDoubleVoting() { }, } - consuAddr := types.NewConsumerConsAddress(sdk.ConsAddress(consuVal.Address.Bytes())) - provAddr := s.providerApp.GetProviderKeeper().GetProviderAddrFromConsumerAddr(s.providerCtx(), s.consumerChain.ChainID, consuAddr) - for _, tc := range testCases { s.Run(tc.name, func() { + consuAddr := types.NewConsumerConsAddress(sdk.ConsAddress(tc.ev.VoteA.ValidatorAddress.Bytes())) + provAddr := s.providerApp.GetProviderKeeper().GetProviderAddrFromConsumerAddr(s.providerCtx(), s.consumerChain.ChainID, consuAddr) + + validator, _ := s.providerApp.GetTestStakingKeeper().GetValidator(s.providerCtx(), provAddr.ToSdkConsAddr().Bytes()) + initialTokens := sdk.NewDecFromInt(validator.GetTokens()) + // reset context for each run - provCtx := s.providerCtx() + provCtx, _ := s.providerCtx().CacheContext() // if the evidence was built using the validator provider address and key, // we remove the consumer key assigned to the validator otherwise @@ -185,14 +188,129 @@ func (s *CCVTestSuite) TestHandleConsumerDoubleVoting() { if tc.expPass { s.Require().NoError(err) - // verifies that the jailing has occurred + // verifies that the jailing and tombstoning has occurred s.Require().True(s.providerApp.GetTestStakingKeeper().IsValidatorJailed(provCtx, provAddr.ToSdkConsAddr())) + s.Require().True(s.providerApp.GetTestSlashingKeeper().IsTombstoned(provCtx, provAddr.ToSdkConsAddr())) + + // verifies that the val gets slashed and has fewer tokens after the slashing + val, _ := s.providerApp.GetTestStakingKeeper().GetValidator(provCtx, provAddr.ToSdkConsAddr().Bytes()) + slashFraction := s.providerApp.GetTestSlashingKeeper().SlashFractionDoubleSign(provCtx) + actualTokens := sdk.NewDecFromInt(val.GetTokens()) + s.Require().True(initialTokens.Sub(initialTokens.Mul(slashFraction)).Equal(actualTokens)) } else { s.Require().Error(err) - // verifies that no jailing and has occurred + // verifies that no jailing and no tombstoning has occurred s.Require().False(s.providerApp.GetTestStakingKeeper().IsValidatorJailed(provCtx, provAddr.ToSdkConsAddr())) + s.Require().False(s.providerApp.GetTestSlashingKeeper().IsTombstoned(provCtx, provAddr.ToSdkConsAddr())) } }) } } + +// TestHandleConsumerDoubleVotingSlashesUndelegations verifies that handling a successful double voting +// evidence of a consumer chain results in the expected slashing of the misbehave validator undelegations +func (s *CCVTestSuite) TestHandleConsumerDoubleVotingSlashesUndelegations() { + s.SetupCCVChannel(s.path) + // required to have the consumer client revision height greater than 0 + s.SendEmptyVSCPacket() + + // create signing info for all validators + for _, v := range s.providerChain.Vals.Validators { + s.setDefaultValSigningInfo(*v) + } + + consuValSet, err := tmtypes.ValidatorSetFromProto(s.consumerChain.LastHeader.ValidatorSet) + s.Require().NoError(err) + consuVal := consuValSet.Validators[0] + consuSigner := s.consumerChain.Signers[consuVal.Address.String()] + + blockID1 := testutil.MakeBlockID([]byte("blockhash"), 1000, []byte("partshash")) + blockID2 := testutil.MakeBlockID([]byte("blockhash2"), 1000, []byte("partshash")) + + // create two votes using the consumer validator key + consuVote := testutil.MakeAndSignVote( + blockID1, + s.consumerCtx().BlockHeight(), + s.consumerCtx().BlockTime(), + consuValSet, + consuSigner, + s.consumerChain.ChainID, + ) + + consuBadVote := testutil.MakeAndSignVote( + blockID2, + s.consumerCtx().BlockHeight(), + s.consumerCtx().BlockTime(), + consuValSet, + consuSigner, + s.consumerChain.ChainID, + ) + + // In order to create an evidence for a consumer chain, + // we create two votes that only differ by their Block IDs and + // signed them using the same validator private key and chain ID + // of the consumer chain + evidence := &tmtypes.DuplicateVoteEvidence{ + VoteA: consuVote, + VoteB: consuBadVote, + ValidatorPower: consuVal.VotingPower, + TotalVotingPower: consuVal.VotingPower, + Timestamp: s.consumerCtx().BlockTime(), + } + + chainID := s.consumerChain.ChainID + pubKey := consuVal.PubKey + + consuAddr := types.NewConsumerConsAddress(sdk.ConsAddress(consuVal.Address.Bytes())) + provAddr := s.providerApp.GetProviderKeeper().GetProviderAddrFromConsumerAddr(s.providerCtx(), s.consumerChain.ChainID, consuAddr) + + validator, found := s.providerApp.GetTestStakingKeeper().GetValidator(s.providerCtx(), provAddr.ToSdkConsAddr().Bytes()) + s.Require().True(found) + + s.Run("slash undelegations when getting double voting evidence", func() { + // convert validator public key + pk, err := cryptocodec.FromTmPubKeyInterface(pubKey) + s.Require().NoError(err) + + // perform a delegation and an undelegation of the whole amount + bondAmt := sdk.NewInt(10000000) + delAddr := s.providerChain.SenderAccount.GetAddress() + + // in order to perform a delegation we need to know the validator's `idx` (that might not be 0) + // loop through all validators to find the right `idx` + idx := 0 + for i := 0; i <= len(s.providerChain.Vals.Validators); i++ { + _, valAddr := s.getValByIdx(i) + if validator.OperatorAddress == valAddr.String() { + idx = i + break + } + } + + _, shares, valAddr := delegateByIdx(s, delAddr, bondAmt, idx) + _ = undelegate(s, delAddr, valAddr, shares) + + _, shares, _ = delegateByIdx(s, delAddr, sdk.NewInt(50000000), idx) + _ = undelegate(s, delAddr, valAddr, shares) + + err = s.providerApp.GetProviderKeeper().HandleConsumerDoubleVoting( + s.providerCtx(), + evidence, + chainID, + pk, + ) + s.Require().NoError(err) + + slashFraction := s.providerApp.GetTestSlashingKeeper().SlashFractionDoubleSign(s.providerCtx()) + + // check undelegations are slashed + ubds, _ := s.providerApp.GetTestStakingKeeper().GetUnbondingDelegation(s.providerCtx(), delAddr, validator.GetOperator()) + s.Require().True(len(ubds.Entries) > 0) + for _, unb := range ubds.Entries { + initialBalance := sdk.NewDecFromInt(unb.InitialBalance) + currentBalance := sdk.NewDecFromInt(unb.Balance) + s.Require().True(initialBalance.Sub(initialBalance.Mul(slashFraction)).Equal(currentBalance)) + } + }) +} diff --git a/tests/integration/misbehaviour.go b/tests/integration/misbehaviour.go index f43df4b285..336a2bf215 100644 --- a/tests/integration/misbehaviour.go +++ b/tests/integration/misbehaviour.go @@ -53,16 +53,26 @@ func (s *CCVTestSuite) TestHandleConsumerMisbehaviour() { ), } + // we assume that all validators have the same number of initial tokens + validator, _ := s.getValByIdx(0) + initialTokens := sdk.NewDecFromInt(validator.GetTokens()) + err := s.providerApp.GetProviderKeeper().HandleConsumerMisbehaviour(s.providerCtx(), *misb) s.NoError(err) - // verify that validators are jailed and tombstoned + // verify that validators are jailed, tombstoned, and slashed for _, v := range clientTMValset.Validators { consuAddr := sdk.ConsAddress(v.Address.Bytes()) provAddr := s.providerApp.GetProviderKeeper().GetProviderAddrFromConsumerAddr(s.providerCtx(), s.consumerChain.ChainID, types.NewConsumerConsAddress(consuAddr)) val, ok := s.providerApp.GetTestStakingKeeper().GetValidatorByConsAddr(s.providerCtx(), provAddr.Address) s.Require().True(ok) s.Require().True(val.Jailed) + s.Require().True(s.providerApp.GetTestSlashingKeeper().IsTombstoned(s.providerCtx(), provAddr.ToSdkConsAddr())) + + validator, _ := s.providerApp.GetTestStakingKeeper().GetValidator(s.providerCtx(), provAddr.ToSdkConsAddr().Bytes()) + slashFraction := s.providerApp.GetTestSlashingKeeper().SlashFractionDoubleSign(s.providerCtx()) + actualTokens := sdk.NewDecFromInt(validator.GetTokens()) + s.Require().True(initialTokens.Sub(initialTokens.Mul(slashFraction)).Equal(actualTokens)) } } diff --git a/testutil/integration/debug_test.go b/testutil/integration/debug_test.go index d06a30e1b2..a2132266e7 100644 --- a/testutil/integration/debug_test.go +++ b/testutil/integration/debug_test.go @@ -274,7 +274,7 @@ func TestCheckMisbehaviour(t *testing.T) { } // -// Equivocation test +// Consumer Equivocation test // func TestHandleConsumerDoubleVoting(t *testing.T) { diff --git a/testutil/keeper/mocks.go b/testutil/keeper/mocks.go index 0311873349..b00678a50a 100644 --- a/testutil/keeper/mocks.go +++ b/testutil/keeper/mocks.go @@ -117,6 +117,34 @@ func (mr *MockStakingKeeperMockRecorder) GetLastValidators(ctx interface{}) *gom return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLastValidators", reflect.TypeOf((*MockStakingKeeper)(nil).GetLastValidators), ctx) } +// GetRedelegationsFromSrcValidator mocks base method. +func (m *MockStakingKeeper) GetRedelegationsFromSrcValidator(ctx types0.Context, valAddr types0.ValAddress) []types4.Redelegation { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetRedelegationsFromSrcValidator", ctx, valAddr) + ret0, _ := ret[0].([]types4.Redelegation) + return ret0 +} + +// GetRedelegationsFromSrcValidator indicates an expected call of GetRedelegationsFromSrcValidator. +func (mr *MockStakingKeeperMockRecorder) GetRedelegationsFromSrcValidator(ctx, valAddr interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRedelegationsFromSrcValidator", reflect.TypeOf((*MockStakingKeeper)(nil).GetRedelegationsFromSrcValidator), ctx, valAddr) +} + +// GetUnbondingDelegationsFromValidator mocks base method. +func (m *MockStakingKeeper) GetUnbondingDelegationsFromValidator(ctx types0.Context, valAddr types0.ValAddress) []types4.UnbondingDelegation { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUnbondingDelegationsFromValidator", ctx, valAddr) + ret0, _ := ret[0].([]types4.UnbondingDelegation) + return ret0 +} + +// GetUnbondingDelegationsFromValidator indicates an expected call of GetUnbondingDelegationsFromValidator. +func (mr *MockStakingKeeperMockRecorder) GetUnbondingDelegationsFromValidator(ctx, valAddr interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUnbondingDelegationsFromValidator", reflect.TypeOf((*MockStakingKeeper)(nil).GetUnbondingDelegationsFromValidator), ctx, valAddr) +} + // GetUnbondingType mocks base method. func (m *MockStakingKeeper) GetUnbondingType(ctx types0.Context, id uint64) (types4.UnbondingType, bool) { m.ctrl.T.Helper() @@ -282,6 +310,34 @@ func (mr *MockStakingKeeperMockRecorder) Slash(arg0, arg1, arg2, arg3, arg4 inte return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Slash", reflect.TypeOf((*MockStakingKeeper)(nil).Slash), arg0, arg1, arg2, arg3, arg4) } +// SlashRedelegation mocks base method. +func (m *MockStakingKeeper) SlashRedelegation(arg0 types0.Context, arg1 types4.Validator, arg2 types4.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) + return ret0 +} + +// SlashRedelegation indicates an expected call of SlashRedelegation. +func (mr *MockStakingKeeperMockRecorder) SlashRedelegation(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SlashRedelegation", reflect.TypeOf((*MockStakingKeeper)(nil).SlashRedelegation), arg0, arg1, arg2, arg3, arg4) +} + +// SlashUnbondingDelegation mocks base method. +func (m *MockStakingKeeper) SlashUnbondingDelegation(arg0 types0.Context, arg1 types4.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) + return ret0 +} + +// SlashUnbondingDelegation indicates an expected call of SlashUnbondingDelegation. +func (mr *MockStakingKeeperMockRecorder) SlashUnbondingDelegation(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SlashUnbondingDelegation", reflect.TypeOf((*MockStakingKeeper)(nil).SlashUnbondingDelegation), arg0, arg1, arg2, arg3) +} + // 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 { m.ctrl.T.Helper() diff --git a/x/ccv/provider/keeper/double_vote.go b/x/ccv/provider/keeper/double_vote.go index 7e78d7bee6..0d18eed809 100644 --- a/x/ccv/provider/keeper/double_vote.go +++ b/x/ccv/provider/keeper/double_vote.go @@ -33,8 +33,12 @@ func (k Keeper) HandleConsumerDoubleVoting( types.NewConsumerConsAddress(sdk.ConsAddress(evidence.VoteA.ValidatorAddress.Bytes())), ) - // execute the jailing - k.JailValidator(ctx, providerAddr) + if err := k.SlashValidator(ctx, providerAddr); err != nil { + return err + } + if err := k.JailAndTombstoneValidator(ctx, providerAddr); err != nil { + return err + } k.Logger(ctx).Info( "confirmed equivocation", diff --git a/x/ccv/provider/keeper/misbehaviour.go b/x/ccv/provider/keeper/misbehaviour.go index c75b559cd7..b366a5ebc8 100644 --- a/x/ccv/provider/keeper/misbehaviour.go +++ b/x/ccv/provider/keeper/misbehaviour.go @@ -1,6 +1,8 @@ package keeper import ( + "fmt" + tmtypes "github.com/cometbft/cometbft/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -33,14 +35,22 @@ func (k Keeper) HandleConsumerMisbehaviour(ctx sdk.Context, misbehaviour ibctmty provAddrs := make([]types.ProviderConsAddress, len(byzantineValidators)) - // jail the Byzantine validators + var errors []error + // slash, jail, and tombstone the Byzantine validators for _, v := range byzantineValidators { providerAddr := k.GetProviderAddrFromConsumerAddr( ctx, misbehaviour.Header1.Header.ChainID, types.NewConsumerConsAddress(sdk.ConsAddress(v.Address.Bytes())), ) - k.JailValidator(ctx, providerAddr) + err := k.SlashValidator(ctx, providerAddr) + if err != nil { + errors = append(errors, err) + } + err = k.JailAndTombstoneValidator(ctx, providerAddr) + if err != nil { + errors = append(errors, err) + } provAddrs = append(provAddrs, providerAddr) } @@ -49,6 +59,16 @@ func (k Keeper) HandleConsumerMisbehaviour(ctx sdk.Context, misbehaviour ibctmty "byzantine validators", provAddrs, ) + // If we fail to slash all validators we return an error. However, if we only fail to slash some validators + // we just log an error to avoid having the whole `MsgSubmitMisbehaviour` failing and reverting the partial slashing. + if len(errors) == len(byzantineValidators) { + return fmt.Errorf("failed to slash, jail, or tombstone all validators: %v", errors) + } + + if len(errors) > 0 { + logger.Error("failed to slash, jail, or tombstone validators: %v", errors) + } + return nil } diff --git a/x/ccv/provider/keeper/punish_validator.go b/x/ccv/provider/keeper/punish_validator.go index b9ededfd00..e008bdeed6 100644 --- a/x/ccv/provider/keeper/punish_validator.go +++ b/x/ccv/provider/keeper/punish_validator.go @@ -1,38 +1,104 @@ package keeper import ( + "fmt" + + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ) -// JailValidator jails the validator with the given provider consensus address -// Note that the tombstoning is temporarily removed until we slash validator -// for double signing on a consumer chain, see comment -// https://github.com/cosmos/interchain-security/pull/1232#issuecomment-1693127641. -func (k Keeper) JailValidator(ctx sdk.Context, providerAddr types.ProviderConsAddress) { - logger := k.Logger(ctx) +// JailAndTombstoneValidator jails and tombstones the validator with the given provider consensus address +func (k Keeper) JailAndTombstoneValidator(ctx sdk.Context, providerAddr types.ProviderConsAddress) error { + validator, found := k.stakingKeeper.GetValidatorByConsAddr(ctx, providerAddr.ToSdkConsAddr()) + if !found { + return errorsmod.Wrapf(slashingtypes.ErrNoValidatorForAddress, "provider consensus address: %s", providerAddr.String()) + } - // get validator - val, ok := k.stakingKeeper.GetValidatorByConsAddr(ctx, providerAddr.ToSdkConsAddr()) - if !ok || val.IsUnbonded() { - logger.Error("validator not found or is unbonded", providerAddr.String()) - return + if validator.IsUnbonded() { + return fmt.Errorf("validator is unbonded. provider consensus address: %s", providerAddr.String()) } - // check that the validator isn't tombstoned if k.slashingKeeper.IsTombstoned(ctx, providerAddr.ToSdkConsAddr()) { - logger.Info("validator is already tombstoned", "provider cons addr", providerAddr.String()) - return + return fmt.Errorf("validator is tombstoned. provider consensus address: %s", providerAddr.String()) } // jail validator if not already - if !val.IsJailed() { + if !validator.IsJailed() { k.stakingKeeper.Jail(ctx, providerAddr.ToSdkConsAddr()) } - // update jail time to end after double sign jail duration + // Jail the validator to trigger the unbonding of the validator + // (see cosmos/cosmos-sdk/blob/v0.45.16-ics-lsm/x/staking/keeper/val_state_change.go#L192). k.slashingKeeper.JailUntil(ctx, providerAddr.ToSdkConsAddr(), evidencetypes.DoubleSignJailEndTime) - // TODO: add tombstoning back once we integrate the slashing + // Tombstone the validator so that we cannot slash the validator more than once + // (see cosmos/cosmos-sdk/blob/v0.45.16-ics-lsm/x/evidence/keeper/infraction.go#L81). + // Note that we cannot simply use the fact that a validator is jailed to avoid slashing more than once + // because then a validator could i) perform an equivocation, ii) get jailed (e.g., through downtime) + // and in such a case the validator would not get slashed when we call `SlashValidator`. + k.slashingKeeper.Tombstone(ctx, providerAddr.ToSdkConsAddr()) + + return nil +} + +// ComputePowerToSlash computes the power to be slashed based on the tokens in non-matured `undelegations` and +// `redelegations`, as well as the current `power` of the validator. +// Note that this method does not perform any slashing. +func (k Keeper) ComputePowerToSlash(ctx sdk.Context, validator stakingtypes.Validator, undelegations []stakingtypes.UnbondingDelegation, + redelegations []stakingtypes.Redelegation, power int64, powerReduction sdk.Int, +) int64 { + // compute the total numbers of tokens currently being undelegated + undelegationsInTokens := sdk.NewInt(0) + + // Note that we use a **cached** context to avoid any actual slashing of undelegations or redelegations. + cachedCtx, _ := ctx.CacheContext() + for _, u := range undelegations { + amountSlashed := k.stakingKeeper.SlashUnbondingDelegation(cachedCtx, u, 0, sdk.NewDec(1)) + undelegationsInTokens = undelegationsInTokens.Add(amountSlashed) + } + + // compute the total numbers of tokens currently being redelegated + redelegationsInTokens := sdk.NewInt(0) + for _, r := range redelegations { + amountSlashed := k.stakingKeeper.SlashRedelegation(cachedCtx, validator, r, 0, sdk.NewDec(1)) + redelegationsInTokens = redelegationsInTokens.Add(amountSlashed) + } + + // The power we pass to staking's keeper `Slash` method is the current power of the validator together with the total + // power of all the currently undelegated and redelegated tokens (see docs/docs/adrs/adr-013-equivocation-slashing.md). + undelegationsAndRedelegationsInPower := sdk.TokensToConsensusPower( + undelegationsInTokens.Add(redelegationsInTokens), powerReduction) + + return power + undelegationsAndRedelegationsInPower +} + +// SlashValidator slashes validator with `providerAddr` +func (k Keeper) SlashValidator(ctx sdk.Context, providerAddr types.ProviderConsAddress) error { + validator, found := k.stakingKeeper.GetValidatorByConsAddr(ctx, providerAddr.ToSdkConsAddr()) + if !found { + return errorsmod.Wrapf(slashingtypes.ErrNoValidatorForAddress, "provider consensus address: %s", providerAddr.String()) + } + + if validator.IsUnbonded() { + return fmt.Errorf("validator is unbonded. provider consensus address: %s", providerAddr.String()) + } + + if k.slashingKeeper.IsTombstoned(ctx, providerAddr.ToSdkConsAddr()) { + return fmt.Errorf("validator is tombstoned. provider consensus address: %s", providerAddr.String()) + } + + undelegations := k.stakingKeeper.GetUnbondingDelegationsFromValidator(ctx, validator.GetOperator()) + redelegations := k.stakingKeeper.GetRedelegationsFromSrcValidator(ctx, validator.GetOperator()) + lastPower := k.stakingKeeper.GetLastValidatorPower(ctx, validator.GetOperator()) + powerReduction := k.stakingKeeper.PowerReduction(ctx) + totalPower := k.ComputePowerToSlash(ctx, validator, undelegations, redelegations, lastPower, powerReduction) + slashFraction := k.slashingKeeper.SlashFractionDoubleSign(ctx) + + k.stakingKeeper.SlashWithInfractionReason(ctx, providerAddr.ToSdkConsAddr(), 0, totalPower, slashFraction, stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN) + return nil } diff --git a/x/ccv/provider/keeper/punish_validator_test.go b/x/ccv/provider/keeper/punish_validator_test.go index 28c3529d51..2efc0c26e2 100644 --- a/x/ccv/provider/keeper/punish_validator_test.go +++ b/x/ccv/provider/keeper/punish_validator_test.go @@ -1,7 +1,13 @@ package keeper_test import ( + "fmt" "testing" + "time" + + "cosmossdk.io/math" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" sdk "github.com/cosmos/cosmos-sdk/types" evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" @@ -10,11 +16,14 @@ import ( testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" "github.com/golang/mock/gomock" + + tmtypes "github.com/cometbft/cometbft/types" + "github.com/stretchr/testify/require" ) -// TestJailValidator tests that the jailing of a validator is only executed -// under the conditions that the validator is neither unbonded, already jailed, nor tombstoned. -func TestJailValidator(t *testing.T) { +// TestJailAndTombstoneValidator tests that the jailing of a validator is only executed +// under the conditions that the validator is neither unbonded, nor jailed, nor tombstoned. +func TestJailAndTombstoneValidator(t *testing.T) { providerConsAddr := cryptotestutil.NewCryptoIdentityFromIntSeed(7842334).ProviderConsAddress() testCases := []struct { name string @@ -88,6 +97,9 @@ func TestJailValidator(t *testing.T) { mocks.MockSlashingKeeper.EXPECT().JailUntil( ctx, providerConsAddr.ToSdkConsAddr(), evidencetypes.DoubleSignJailEndTime). Times(1), + mocks.MockSlashingKeeper.EXPECT().Tombstone( + ctx, providerConsAddr.ToSdkConsAddr()). + Times(1), } }, }, @@ -112,6 +124,9 @@ func TestJailValidator(t *testing.T) { mocks.MockSlashingKeeper.EXPECT().JailUntil( ctx, providerConsAddr.ToSdkConsAddr(), evidencetypes.DoubleSignJailEndTime). Times(1), + mocks.MockSlashingKeeper.EXPECT().Tombstone( + ctx, providerConsAddr.ToSdkConsAddr()). + Times(1), } }, }, @@ -125,8 +140,344 @@ func TestJailValidator(t *testing.T) { gomock.InOrder(tc.expectedCalls(ctx, mocks, tc.provAddr)...) // Execute method and assert expected mock calls - providerKeeper.JailValidator(ctx, tc.provAddr) + providerKeeper.JailAndTombstoneValidator(ctx, tc.provAddr) ctrl.Finish() } } + +// createUndelegation creates an undelegation with `len(initialBalances)` entries +func createUndelegation(initialBalances []int64, completionTimes []time.Time) stakingtypes.UnbondingDelegation { + var entries []stakingtypes.UnbondingDelegationEntry + for i, balance := range initialBalances { + entry := stakingtypes.UnbondingDelegationEntry{ + InitialBalance: sdk.NewInt(balance), + CompletionTime: completionTimes[i], + } + entries = append(entries, entry) + } + + return stakingtypes.UnbondingDelegation{Entries: entries} +} + +// createRedelegation creates a redelegation with `len(initialBalances)` entries +func createRedelegation(initialBalances []int64, completionTimes []time.Time) stakingtypes.Redelegation { + var entries []stakingtypes.RedelegationEntry + for i, balance := range initialBalances { + entry := stakingtypes.RedelegationEntry{ + InitialBalance: sdk.NewInt(balance), + CompletionTime: completionTimes[i], + } + entries = append(entries, entry) + } + + return stakingtypes.Redelegation{Entries: entries} +} + +// TestComputePowerToSlash tests that `ComputePowerToSlash` computes the correct power to be slashed based on +// the tokens in non-mature undelegation and redelegation entries, as well as the current power of the validator +func TestComputePowerToSlash(t *testing.T) { + providerKeeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + // undelegation or redelegation entries with completion time `now` have matured + now := ctx.BlockHeader().Time + // undelegation or redelegation entries with completion time one hour in the future have not yet matured + nowPlus1Hour := now.Add(time.Hour) + + testCases := []struct { + name string + undelegations []stakingtypes.UnbondingDelegation + redelegations []stakingtypes.Redelegation + power int64 + powerReduction sdk.Int + expectedPower int64 + }{ + { + "both undelegations and redelegations 1", + // 1000 total undelegation tokens + []stakingtypes.UnbondingDelegation{ + createUndelegation([]int64{250, 250}, []time.Time{nowPlus1Hour, nowPlus1Hour}), + createUndelegation([]int64{500}, []time.Time{nowPlus1Hour, nowPlus1Hour}), + }, + // 1000 total redelegation tokens + []stakingtypes.Redelegation{ + createRedelegation([]int64{500}, []time.Time{nowPlus1Hour, nowPlus1Hour}), + createRedelegation([]int64{250, 250}, []time.Time{nowPlus1Hour, nowPlus1Hour}), + }, + int64(1000), + sdk.NewInt(1), + int64(2000/1 + 1000), + }, + { + "both undelegations and redelegations 2", + // 2000 total undelegation tokens + []stakingtypes.UnbondingDelegation{ + createUndelegation([]int64{250, 250}, []time.Time{nowPlus1Hour, nowPlus1Hour}), + createUndelegation([]int64{}, []time.Time{}), + createUndelegation([]int64{100, 100}, []time.Time{nowPlus1Hour, nowPlus1Hour}), + createUndelegation([]int64{800}, []time.Time{nowPlus1Hour}), + createUndelegation([]int64{500}, []time.Time{nowPlus1Hour}), + }, + // 3500 total redelegation tokens + []stakingtypes.Redelegation{ + createRedelegation([]int64{}, []time.Time{}), + createRedelegation([]int64{1600}, []time.Time{nowPlus1Hour}), + createRedelegation([]int64{350, 250}, []time.Time{nowPlus1Hour, nowPlus1Hour}), + createRedelegation([]int64{700, 200}, []time.Time{nowPlus1Hour, nowPlus1Hour}), + createRedelegation([]int64{}, []time.Time{}), + createRedelegation([]int64{400}, []time.Time{nowPlus1Hour}), + }, + int64(8391), + sdk.NewInt(2), + int64((2000+3500)/2 + 8391), + }, + { + "no undelegations or redelegations, return provided power", + []stakingtypes.UnbondingDelegation{}, + []stakingtypes.Redelegation{}, + int64(3000), + sdk.NewInt(5), + int64(3000), // expectedPower is 0/5 + 3000 + }, + { + "no undelegations", + []stakingtypes.UnbondingDelegation{}, + // 2000 total redelegation tokens + []stakingtypes.Redelegation{ + createRedelegation([]int64{}, []time.Time{}), + createRedelegation([]int64{500}, []time.Time{nowPlus1Hour}), + createRedelegation([]int64{250, 250}, []time.Time{nowPlus1Hour, nowPlus1Hour}), + createRedelegation([]int64{700, 200}, []time.Time{nowPlus1Hour, nowPlus1Hour}), + createRedelegation([]int64{}, []time.Time{}), + createRedelegation([]int64{100}, []time.Time{nowPlus1Hour}), + }, + int64(17), + sdk.NewInt(3), + int64(2000/3 + 17), + }, + { + "no redelegations", + // 2000 total undelegation tokens + []stakingtypes.UnbondingDelegation{ + createUndelegation([]int64{250, 250}, []time.Time{nowPlus1Hour, nowPlus1Hour}), + createUndelegation([]int64{}, []time.Time{}), + createUndelegation([]int64{100, 100}, []time.Time{nowPlus1Hour, nowPlus1Hour}), + createUndelegation([]int64{800}, []time.Time{nowPlus1Hour}), + createUndelegation([]int64{500}, []time.Time{nowPlus1Hour}), + }, + []stakingtypes.Redelegation{}, + int64(1), + sdk.NewInt(3), + int64(2000/3 + 1), + }, + { + "both (mature) undelegations and redelegations", + // 2000 total undelegation tokens, 250 + 100 + 500 = 850 of those are from mature undelegations, + // so 2000 - 850 = 1150 + []stakingtypes.UnbondingDelegation{ + createUndelegation([]int64{250, 250}, []time.Time{nowPlus1Hour, now}), + createUndelegation([]int64{}, []time.Time{}), + createUndelegation([]int64{100, 100}, []time.Time{now, nowPlus1Hour}), + createUndelegation([]int64{800}, []time.Time{nowPlus1Hour}), + createUndelegation([]int64{500}, []time.Time{now}), + }, + // 3500 total redelegation tokens, 350 + 200 + 400 = 950 of those are from mature redelegations + // so 3500 - 950 = 2550 + []stakingtypes.Redelegation{ + createRedelegation([]int64{}, []time.Time{}), + createRedelegation([]int64{1600}, []time.Time{nowPlus1Hour}), + createRedelegation([]int64{350, 250}, []time.Time{now, nowPlus1Hour}), + createRedelegation([]int64{700, 200}, []time.Time{nowPlus1Hour, now}), + createRedelegation([]int64{}, []time.Time{}), + createRedelegation([]int64{400}, []time.Time{now}), + }, + int64(8391), + sdk.NewInt(2), + int64((1150+2550)/2 + 8391), + }, + } + + pubKey, _ := cryptocodec.FromTmPubKeyInterface(tmtypes.NewMockPV().PrivKey.PubKey()) + validator, _ := stakingtypes.NewValidator(pubKey.Address().Bytes(), pubKey, stakingtypes.Description{}) + + for _, tc := range testCases { + gomock.InOrder(mocks.MockStakingKeeper.EXPECT(). + SlashUnbondingDelegation(gomock.Any(), gomock.Any(), int64(0), sdk.NewDec(1)). + DoAndReturn( + func(_ sdk.Context, undelegation stakingtypes.UnbondingDelegation, _ int64, _ sdk.Dec) sdk.Int { + sum := sdk.NewInt(0) + for _, r := range undelegation.Entries { + if r.IsMature(ctx.BlockTime()) { + continue + } + sum = sum.Add(sdk.NewInt(r.InitialBalance.Int64())) + } + return sum + }).AnyTimes(), + mocks.MockStakingKeeper.EXPECT(). + SlashRedelegation(gomock.Any(), gomock.Any(), gomock.Any(), int64(0), sdk.NewDec(1)). + DoAndReturn( + func(ctx sdk.Context, _ stakingtypes.Validator, redelegation stakingtypes.Redelegation, _ int64, _ sdk.Dec) sdk.Int { + sum := sdk.NewInt(0) + for _, r := range redelegation.Entries { + if r.IsMature(ctx.BlockTime()) { + continue + } + sum = sum.Add(sdk.NewInt(r.InitialBalance.Int64())) + } + return sum + }).AnyTimes(), + ) + + actualPower := providerKeeper.ComputePowerToSlash(ctx, validator, + tc.undelegations, tc.redelegations, tc.power, tc.powerReduction) + + if tc.expectedPower != actualPower { + require.Fail(t, fmt.Sprintf("\"%s\" failed", tc.name), + "expected is %d but actual is %d", tc.expectedPower, actualPower) + } + } +} + +// TestSlashValidator asserts that `SlashValidator` calls the staking module's `Slash` method +// with the correct arguments (i.e., `infractionHeight` of 0 and the expected slash power) +func TestSlashValidator(t *testing.T) { + keeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + // undelegation or redelegation entries with completion time `now` have matured + now := ctx.BlockHeader().Time + // undelegation or redelegation entries with completion time one hour in the future have not yet matured + nowPlus1Hour := now.Add(time.Hour) + + keeperParams := testkeeper.NewInMemKeeperParams(t) + testkeeper.NewInMemProviderKeeper(keeperParams, mocks) + + pubKey, _ := cryptocodec.FromTmPubKeyInterface(tmtypes.NewMockPV().PrivKey.PubKey()) + pkAny, _ := codectypes.NewAnyWithValue(pubKey) + + // manually build a validator instead of using `stakingtypes.NewValidator` to guarantee that the validator is bonded + validator := stakingtypes.Validator{ + OperatorAddress: sdk.ValAddress(pubKey.Address().Bytes()).String(), + ConsensusPubkey: pkAny, + Jailed: false, + Status: stakingtypes.Bonded, + Tokens: sdk.ZeroInt(), + DelegatorShares: sdk.ZeroDec(), + Description: stakingtypes.Description{}, + UnbondingHeight: int64(0), + UnbondingTime: time.Unix(0, 0).UTC(), + Commission: stakingtypes.NewCommission(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()), + MinSelfDelegation: math.OneInt(), + UnbondingOnHoldRefCount: 0, + } + + consAddr, _ := validator.GetConsAddr() + providerAddr := types.NewProviderConsAddress(consAddr) + + // we create 1000 tokens worth of undelegations, 750 of them are non-matured + // we also create 1000 tokens worth of redelegations, 750 of them are non-matured + undelegations := []stakingtypes.UnbondingDelegation{ + createUndelegation([]int64{250, 250}, []time.Time{nowPlus1Hour, now}), + createUndelegation([]int64{500}, []time.Time{nowPlus1Hour}), + } + redelegations := []stakingtypes.Redelegation{ + createRedelegation([]int64{250, 250}, []time.Time{now, nowPlus1Hour}), + createRedelegation([]int64{500}, []time.Time{nowPlus1Hour}), + } + + // validator's current power + currentPower := int64(3000) + + powerReduction := sdk.NewInt(2) + slashFraction, _ := sdk.NewDecFromStr("0.5") + + // the call to `Slash` should provide an `infractionHeight` of 0 and an expected power of + // (750 (undelegations) + 750 (redelegations)) / 2 (= powerReduction) + 3000 (currentPower) = 3750 + expectedInfractionHeight := int64(0) + expectedSlashPower := int64(3750) + + expectedCalls := []*gomock.Call{ + mocks.MockStakingKeeper.EXPECT(). + GetValidatorByConsAddr(ctx, gomock.Any()). + Return(validator, true), + mocks.MockSlashingKeeper.EXPECT(). + IsTombstoned(ctx, consAddr). + Return(false), + mocks.MockStakingKeeper.EXPECT(). + GetUnbondingDelegationsFromValidator(ctx, validator.GetOperator()). + Return(undelegations), + mocks.MockStakingKeeper.EXPECT(). + GetRedelegationsFromSrcValidator(ctx, validator.GetOperator()). + Return(redelegations), + mocks.MockStakingKeeper.EXPECT(). + GetLastValidatorPower(ctx, validator.GetOperator()). + Return(currentPower), + mocks.MockStakingKeeper.EXPECT(). + PowerReduction(ctx). + Return(powerReduction), + mocks.MockStakingKeeper.EXPECT(). + SlashUnbondingDelegation(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). + DoAndReturn( + func(_ sdk.Context, undelegation stakingtypes.UnbondingDelegation, _ int64, _ sdk.Dec) sdk.Int { + sum := sdk.NewInt(0) + for _, r := range undelegation.Entries { + if r.IsMature(ctx.BlockTime()) { + continue + } + sum = sum.Add(sdk.NewInt(r.InitialBalance.Int64())) + } + return sum + }).AnyTimes(), + mocks.MockStakingKeeper.EXPECT(). + SlashRedelegation(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). + DoAndReturn( + func(_ sdk.Context, _ stakingtypes.Validator, redelegation stakingtypes.Redelegation, _ int64, _ sdk.Dec) sdk.Int { + sum := sdk.NewInt(0) + for _, r := range redelegation.Entries { + if r.IsMature(ctx.BlockTime()) { + continue + } + sum = sum.Add(sdk.NewInt(r.InitialBalance.Int64())) + } + return sum + }).AnyTimes(), + mocks.MockSlashingKeeper.EXPECT(). + SlashFractionDoubleSign(ctx). + Return(slashFraction), + mocks.MockStakingKeeper.EXPECT(). + SlashWithInfractionReason(ctx, consAddr, expectedInfractionHeight, expectedSlashPower, slashFraction, stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN). + Times(1), + } + + gomock.InOrder(expectedCalls...) + keeper.SlashValidator(ctx, providerAddr) +} + +// TestSlashValidatorDoesNotSlashIfValidatorIsUnbonded asserts that `SlashValidator` does not call +// the staking module's `Slash` method if the validator to be slashed is unbonded +func TestSlashValidatorDoesNotSlashIfValidatorIsUnbonded(t *testing.T) { + keeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + keeperParams := testkeeper.NewInMemKeeperParams(t) + testkeeper.NewInMemProviderKeeper(keeperParams, mocks) + + pubKey, _ := cryptocodec.FromTmPubKeyInterface(tmtypes.NewMockPV().PrivKey.PubKey()) + + // validator is initially unbonded + validator, _ := stakingtypes.NewValidator(pubKey.Address().Bytes(), pubKey, stakingtypes.Description{}) + + consAddr, _ := validator.GetConsAddr() + providerAddr := types.NewProviderConsAddress(consAddr) + + expectedCalls := []*gomock.Call{ + mocks.MockStakingKeeper.EXPECT(). + GetValidatorByConsAddr(ctx, gomock.Any()). + Return(validator, true), + } + + gomock.InOrder(expectedCalls...) + keeper.SlashValidator(ctx, providerAddr) +} diff --git a/x/ccv/types/expected_keepers.go b/x/ccv/types/expected_keepers.go index ac11c5dce5..2c561ab0c9 100644 --- a/x/ccv/types/expected_keepers.go +++ b/x/ccv/types/expected_keepers.go @@ -16,6 +16,7 @@ import ( auth "github.com/cosmos/cosmos-sdk/x/auth/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + "github.com/cosmos/cosmos-sdk/x/staking/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" abci "github.com/cometbft/cometbft/abci/types" @@ -30,10 +31,11 @@ type StakingKeeper interface { UnbondingTime(ctx sdk.Context) time.Duration GetValidatorByConsAddr(ctx sdk.Context, consAddr sdk.ConsAddress) (validator stakingtypes.Validator, found bool) GetLastValidatorPower(ctx sdk.Context, operator sdk.ValAddress) (power int64) - // slash the validator and delegators of the validator, specifying offence height, offence power, and slash fraction Jail(sdk.Context, sdk.ConsAddress) // jail a validator Slash(sdk.Context, sdk.ConsAddress, int64, int64, sdk.Dec) math.Int SlashWithInfractionReason(sdk.Context, sdk.ConsAddress, int64, int64, sdk.Dec, stakingtypes.Infraction) math.Int + SlashUnbondingDelegation(sdk.Context, types.UnbondingDelegation, int64, sdk.Dec) math.Int + SlashRedelegation(sdk.Context, types.Validator, types.Redelegation, int64, sdk.Dec) math.Int Unjail(ctx sdk.Context, addr sdk.ConsAddress) GetValidator(ctx sdk.Context, addr sdk.ValAddress) (validator stakingtypes.Validator, found bool) IterateLastValidatorPowers(ctx sdk.Context, cb func(addr sdk.ValAddress, power int64) (stop bool)) @@ -47,8 +49,10 @@ type StakingKeeper interface { MaxValidators(ctx sdk.Context) uint32 GetLastTotalPower(ctx sdk.Context) math.Int GetLastValidators(ctx sdk.Context) (validators []stakingtypes.Validator) - GetUnbondingType(ctx sdk.Context, id uint64) (unbondingType stakingtypes.UnbondingType, found bool) BondDenom(ctx sdk.Context) (res string) + 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) } // SlashingKeeper defines the contract expected to perform ccv slashing From 1fd84094dbb31667220acfed1811c7d7a9c260f2 Mon Sep 17 00:00:00 2001 From: Simon Noetzlin Date: Tue, 3 Oct 2023 14:55:22 +0200 Subject: [PATCH 134/134] lint --- app/provider/app.go | 2 +- app/sovereign/app.go | 1 - tests/e2e/actions.go | 5 ----- tests/e2e/state.go | 1 - tests/integration/double_vote.go | 6 +++-- tests/integration/misbehaviour.go | 6 +++-- x/ccv/provider/client/cli/tx.go | 6 ++--- x/ccv/provider/keeper/double_vote.go | 12 +++++----- x/ccv/provider/keeper/double_vote_test.go | 7 ++++-- x/ccv/provider/keeper/misbehaviour.go | 16 +++++++++----- x/ccv/provider/keeper/msg_server.go | 5 ++--- x/ccv/provider/keeper/punish_validator.go | 4 +++- .../provider/keeper/punish_validator_test.go | 22 ++++++++++--------- x/ccv/provider/types/msg.go | 12 ++++++---- x/ccv/types/expected_keepers.go | 5 ++--- 15 files changed, 61 insertions(+), 49 deletions(-) diff --git a/app/provider/app.go b/app/provider/app.go index 5680f254b5..497158449a 100644 --- a/app/provider/app.go +++ b/app/provider/app.go @@ -25,7 +25,6 @@ import ( autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" - evidencekeeper "github.com/cosmos/cosmos-sdk/x/evidence/keeper" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" @@ -67,6 +66,7 @@ import ( distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" "github.com/cosmos/cosmos-sdk/x/evidence" + evidencekeeper "github.com/cosmos/cosmos-sdk/x/evidence/keeper" evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" "github.com/cosmos/cosmos-sdk/x/genutil" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" diff --git a/app/sovereign/app.go b/app/sovereign/app.go index c6ffb0e853..b5629bfc22 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 bcfff03483..52abaa37a1 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -1260,11 +1260,6 @@ func (tr TestRun) relayPacketsHermes( ) { // hermes clear packets ibc0 transfer channel-13 //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. - fmt.Println("hermes", "clear", "packets", - "--chain", string(tr.chainConfigs[action.ChainA].ChainId), - "--port", action.Port, - "--channel", "channel-"+fmt.Sprint(action.Channel)) - cmd := exec.Command("docker", "exec", tr.containerConfig.InstanceName, "hermes", "clear", "packets", "--chain", string(tr.chainConfigs[action.ChainA].ChainId), "--port", action.Port, diff --git a/tests/e2e/state.go b/tests/e2e/state.go index 61f7410283..e59c91b7d2 100644 --- a/tests/e2e/state.go +++ b/tests/e2e/state.go @@ -319,7 +319,6 @@ func (tr TestRun) getRewards(chain ChainID, modelState Rewards) Rewards { } func (tr TestRun) getReward(chain ChainID, validator ValidatorID, blockHeight uint, isNativeDenom bool) float64 { - delAddresss := tr.validatorConfigs[validator].DelAddress if chain != ChainID("provi") && tr.validatorConfigs[validator].UseConsumerKey { delAddresss = tr.validatorConfigs[validator].ConsumerDelAddress diff --git a/tests/integration/double_vote.go b/tests/integration/double_vote.go index 679a7c664b..c5309b17fb 100644 --- a/tests/integration/double_vote.go +++ b/tests/integration/double_vote.go @@ -1,10 +1,12 @@ package integration import ( - tmcrypto "github.com/cometbft/cometbft/crypto" - tmtypes "github.com/cometbft/cometbft/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" sdk "github.com/cosmos/cosmos-sdk/types" + + tmcrypto "github.com/cometbft/cometbft/crypto" + tmtypes "github.com/cometbft/cometbft/types" + testutil "github.com/cosmos/interchain-security/v3/testutil/crypto" "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ) diff --git a/tests/integration/misbehaviour.go b/tests/integration/misbehaviour.go index 336a2bf215..f531f79178 100644 --- a/tests/integration/misbehaviour.go +++ b/tests/integration/misbehaviour.go @@ -3,11 +3,13 @@ package integration import ( "time" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" tmtypes "github.com/cometbft/cometbft/types" - ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + + "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ) // TestHandleConsumerMisbehaviour tests that handling a valid misbehaviour, diff --git a/x/ccv/provider/client/cli/tx.go b/x/ccv/provider/client/cli/tx.go index 4d97cd6d4f..994bdd0c10 100644 --- a/x/ccv/provider/client/cli/tx.go +++ b/x/ccv/provider/client/cli/tx.go @@ -4,16 +4,16 @@ import ( "fmt" "strings" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" "github.com/spf13/cobra" - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/tx" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" - ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - sdk "github.com/cosmos/cosmos-sdk/types" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ) diff --git a/x/ccv/provider/keeper/double_vote.go b/x/ccv/provider/keeper/double_vote.go index 0d18eed809..3b459bb8c1 100644 --- a/x/ccv/provider/keeper/double_vote.go +++ b/x/ccv/provider/keeper/double_vote.go @@ -4,11 +4,13 @@ import ( "bytes" "fmt" + errorsmod "cosmossdk.io/errors" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" tmtypes "github.com/cometbft/cometbft/types" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) @@ -67,7 +69,7 @@ func (k Keeper) VerifyDoubleVotingEvidence( if evidence.VoteA.Height != evidence.VoteB.Height || evidence.VoteA.Round != evidence.VoteB.Round || evidence.VoteA.Type != evidence.VoteB.Type { - return sdkerrors.Wrapf( + return errorsmod.Wrapf( ccvtypes.ErrInvalidDoubleVotingEvidence, "h/r/s does not match: %d/%d/%v vs %d/%d/%v", evidence.VoteA.Height, evidence.VoteA.Round, evidence.VoteA.Type, @@ -76,7 +78,7 @@ func (k Keeper) VerifyDoubleVotingEvidence( // Addresses must be the same if !bytes.Equal(evidence.VoteA.ValidatorAddress, evidence.VoteB.ValidatorAddress) { - return sdkerrors.Wrapf( + return errorsmod.Wrapf( ccvtypes.ErrInvalidDoubleVotingEvidence, "validator addresses do not match: %X vs %X", evidence.VoteA.ValidatorAddress, @@ -86,7 +88,7 @@ func (k Keeper) VerifyDoubleVotingEvidence( // BlockIDs must be different if evidence.VoteA.BlockID.Equals(evidence.VoteB.BlockID) { - return sdkerrors.Wrapf( + return errorsmod.Wrapf( ccvtypes.ErrInvalidDoubleVotingEvidence, "block IDs are the same (%v) - not a real duplicate vote", evidence.VoteA.BlockID, diff --git a/x/ccv/provider/keeper/double_vote_test.go b/x/ccv/provider/keeper/double_vote_test.go index 175607b2b0..d3f8e86e45 100644 --- a/x/ccv/provider/keeper/double_vote_test.go +++ b/x/ccv/provider/keeper/double_vote_test.go @@ -4,12 +4,15 @@ import ( "testing" "time" - tmtypes "github.com/cometbft/cometbft/types" + "github.com/stretchr/testify/require" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + + tmtypes "github.com/cometbft/cometbft/types" + testutil "github.com/cosmos/interchain-security/v3/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" - "github.com/stretchr/testify/require" ) func TestVerifyDoubleVotingEvidence(t *testing.T) { diff --git a/x/ccv/provider/keeper/misbehaviour.go b/x/ccv/provider/keeper/misbehaviour.go index b366a5ebc8..fd7ec6bf0d 100644 --- a/x/ccv/provider/keeper/misbehaviour.go +++ b/x/ccv/provider/keeper/misbehaviour.go @@ -3,11 +3,15 @@ package keeper import ( "fmt" - tmtypes "github.com/cometbft/cometbft/types" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ibcclienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + + errorsmod "cosmossdk.io/errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + + tmtypes "github.com/cometbft/cometbft/types" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ) @@ -137,7 +141,7 @@ func headerToLightBlock(h ibctmtypes.Header) (*tmtypes.LightBlock, error) { func (k Keeper) CheckMisbehaviour(ctx sdk.Context, misbehaviour ibctmtypes.Misbehaviour) error { clientState, found := k.clientKeeper.GetClientState(ctx, misbehaviour.ClientId) if !found { - return sdkerrors.Wrapf(ibcclienttypes.ErrClientNotFound, "cannot check misbehaviour for client with ID %s", misbehaviour.ClientId) + return errorsmod.Wrapf(ibcclienttypes.ErrClientNotFound, "cannot check misbehaviour for client with ID %s", misbehaviour.ClientId) } clientStore := k.clientKeeper.ClientStore(ctx, misbehaviour.ClientId) @@ -146,7 +150,7 @@ func (k Keeper) CheckMisbehaviour(ctx sdk.Context, misbehaviour ibctmtypes.Misbe // the misbehaviour is for a light client attack and not a time violation, // see ibc-go/modules/light-clients/07-tendermint/types/misbehaviour_handle.go if !misbehaviour.Header1.GetHeight().EQ(misbehaviour.Header2.GetHeight()) { - return sdkerrors.Wrap(ibcclienttypes.ErrInvalidMisbehaviour, "headers are not at same height") + return errorsmod.Wrap(ibcclienttypes.ErrInvalidMisbehaviour, "headers are not at same height") } // CheckMisbehaviourAndUpdateState verifies the misbehaviour against the trusted consensus states @@ -155,7 +159,7 @@ func (k Keeper) CheckMisbehaviour(ctx sdk.Context, misbehaviour ibctmtypes.Misbe // see ibc-go/modules/light-clients/07-tendermint/types/misbehaviour_handle.go ok := clientState.CheckForMisbehaviour(ctx, k.cdc, clientStore, &misbehaviour) if !ok { - return sdkerrors.Wrapf(ibcclienttypes.ErrInvalidMisbehaviour, "invalid misbehaviour for client-id: %s", misbehaviour.ClientId) + return errorsmod.Wrapf(ibcclienttypes.ErrInvalidMisbehaviour, "invalid misbehaviour for client-id: %s", misbehaviour.ClientId) } return nil diff --git a/x/ccv/provider/keeper/msg_server.go b/x/ccv/provider/keeper/msg_server.go index 08d4c708d2..cc08c7f32f 100644 --- a/x/ccv/provider/keeper/msg_server.go +++ b/x/ccv/provider/keeper/msg_server.go @@ -4,15 +4,14 @@ import ( "context" "encoding/base64" - cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" - 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" tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" + tmtypes "github.com/cometbft/cometbft/types" "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" diff --git a/x/ccv/provider/keeper/punish_validator.go b/x/ccv/provider/keeper/punish_validator.go index e008bdeed6..29664841c0 100644 --- a/x/ccv/provider/keeper/punish_validator.go +++ b/x/ccv/provider/keeper/punish_validator.go @@ -4,11 +4,13 @@ import ( "fmt" errorsmod "cosmossdk.io/errors" + "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" ) @@ -50,7 +52,7 @@ func (k Keeper) JailAndTombstoneValidator(ctx sdk.Context, providerAddr types.Pr // `redelegations`, as well as the current `power` of the validator. // Note that this method does not perform any slashing. func (k Keeper) ComputePowerToSlash(ctx sdk.Context, validator stakingtypes.Validator, undelegations []stakingtypes.UnbondingDelegation, - redelegations []stakingtypes.Redelegation, power int64, powerReduction sdk.Int, + redelegations []stakingtypes.Redelegation, power int64, powerReduction math.Int, ) int64 { // compute the total numbers of tokens currently being undelegated undelegationsInTokens := sdk.NewInt(0) diff --git a/x/ccv/provider/keeper/punish_validator_test.go b/x/ccv/provider/keeper/punish_validator_test.go index 2efc0c26e2..cce8749710 100644 --- a/x/ccv/provider/keeper/punish_validator_test.go +++ b/x/ccv/provider/keeper/punish_validator_test.go @@ -5,20 +5,22 @@ import ( "testing" "time" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" + "cosmossdk.io/math" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" - sdk "github.com/cosmos/cosmos-sdk/types" evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + tmtypes "github.com/cometbft/cometbft/types" + cryptotestutil "github.com/cosmos/interchain-security/v3/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v3/testutil/keeper" "github.com/cosmos/interchain-security/v3/x/ccv/provider/types" - "github.com/golang/mock/gomock" - - tmtypes "github.com/cometbft/cometbft/types" - "github.com/stretchr/testify/require" ) // TestJailAndTombstoneValidator tests that the jailing of a validator is only executed @@ -190,7 +192,7 @@ func TestComputePowerToSlash(t *testing.T) { undelegations []stakingtypes.UnbondingDelegation redelegations []stakingtypes.Redelegation power int64 - powerReduction sdk.Int + powerReduction math.Int expectedPower int64 }{ { @@ -305,7 +307,7 @@ func TestComputePowerToSlash(t *testing.T) { gomock.InOrder(mocks.MockStakingKeeper.EXPECT(). SlashUnbondingDelegation(gomock.Any(), gomock.Any(), int64(0), sdk.NewDec(1)). DoAndReturn( - func(_ sdk.Context, undelegation stakingtypes.UnbondingDelegation, _ int64, _ sdk.Dec) sdk.Int { + func(_ sdk.Context, undelegation stakingtypes.UnbondingDelegation, _ int64, _ sdk.Dec) math.Int { sum := sdk.NewInt(0) for _, r := range undelegation.Entries { if r.IsMature(ctx.BlockTime()) { @@ -318,7 +320,7 @@ func TestComputePowerToSlash(t *testing.T) { mocks.MockStakingKeeper.EXPECT(). SlashRedelegation(gomock.Any(), gomock.Any(), gomock.Any(), int64(0), sdk.NewDec(1)). DoAndReturn( - func(ctx sdk.Context, _ stakingtypes.Validator, redelegation stakingtypes.Redelegation, _ int64, _ sdk.Dec) sdk.Int { + func(ctx sdk.Context, _ stakingtypes.Validator, redelegation stakingtypes.Redelegation, _ int64, _ sdk.Dec) math.Int { sum := sdk.NewInt(0) for _, r := range redelegation.Entries { if r.IsMature(ctx.BlockTime()) { @@ -420,7 +422,7 @@ func TestSlashValidator(t *testing.T) { mocks.MockStakingKeeper.EXPECT(). SlashUnbondingDelegation(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). DoAndReturn( - func(_ sdk.Context, undelegation stakingtypes.UnbondingDelegation, _ int64, _ sdk.Dec) sdk.Int { + func(_ sdk.Context, undelegation stakingtypes.UnbondingDelegation, _ int64, _ sdk.Dec) math.Int { sum := sdk.NewInt(0) for _, r := range undelegation.Entries { if r.IsMature(ctx.BlockTime()) { @@ -433,7 +435,7 @@ func TestSlashValidator(t *testing.T) { mocks.MockStakingKeeper.EXPECT(). SlashRedelegation(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). DoAndReturn( - func(_ sdk.Context, _ stakingtypes.Validator, redelegation stakingtypes.Redelegation, _ int64, _ sdk.Dec) sdk.Int { + func(_ sdk.Context, _ stakingtypes.Validator, redelegation stakingtypes.Redelegation, _ int64, _ sdk.Dec) math.Int { sum := sdk.NewInt(0) for _, r := range redelegation.Entries { if r.IsMature(ctx.BlockTime()) { diff --git a/x/ccv/provider/types/msg.go b/x/ccv/provider/types/msg.go index 426c6b316f..c2551f9ceb 100644 --- a/x/ccv/provider/types/msg.go +++ b/x/ccv/provider/types/msg.go @@ -5,11 +5,15 @@ import ( "fmt" "strings" - tmtypes "github.com/cometbft/cometbft/proto/tendermint/types" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + tmtypes "github.com/cometbft/cometbft/proto/tendermint/types" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" ) @@ -121,7 +125,7 @@ func (msg MsgSubmitConsumerMisbehaviour) Type() string { // Type implements the sdk.Msg interface. func (msg MsgSubmitConsumerMisbehaviour) ValidateBasic() error { if msg.Submitter == "" { - return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Submitter) + return errorsmod.Wrap(sdkerrors.ErrInvalidAddress, msg.Submitter) } if err := msg.Misbehaviour.ValidateBasic(); err != nil { @@ -161,7 +165,7 @@ func (msg MsgSubmitConsumerDoubleVoting) Type() string { // Type implements the sdk.Msg interface. func (msg MsgSubmitConsumerDoubleVoting) ValidateBasic() error { if msg.Submitter == "" { - return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Submitter) + return errorsmod.Wrap(sdkerrors.ErrInvalidAddress, msg.Submitter) } if msg.DuplicateVoteEvidence == nil { return fmt.Errorf("double voting evidence cannot be nil") diff --git a/x/ccv/types/expected_keepers.go b/x/ccv/types/expected_keepers.go index 2c561ab0c9..5b2f3f7a53 100644 --- a/x/ccv/types/expected_keepers.go +++ b/x/ccv/types/expected_keepers.go @@ -16,7 +16,6 @@ import ( auth "github.com/cosmos/cosmos-sdk/x/auth/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" - "github.com/cosmos/cosmos-sdk/x/staking/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" abci "github.com/cometbft/cometbft/abci/types" @@ -34,8 +33,8 @@ type StakingKeeper interface { Jail(sdk.Context, sdk.ConsAddress) // jail a validator Slash(sdk.Context, sdk.ConsAddress, int64, int64, sdk.Dec) math.Int SlashWithInfractionReason(sdk.Context, sdk.ConsAddress, int64, int64, sdk.Dec, stakingtypes.Infraction) math.Int - SlashUnbondingDelegation(sdk.Context, types.UnbondingDelegation, int64, sdk.Dec) math.Int - SlashRedelegation(sdk.Context, types.Validator, types.Redelegation, int64, sdk.Dec) math.Int + SlashUnbondingDelegation(sdk.Context, stakingtypes.UnbondingDelegation, int64, sdk.Dec) math.Int + SlashRedelegation(sdk.Context, stakingtypes.Validator, stakingtypes.Redelegation, int64, sdk.Dec) math.Int Unjail(ctx sdk.Context, addr sdk.ConsAddress) GetValidator(ctx sdk.Context, addr sdk.ValAddress) (validator stakingtypes.Validator, found bool) IterateLastValidatorPowers(ctx sdk.Context, cb func(addr sdk.ValAddress, power int64) (stop bool))