diff --git a/.changelog/unreleased/api-breaking/provider/2130-remove-legacy-proposal.md b/.changelog/unreleased/api-breaking/provider/2130-remove-legacy-proposal.md new file mode 100644 index 0000000000..404e134ea5 --- /dev/null +++ b/.changelog/unreleased/api-breaking/provider/2130-remove-legacy-proposal.md @@ -0,0 +1,25 @@ +- Remove support for legacy-proposal to add/modify/remove consumer proposals and change reward denoms + ([\#2130](https://github.com/cosmos/interchain-security/pull/2130)) + To submit a proposal to add/modify/remove a consumer use the following command + ```shell + interchain-security-pd tx gov submit-proposal [proposal-file] + ``` + + Run `interchain-security-pd tx gov draft-proposal` command and select in `other` one of the following + message types to generate a draft proposal json file: + - `/interchain_security.ccv.provider.v1.MsgConsumerAddition` + + - `/interchain_security.ccv.provider.v1.MsgConsumerModification` + + - `/interchain_security.ccv.provider.v1.MsgConsumerRemoval` + + - `/interchain_security.ccv.provider.v1.MsgChangeRewardDenoms` + + This replaces the following command which are not supported anymore: + + ```shell + interchain-security-pd tx gov submit-legacy-proposal consumer-addition [proposal-file] + interchain-security-pd tx gov submit-legacy-proposal consumer-modification [proposal-file] + interchain-security-pd tx gov submit-legacy-proposal consumer-removal [proposal-file] + interchain-security-pd tx gov submit-legacy-proposal change-reward-denoms [proposal-file] + ``` \ No newline at end of file diff --git a/.github/workflows/nightly-e2e.yml b/.github/workflows/nightly-e2e.yml index 5eeadba12d..33a67ec00d 100644 --- a/.github/workflows/nightly-e2e.yml +++ b/.github/workflows/nightly-e2e.yml @@ -36,7 +36,7 @@ jobs: # Run compatibility tests for different consumer (-cv) and provider (-pv) versions. # Combination of all provider versions with consumer versions are tested. # For new versions to be tested add/modify -pc/-cv parameters. - run: go run ./tests/e2e/... --tc compatibility -pv latest -pv v4.3.0-lsm -pv v3.3.3-lsm -cv latest -cv v4.3.0 -cv v3.3.0 + run: go run ./tests/e2e/... --tc compatibility -pv latest -pv v4.3.1-lsm -pv v3.3.3-lsm -cv latest -cv v4.4.0 -cv v3.3.0 happy-path-test: runs-on: ubuntu-latest timeout-minutes: 20 diff --git a/UPGRADING.md b/UPGRADING.md index 1cf021290b..a3f2d5e84d 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -27,6 +27,74 @@ func InitializeMaxProviderConsensusParam(ctx sdk.Context, providerKeeper provide } ``` +### Governance Proposals + +Legacy proposals are not supported anymore by the current version of the provider. Legacy proposals which are still active (voting period or deposit period) and contain one of the following messages that need to be migrated as described below: +- `ConsumerAdditionProposal` needs to be converted to `MsgConsumerAddition` +- `ConsumerModificationProposal` needs to be converted to `MsgConsumerModification` +- `ConsumerRemovalProposal` needs to be converted to `MsgConsumerRemoval` +- `ChangeRewardDenomsProposal` needs to be converted to `MsgChangeRewardDenoms` + +The following shows an example on how to migrate a proposal containing a legacy consumer addition proposal message. +Migration for the other messages aobve follows the same pattern. The resulting migration code has to be added to the upgrade handler of the provider chain. + +#### Migrate Legacy Proposal Content + +```go + +// MigrateLegacyConsumerAddition converts a ConsumerAdditionProposal to a MsgConsumerAdditionProposal +// and returns it as `Any` suitable to replace the legacy message. +// `authority` contains the signer address +func MigrateLegacyConsumerAddition(msg providertypes.ConsumerAdditionProposal, authority string) (*codec.Any, error) { + sdkMsg := providertypes.MsgConsumerAddition{ + ChainId: msg.ChainId, + InitialHeight: msg.InitialHeight, + GenesisHash: msg.GenesisHash, + BinaryHash: msg.BinaryHash, + SpawnTime: msg.SpawnTime, + UnbondingPeriod: msg.UnbondingPeriod, + CcvTimeoutPeriod: msg.CcvTimeoutPeriod, + TransferTimeoutPeriod: msg.TransferTimeoutPeriod, + ConsumerRedistributionFraction: msg.ConsumerRedistributionFraction, + BlocksPerDistributionTransmission: msg.BlocksPerDistributionTransmission, + HistoricalEntries: msg.HistoricalEntries, + DistributionTransmissionChannel: msg.DistributionTransmissionChannel, + Top_N: msg.Top_N, + ValidatorsPowerCap: msg.ValidatorsPowerCap, + ValidatorSetCap: msg.ValidatorSetCap, + Allowlist: msg.Allowlist, + Denylist: msg.Denylist, + Authority: authority, + MinStake: msg.MinStake, + AllowInactiveVals: msg.AllowInactiveVals, + } + return codec.NewAnyWithValue(&sdkMsg) +} + +func MigrateProposal(proposal proposal govtypes.Proposal) err { + for idx, msg := range proposal.GetMessages() { + sdkLegacyMsg, isLegacyProposal := msg.GetCachedValue().(*govtypes.MsgExecLegacyContent) + if !isLegacyProposal { + continue + } + content, err := govtypes.LegacyContentFromMessage(sdkLegacyMsg) + if err != nil { + continue + } + + msgAdd, ok := content.(*providertypes.ConsumerAdditionProposal) + if ok { + anyMsg, err := migrateLegacyConsumerAddition(*msgAdd, govKeeper.GetAuthority()) + if err != nil { + return err + } + proposal.Messages[idx] = anyMsg + } + } + return govKeeper.SetProposal(ctx, proposal) +} +``` + ## [v5.1.x](https://github.com/cosmos/interchain-security/releases/tag/v5.1.0) ### Provider @@ -41,7 +109,7 @@ Upgrade code will be executed automatically during the upgrade procedure. ### Consumer -Upgrading the consumer from `v5.0.0` to `v5.1.0` will not require state migration. +Upgrading the consumer from `v5.0.0` to `v5.1.0` will not require state migration. This guide provides instructions for upgrading to specific versions of Replicated Security. @@ -55,7 +123,7 @@ v5.0.0 was a **consumer only release**. ### Consumer -Upgrading the consumer from `v4.x` to `v5.0.0` will require state migrations. +Upgrading the consumer from `v4.x` to `v5.0.0` will require state migrations. Consumer versions `v4.0.x`, `v4.1.x`, `v4.2.x`, `v4.3.x` and `v4.4.x` can cleanly be upgraded to `v5.0.0`. @@ -69,7 +137,7 @@ Upgrade code will be executed automatically during the upgrade procedure. ### Consumer -Upgrading the consumer from `v4.0.0` to `v4.4.0` will not require state migration. +Upgrading the consumer from `v4.0.0` to `v4.4.0` will not require state migration. This guide provides instructions for upgrading to specific versions of Replicated Security. @@ -77,7 +145,7 @@ This guide provides instructions for upgrading to specific versions of Replicate ### Provider -Upgrading a provider from `v4.2.0` to `v4.3.0` requires state migrations that will be done automatically via the upgrade module. +Upgrading a provider from `v4.2.0` to `v4.3.0` requires state migrations that will be done automatically via the upgrade module. ### Consumer @@ -132,17 +200,17 @@ func InitICSEpochs(ctx sdk.Context, pk providerkeeper.Keeper, sk stakingkeeper.K ## [v4.0.x](https://github.com/cosmos/interchain-security/tree/release/v4.0.x) -`v4.0.x` sets the minimum required version of Go to `1.21`, see https://github.com/cosmos/interchain-security/blob/release/v4.0.x/go.mod#L3. +`v4.0.x` sets the minimum required version of Go to `1.21`, see https://github.com/cosmos/interchain-security/blob/release/v4.0.x/go.mod#L3. -### Provider +### Provider -Upgrading a provider from `v3.3.0` to `v4.0.0` will require state migrations, see https://github.com/cosmos/interchain-security/blob/release/v4.0.x/x/ccv/provider/migrations/migrator.go#L31. +Upgrading a provider from `v3.3.0` to `v4.0.0` will require state migrations, see https://github.com/cosmos/interchain-security/blob/release/v4.0.x/x/ccv/provider/migrations/migrator.go#L31. -### Consumer +### Consumer -***Note that consumer chains can upgrade directly from `v3.1.0` to `v4.0.0`.*** +***Note that consumer chains can upgrade directly from `v3.1.0` to `v4.0.0`.*** -Upgrading a consumer from `v3.2.0` to `v4.0.0` will not require state migration, however, upgrading directly from `v3.1.0` to `v4.0.0` will require state migrations, see https://github.com/cosmos/interchain-security/blob/release/v4.0.x/x/ccv/consumer/keeper/migrations.go#L22. +Upgrading a consumer from `v3.2.0` to `v4.0.0` will not require state migration, however, upgrading directly from `v3.1.0` to `v4.0.0` will require state migrations, see https://github.com/cosmos/interchain-security/blob/release/v4.0.x/x/ccv/consumer/keeper/migrations.go#L22. In addition, the following migration needs to be added to the upgrade handler of the consumer chain: ```golang @@ -166,15 +234,15 @@ func migrateICSOutstandingDowntime(ctx sdk.Context, keepers *upgrades.UpgradeKee ## [v3.3.x](https://github.com/cosmos/interchain-security/tree/release/v3.2.x) -### Provider +### Provider -Upgrading the provider from `v2.x.y` to `v3.3.0` will not require state migration. +Upgrading the provider from `v2.x.y` to `v3.3.0` will not require state migration. ## [v3.2.x](https://github.com/cosmos/interchain-security/tree/release/v3.2.x) `v3.2.0` bumps IBC to `v7.3`. As a result, `legacy_ibc_testing` is not longer required and was removed, see https://github.com/cosmos/interchain-security/pull/1185. This means that when upgrading to `v3.2.0`, any customized tests relying on `legacy_ibc_testing` need to be updated. -### Consumer +### Consumer Upgrading the consumer from either `v3.0.0` or `v3.1.0` to `v3.2.0` will require state migrations, see https://github.com/cosmos/interchain-security/blob/release/v3.2.x/x/ccv/consumer/keeper/migration.go#L25. @@ -184,13 +252,13 @@ Upgrading the consumer from either `v3.0.0` or `v3.1.0` to `v3.2.0` will require 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 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](https://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 +Legacy APIs of the `AppModule` interface have been removed from ccv modules. For example, for ```diff - // Route implements the AppModule interface @@ -240,10 +308,10 @@ import ( ## [v2.0.x](https://github.com/cosmos/interchain-security/releases/tag/v2.0.0) -### Provider +### Provider Upgrading a provider from `v1.1.0-multiden` to `v2.0.0` will require state migrations. See [migration.go](https://github.com/cosmos/interchain-security/blob/v2.0.0/x/ccv/provider/keeper/migration.go). ### Consumer -Upgrading a consumer from `v1.2.0-multiden` to `v2.0.0` will NOT require state migrations. +Upgrading a consumer from `v1.2.0-multiden` to `v2.0.0` will NOT require state migrations. diff --git a/app/provider/app.go b/app/provider/app.go index 214d191b71..0e6e4b3b80 100644 --- a/app/provider/app.go +++ b/app/provider/app.go @@ -114,7 +114,6 @@ import ( no_valupdates_genutil "github.com/cosmos/interchain-security/v5/x/ccv/no_valupdates_genutil" no_valupdates_staking "github.com/cosmos/interchain-security/v5/x/ccv/no_valupdates_staking" ibcprovider "github.com/cosmos/interchain-security/v5/x/ccv/provider" - ibcproviderclient "github.com/cosmos/interchain-security/v5/x/ccv/provider/client" ibcproviderkeeper "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper" providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ) @@ -144,10 +143,6 @@ var ( gov.NewAppModuleBasic( []govclient.ProposalHandler{ paramsclient.ProposalHandler, - ibcproviderclient.ConsumerAdditionProposalHandler, - ibcproviderclient.ConsumerRemovalProposalHandler, - ibcproviderclient.ConsumerModificationProposalHandler, - ibcproviderclient.ChangeRewardDenomsProposalHandler, }, ), mint.AppModuleBasic{}, @@ -579,10 +574,6 @@ func New( govtypes.ModuleName: gov.NewAppModuleBasic( []govclient.ProposalHandler{ paramsclient.ProposalHandler, - ibcproviderclient.ConsumerAdditionProposalHandler, - ibcproviderclient.ConsumerRemovalProposalHandler, - ibcproviderclient.ConsumerModificationProposalHandler, - ibcproviderclient.ChangeRewardDenomsProposalHandler, }, ), }) diff --git a/tests/e2e/action_rapid_test.go b/tests/e2e/action_rapid_test.go index d0a9ede282..004eb30d95 100644 --- a/tests/e2e/action_rapid_test.go +++ b/tests/e2e/action_rapid_test.go @@ -99,6 +99,7 @@ func GetActionGen() *rapid.Generator[any] { func CreateSubmitChangeRewardDenomsProposalActionGen() *rapid.Generator[SubmitChangeRewardDenomsProposalAction] { return rapid.Custom(func(t *rapid.T) SubmitChangeRewardDenomsProposalAction { return SubmitChangeRewardDenomsProposalAction{ + Chain: GetChainIDGen().Draw(t, "Chain"), From: GetValidatorIDGen().Draw(t, "From"), Deposit: rapid.Uint().Draw(t, "Deposit"), Denom: rapid.String().Draw(t, "Denom"), diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index 2efd0b69e7..22333aad8c 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -2,6 +2,7 @@ package main import ( "bufio" + "encoding/base64" "encoding/json" "fmt" "log" @@ -270,6 +271,106 @@ type SubmitConsumerAdditionProposalAction struct { func (tr Chain) submitConsumerAdditionProposal( action SubmitConsumerAdditionProposalAction, verbose bool, +) { + spawnTime := tr.testConfig.containerConfig.Now.Add(time.Duration(action.SpawnTime) * time.Millisecond) + params := ccvtypes.DefaultParams() + template := ` + { + "messages": [ + { + "@type": "/interchain_security.ccv.provider.v1.MsgConsumerAddition", + "chain_id": "%s", + "initial_height": { + "revision_number": "%d", + "revision_height": "%d" + }, + "genesis_hash": "%s", + "binary_hash": "%s", + "spawn_time": "%s", + "unbonding_period": "%s", + "ccv_timeout_period": "%s", + "transfer_timeout_period": "%s", + "consumer_redistribution_fraction": "%s", + "blocks_per_distribution_transmission": "%d", + "historical_entries": "%d", + "distribution_transmission_channel": "%s", + "top_N": %d, + "validators_power_cap": %d, + "validator_set_cap": %d, + "allowlist": %s, + "denylist": %s, + "authority": "cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn" + } + ], +"metadata": "ipfs://CID", +"deposit": "%dstake", +"title": "Propose the addition of a new chain", +"summary": "Gonna be a great chain", +"expedited": false +}` + jsonStr := fmt.Sprintf(template, + string(tr.testConfig.chainConfigs[action.ConsumerChain].ChainId), + action.InitialHeight.RevisionNumber, + action.InitialHeight.RevisionHeight, + base64.StdEncoding.EncodeToString([]byte("gen_hash")), + base64.StdEncoding.EncodeToString([]byte("bin_hash")), + spawnTime.Local().Format(time.RFC3339Nano), + params.UnbondingPeriod, + params.CcvTimeoutPeriod, + params.TransferTimeoutPeriod, + params.ConsumerRedistributionFraction, + params.BlocksPerDistributionTransmission, + params.HistoricalEntries, + action.DistributionChannel, + action.TopN, + action.ValidatorsPowerCap, + action.ValidatorSetCap, + action.Allowlist, + action.Denylist, + action.Deposit) + + //#nosec G204 -- bypass unsafe quoting warning (no production code) + proposalFile := "/consumer-addition.proposal" + bz, err := tr.target.ExecCommand( + "/bin/bash", "-c", fmt.Sprintf(`echo '%s' > %s`, jsonStr, proposalFile), + ).CombinedOutput() + if err != nil { + log.Fatal(err, "\n", string(bz)) + } + + // CONSUMER ADDITION PROPOSAL + cmd := tr.target.ExecCommand( + tr.testConfig.chainConfigs[action.Chain].BinaryName, + "tx", "gov", "submit-proposal", proposalFile, + `--from`, `validator`+fmt.Sprint(action.From), + `--chain-id`, string(tr.testConfig.chainConfigs[action.Chain].ChainId), + `--home`, tr.getValidatorHome(action.Chain, action.From), + `--gas`, `900000`, + `--node`, tr.getValidatorNode(action.Chain, action.From), + `--keyring-backend`, `test`, + `-y`, + ) + + if verbose { + fmt.Println("submitConsumerAdditionProposal cmd:", cmd.String()) + fmt.Println("submitConsumerAdditionProposal json:", jsonStr) + } + bz, err = cmd.CombinedOutput() + if err != nil { + log.Fatal("submit-proposal failed:", err, "\n", string(bz)) + } + + if verbose { + fmt.Println("submitConsumerAdditionProposal output:", string(bz)) + } + + // wait for inclusion in a block -> '--broadcast-mode block' is deprecated + tr.waitBlocks(action.Chain, 2, 10*time.Second) +} + +func (tr Chain) submitConsumerAdditionLegacyProposal( + action SubmitConsumerAdditionProposalAction, + verbose bool, ) { spawnTime := tr.testConfig.containerConfig.Now.Add(time.Duration(action.SpawnTime) * time.Millisecond) params := ccvtypes.DefaultParams() @@ -361,6 +462,75 @@ type SubmitConsumerRemovalProposalAction struct { func (tr Chain) submitConsumerRemovalProposal( action SubmitConsumerRemovalProposalAction, verbose bool, +) { + template := ` + { + "messages": [ + { + "@type": "/interchain_security.ccv.provider.v1.MsgConsumerRemoval", + "chain_id": "%s", + "stop_time": "%s", + "authority": "cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn" + } + ], + "metadata": "ipfs://CID", + "deposit": "%dstake", + "title": "%s", + "summary": "It was a great chain", + "expedited": false + } +` + title := fmt.Sprintf("Stop the %v chain", action.ConsumerChain) + stopTime := tr.testConfig.containerConfig.Now.Add(action.StopTimeOffset).Format(time.RFC3339Nano) + + jsonStr := fmt.Sprintf(template, + string(tr.testConfig.chainConfigs[action.ConsumerChain].ChainId), + stopTime, + action.Deposit, + title) + + // #nosec G204 -- bypass unsafe quoting warning (no production code) + proposalFile := "/consumer-removal.proposal" + bz, err := tr.target.ExecCommand( + "/bin/bash", "-c", fmt.Sprintf(`echo '%s' > %s`, jsonStr, proposalFile), + ).CombinedOutput() + if err != nil { + log.Fatal(err, "\n", string(bz)) + } + + // CONSUMER REMOVAL PROPOSAL + cmd := tr.target.ExecCommand( + tr.testConfig.chainConfigs[action.Chain].BinaryName, + "tx", "gov", "submit-proposal", proposalFile, + `--from`, `validator`+fmt.Sprint(action.From), + `--chain-id`, string(tr.testConfig.chainConfigs[action.Chain].ChainId), + `--home`, tr.getValidatorHome(action.Chain, action.From), + `--gas`, `900000`, + `--node`, tr.getValidatorNode(action.Chain, action.From), + `--keyring-backend`, `test`, + `-y`, + ) + + if verbose { + fmt.Println("submitConsumerRemovalProposal cmd:", cmd.String()) + fmt.Println("submitConsumerRemovalProposal json:", jsonStr) + } + bz, err = cmd.CombinedOutput() + if err != nil { + log.Fatal("submit consumer removal proposal failed:", err, "\n", string(bz)) + } + + if verbose { + fmt.Println("submitConsumerRemovalProposal output:", string(bz)) + } + + // wait for inclusion in a block -> '--broadcast-mode block' is deprecated + tr.waitBlocks(ChainID("provi"), 2, 20*time.Second) +} + +func (tr Chain) submitConsumerRemovalLegacyProposal( + action SubmitConsumerRemovalProposalAction, + verbose bool, ) { stopTime := tr.testConfig.containerConfig.Now.Add(action.StopTimeOffset) prop := client.ConsumerRemovalProposalJSON{ @@ -423,6 +593,87 @@ func (tr Chain) submitConsumerModificationProposal( action SubmitConsumerModificationProposalAction, verbose bool, ) { + + template := ` + +{ +"messages": [ + { + "@type": "/interchain_security.ccv.provider.v1.MsgConsumerModification", + "title": "Propose the modification of the PSS parameters of a chain", + "description": "description of the consumer modification proposal", + "chain_id": "%s", + "top_N": %d, + "validators_power_cap": %d, + "validator_set_cap": %d, + "allowlist": %s, + "denylist": %s, + "authority": "cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn", + "min_stake": "0", + "allow_inactive_vals": false + } + ], +"metadata": "ipfs://CID", +"deposit": "%sstake", +"title": "Propose the modification of the PSS parameters of a chain", +"summary": "summary of a modification proposal", +"expedited": false + } +` + + jsonStr := fmt.Sprintf(template, + string(tr.testConfig.chainConfigs[action.ConsumerChain].ChainId), + action.TopN, + action.ValidatorsPowerCap, + action.ValidatorSetCap, + action.Allowlist, + action.Denylist, + action.Deposit, + ) + + // #nosec G204 -- bypass unsafe quoting warning (no production code) + proposalFile := "/consumer-mod.proposal" + bz, err := tr.target.ExecCommand( + "/bin/bash", "-c", fmt.Sprintf(`echo '%s' > %s`, jsonStr, proposalFile), + ).CombinedOutput() + if err != nil { + log.Fatal(err, "\n", string(bz)) + } + + // CONSUMER MODIFICATION PROPOSAL + cmd := tr.target.ExecCommand( + tr.testConfig.chainConfigs[action.Chain].BinaryName, + "tx", "gov", "submit-proposal", proposalFile, + `--from`, `validator`+fmt.Sprint(action.From), + `--chain-id`, string(tr.testConfig.chainConfigs[action.Chain].ChainId), + `--home`, tr.getValidatorHome(action.Chain, action.From), + `--gas`, `900000`, + `--node`, tr.getValidatorNode(action.Chain, action.From), + `--keyring-backend`, `test`, + `-y`, + ) + + if verbose { + fmt.Println("submitConsumerModificationProposal cmd:", cmd.String()) + fmt.Println("submitConsumerModificationProposal json:", jsonStr) + } + bz, err = cmd.CombinedOutput() + if err != nil { + log.Fatal("submit consumer modification proposal failed:", err, "\n", string(bz)) + } + + if verbose { + fmt.Println("submitConsumerModificationProposal output:", string(bz)) + } + + // wait for inclusion in a block -> '--broadcast-mode block' is deprecated + tr.waitBlocks(ChainID("provi"), 2, 10*time.Second) +} + +func (tr Chain) submitConsumerModificationLegacyProposal( + action SubmitConsumerModificationProposalAction, + verbose bool, +) { prop := client.ConsumerModificationProposalJSON{ Title: "Propose the modification of the PSS parameters of a chain", Summary: "summary of a modification proposal", @@ -1964,13 +2215,78 @@ func (tr Chain) registerRepresentative( } type SubmitChangeRewardDenomsProposalAction struct { + Chain ChainID Denom string Deposit uint From ValidatorID } func (tr Chain) submitChangeRewardDenomsProposal(action SubmitChangeRewardDenomsProposalAction, verbose bool) { - providerChain := tr.testConfig.chainConfigs[ChainID("provi")] + template := ` +{ + "messages": [ + { + "@type": "/interchain_security.ccv.provider.v1.MsgChangeRewardDenoms", + "denoms_to_add": %s, + "denoms_to_remove": %s, + "authority": "cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn" + } + ], + "metadata": "ipfs://CID", + "deposit": "%dstake", + "title": "change reward denoms", + "summary": "Proposal to change reward denoms", + "expedited": false +}` + + denomsToAdd := []string{action.Denom} + denomsToRemove := []string{"stake"} + jsonStr := fmt.Sprintf(template, + denomsToAdd, + denomsToRemove, + action.Deposit) + + //#nosec G204 -- bypass unsafe quoting warning (no production code) + proposalFile := "/consumer-addition.proposal" + bz, err := tr.target.ExecCommand( + "/bin/bash", "-c", fmt.Sprintf(`echo '%s' > %s`, jsonStr, proposalFile), + ).CombinedOutput() + if err != nil { + log.Fatal(err, "\n", string(bz)) + } + + // CHANGE REWARDS DENOM PROPOSAL + cmd := tr.target.ExecCommand( + tr.testConfig.chainConfigs[action.Chain].BinaryName, + "tx", "gov", "submit-proposal", proposalFile, + `--from`, `validator`+fmt.Sprint(action.From), + `--chain-id`, string(tr.testConfig.chainConfigs[action.Chain].ChainId), + `--home`, tr.getValidatorHome(action.Chain, action.From), + `--gas`, `900000`, + `--node`, tr.getValidatorNode(action.Chain, action.From), + `--keyring-backend`, `test`, + `-y`, + ) + + if verbose { + fmt.Println("change rewards denom props cmd:", cmd.String()) + fmt.Println("change rewards denom props json:", jsonStr) + } + bz, err = cmd.CombinedOutput() + if err != nil { + log.Fatal("submit-proposal failed:", err, "\n", string(bz)) + } + + if verbose { + fmt.Println("change rewards denom props output:", string(bz)) + } + + // wait for inclusion in a block -> '--broadcast-mode block' is deprecated + tr.waitBlocks(ChainID("provi"), 2, 30*time.Second) +} + +func (tr Chain) submitChangeRewardDenomsLegacyProposal(action SubmitChangeRewardDenomsProposalAction, verbose bool) { + providerChain := tr.testConfig.chainConfigs[action.Chain] prop := client.ChangeRewardDenomsProposalJSON{ Summary: "Change reward denoms", diff --git a/tests/e2e/state.go b/tests/e2e/state.go index fba5e36c3a..f29c8f59f0 100644 --- a/tests/e2e/state.go +++ b/tests/e2e/state.go @@ -465,7 +465,7 @@ func (tr Commands) GetProposal(chain ChainID, proposal uint) Proposal { Title: title, Description: description, } - case "/interchain_security.ccv.provider.v1.ConsumerAdditionProposal": + case "/interchain_security.ccv.provider.v1.MsgConsumerAddition": chainId := rawContent.Get("chain_id").String() spawnTime := rawContent.Get("spawn_time").Time().Sub(tr.containerConfig.Now) @@ -498,7 +498,7 @@ func (tr Commands) GetProposal(chain ChainID, proposal uint) Proposal { Title: title, Type: "/cosmos.upgrade.v1beta1.SoftwareUpgradeProposal", } - case "/interchain_security.ccv.provider.v1.ConsumerRemovalProposal": + case "/interchain_security.ccv.provider.v1.MsgConsumerRemoval": chainId := rawContent.Get("chain_id").String() stopTime := rawContent.Get("stop_time").Time().Sub(tr.containerConfig.Now) @@ -529,7 +529,7 @@ func (tr Commands) GetProposal(chain ChainID, proposal uint) Proposal { Params: params, } - case "/interchain_security.ccv.provider.v1.ConsumerModificationProposal": + case "/interchain_security.ccv.provider.v1.MsgConsumerModification": chainId := rawContent.Get("chain_id").String() var chain ChainID @@ -555,7 +555,7 @@ func (tr Commands) GetProposal(chain ChainID, proposal uint) Proposal { } } - log.Fatal("received unknown proposal type: ", propType, "proposal JSON:", propRaw) + log.Fatal("received unknown proposal type: '", propType, "', proposal JSON:", propRaw) return nil } diff --git a/tests/e2e/steps_democracy.go b/tests/e2e/steps_democracy.go index 82e1d237af..ef9c3787f0 100644 --- a/tests/e2e/steps_democracy.go +++ b/tests/e2e/steps_democracy.go @@ -152,6 +152,7 @@ func stepsDemocracy(consumerName string, expectRegisteredRewardDistribution bool }, { Action: SubmitChangeRewardDenomsProposalAction{ + Chain: ChainID("provi"), Denom: consumerRewardDenom, Deposit: 10000001, From: ValidatorID("bob"), diff --git a/tests/e2e/test_driver.go b/tests/e2e/test_driver.go index 7a1996c01c..e25b27f330 100644 --- a/tests/e2e/test_driver.go +++ b/tests/e2e/test_driver.go @@ -83,7 +83,7 @@ func (td *DefaultDriver) getTargetDriver(chainID ChainID) Chain { } icsVersion := td.getIcsVersion(chainID) switch icsVersion { - case "v4": + case "v3", "v4": if td.verbose { fmt.Println("Using 'v4' driver for chain ", chainID) } @@ -101,7 +101,7 @@ func (td *DefaultDriver) getTargetDriver(chainID ChainID) Chain { target: td.target, } if td.verbose { - fmt.Println("Using default driver ", icsVersion, " for chain ", chainID) + fmt.Println("Using default driver for version", icsVersion, " for chain ", chainID) } } @@ -140,13 +140,31 @@ func (td *DefaultDriver) runAction(action interface{}) error { case SubmitTextProposalAction: target.submitTextProposal(action, td.verbose) case SubmitConsumerAdditionProposalAction: - target.submitConsumerAdditionProposal(action, td.verbose) + target = td.getTargetDriver(action.Chain) + version := target.testConfig.providerVersion + if semver.IsValid(version) && semver.Compare(semver.Major(version), "v5") < 0 { + target.submitConsumerAdditionLegacyProposal(action, td.verbose) + } else { + target.submitConsumerAdditionProposal(action, td.verbose) + } case SubmitConsumerRemovalProposalAction: - target.submitConsumerRemovalProposal(action, td.verbose) + version := target.testConfig.providerVersion + target = td.getTargetDriver(action.Chain) + if semver.IsValid(version) && semver.Compare(semver.Major(version), "v5") < 0 { + target.submitConsumerRemovalLegacyProposal(action, td.verbose) + } else { + target.submitConsumerRemovalProposal(action, td.verbose) + } case SubmitEnableTransfersProposalAction: target.submitEnableTransfersProposalAction(action, td.verbose) case SubmitConsumerModificationProposalAction: - target.submitConsumerModificationProposal(action, td.verbose) + target = td.getTargetDriver(action.Chain) + version := target.testConfig.providerVersion + if semver.IsValid(version) && semver.Compare(semver.Major(version), "v5") < 0 { + target.submitConsumerModificationLegacyProposal(action, td.verbose) + } else { + target.submitConsumerModificationProposal(action, td.verbose) + } case VoteGovProposalAction: target.voteGovProposal(action, td.verbose) case StartConsumerChainAction: @@ -202,7 +220,12 @@ func (td *DefaultDriver) runAction(action interface{}) error { case StartConsumerEvidenceDetectorAction: target.startConsumerEvidenceDetector(action, td.verbose) case SubmitChangeRewardDenomsProposalAction: - target.submitChangeRewardDenomsProposal(action, td.verbose) + target = td.getTargetDriver(action.Chain) + if semver.Compare(semver.Major(target.testConfig.providerVersion), "v5") < 0 { + target.submitChangeRewardDenomsLegacyProposal(action, td.verbose) + } else { + target.submitChangeRewardDenomsProposal(action, td.verbose) + } case OptInAction: target.optIn(action, td.target, td.verbose) case OptOutAction: diff --git a/tests/integration/provider_gov_hooks.go b/tests/integration/provider_gov_hooks.go index e3f9cc8ace..813a62a671 100644 --- a/tests/integration/provider_gov_hooks.go +++ b/tests/integration/provider_gov_hooks.go @@ -21,15 +21,9 @@ func (s *CCVTestSuite) TestAfterPropSubmissionAndVotingPeriodEnded() { govKeeper := s.providerApp.GetTestGovKeeper() proposer := s.providerChain.SenderAccount - content := testkeeper.GetTestConsumerAdditionProp() - content.ChainId = "newchain-0" - legacyPropContent, err := v1.NewLegacyContent( - content, - authtypes.NewModuleAddress("gov").String(), - ) - s.Require().NoError(err) + addConsumerProp := testkeeper.GetTestMsgConsumerAddition() - proposal, err := v1.NewProposal([]sdk.Msg{legacyPropContent}, 1, time.Now(), time.Now().Add(1*time.Hour), "metadata", "title", "summary", proposer.GetAddress(), false) + proposal, err := v1.NewProposal([]sdk.Msg{&addConsumerProp}, 1, time.Now(), time.Now().Add(1*time.Hour), "metadata", "title", "summary", proposer.GetAddress(), false) s.Require().NoError(err) err = govKeeper.SetProposal(ctx, proposal) @@ -41,14 +35,14 @@ func (s *CCVTestSuite) TestAfterPropSubmissionAndVotingPeriodEnded() { proposalIdOnProvider, ok := providerKeeper.GetProposedConsumerChain(ctx, proposal.Id) s.Require().True(ok) s.Require().NotEmpty(proposalIdOnProvider) - s.Require().Equal(content.ChainId, proposalIdOnProvider) + s.Require().Equal(addConsumerProp.ChainId, proposalIdOnProvider) providerKeeper.Hooks().AfterProposalVotingPeriodEnded(ctx, proposal.Id) // verify that the proposal ID is deleted s.Require().Empty(providerKeeper.GetProposedConsumerChain(ctx, proposal.Id)) } -func (s *CCVTestSuite) TestGetConsumerAdditionLegacyPropFromProp() { +func (s *CCVTestSuite) TestGetConsumerAdditionFromProp() { ctx := s.providerChain.GetContext() proposer := s.providerChain.SenderAccount @@ -59,13 +53,19 @@ func (s *CCVTestSuite) TestGetConsumerAdditionLegacyPropFromProp() { Amount: sdk.NewCoins(sdk.NewCoin("stake", math.OneInt())), } + // create a legacy proposal textProp, err := v1.NewLegacyContent( v1beta1.NewTextProposal("a title", "a legacy text prop"), authtypes.NewModuleAddress("gov").String(), ) s.Require().NoError(err) - addConsumerProp, err := v1.NewLegacyContent( + // create a valid consumer addition message + msgConsumerAddition := testkeeper.GetTestMsgConsumerAddition() + + // create a legacy consumer addition proposal content + // (not supported anymore) + addConsumerPropLegacy, err := v1.NewLegacyContent( testkeeper.GetTestConsumerAdditionProp(), authtypes.NewModuleAddress("gov").String(), ) @@ -84,7 +84,7 @@ func (s *CCVTestSuite) TestGetConsumerAdditionLegacyPropFromProp() { expPanic: false, }, { - name: "msgs in prop contain no legacy props", + name: "msgs in prop contain no consumer addition props", propMsg: dummyMsg, expectConsumerPropFound: false, expPanic: false, @@ -98,11 +98,17 @@ func (s *CCVTestSuite) TestGetConsumerAdditionLegacyPropFromProp() { name: "msgs contain an invalid legacy prop", propMsg: &v1.MsgExecLegacyContent{}, expectConsumerPropFound: false, - expPanic: true, + expPanic: false, + }, + { + name: "msg contains a prop of legacy ConsumerAdditionProposal type - hook should NOT create a new proposed chain", + propMsg: addConsumerPropLegacy, + expectConsumerPropFound: false, + expPanic: false, }, { - name: "msg contains a prop of ConsumerAdditionProposal type - hook should create a new proposed chain", - propMsg: addConsumerProp, + name: "msg contains a prop of MsgConsumerAddition type - hook should create a new proposed chain", + propMsg: &msgConsumerAddition, expectConsumerPropFound: true, expPanic: false, }, @@ -132,12 +138,12 @@ func (s *CCVTestSuite) TestGetConsumerAdditionLegacyPropFromProp() { if tc.expPanic { s.Require().Panics(func() { // this panics with a nil pointer dereference because the proposal is invalid and cannot be unmarshalled - providerKeeper.Hooks().GetConsumerAdditionLegacyPropFromProp(ctx, proposal.Id) + providerKeeper.Hooks().GetConsumerAdditionFromProp(ctx, proposal.Id) }) return } - savedProp, found := providerKeeper.Hooks().GetConsumerAdditionLegacyPropFromProp(ctx, proposal.Id) + savedProp, found := providerKeeper.Hooks().GetConsumerAdditionFromProp(ctx, proposal.Id) if tc.expectConsumerPropFound { s.Require().True(found) s.Require().NotEmpty(savedProp, savedProp) diff --git a/testutil/integration/debug_test.go b/testutil/integration/debug_test.go index 022cc71429..dedd937eaa 100644 --- a/testutil/integration/debug_test.go +++ b/testutil/integration/debug_test.go @@ -265,8 +265,8 @@ func TestAfterPropSubmissionAndVotingPeriodEnded(t *testing.T) { runCCVTestByName(t, "TestAfterPropSubmissionAndVotingPeriodEnded") } -func TestGetConsumerAdditionLegacyPropFromProp(t *testing.T) { - runCCVTestByName(t, "TestGetConsumerAdditionLegacyPropFromProp") +func TestGetConsumerAdditionFromProp(t *testing.T) { + runCCVTestByName(t, "TestGetConsumerAdditionFromProp") } func TestIBCTransferMiddleware(t *testing.T) { @@ -277,14 +277,6 @@ func TestAllocateTokens(t *testing.T) { runCCVTestByName(t, "TestAllocateTokens") } -func TestTransferConsumerRewardsToDistributionModule(t *testing.T) { - runCCVTestByName(t, "TransferConsumerRewardsToDistributionModule") -} - -func TestAllocateTokensToValidator(t *testing.T) { - runCCVTestByName(t, "TestAllocateTokensToValidator") -} - func TestMultiConsumerRewardsDistribution(t *testing.T) { runCCVTestByName(t, "TestMultiConsumerRewardsDistribution") } diff --git a/testutil/keeper/unit_test_helpers.go b/testutil/keeper/unit_test_helpers.go index 72a59a1207..0ac48f8e6c 100644 --- a/testutil/keeper/unit_test_helpers.go +++ b/testutil/keeper/unit_test_helpers.go @@ -2,6 +2,7 @@ package keeper import ( "crypto/rand" + "encoding/base64" "encoding/binary" "testing" "time" @@ -293,6 +294,29 @@ func GetTestConsumerAdditionProp() *providertypes.ConsumerAdditionProposal { return prop } +func GetTestMsgConsumerAddition() providertypes.MsgConsumerAddition { + return providertypes.MsgConsumerAddition{ + ChainId: "a ChainID", + InitialHeight: clienttypes.NewHeight(4, 5), + GenesisHash: []byte(base64.StdEncoding.EncodeToString([]byte("gen_hash"))), + BinaryHash: []byte(base64.StdEncoding.EncodeToString([]byte("bin_hash"))), + SpawnTime: time.Now(), + UnbondingPeriod: types.DefaultConsumerUnbondingPeriod, + CcvTimeoutPeriod: types.DefaultCCVTimeoutPeriod, + TransferTimeoutPeriod: types.DefaultTransferTimeoutPeriod, + ConsumerRedistributionFraction: types.DefaultConsumerRedistributeFrac, + BlocksPerDistributionTransmission: types.DefaultBlocksPerDistributionTransmission, + HistoricalEntries: types.DefaultHistoricalEntries, + DistributionTransmissionChannel: "", + Top_N: 10, + ValidatorsPowerCap: 0, + ValidatorSetCap: 0, + Allowlist: nil, + Denylist: nil, + Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), + } +} + // Obtains a CrossChainValidator with a newly generated key, and randomized field values func GetNewCrossChainValidator(t *testing.T) consumertypes.CrossChainValidator { t.Helper() diff --git a/x/ccv/provider/client/legacy_proposal_handler.go b/x/ccv/provider/client/legacy_proposal_handler.go deleted file mode 100644 index 6a792ef4b0..0000000000 --- a/x/ccv/provider/client/legacy_proposal_handler.go +++ /dev/null @@ -1,291 +0,0 @@ -package client - -import ( - "github.com/spf13/cobra" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/tx" - sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - govclient "github.com/cosmos/cosmos-sdk/x/gov/client" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" - - "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" -) - -var ( - ConsumerAdditionProposalHandler = govclient.NewProposalHandler(SubmitConsumerAdditionPropTxCmd) - ConsumerRemovalProposalHandler = govclient.NewProposalHandler(SubmitConsumerRemovalProposalTxCmd) - ChangeRewardDenomsProposalHandler = govclient.NewProposalHandler(SubmitChangeRewardDenomsProposalTxCmd) - ConsumerModificationProposalHandler = govclient.NewProposalHandler(SubmitConsumerModificationProposalTxCmd) -) - -// SubmitConsumerAdditionPropTxCmd returns a CLI command handler for submitting -// a consumer addition proposal via a transaction. -func SubmitConsumerAdditionPropTxCmd() *cobra.Command { - return &cobra.Command{ - Use: "consumer-addition [proposal-file]", - Args: cobra.ExactArgs(1), - Short: "Submit a consumer addition proposal", - Long: ` -Submit a consumer addition proposal along with an initial deposit. -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-legacy-proposal consumer-addition --from= - -Where proposal.json contains: - -{ - "title": "Create the FooChain", - "summary": "Gonna be a great chain", - "chain_id": "foochain", - "initial_height": { - "revision_number": 2, - "revision_height": 3 - }, - "genesis_hash": "Z2VuZXNpcyBoYXNo", - "binary_hash": "YmluYXJ5IGhhc2g=", - "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, - "unbonding_period": 1728000000000000, - "deposit": "10000stake", - "top_n": 0, - "validators_power_cap": 32, - "validator_set_cap": 50, - "allowlist": [], - "denylist": ["validatorAConsensusAddress", "validatorBConsensusAddress"], - "min_stake": 100000000000, - "allow_inactive_vals": false -} - `, - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - proposal, err := ParseConsumerAdditionProposalJSON(args[0]) - if err != nil { - return err - } - - // do not fail for errors regarding the unbonding period, but just log a warning - CheckPropUnbondingPeriod(clientCtx, proposal.UnbondingPeriod) - - content := types.NewConsumerAdditionProposal( - proposal.Title, proposal.Summary, proposal.ChainId, proposal.InitialHeight, - proposal.GenesisHash, proposal.BinaryHash, proposal.SpawnTime, - proposal.ConsumerRedistributionFraction, proposal.BlocksPerDistributionTransmission, - proposal.DistributionTransmissionChannel, proposal.HistoricalEntries, - proposal.CcvTimeoutPeriod, proposal.TransferTimeoutPeriod, proposal.UnbondingPeriod, proposal.TopN, - proposal.ValidatorsPowerCap, proposal.ValidatorSetCap, proposal.Allowlist, proposal.Denylist, - proposal.MinStake, proposal.AllowInactiveVals) - - from := clientCtx.GetFromAddress() - - deposit, err := sdk.ParseCoinsNormalized(proposal.Deposit) - if err != nil { - return err - } - - 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, false) - if err != nil { - return err - } - - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) - }, - } -} - -// SubmitConsumerRemovalPropTxCmd returns a CLI command handler for submitting -// a consumer addition proposal via a transaction. -func SubmitConsumerRemovalProposalTxCmd() *cobra.Command { - return &cobra.Command{ - Use: "consumer-removal [proposal-file]", - Args: cobra.ExactArgs(1), - Short: "Submit a consumer chain removal proposal", - Long: ` -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-legacy-proposal consumer-removal --from= - -Where proposal.json contains: -{ - "title": "Stop the FooChain", - "summary": "It was a great chain", - "chain_id": "foochain", - "stop_time": "2022-01-27T15:59:50.121607-08:00", - "deposit": "10000stake" -} - `, RunE: func(cmd *cobra.Command, args []string) error { - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - proposal, err := ParseConsumerRemovalProposalJSON(args[0]) - if err != nil { - return err - } - - 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 := govv1.NewMsgSubmitProposal([]sdk.Msg{msgContent}, deposit, from.String(), "", content.GetTitle(), proposal.Summary, false) - 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 { - 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, false) - if err != nil { - return err - } - - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) - }, - } -} - -// SubmitConsumerModificationProposalTxCmd returns a CLI command handler for submitting -// a consumer modification proposal via a transaction. -func SubmitConsumerModificationProposalTxCmd() *cobra.Command { - return &cobra.Command{ - Use: "consumer-modification [proposal-file]", - Args: cobra.ExactArgs(1), - Short: "Submit a consumer modification proposal", - Long: ` -Submit a consumer modification proposal along with an initial deposit. -The proposal details must be supplied via a JSON file. - -Example: -$ tx gov submit-legacy-proposal consumer-modification --from= - -Where proposal.json contains: - -{ - "title": "Modify FooChain", - "summary": "Make it an Opt In chain", - "chain_id": "foochain", - "top_n": 0, - "validators_power_cap": 32, - "validator_set_cap": 50, - "allowlist": [], - "denylist": ["validatorAConsensusAddress", "validatorBConsensusAddress"], - "min_stake": 100000000000, - "allow_inactive_vals": false -} - `, - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - proposal, err := ParseConsumerModificationProposalJSON(args[0]) - if err != nil { - return err - } - - content := types.NewConsumerModificationProposal( - proposal.Title, proposal.Summary, proposal.ChainId, proposal.TopN, - proposal.ValidatorsPowerCap, proposal.ValidatorSetCap, proposal.Allowlist, proposal.Denylist, proposal.MinStake, proposal.AllowInactiveVals) - - from := clientCtx.GetFromAddress() - - deposit, err := sdk.ParseCoinsNormalized(proposal.Deposit) - if err != nil { - return err - } - - 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, false) - if err != nil { - return err - } - - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) - }, - } -} diff --git a/x/ccv/provider/keeper/hooks.go b/x/ccv/provider/keeper/hooks.go index 15d5d0e769..a72f60080f 100644 --- a/x/ccv/provider/keeper/hooks.go +++ b/x/ccv/provider/keeper/hooks.go @@ -2,12 +2,10 @@ package keeper import ( "context" - "fmt" "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" sdkgov "github.com/cosmos/cosmos-sdk/x/gov/types" - v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" @@ -112,8 +110,7 @@ func (h Hooks) BeforeTokenizeShareRecordRemoved(_ context.Context, _ uint64) err // that maps the proposal ID to the consumer chain ID. func (h Hooks) AfterProposalSubmission(goCtx context.Context, proposalID uint64) error { ctx := sdk.UnwrapSDKContext(goCtx) - - if p, ok := h.GetConsumerAdditionLegacyPropFromProp(ctx, proposalID); ok { + if p, ok := h.GetConsumerAdditionFromProp(ctx, proposalID); ok { h.k.SetProposedConsumerChain(ctx, p.ChainId, proposalID) } return nil @@ -126,7 +123,7 @@ func (h Hooks) AfterProposalSubmission(goCtx context.Context, proposalID uint64) func (h Hooks) AfterProposalVotingPeriodEnded(goCtx context.Context, proposalID uint64) error { ctx := sdk.UnwrapSDKContext(goCtx) - if _, ok := h.GetConsumerAdditionLegacyPropFromProp(ctx, proposalID); ok { + if _, ok := h.GetConsumerAdditionFromProp(ctx, proposalID); ok { h.k.DeleteProposedConsumerChainInStore(ctx, proposalID) } return nil @@ -144,9 +141,9 @@ func (h Hooks) AfterProposalFailedMinDeposit(ctx context.Context, proposalID uin return nil } -// GetConsumerAdditionLegacyPropFromProp extracts a consumer addition legacy proposal from +// GetConsumerAdditionFromProp extracts a consumer addition proposal from // the proposal with the given ID -func (h Hooks) GetConsumerAdditionLegacyPropFromProp( +func (h Hooks) GetConsumerAdditionFromProp( ctx sdk.Context, proposalID uint64, ) (providertypes.ConsumerAdditionProposal, bool) { @@ -158,21 +155,33 @@ func (h Hooks) GetConsumerAdditionLegacyPropFromProp( // Iterate over the messages in the proposal // Note that it's assumed that at most ONE message can contain a consumer addition proposal for _, msg := range p.GetMessages() { - sdkMsg, isLegacyProposal := msg.GetCachedValue().(*v1.MsgExecLegacyContent) - if !isLegacyProposal { + sdkMsg, isConsumerAddition := msg.GetCachedValue().(*providertypes.MsgConsumerAddition) + if !isConsumerAddition { continue } - content, err := v1.LegacyContentFromMessage(sdkMsg) - if err != nil { - panic(fmt.Errorf("failed to get legacy proposal %d from prop message", proposalID)) - } - - // returns if legacy prop is of ConsumerAddition proposal type - prop, ok := content.(*providertypes.ConsumerAdditionProposal) - if ok { - return *prop, true + proposal := providertypes.ConsumerAdditionProposal{ + Title: p.Title, + Description: p.Summary, + ChainId: sdkMsg.ChainId, + InitialHeight: sdkMsg.InitialHeight, + GenesisHash: sdkMsg.GenesisHash, + BinaryHash: sdkMsg.BinaryHash, + SpawnTime: sdkMsg.SpawnTime, + UnbondingPeriod: sdkMsg.UnbondingPeriod, + CcvTimeoutPeriod: sdkMsg.CcvTimeoutPeriod, + TransferTimeoutPeriod: sdkMsg.TransferTimeoutPeriod, + ConsumerRedistributionFraction: sdkMsg.ConsumerRedistributionFraction, + BlocksPerDistributionTransmission: sdkMsg.BlocksPerDistributionTransmission, + HistoricalEntries: sdkMsg.HistoricalEntries, + DistributionTransmissionChannel: sdkMsg.DistributionTransmissionChannel, + Top_N: sdkMsg.Top_N, + ValidatorsPowerCap: sdkMsg.ValidatorsPowerCap, + ValidatorSetCap: sdkMsg.ValidatorSetCap, + Allowlist: sdkMsg.Allowlist, + Denylist: sdkMsg.Denylist, } + return proposal, true } return providertypes.ConsumerAdditionProposal{}, false }