diff --git a/.github/compatibility-test-matrices/main/client-chain-a.json b/.github/compatibility-test-matrices/main/client-chain-a.json index e4e3117a16e..c389c981465 100644 --- a/.github/compatibility-test-matrices/main/client-chain-a.json +++ b/.github/compatibility-test-matrices/main/client-chain-a.json @@ -18,7 +18,7 @@ "TestClientTestSuite" ], "test": [ - "TestClientUpdateProposal_Succeeds", + "TestRecoverClient_Succeeds", "TestClient_Update_Misbehaviour", "TestAllowedClientsParam" ], diff --git a/.github/compatibility-test-matrices/main/client-chain-b.json b/.github/compatibility-test-matrices/main/client-chain-b.json index ca52092c2cd..f5fce3a32d8 100644 --- a/.github/compatibility-test-matrices/main/client-chain-b.json +++ b/.github/compatibility-test-matrices/main/client-chain-b.json @@ -18,7 +18,7 @@ "TestClientTestSuite" ], "test": [ - "TestClientUpdateProposal_Succeeds", + "TestRecoverClient_Succeeds", "TestClient_Update_Misbehaviour" ], "relayer-type": [ diff --git a/.github/compatibility-test-matrices/release-v6.1.x/client-chain-a.json b/.github/compatibility-test-matrices/release-v6.1.x/client-chain-a.json index 24ea765b887..82d676d3c18 100644 --- a/.github/compatibility-test-matrices/release-v6.1.x/client-chain-a.json +++ b/.github/compatibility-test-matrices/release-v6.1.x/client-chain-a.json @@ -17,7 +17,7 @@ "TestClientTestSuite" ], "test": [ - "TestClientUpdateProposal_Succeeds", + "TestRecoverClient_Succeeds", "TestClient_Update_Misbehaviour", "TestAllowedClientsParam" ], diff --git a/.github/compatibility-test-matrices/release-v6.1.x/client-chain-b.json b/.github/compatibility-test-matrices/release-v6.1.x/client-chain-b.json index d423dabf97b..6a6db3424fc 100644 --- a/.github/compatibility-test-matrices/release-v6.1.x/client-chain-b.json +++ b/.github/compatibility-test-matrices/release-v6.1.x/client-chain-b.json @@ -17,7 +17,7 @@ "TestClientTestSuite" ], "test": [ - "TestClientUpdateProposal_Succeeds", + "TestRecoverClient_Succeeds", "TestClient_Update_Misbehaviour" ], "relayer-type": [ diff --git a/.github/compatibility-test-matrices/release-v6.2.x/client-chain-a.json b/.github/compatibility-test-matrices/release-v6.2.x/client-chain-a.json index 1ba47832a7b..e180af2505a 100644 --- a/.github/compatibility-test-matrices/release-v6.2.x/client-chain-a.json +++ b/.github/compatibility-test-matrices/release-v6.2.x/client-chain-a.json @@ -17,7 +17,7 @@ "TestClientTestSuite" ], "test": [ - "TestClientUpdateProposal_Succeeds", + "TestRecoverClient_Succeeds", "TestClient_Update_Misbehaviour", "TestAllowedClientsParam" ], diff --git a/.github/compatibility-test-matrices/release-v6.2.x/client-chain-b.json b/.github/compatibility-test-matrices/release-v6.2.x/client-chain-b.json index d55679c29b3..1f389cb3ea8 100644 --- a/.github/compatibility-test-matrices/release-v6.2.x/client-chain-b.json +++ b/.github/compatibility-test-matrices/release-v6.2.x/client-chain-b.json @@ -17,7 +17,7 @@ "TestClientTestSuite" ], "test": [ - "TestClientUpdateProposal_Succeeds", + "TestRecoverClient_Succeeds", "TestClient_Update_Misbehaviour" ], "relayer-type": [ diff --git a/.github/compatibility-test-matrices/release-v7.2.x/client-chain-a.json b/.github/compatibility-test-matrices/release-v7.2.x/client-chain-a.json index 7c8d51cc7b8..b5520a248b4 100644 --- a/.github/compatibility-test-matrices/release-v7.2.x/client-chain-a.json +++ b/.github/compatibility-test-matrices/release-v7.2.x/client-chain-a.json @@ -17,7 +17,7 @@ "TestClientTestSuite" ], "test": [ - "TestClientUpdateProposal_Succeeds", + "TestRecoverClient_Succeeds", "TestClient_Update_Misbehaviour", "TestAllowedClientsParam" ], diff --git a/.github/compatibility-test-matrices/release-v7.2.x/client-chain-b.json b/.github/compatibility-test-matrices/release-v7.2.x/client-chain-b.json index 00890b0ee3b..5d6d51b0605 100644 --- a/.github/compatibility-test-matrices/release-v7.2.x/client-chain-b.json +++ b/.github/compatibility-test-matrices/release-v7.2.x/client-chain-b.json @@ -17,7 +17,7 @@ "TestClientTestSuite" ], "test": [ - "TestClientUpdateProposal_Succeeds", + "TestRecoverClient_Succeeds", "TestClient_Update_Misbehaviour" ], "relayer-type": [ diff --git a/.github/compatibility-test-matrices/release-v7.3.x/client-chain-a.json b/.github/compatibility-test-matrices/release-v7.3.x/client-chain-a.json index 29b125aace1..ab8f51f9bae 100644 --- a/.github/compatibility-test-matrices/release-v7.3.x/client-chain-a.json +++ b/.github/compatibility-test-matrices/release-v7.3.x/client-chain-a.json @@ -17,7 +17,7 @@ "TestClientTestSuite" ], "test": [ - "TestClientUpdateProposal_Succeeds", + "TestRecoverClient_Succeeds", "TestClient_Update_Misbehaviour", "TestAllowedClientsParam" ], diff --git a/.github/compatibility-test-matrices/release-v7.3.x/client-chain-b.json b/.github/compatibility-test-matrices/release-v7.3.x/client-chain-b.json index 0c8950e2eda..ecec881f080 100644 --- a/.github/compatibility-test-matrices/release-v7.3.x/client-chain-b.json +++ b/.github/compatibility-test-matrices/release-v7.3.x/client-chain-b.json @@ -17,7 +17,7 @@ "TestClientTestSuite" ], "test": [ - "TestClientUpdateProposal_Succeeds", + "TestRecoverClient_Succeeds", "TestClient_Update_Misbehaviour" ], "relayer-type": [ diff --git a/.github/compatibility-test-matrices/unreleased/client.json b/.github/compatibility-test-matrices/unreleased/client.json index b0a6412a8c5..2b3e2376be2 100644 --- a/.github/compatibility-test-matrices/unreleased/client.json +++ b/.github/compatibility-test-matrices/unreleased/client.json @@ -21,7 +21,7 @@ "TestClientTestSuite" ], "test": [ - "TestClientUpdateProposal_Succeeds", + "TestRecoverClient_Succeeds", "TestClient_Update_Misbehaviour", "TestAllowedClientsParam" ], diff --git a/docs/architecture/adr-026-ibc-client-recovery-mechanisms.md b/docs/architecture/adr-026-ibc-client-recovery-mechanisms.md index e34244f1d6b..05f615a7aaf 100644 --- a/docs/architecture/adr-026-ibc-client-recovery-mechanisms.md +++ b/docs/architecture/adr-026-ibc-client-recovery-mechanisms.md @@ -8,6 +8,7 @@ - 2021/05/20: Revision to simplify consensus state copying, remove initial height - 2022/04/08: Revision to deprecate AllowUpdateAfterExpiry and AllowUpdateAfterMisbehaviour - 2022/07/15: Revision to allow updating of TrustingPeriod +- 2023/09/05: Revision to migrate from gov v1beta1 to gov v1 ## Status @@ -44,16 +45,19 @@ We elect not to deal with chains which have actually halted, which is necessaril 1. `allow_update_after_misbehaviour` (boolean, default true). Note that this flag has been deprecated, it remains to signal intent but checks against this value will not be enforced. 1. Require Tendermint light clients (ICS 07) to expose the following additional state mutation functions 1. `Unfreeze()`, which unfreezes a light client after misbehaviour and clears any frozen height previously set -1. Add a new governance proposal type, `ClientUpdateProposal`, in the `x/ibc` module - 1. Extend the base `Proposal` with two client identifiers (`string`). +1. Add a new governance proposal with `MsgRecoverClient`. + 1. Create a new Msg with two client identifiers (`string`) and a signer. 1. The first client identifier is the proposed client to be updated. This client must be either frozen or expired. 1. The second client is a substitute client. It carries all the state for the client which may be updated. It must have identitical client and chain parameters to the client which may be updated (except for latest height, frozen height, and chain-id). It should be continually updated during the voting period. 1. If this governance proposal passes, the client on trial will be updated to the latest state of the substitute. + 1. The signer must be the authority set for the ibc module. Previously, `AllowUpdateAfterExpiry` and `AllowUpdateAfterMisbehaviour` were used to signal the recovery options for an expired or frozen client, and governance proposals were not allowed to overwrite the client if these parameters were set to false. However, this has now been deprecated because a code migration can overwrite the client and consensus states regardless of the value of these parameters. If governance would vote to overwrite a client or consensus state, it is likely that governance would also be willing to perform a code migration to do the same. In addition, `TrustingPeriod` was initally not allowed to be updated by a client upgrade proposal. However, due to the number of situations experienced in production where the `TrustingPeriod` of a client should be allowed to be updated because of ie: initial misconfiguration for a canonical channel, governance should be allowed to update this client parameter. + In versions older than ibc-go v8, `MsgRecoverClient` was a governance proposal type `ClientUpdateProposal`. It has been removed and replaced by `MsgRecoverClient` in the migration from governance v1beta1 to governance v1. + Note that this should NOT be lightly updated, as there may be a gap in time between when misbehaviour has occured and when the evidence of misbehaviour is submitted. For example, if the `UnbondingPeriod` is 2 weeks and the `TrustingPeriod` has also been set to two weeks, a validator could wait until right before `UnbondingPeriod` finishes, submit false information, then unbond and exit without being slashed for misbehaviour. Therefore, we recommend that the trusting period for the 07-tendermint client be set to 2/3 of the `UnbondingPeriod`. Note that clients frozen due to misbehaviour must wait for the evidence to expire to avoid becoming refrozen. @@ -83,3 +87,4 @@ No neutral consequences. - [Prior discussion](https://github.com/cosmos/ics/issues/421) - [Epoch number discussion](https://github.com/cosmos/ics/issues/439) - [Upgrade plan discussion](https://github.com/cosmos/ics/issues/445) +- [Migration from gov v1beta1 to gov v1](https://github.com/cosmos/ibc-go/issues/3672) diff --git a/docs/ibc/events.md b/docs/ibc/events.md index ea077454c72..ee8b4e44fb7 100644 --- a/docs/ibc/events.md +++ b/docs/ibc/events.md @@ -58,12 +58,12 @@ callbacks to IBC applications. | update_client_proposal | client_type | {clientType} | | update_client_proposal | consensus_height | {consensusHeight} | -### UpgradeProposal +### IBCSoftwareUpgrade -| Type | Attribute Key | Attribute Value | -|-------------------------|-----------------|-------------------| -| upgrade_client_proposal | title | {title} | -| upgrade_client_proposal | height | {height} | +| Type | Attribute Key | Attribute Value | +|-------------------------------|---------------------|---------------------------------| +| schedule_ibc_software_upgrade | title | {title} | +| schedule_ibc_software_upgrade | upgrade_plan_height | {plan.height} | ## ICS 03 - Connection diff --git a/docs/ibc/proposals.md b/docs/ibc/proposals.md index dc22eb441af..e326daf3cc7 100644 --- a/docs/ibc/proposals.md +++ b/docs/ibc/proposals.md @@ -51,7 +51,6 @@ See also the relevant documentation: [ADR-026, IBC client recovery mechanisms](. ## Preconditions -- The chain is updated with ibc-go >= v1.1.0. - There exists an active client (with a known client identifier) for the same counterparty chain as the expired client. - The governance deposit. @@ -76,11 +75,10 @@ The client is attached to the expected Akash `chain-id`. Note that although the ### Step 2 -If the chain has been updated to ibc-go >= v1.1.0, anyone can submit the governance proposal to recover the client by executing this via CLI. +Anyone can submit the governance proposal to recover the client by executing the following via CLI. +If the chain is on an ibc-go version older than v8, please see the [relevant documentation](https://ibc.cosmos.network/v7.3.0/ibc/proposals.html). -> Note that the Cosmos SDK has updated how governance proposals are submitted in SDK v0.46, now requiring to pass a .json proposal file - -- From SDK v0.46.x onwards +- From ibc-go v8 onwards ```shell tx gov submit-proposal [path-to-proposal-json] @@ -92,30 +90,20 @@ If the chain has been updated to ibc-go >= v1.1.0, anyone can submit the governa { "messages": [ { - "@type": "/ibc.core.client.v1.ClientUpdateProposal", - "title": "title_string", - "description": "description_string", + "@type": "/ibc.core.client.v1.MsgRecoverClient", "subject_client_id": "expired_client_id_string", - "substitute_client_id": "active_client_id_string" + "substitute_client_id": "active_client_id_string", + "signer": "" } ], "metadata": "", "deposit": "10stake" + "title": "My proposal", + "summary": "A short summary of my proposal", + "expedited": false } ``` - Alternatively there's a legacy command (that is no longer recommended though): - - ```shell - tx gov submit-legacy-proposal update-client - ``` - -- Until SDK v0.45.x - - ```shell - tx gov submit-proposal update-client - ``` - The `` identifier is the proposed client to be updated. This client must be either frozen or expired. The `` represents a substitute client. It carries all the state for the client which may be updated. It must have identical client and chain parameters to the client which may be updated (except for latest height, frozen height, and chain ID). It should be continually updated during the voting period. @@ -124,6 +112,4 @@ After this, all that remains is deciding who funds the governance deposit and en ## Important considerations -Please note that from v1.0.0 of ibc-go it will not be allowed for transactions to go to expired clients anymore, so please update to at least this version to prevent similar issues in the future. - -Please also note that if the client on the other end of the transaction is also expired, that client will also need to update. This process updates only one client. +Please note that if the counterparty client is also expired, that client will also need to update. This process updates only one client. diff --git a/docs/ibc/upgrades/genesis-restart.md b/docs/ibc/upgrades/genesis-restart.md index abb0fa9a817..22a4c375718 100644 --- a/docs/ibc/upgrades/genesis-restart.md +++ b/docs/ibc/upgrades/genesis-restart.md @@ -20,18 +20,18 @@ Genesis restarts still require the usage of an IBC upgrade proposal in order to If the IBC-connected chain is conducting an upgrade that will break counterparty clients, it must ensure that the upgrade is first supported by IBC using the [IBC Client Breaking Upgrade List](https://github.com/cosmos/ibc-go/blob/main/docs/ibc/upgrades/quick-guide.md#ibc-client-breaking-upgrades) and then execute the upgrade process described below in order to prevent counterparty clients from breaking. -1. Create a 02-client [`UpgradeProposal`](https://github.com/cosmos/ibc-go/blob/main/docs/ibc/proto-docs.md#upgradeproposal) with an `UpgradePlan` and a new IBC ClientState in the `UpgradedClientState` field. Note that the `UpgradePlan` must specify an upgrade height **only** (no upgrade time), and the `ClientState` should only include the fields common to all valid clients and zero out any client-customizable fields (such as TrustingPeriod). -2. Vote on and pass the `UpgradeProposal`. +1. Create a governance proposal with the [`MsgIBCSoftwareUpgrade`](https://buf.build/cosmos/ibc/docs/main:ibc.core.client.v1#ibc.core.client.v1.MsgIBCSoftwareUpgrade) which contains an `UpgradePlan` and a new IBC `ClientState` in the `UpgradedClientState` field. Note that the `UpgradePlan` must specify an upgrade height **only** (no upgrade time), and the `ClientState` should only include the fields common to all valid clients and zero out any client-customizable fields (such as `TrustingPeriod`). +2. Vote on and pass the governance proposal. 3. Halt the node after successful upgrade. 4. Export the genesis file. 5. Swap to the new binary. 6. Run migrations on the genesis file. -7. Remove the `UpgradeProposal` plan from the genesis file. This may be done by migrations. +7. Remove the upgrade plan set by the governance proposal from the genesis file. This may be done by migrations. 8. Change desired chain-specific fields (chain id, unbonding period, etc). This may be done by migrations. 8. Reset the node's data. 9. Start the chain. -Upon the `UpgradeProposal` passing, the upgrade module will commit the UpgradedClient under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedClient`. On the block right before the upgrade height, the upgrade module will also commit an initial consensus state for the next chain under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedConsState`. +Upon passing the governance proposal, the upgrade module will commit the `UpgradedClient` under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedClient`. On the block right before the upgrade height, the upgrade module will also commit an initial consensus state for the next chain under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedConsState`. Once the chain reaches the upgrade height and halts, a relayer can upgrade the counterparty clients to the last block of the old chain. They can then submit the proofs of the `UpgradedClient` and `UpgradedConsensusState` against this last block and upgrade the counterparty client. diff --git a/docs/ibc/upgrades/quick-guide.md b/docs/ibc/upgrades/quick-guide.md index 1bdca7a567e..021cb7ce5a1 100644 --- a/docs/ibc/upgrades/quick-guide.md +++ b/docs/ibc/upgrades/quick-guide.md @@ -30,10 +30,10 @@ Note: Since upgrades are only implemented for Tendermint clients, this doc only If the IBC-connected chain is conducting an upgrade that will break counterparty clients, it must ensure that the upgrade is first supported by IBC using the list above and then execute the upgrade process described below in order to prevent counterparty clients from breaking. -1. Create a 02-client [`UpgradeProposal`](https://github.com/cosmos/ibc-go/blob/main/docs/ibc/proto-docs.md#upgradeproposal) with an `UpgradePlan` and a new IBC ClientState in the `UpgradedClientState` field. Note that the `UpgradePlan` must specify an upgrade height **only** (no upgrade time), and the `ClientState` should only include the fields common to all valid clients and zero out any client-customizable fields (such as TrustingPeriod). -2. Vote on and pass the `UpgradeProposal`. +1. Create a governance proposal with the [`MsgIBCSoftwareUpgrade`](https://buf.build/cosmos/ibc/docs/main:ibc.core.client.v1#ibc.core.client.v1.MsgIBCSoftwareUpgrade) message which contains an `UpgradePlan` and a new IBC `ClientState` in the `UpgradedClientState` field. Note that the `UpgradePlan` must specify an upgrade height **only** (no upgrade time), and the `ClientState` should only include the fields common to all valid clients (chain-specified parameters) and zero out any client-customizable fields (such as `TrustingPeriod`). +2. Vote on and pass the governance proposal. -Upon the `UpgradeProposal` passing, the upgrade module will commit the UpgradedClient under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedClient`. On the block right before the upgrade height, the upgrade module will also commit an initial consensus state for the next chain under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedConsState`. +Upon passing the governance proposal, the upgrade module will commit the `UpgradedClient` under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedClient`. On the block right before the upgrade height, the upgrade module will also commit an initial consensus state for the next chain under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedConsState`. Once the chain reaches the upgrade height and halts, a relayer can upgrade the counterparty clients to the last block of the old chain. They can then submit the proofs of the `UpgradedClient` and `UpgradedConsensusState` against this last block and upgrade the counterparty client. diff --git a/e2e/go.mod b/e2e/go.mod index 57c96b70d00..290336bd40c 100644 --- a/e2e/go.mod +++ b/e2e/go.mod @@ -25,26 +25,6 @@ require ( cloud.google.com/go/compute/metadata v0.2.3 // indirect cloud.google.com/go/iam v1.1.1 // indirect cloud.google.com/go/storage v1.30.1 // indirect - github.com/aws/aws-sdk-go v1.44.224 // indirect - github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/google/s2a-go v0.1.4 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect - github.com/googleapis/gax-go/v2 v2.11.0 // indirect - github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-getter v1.7.1 // indirect - github.com/hashicorp/go-safetemp v1.0.0 // indirect - github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/ulikunitz/xz v0.5.11 // indirect - go.opencensus.io v0.24.0 // indirect - golang.org/x/oauth2 v0.8.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 -) - -require ( cosmossdk.io/api v0.7.0 // indirect cosmossdk.io/client/v2 v2.0.0-20230818115413-c402c51a1508 // indirect cosmossdk.io/collections v0.4.0 // indirect @@ -63,8 +43,10 @@ require ( github.com/DataDog/zstd v1.5.5 // indirect github.com/Microsoft/go-winio v0.6.0 // indirect github.com/avast/retry-go/v4 v4.5.0 // indirect + github.com/aws/aws-sdk-go v1.44.224 // indirect github.com/benbjohnson/clock v1.3.0 // 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/bits-and-blooms/bitset v1.8.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect @@ -116,23 +98,30 @@ require ( github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.3 // indirect github.com/golang/glog v1.1.0 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.3 // 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/orderedcode v0.0.1 // indirect + github.com/google/s2a-go v0.1.4 // 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.11.0 // indirect github.com/gorilla/handlers v1.5.1 // indirect github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-getter v1.7.1 // indirect github.com/hashicorp/go-hclog v1.5.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-metrics v0.5.1 // indirect github.com/hashicorp/go-plugin v1.4.10 // indirect + github.com/hashicorp/go-safetemp v1.0.0 // indirect github.com/hashicorp/go-version v1.6.0 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/hashicorp/hcl v1.0.0 // indirect @@ -143,6 +132,7 @@ require ( github.com/icza/dyno v0.0.0-20220812133438-f0b6f8a18845 // 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/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/klauspost/compress v1.16.7 // indirect @@ -157,6 +147,7 @@ require ( github.com/mattn/go-isatty v0.0.19 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // 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 @@ -190,19 +181,24 @@ require ( 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.6.0 // indirect - github.com/ugorji/go/codec v1.2.11 // 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.7 // indirect + go.opencensus.io v0.24.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.13.0 // indirect golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect golang.org/x/net v0.15.0 // indirect + golang.org/x/oauth2 v0.8.0 // indirect golang.org/x/sync v0.3.0 // indirect golang.org/x/sys v0.12.0 // indirect golang.org/x/term v0.12.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/tools v0.13.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 google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230815205213-6bfd019c3878 // indirect diff --git a/e2e/go.sum b/e2e/go.sum index eff469eb092..c699fdf4aae 100644 --- a/e2e/go.sum +++ b/e2e/go.sum @@ -496,9 +496,8 @@ github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u1 github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= github.com/gobwas/pool v0.2.1/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/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA= -github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= @@ -1025,11 +1024,12 @@ github.com/tidwall/btree v1.6.0 h1:LDZfKfQIBHGHWSwckhXI0RPSXzlo+KYdjK7FWSqOzzg= github.com/tidwall/btree v1.6.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +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= -github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +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= diff --git a/e2e/tests/core/02-client/client_test.go b/e2e/tests/core/02-client/client_test.go index 1bb72b5409d..21b4cbbf0e0 100644 --- a/e2e/tests/core/02-client/client_test.go +++ b/e2e/tests/core/02-client/client_test.go @@ -14,6 +14,8 @@ import ( test "github.com/strangelove-ventures/interchaintest/v8/testutil" testifysuite "github.com/stretchr/testify/suite" + "cosmossdk.io/x/upgrade/types" + "github.com/cosmos/cosmos-sdk/client/grpc/cmtservice" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" @@ -71,7 +73,67 @@ func (s *ClientTestSuite) QueryAllowedClients(ctx context.Context, chain ibc.Cha return res.Params.AllowedClients } -func (s *ClientTestSuite) TestClientUpdateProposal_Succeeds() { +// TestScheduleIBCUpgrade_Succeeds tests that a governance proposal to schedule an IBC software upgrade is successful. +func (s *ClientTestSuite) TestScheduleIBCUpgrade_Succeeds() { + t := s.T() + ctx := context.TODO() + + _, _ = s.SetupChainsRelayerAndChannel(ctx) + chainA, chainB := s.GetChains() + chainAWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount) + + const planHeight = int64(75) + var newChainID string + + t.Run("execute proposal for MsgIBCSoftwareUpgrade", func(t *testing.T) { + authority, err := s.QueryModuleAccountAddress(ctx, govtypes.ModuleName, chainA) + s.Require().NoError(err) + s.Require().NotNil(authority) + + clientState, err := s.QueryClientState(ctx, chainB, ibctesting.FirstClientID) + s.Require().NoError(err) + + originalChainID := clientState.(*ibctm.ClientState).ChainId + revisionNumber := clienttypes.ParseChainID(fmt.Sprintf("%s-%d", originalChainID, 1)) + // increment revision number even with new chain ID to prevent loss of misbehaviour detection support + newChainID, err = clienttypes.SetRevisionNumber(fmt.Sprintf("%s-%d", originalChainID, 1), revisionNumber+1) + s.Require().NoError(err) + s.Require().NotEqual(originalChainID, newChainID) + + upgradedClientState := clientState.(*ibctm.ClientState) + upgradedClientState.ChainId = newChainID + + scheduleUpgradeMsg, err := clienttypes.NewMsgIBCSoftwareUpgrade( + authority.String(), + types.Plan{ + Name: "upgrade-client", + Height: planHeight, + }, + upgradedClientState, + ) + s.Require().NoError(err) + s.ExecuteGovV1Proposal(ctx, scheduleUpgradeMsg, chainA, chainAWallet, 1) + }) + + t.Run("check that IBC software upgrade has been scheduled successfully on chainA", func(t *testing.T) { + // checks there is an upgraded client state stored + cs, err := s.QueryUpgradedClientState(ctx, chainA, ibctesting.FirstClientID) + s.Require().NoError(err) + + upgradedClientState, ok := cs.(*ibctm.ClientState) + s.Require().True(ok) + s.Require().Equal(upgradedClientState.ChainId, newChainID) + + plan, err := s.QueryCurrentUpgradePlan(ctx, chainA) + s.Require().NoError(err) + + s.Require().Equal("upgrade-client", plan.Name) + s.Require().Equal(planHeight, plan.Height) + }) +} + +// TestRecoverClient_Succeeds tests that a governance proposal to recover a client using a MsgRecoverClient is successful. +func (s *ClientTestSuite) TestRecoverClient_Succeeds() { t := s.T() ctx := context.TODO() @@ -133,9 +195,12 @@ func (s *ClientTestSuite) TestClientUpdateProposal_Succeeds() { }) }) - t.Run("pass client update proposal", func(t *testing.T) { - proposal := clienttypes.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, subjectClientID, substituteClientID) - s.ExecuteGovV1Beta1Proposal(ctx, chainA, chainAWallet, proposal) + t.Run("execute proposal for MsgRecoverClient", func(t *testing.T) { + authority, err := s.QueryModuleAccountAddress(ctx, govtypes.ModuleName, chainA) + s.Require().NoError(err) + recoverClientMsg := clienttypes.NewMsgRecoverClient(authority.String(), subjectClientID, substituteClientID) + s.Require().NotNil(recoverClientMsg) + s.ExecuteGovV1Proposal(ctx, recoverClientMsg, chainA, chainAWallet, 1) }) t.Run("check status of each client", func(t *testing.T) { diff --git a/e2e/testsuite/grpc_query.go b/e2e/testsuite/grpc_query.go index 5b9e5b75fdf..c89d340abd8 100644 --- a/e2e/testsuite/grpc_query.go +++ b/e2e/testsuite/grpc_query.go @@ -12,6 +12,8 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" + upgradetypes "cosmossdk.io/x/upgrade/types" + "github.com/cosmos/cosmos-sdk/client/grpc/cmtservice" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -45,12 +47,13 @@ type GRPCClients struct { // InterTxQueryClient intertxtypes.QueryClient // SDK query clients - GovQueryClient govtypesv1beta1.QueryClient - GovQueryClientV1 govtypesv1.QueryClient - GroupsQueryClient grouptypes.QueryClient - ParamsQueryClient paramsproposaltypes.QueryClient - AuthQueryClient authtypes.QueryClient - AuthZQueryClient authz.QueryClient + GovQueryClient govtypesv1beta1.QueryClient + GovQueryClientV1 govtypesv1.QueryClient + GroupsQueryClient grouptypes.QueryClient + ParamsQueryClient paramsproposaltypes.QueryClient + AuthQueryClient authtypes.QueryClient + AuthZQueryClient authz.QueryClient + UpgradeQueryClient upgradetypes.QueryClient ConsensusServiceClient cmtservice.ServiceClient } @@ -90,6 +93,7 @@ func (s *E2ETestSuite) InitGRPCClients(chain *cosmos.CosmosChain) { AuthQueryClient: authtypes.NewQueryClient(grpcConn), AuthZQueryClient: authz.NewQueryClient(grpcConn), ConsensusServiceClient: cmtservice.NewServiceClient(grpcConn), + UpgradeQueryClient: upgradetypes.NewQueryClient(grpcConn), } } @@ -119,6 +123,23 @@ func (s *E2ETestSuite) QueryClientState(ctx context.Context, chain ibc.Chain, cl return clientState, nil } +// QueryUpgradedClientState queries the upgraded client state on the given chain for the provided clientID. +func (s *E2ETestSuite) QueryUpgradedClientState(ctx context.Context, chain ibc.Chain, clientID string) (ibcexported.ClientState, error) { + queryClient := s.GetChainGRCPClients(chain).ClientQueryClient + res, err := queryClient.UpgradedClientState(ctx, &clienttypes.QueryUpgradedClientStateRequest{}) + if err != nil { + return nil, err + } + + cfg := EncodingConfig() + var clientState ibcexported.ClientState + if err := cfg.InterfaceRegistry.UnpackAny(res.UpgradedClientState, &clientState); err != nil { + return nil, err + } + + return clientState, nil +} + // QueryClientStatus queries the status of the client by clientID func (s *E2ETestSuite) QueryClientStatus(ctx context.Context, chain ibc.Chain, clientID string) (string, error) { queryClient := s.GetChainGRCPClients(chain).ClientQueryClient @@ -132,6 +153,17 @@ func (s *E2ETestSuite) QueryClientStatus(ctx context.Context, chain ibc.Chain, c return res.Status, nil } +// QueryCurrentUpgradePlan queries the currently scheduled upgrade plans. +func (s *E2ETestSuite) QueryCurrentUpgradePlan(ctx context.Context, chain ibc.Chain) (upgradetypes.Plan, error) { + queryClient := s.GetChainGRCPClients(chain).UpgradeQueryClient + res, err := queryClient.CurrentPlan(ctx, &upgradetypes.QueryCurrentPlanRequest{}) + if err != nil { + return upgradetypes.Plan{}, err + } + + return *res.Plan, nil +} + // QueryConnection queries the connection end using the given chain and connection id. func (s *E2ETestSuite) QueryConnection(ctx context.Context, chain ibc.Chain, connectionID string) (connectiontypes.ConnectionEnd, error) { queryClient := s.GetChainGRCPClients(chain).ConnectionQueryClient diff --git a/go.mod b/go.mod index 72963c780ce..a95eb19fbd4 100644 --- a/go.mod +++ b/go.mod @@ -89,7 +89,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/gobwas/ws v1.1.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 diff --git a/go.sum b/go.sum index 304e1381ed3..446ed0d51bc 100644 --- a/go.sum +++ b/go.sum @@ -481,15 +481,12 @@ github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJ github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +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/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= -github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= +github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= -github.com/gobwas/pool v0.2.1/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/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA= -github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0= github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk= github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= @@ -1271,7 +1268,6 @@ golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7w 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-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/modules/apps/27-interchain-accounts/module.go b/modules/apps/27-interchain-accounts/module.go index 5d02007f402..e7a9b45c384 100644 --- a/modules/apps/27-interchain-accounts/module.go +++ b/modules/apps/27-interchain-accounts/module.go @@ -36,6 +36,7 @@ var ( _ module.AppModule = (*AppModule)(nil) _ module.AppModuleBasic = (*AppModuleBasic)(nil) _ module.AppModuleSimulation = (*AppModule)(nil) + _ module.HasProposalMsgs = (*AppModule)(nil) _ appmodule.AppModule = (*AppModule)(nil) _ porttypes.IBCModule = (*host.IBCModule)(nil) @@ -218,6 +219,11 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) { simulation.RandomizedGenState(simState) } +// ProposalMsgs returns msgs used for governance proposals for simulations. +func (AppModule) ProposalMsgs(simState module.SimulationState) []simtypes.WeightedProposalMsg { + return simulation.ProposalMsgs() +} + // WeightedOperations is unimplemented. func (AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation { return nil diff --git a/modules/apps/27-interchain-accounts/simulation/proposals.go b/modules/apps/27-interchain-accounts/simulation/proposals.go new file mode 100644 index 00000000000..6485aee71a0 --- /dev/null +++ b/modules/apps/27-interchain-accounts/simulation/proposals.go @@ -0,0 +1,60 @@ +package simulation + +import ( + "math/rand" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/simulation" + + controllertypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types" + "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types" +) + +// Simulation operation weights constants +const ( + DefaultWeightMsgUpdateParams int = 100 + + OpWeightMsgUpdateParams = "op_weight_msg_update_params" // #nosec +) + +// ProposalMsgs defines the module weighted proposals' contents +func ProposalMsgs() []simtypes.WeightedProposalMsg { + return []simtypes.WeightedProposalMsg{ + simulation.NewWeightedProposalMsg( + OpWeightMsgUpdateParams, + DefaultWeightMsgUpdateParams, + SimulateHostMsgUpdateParams, + ), + simulation.NewWeightedProposalMsg( + OpWeightMsgUpdateParams, + DefaultWeightMsgUpdateParams, + SimulateControllerMsgUpdateParams, + ), + } +} + +// SimulateHostMsgUpdateParams returns a random MsgUpdateParams for the host module +func SimulateHostMsgUpdateParams(_ *rand.Rand, _ sdk.Context, _ []simtypes.Account) sdk.Msg { + var signer sdk.AccAddress = address.Module("gov") + params := types.DefaultParams() + params.HostEnabled = false + + return &types.MsgUpdateParams{ + Signer: signer.String(), + Params: params, + } +} + +// SimulateControllerMsgUpdateParams returns a random MsgUpdateParams for the controller module +func SimulateControllerMsgUpdateParams(_ *rand.Rand, _ sdk.Context, _ []simtypes.Account) sdk.Msg { + var signer sdk.AccAddress = address.Module("gov") + params := controllertypes.DefaultParams() + params.ControllerEnabled = false + + return &controllertypes.MsgUpdateParams{ + Signer: signer.String(), + Params: params, + } +} diff --git a/modules/apps/27-interchain-accounts/simulation/proposals_test.go b/modules/apps/27-interchain-accounts/simulation/proposals_test.go new file mode 100644 index 00000000000..29d8eae0ebf --- /dev/null +++ b/modules/apps/27-interchain-accounts/simulation/proposals_test.go @@ -0,0 +1,56 @@ +package simulation_test + +import ( + "math/rand" + "testing" + + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + + cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" + + controllertypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types" + "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types" + "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/simulation" +) + +func TestProposalMsgs(t *testing.T) { + // initialize parameters + s := rand.NewSource(1) + r := rand.New(s) + + ctx := sdk.NewContext(nil, cmtproto.Header{}, true, nil) + accounts := simtypes.RandomAccounts(r, 3) + + // execute ProposalMsgs function + weightedProposalMsgs := simulation.ProposalMsgs() + require.Equal(t, 2, len(weightedProposalMsgs)) + w0 := weightedProposalMsgs[0] + + // tests w0 interface: + require.Equal(t, simulation.OpWeightMsgUpdateParams, w0.AppParamsKey()) + require.Equal(t, simulation.DefaultWeightMsgUpdateParams, w0.DefaultWeight()) + + msg := w0.MsgSimulatorFn()(r, ctx, accounts) + msgUpdateHostParams, ok := msg.(*types.MsgUpdateParams) + require.True(t, ok) + + require.Equal(t, sdk.AccAddress(address.Module("gov")).String(), msgUpdateHostParams.Signer) + require.Equal(t, msgUpdateHostParams.Params.HostEnabled, false) + + w1 := weightedProposalMsgs[1] + + // tests w1 interface: + require.Equal(t, simulation.OpWeightMsgUpdateParams, w1.AppParamsKey()) + require.Equal(t, simulation.DefaultWeightMsgUpdateParams, w1.DefaultWeight()) + + msg1 := w1.MsgSimulatorFn()(r, ctx, accounts) + msgUpdateControllerParams, ok := msg1.(*controllertypes.MsgUpdateParams) + require.True(t, ok) + + require.Equal(t, sdk.AccAddress(address.Module("gov")).String(), msgUpdateControllerParams.Signer) + require.Equal(t, msgUpdateControllerParams.Params.ControllerEnabled, false) +} diff --git a/modules/apps/transfer/module.go b/modules/apps/transfer/module.go index fb7df4d7192..10b34e2530a 100644 --- a/modules/apps/transfer/module.go +++ b/modules/apps/transfer/module.go @@ -27,10 +27,11 @@ import ( ) var ( - _ module.AppModule = (*AppModule)(nil) - _ module.AppModuleBasic = (*AppModuleBasic)(nil) - _ appmodule.AppModule = (*AppModule)(nil) - _ porttypes.IBCModule = (*IBCModule)(nil) + _ module.AppModule = (*AppModule)(nil) + _ module.AppModuleBasic = (*AppModuleBasic)(nil) + _ module.HasProposalMsgs = (*AppModule)(nil) + _ appmodule.AppModule = (*AppModule)(nil) + _ porttypes.IBCModule = (*IBCModule)(nil) ) // AppModuleBasic is the IBC Transfer AppModuleBasic @@ -158,6 +159,11 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) { simulation.RandomizedGenState(simState) } +// ProposalMsgs returns msgs used for governance proposals for simulations. +func (AppModule) ProposalMsgs(simState module.SimulationState) []simtypes.WeightedProposalMsg { + return simulation.ProposalMsgs() +} + // RegisterStoreDecoder registers a decoder for transfer module's types func (am AppModule) RegisterStoreDecoder(sdr simtypes.StoreDecoderRegistry) { sdr[types.StoreKey] = simulation.NewDecodeStore(am.keeper) diff --git a/modules/apps/transfer/simulation/proposals.go b/modules/apps/transfer/simulation/proposals.go new file mode 100644 index 00000000000..deef5ec6edc --- /dev/null +++ b/modules/apps/transfer/simulation/proposals.go @@ -0,0 +1,42 @@ +package simulation + +import ( + "math/rand" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/simulation" + + "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" +) + +// Simulation operation weights constants +const ( + DefaultWeightMsgUpdateParams int = 100 + + OpWeightMsgUpdateParams = "op_weight_msg_update_params" // #nosec +) + +// ProposalMsgs defines the module weighted proposals' contents +func ProposalMsgs() []simtypes.WeightedProposalMsg { + return []simtypes.WeightedProposalMsg{ + simulation.NewWeightedProposalMsg( + OpWeightMsgUpdateParams, + DefaultWeightMsgUpdateParams, + SimulateMsgUpdateParams, + ), + } +} + +// SimulateMsgUpdateParams returns a random MsgUpdateParams +func SimulateMsgUpdateParams(_ *rand.Rand, _ sdk.Context, _ []simtypes.Account) sdk.Msg { + var gov sdk.AccAddress = address.Module("gov") + params := types.DefaultParams() + params.SendEnabled = false + + return &types.MsgUpdateParams{ + Signer: gov.String(), + Params: params, + } +} diff --git a/modules/apps/transfer/simulation/proposals_test.go b/modules/apps/transfer/simulation/proposals_test.go new file mode 100644 index 00000000000..d537ef43e10 --- /dev/null +++ b/modules/apps/transfer/simulation/proposals_test.go @@ -0,0 +1,43 @@ +package simulation_test + +import ( + "math/rand" + "testing" + + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + + cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" + + "github.com/cosmos/ibc-go/v8/modules/apps/transfer/simulation" + "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" +) + +func TestProposalMsgs(t *testing.T) { + // initialize parameters + s := rand.NewSource(1) + r := rand.New(s) + + ctx := sdk.NewContext(nil, cmtproto.Header{}, true, nil) + accounts := simtypes.RandomAccounts(r, 3) + + // execute ProposalMsgs function + weightedProposalMsgs := simulation.ProposalMsgs() + require.Equal(t, len(weightedProposalMsgs), 1) + + w0 := weightedProposalMsgs[0] + + // tests w0 interface: + require.Equal(t, simulation.OpWeightMsgUpdateParams, w0.AppParamsKey()) + require.Equal(t, simulation.DefaultWeightMsgUpdateParams, w0.DefaultWeight()) + + msg := w0.MsgSimulatorFn()(r, ctx, accounts) + msgUpdateParams, ok := msg.(*types.MsgUpdateParams) + require.True(t, ok) + + require.Equal(t, sdk.AccAddress(address.Module("gov")).String(), msgUpdateParams.Signer) + require.EqualValues(t, msgUpdateParams.Params.SendEnabled, false) +} diff --git a/modules/core/02-client/client/cli/cli.go b/modules/core/02-client/client/cli/cli.go index bef25b878da..05c79735f44 100644 --- a/modules/core/02-client/client/cli/cli.go +++ b/modules/core/02-client/client/cli/cli.go @@ -44,10 +44,12 @@ func NewTxCmd() *cobra.Command { } txCmd.AddCommand( - NewCreateClientCmd(), - NewUpdateClientCmd(), - NewSubmitMisbehaviourCmd(), // Deprecated - NewUpgradeClientCmd(), + newCreateClientCmd(), + newUpdateClientCmd(), + newSubmitMisbehaviourCmd(), // Deprecated + newUpgradeClientCmd(), + newSubmitRecoverClientProposalCmd(), + newScheduleIBCUpgradeProposalCmd(), ) return txCmd diff --git a/modules/core/02-client/client/cli/tx.go b/modules/core/02-client/client/cli/tx.go index 7960285fccf..46d46678742 100644 --- a/modules/core/02-client/client/cli/tx.go +++ b/modules/core/02-client/client/cli/tx.go @@ -14,16 +14,19 @@ import ( "github.com/cosmos/cosmos-sdk/client/tx" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" "github.com/cosmos/cosmos-sdk/version" govcli "github.com/cosmos/cosmos-sdk/x/gov/client/cli" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" "github.com/cosmos/ibc-go/v8/modules/core/exported" ) -// NewCreateClientCmd defines the command to create a new IBC light client. -func NewCreateClientCmd() *cobra.Command { +const FlagAuthority = "authority" + +// newCreateClientCmd defines the command to create a new IBC light client. +func newCreateClientCmd() *cobra.Command { cmd := &cobra.Command{ Use: "create [path/to/client_state.json] [path/to/consensus_state.json]", Short: "create new IBC client", @@ -84,8 +87,8 @@ func NewCreateClientCmd() *cobra.Command { return cmd } -// NewUpdateClientCmd defines the command to update an IBC client. -func NewUpdateClientCmd() *cobra.Command { +// newUpdateClientCmd defines the command to update an IBC client. +func newUpdateClientCmd() *cobra.Command { cmd := &cobra.Command{ Use: "update [client-id] [path/to/client_msg.json]", Short: "update existing client with a client message", @@ -129,11 +132,11 @@ func NewUpdateClientCmd() *cobra.Command { return cmd } -// NewSubmitMisbehaviourCmd defines the command to submit a misbehaviour to prevent +// newSubmitMisbehaviourCmd defines the command to submit a misbehaviour to prevent // future updates. // Deprecated: NewSubmitMisbehaviourCmd is deprecated and will be removed in a future release. // Please use NewUpdateClientCmd instead. -func NewSubmitMisbehaviourCmd() *cobra.Command { +func newSubmitMisbehaviourCmd() *cobra.Command { cmd := &cobra.Command{ Use: "misbehaviour [clientID] [path/to/misbehaviour.json]", Short: "submit a client misbehaviour", @@ -176,8 +179,8 @@ func NewSubmitMisbehaviourCmd() *cobra.Command { return cmd } -// NewUpgradeClientCmd defines the command to upgrade an IBC light client. -func NewUpgradeClientCmd() *cobra.Command { +// newUpgradeClientCmd defines the command to upgrade an IBC light client. +func newUpgradeClientCmd() *cobra.Command { cmd := &cobra.Command{ Use: "upgrade [client-identifier] [path/to/client_state.json] [path/to/consensus_state.json] [upgrade-client-proof] [upgrade-consensus-state-proof]", Short: "upgrade an IBC client", @@ -242,97 +245,145 @@ func NewUpgradeClientCmd() *cobra.Command { return cmd } -// NewCmdSubmitUpdateClientProposal implements a command handler for submitting an update IBC client proposal transaction. -func NewCmdSubmitUpdateClientProposal() *cobra.Command { +// newSubmitRecoverClientProposalCmd defines the command to recover an IBC light client. +func newSubmitRecoverClientProposalCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "update-client [subject-client-id] [substitute-client-id]", + Use: "recover-client [subject-client-id] [substitute-client-id] [flags]", Args: cobra.ExactArgs(2), - Short: "Submit an update IBC client proposal", - Long: "Submit an update IBC client proposal along with an initial deposit.\n" + - "Please specify a subject client identifier you want to update..\n" + - "Please specify the substitute client the subject client will be updated to.", + Short: "recover an IBC client", + Long: `Submit a recover IBC client proposal along with an initial deposit + Please specify a subject client identifier you want to recover + Please specify the substitute client the subject client will be recovered to.`, RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientTxContext(cmd) if err != nil { return err } - title, err := cmd.Flags().GetString(govcli.FlagTitle) //nolint:staticcheck // need this till full govv1 conversion. - if err != nil { - return err - } - - description, err := cmd.Flags().GetString(govcli.FlagDescription) //nolint:staticcheck // need this till full govv1 conversion. + proposal, err := govcli.ReadGovPropFlags(clientCtx, cmd.Flags()) if err != nil { return err } - subjectClientID := args[0] - substituteClientID := args[1] + subjectClientID, substituteClientID := args[0], args[1] - content := types.NewClientUpdateProposal(title, description, subjectClientID, substituteClientID) + authority, _ := cmd.Flags().GetString(FlagAuthority) + if authority != "" { + if _, err = sdk.AccAddressFromBech32(authority); err != nil { + return fmt.Errorf("invalid authority address: %w", err) + } + } else { + authority = sdk.AccAddress(address.Module(govtypes.ModuleName)).String() + } - from := clientCtx.GetFromAddress() + msg := types.NewMsgRecoverClient(authority, subjectClientID, substituteClientID) - depositStr, err := cmd.Flags().GetString(govcli.FlagDeposit) - if err != nil { - return err - } - deposit, err := sdk.ParseCoinsNormalized(depositStr) - if err != nil { - return err + if err = msg.ValidateBasic(); err != nil { + return fmt.Errorf("error validating %T: %w", types.MsgRecoverClient{}, err) } - msg, err := govtypes.NewMsgSubmitProposal(content, deposit, from) - if err != nil { - return err + if err := proposal.SetMsgs([]sdk.Msg{msg}); err != nil { + return fmt.Errorf("failed to create recover client proposal message: %w", err) } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), proposal) }, } - cmd.Flags().String(govcli.FlagTitle, "", "title of proposal") //nolint:staticcheck // need this till full govv1 conversion. - cmd.Flags().String(govcli.FlagDescription, "", "description of proposal") //nolint:staticcheck // need this till full govv1 conversion. - cmd.Flags().String(govcli.FlagDeposit, "", "deposit of proposal") + cmd.Flags().String(FlagAuthority, "", "The address of the client module authority (defaults to gov)") + + flags.AddTxFlagsToCmd(cmd) + govcli.AddGovPropFlagsToCmd(cmd) + err := cmd.MarkFlagRequired(govcli.FlagTitle) + if err != nil { + panic(err) + } return cmd } -// NewCmdSubmitUpgradeProposal implements a command handler for submitting an upgrade IBC client proposal transaction. -func NewCmdSubmitUpgradeProposal() *cobra.Command { +// newScheduleIBCUpgradeProposalCmd defines the command for submitting an IBC software upgrade proposal. +func newScheduleIBCUpgradeProposalCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "ibc-upgrade [name] [height] [path/to/upgraded_client_state.json] [flags]", + Use: "schedule-ibc-upgrade [name] [height] [path/to/upgraded_client_state.json] [flags]", Args: cobra.ExactArgs(3), - Short: "Submit an IBC upgrade proposal", - Long: "Submit an IBC client breaking upgrade proposal along with an initial deposit.\n" + - "The client state specified is the upgraded client state representing the upgraded chain\n" + - `Example Upgraded Client State JSON: -{ - "@type":"/ibc.lightclients.tendermint.v1.ClientState", - "chain_id":"testchain1", - "unbonding_period":"1814400s", - "latest_height":{"revision_number":"0","revision_height":"2"}, - "proof_specs":[{"leaf_spec":{"hash":"SHA256","prehash_key":"NO_HASH","prehash_value":"SHA256","length":"VAR_PROTO","prefix":"AA=="},"inner_spec":{"child_order":[0,1],"child_size":33,"min_prefix_length":4,"max_prefix_length":12,"empty_child":null,"hash":"SHA256"},"max_depth":0,"min_depth":0},{"leaf_spec":{"hash":"SHA256","prehash_key":"NO_HASH","prehash_value":"SHA256","length":"VAR_PROTO","prefix":"AA=="},"inner_spec":{"child_order":[0,1],"child_size":32,"min_prefix_length":1,"max_prefix_length":1,"empty_child":null,"hash":"SHA256"},"max_depth":0,"min_depth":0}], - "upgrade_path":["upgrade","upgradedIBCState"], -} - `, + Short: "Submit an IBC software upgrade proposal", + Long: `Please specify a unique name and height for the upgrade to take effect. + The client state specified is the upgraded client state representing the upgraded chain + + Example Upgraded Client State JSON: + { + "@type":"/ibc.lightclients.tendermint.v1.ClientState", + "chain_id":"testchain1", + "unbonding_period":"1814400s", + "latest_height":{ + "revision_number":"0", + "revision_height":"2" + }, + "proof_specs":[ + { + "leaf_spec":{ + "hash":"SHA256", + "prehash_key":"NO_HASH", + "prehash_value":"SHA256", + "length":"VAR_PROTO", + "prefix":"AA==" + }, + "inner_spec":{ + "child_order":[ + 0, + 1 + ], + "child_size":33, + "min_prefix_length":4, + "max_prefix_length":12, + "empty_child":null, + "hash":"SHA256" + }, + "max_depth":0, + "min_depth":0 + }, + { + "leaf_spec":{ + "hash":"SHA256", + "prehash_key":"NO_HASH", + "prehash_value":"SHA256", + "length":"VAR_PROTO", + "prefix":"AA==" + }, + "inner_spec":{ + "child_order":[ + 0, + 1 + ], + "child_size":32, + "min_prefix_length":1, + "max_prefix_length":1, + "empty_child":null, + "hash":"SHA256" + }, + "max_depth":0, + "min_depth":0 + } + ], + "upgrade_path":[ + "upgrade", + "upgradedIBCState" + ] + } + `, RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientTxContext(cmd) if err != nil { return err } - cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry) - title, err := cmd.Flags().GetString(govcli.FlagTitle) //nolint:staticcheck // need this till full govv1 conversion. + proposal, err := govcli.ReadGovPropFlags(clientCtx, cmd.Flags()) if err != nil { return err } - description, err := cmd.Flags().GetString(govcli.FlagDescription) //nolint:staticcheck // need this till full govv1 conversion. - if err != nil { - return err - } + cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry) name := args[0] @@ -362,34 +413,40 @@ func NewCmdSubmitUpgradeProposal() *cobra.Command { } } - content, err := types.NewUpgradeProposal(title, description, plan, clientState) - if err != nil { - return err + authority, _ := cmd.Flags().GetString(FlagAuthority) + if authority != "" { + if _, err = sdk.AccAddressFromBech32(authority); err != nil { + return fmt.Errorf("invalid authority address: %w", err) + } + } else { + authority = sdk.AccAddress(address.Module(govtypes.ModuleName)).String() } - from := clientCtx.GetFromAddress() - - depositStr, err := cmd.Flags().GetString(govcli.FlagDeposit) + msg, err := types.NewMsgIBCSoftwareUpgrade(authority, plan, clientState) if err != nil { - return err + return fmt.Errorf("error in %T: %w", types.MsgIBCSoftwareUpgrade{}, err) } - deposit, err := sdk.ParseCoinsNormalized(depositStr) - if err != nil { - return err + + if err = msg.ValidateBasic(); err != nil { + return fmt.Errorf("error validating %T: %w", types.MsgIBCSoftwareUpgrade{}, err) } - msg, err := govtypes.NewMsgSubmitProposal(content, deposit, from) - if err != nil { - return err + if err := proposal.SetMsgs([]sdk.Msg{msg}); err != nil { + return fmt.Errorf("failed to create proposal message for scheduling an IBC software upgrade: %w", err) } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), proposal) }, } - cmd.Flags().String(govcli.FlagTitle, "", "title of proposal") //nolint:staticcheck // need this till full govv1 conversion. - cmd.Flags().String(govcli.FlagDescription, "", "description of proposal") //nolint:staticcheck // need this till full govv1 conversion. - cmd.Flags().String(govcli.FlagDeposit, "", "deposit of proposal") + cmd.Flags().String(FlagAuthority, "", "The address of the client module authority (defaults to gov)") + + flags.AddTxFlagsToCmd(cmd) + govcli.AddGovPropFlagsToCmd(cmd) + err := cmd.MarkFlagRequired(govcli.FlagTitle) + if err != nil { + panic(err) + } return cmd } diff --git a/modules/core/02-client/client/proposal_handler.go b/modules/core/02-client/client/proposal_handler.go deleted file mode 100644 index 21e549e1cd2..00000000000 --- a/modules/core/02-client/client/proposal_handler.go +++ /dev/null @@ -1,12 +0,0 @@ -package client - -import ( - govclient "github.com/cosmos/cosmos-sdk/x/gov/client" - - "github.com/cosmos/ibc-go/v8/modules/core/02-client/client/cli" -) - -var ( - UpdateClientProposalHandler = govclient.NewProposalHandler(cli.NewCmdSubmitUpdateClientProposal) - UpgradeProposalHandler = govclient.NewProposalHandler(cli.NewCmdSubmitUpgradeProposal) -) diff --git a/modules/core/02-client/keeper/client.go b/modules/core/02-client/keeper/client.go index f2f621fae2a..d17d41679b8 100644 --- a/modules/core/02-client/keeper/client.go +++ b/modules/core/02-client/keeper/client.go @@ -149,3 +149,59 @@ func (k Keeper) UpgradeClient(ctx sdk.Context, clientID string, upgradedClient e return nil } + +// RecoverClient will retrieve the subject and substitute client. +// A callback will occur to the subject client state with the client +// prefixed store being provided for both the subject and the substitute client. +// The IBC client implementations are responsible for validating the parameters of the +// substitute (ensuring they match the subject's parameters) as well as copying +// the necessary consensus states from the substitute to the subject client +// store. The substitute must be Active and the subject must not be Active. +func (k Keeper) RecoverClient(ctx sdk.Context, subjectClientID, substituteClientID string) error { + subjectClientState, found := k.GetClientState(ctx, subjectClientID) + if !found { + return errorsmod.Wrapf(types.ErrClientNotFound, "subject client with ID %s", subjectClientID) + } + + subjectClientStore := k.ClientStore(ctx, subjectClientID) + + if status := k.GetClientStatus(ctx, subjectClientState, subjectClientID); status == exported.Active { + return errorsmod.Wrapf(types.ErrInvalidRecoveryClient, "cannot recover %s subject client", exported.Active) + } + + substituteClientState, found := k.GetClientState(ctx, substituteClientID) + if !found { + return errorsmod.Wrapf(types.ErrClientNotFound, "substitute client with ID %s", substituteClientID) + } + + if subjectClientState.GetLatestHeight().GTE(substituteClientState.GetLatestHeight()) { + return errorsmod.Wrapf(types.ErrInvalidHeight, "subject client state latest height is greater or equal to substitute client state latest height (%s >= %s)", subjectClientState.GetLatestHeight(), substituteClientState.GetLatestHeight()) + } + + substituteClientStore := k.ClientStore(ctx, substituteClientID) + + if status := k.GetClientStatus(ctx, substituteClientState, substituteClientID); status != exported.Active { + return errorsmod.Wrapf(types.ErrClientNotActive, "substitute client is not %s, status is %s", status, exported.Active) + } + + if err := subjectClientState.CheckSubstituteAndUpdateState(ctx, k.cdc, subjectClientStore, substituteClientStore, substituteClientState); err != nil { + return errorsmod.Wrap(err, "failed to validate substitute client") + } + + k.Logger(ctx).Info("client recovered", "client-id", subjectClientID) + + defer telemetry.IncrCounterWithLabels( + []string{"ibc", "client", "update"}, + 1, + []metrics.Label{ + telemetry.NewLabel(types.LabelClientType, substituteClientState.ClientType()), + telemetry.NewLabel(types.LabelClientID, subjectClientID), + telemetry.NewLabel(types.LabelUpdateType, "recovery"), + }, + ) + + // emitting events in the keeper for recovering clients + emitRecoverClientEvent(ctx, subjectClientID, substituteClientState.ClientType()) + + return nil +} diff --git a/modules/core/02-client/keeper/client_test.go b/modules/core/02-client/keeper/client_test.go index 5d75c415b3a..0f0786fa873 100644 --- a/modules/core/02-client/keeper/client_test.go +++ b/modules/core/02-client/keeper/client_test.go @@ -508,3 +508,152 @@ func (suite *KeeperTestSuite) TestUpdateClientEventEmission() { } suite.Require().True(contains) } + +func (suite *KeeperTestSuite) TestRecoverClient() { + var ( + subject, substitute string + subjectClientState, substituteClientState exported.ClientState + ) + + testCases := []struct { + msg string + malleate func() + expErr error + }{ + { + "success", + func() {}, + nil, + }, + { + "success, subject and substitute use different revision number", + func() { + tmClientState, ok := substituteClientState.(*ibctm.ClientState) + suite.Require().True(ok) + consState, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientConsensusState(suite.chainA.GetContext(), substitute, tmClientState.LatestHeight) + suite.Require().True(found) + newRevisionNumber := tmClientState.GetLatestHeight().GetRevisionNumber() + 1 + + tmClientState.LatestHeight = clienttypes.NewHeight(newRevisionNumber, tmClientState.GetLatestHeight().GetRevisionHeight()) + + suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), substitute, tmClientState.LatestHeight, consState) + clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), substitute) + ibctm.SetProcessedTime(clientStore, tmClientState.LatestHeight, 100) + ibctm.SetProcessedHeight(clientStore, tmClientState.LatestHeight, clienttypes.NewHeight(0, 1)) + suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), substitute, tmClientState) + }, + nil, + }, + { + "subject client does not exist", + func() { + subject = ibctesting.InvalidID + }, + clienttypes.ErrClientNotFound, + }, + { + "subject is Active", + func() { + tmClientState, ok := subjectClientState.(*ibctm.ClientState) + suite.Require().True(ok) + // Set FrozenHeight to zero to ensure client is reported as Active + tmClientState.FrozenHeight = clienttypes.ZeroHeight() + suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), subject, tmClientState) + }, + clienttypes.ErrInvalidRecoveryClient, + }, + { + "substitute client does not exist", + func() { + substitute = ibctesting.InvalidID + }, + clienttypes.ErrClientNotFound, + }, + { + "subject and substitute have equal latest height", + func() { + tmClientState, ok := subjectClientState.(*ibctm.ClientState) + suite.Require().True(ok) + tmClientState.LatestHeight = substituteClientState.GetLatestHeight().(clienttypes.Height) + suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), subject, tmClientState) + }, + clienttypes.ErrInvalidHeight, + }, + { + "subject height is greater than substitute height", + func() { + tmClientState, ok := subjectClientState.(*ibctm.ClientState) + suite.Require().True(ok) + tmClientState.LatestHeight = substituteClientState.GetLatestHeight().Increment().(clienttypes.Height) + suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), subject, tmClientState) + }, + clienttypes.ErrInvalidHeight, + }, + { + "substitute is frozen", + func() { + tmClientState, ok := substituteClientState.(*ibctm.ClientState) + suite.Require().True(ok) + tmClientState.FrozenHeight = clienttypes.NewHeight(0, 1) + suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), substitute, tmClientState) + }, + clienttypes.ErrClientNotActive, + }, + { + "CheckSubstituteAndUpdateState fails, substitute client trust level doesn't match subject client trust level", + func() { + tmClientState, ok := substituteClientState.(*ibctm.ClientState) + suite.Require().True(ok) + tmClientState.UnbondingPeriod += time.Minute + suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), substitute, tmClientState) + }, + clienttypes.ErrInvalidSubstitute, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.msg, func() { + suite.SetupTest() // reset + + subjectPath := ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.SetupClients(subjectPath) + subject = subjectPath.EndpointA.ClientID + subjectClientState = suite.chainA.GetClientState(subject) + + substitutePath := ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.SetupClients(substitutePath) + substitute = substitutePath.EndpointA.ClientID + + // update substitute twice + err := substitutePath.EndpointA.UpdateClient() + suite.Require().NoError(err) + err = substitutePath.EndpointA.UpdateClient() + suite.Require().NoError(err) + substituteClientState = suite.chainA.GetClientState(substitute) + + tmClientState, ok := subjectClientState.(*ibctm.ClientState) + suite.Require().True(ok) + tmClientState.FrozenHeight = tmClientState.LatestHeight + suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), subject, tmClientState) + + tc.malleate() + + err = suite.chainA.App.GetIBCKeeper().ClientKeeper.RecoverClient(suite.chainA.GetContext(), subject, substitute) + + expPass := tc.expErr == nil + if expPass { + suite.Require().NoError(err) + + // Assert that client status is now Active + clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), subjectPath.EndpointA.ClientID) + tmClientState := subjectPath.EndpointA.GetClientState().(*ibctm.ClientState) + suite.Require().Equal(tmClientState.Status(suite.chainA.GetContext(), clientStore, suite.chainA.App.AppCodec()), exported.Active) + } else { + suite.Require().Error(err) + suite.Require().ErrorIs(err, tc.expErr) + } + }) + } +} diff --git a/modules/core/02-client/keeper/events.go b/modules/core/02-client/keeper/events.go index b855517fdbc..c8809c6183e 100644 --- a/modules/core/02-client/keeper/events.go +++ b/modules/core/02-client/keeper/events.go @@ -82,13 +82,13 @@ func emitUpgradeClientEvent(ctx sdk.Context, clientID string, clientState export }) } -// emitUpdateClientProposalEvent emits an update client proposal event -func emitUpdateClientProposalEvent(ctx sdk.Context, clientID, clientType string) { +// emitSubmitMisbehaviourEvent emits a client misbehaviour event +func emitSubmitMisbehaviourEvent(ctx sdk.Context, clientID string, clientState exported.ClientState) { ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( - types.EventTypeUpdateClientProposal, - sdk.NewAttribute(types.AttributeKeySubjectClientID, clientID), - sdk.NewAttribute(types.AttributeKeyClientType, clientType), + types.EventTypeSubmitMisbehaviour, + sdk.NewAttribute(types.AttributeKeyClientID, clientID), + sdk.NewAttribute(types.AttributeKeyClientType, clientState.ClientType()), ), sdk.NewEvent( sdk.EventTypeMessage, @@ -97,13 +97,13 @@ func emitUpdateClientProposalEvent(ctx sdk.Context, clientID, clientType string) }) } -// emitUpgradeClientProposalEvent emits an upgrade client proposal event -func emitUpgradeClientProposalEvent(ctx sdk.Context, title string, height int64) { +// emitRecoverClientEvent emits a recover client event +func emitRecoverClientEvent(ctx sdk.Context, clientID, clientType string) { ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( - types.EventTypeUpgradeClientProposal, - sdk.NewAttribute(types.AttributeKeyUpgradePlanTitle, title), - sdk.NewAttribute(types.AttributeKeyUpgradePlanHeight, fmt.Sprintf("%d", height)), + types.EventTypeRecoverClient, + sdk.NewAttribute(types.AttributeKeySubjectClientID, clientID), + sdk.NewAttribute(types.AttributeKeyClientType, clientType), ), sdk.NewEvent( sdk.EventTypeMessage, @@ -112,13 +112,13 @@ func emitUpgradeClientProposalEvent(ctx sdk.Context, title string, height int64) }) } -// emitSubmitMisbehaviourEvent emits a client misbehaviour event -func emitSubmitMisbehaviourEvent(ctx sdk.Context, clientID string, clientState exported.ClientState) { +// emitScheduleIBCSoftwareUpgradeEvent emits a schedule IBC software upgrade event +func emitScheduleIBCSoftwareUpgradeEvent(ctx sdk.Context, title string, height int64) { ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( - types.EventTypeSubmitMisbehaviour, - sdk.NewAttribute(types.AttributeKeyClientID, clientID), - sdk.NewAttribute(types.AttributeKeyClientType, clientState.ClientType()), + types.EventTypeScheduleIBCSoftwareUpgrade, + sdk.NewAttribute(types.AttributeKeyUpgradePlanTitle, title), + sdk.NewAttribute(types.AttributeKeyUpgradePlanHeight, fmt.Sprintf("%d", height)), ), sdk.NewEvent( sdk.EventTypeMessage, diff --git a/modules/core/02-client/keeper/keeper.go b/modules/core/02-client/keeper/keeper.go index 32ffa35db04..8efb679e18e 100644 --- a/modules/core/02-client/keeper/keeper.go +++ b/modules/core/02-client/keeper/keeper.go @@ -439,3 +439,28 @@ func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { bz := k.cdc.MustMarshal(¶ms) store.Set([]byte(types.ParamsKey), bz) } + +// ScheduleIBCSoftwareUpgrade schedules an upgrade for the IBC client. +func (k Keeper) ScheduleIBCSoftwareUpgrade(ctx sdk.Context, plan upgradetypes.Plan, upgradedClientState exported.ClientState) error { + // zero out any custom fields before setting + cs := upgradedClientState.ZeroCustomFields() + bz, err := types.MarshalClientState(k.cdc, cs) + if err != nil { + return errorsmod.Wrap(err, "could not marshal UpgradedClientState") + } + + if err := k.upgradeKeeper.ScheduleUpgrade(ctx, plan); err != nil { + return err + } + + // sets the new upgraded client last height committed on this chain at plan.Height, + // since the chain will panic at plan.Height and new chain will resume at plan.Height + if err = k.upgradeKeeper.SetUpgradedClient(ctx, plan.Height, bz); err != nil { + return err + } + + // emitting an event for scheduling an upgrade plan + emitScheduleIBCSoftwareUpgradeEvent(ctx, plan.Name, plan.Height) + + return nil +} diff --git a/modules/core/02-client/keeper/keeper_test.go b/modules/core/02-client/keeper/keeper_test.go index b000ee79650..f9cdb3eeae3 100644 --- a/modules/core/02-client/keeper/keeper_test.go +++ b/modules/core/02-client/keeper/keeper_test.go @@ -8,10 +8,12 @@ import ( testifysuite "github.com/stretchr/testify/suite" sdkmath "cosmossdk.io/math" + upgradetypes "cosmossdk.io/x/upgrade/types" "github.com/cosmos/cosmos-sdk/codec" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" tmbytes "github.com/cometbft/cometbft/libs/bytes" @@ -480,3 +482,113 @@ func (suite *KeeperTestSuite) TestUnsetParams() { suite.chainA.GetSimApp().IBCKeeper.ClientKeeper.GetParams(ctx) }) } + +// TestIBCSoftwareUpgrade tests that an IBC client upgrade has been properly scheduled +func (suite *KeeperTestSuite) TestIBCSoftwareUpgrade() { + var ( + upgradedClientState *ibctm.ClientState + oldPlan, plan upgradetypes.Plan + ) + + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "valid upgrade proposal", + func() {}, + nil, + }, + { + "valid upgrade proposal with previous IBC state", func() { + oldPlan = upgradetypes.Plan{ + Name: "upgrade IBC clients", + Height: 100, + } + }, + nil, + }, + { + "fail: scheduling upgrade with plan height 0", + func() { + plan.Height = 0 + }, + sdkerrors.ErrInvalidRequest, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + oldPlan.Height = 0 // reset + + path := ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.SetupClients(path) + upgradedClientState = suite.chainA.GetClientState(path.EndpointA.ClientID).ZeroCustomFields().(*ibctm.ClientState) + + // use height 1000 to distinguish from old plan + plan = upgradetypes.Plan{ + Name: "upgrade IBC clients", + Height: 1000, + } + + tc.malleate() + + // set the old plan if it is not empty + if oldPlan.Height != 0 { + // set upgrade plan in the upgrade store + store := suite.chainA.GetContext().KVStore(suite.chainA.GetSimApp().GetKey(upgradetypes.StoreKey)) + bz := suite.chainA.App.AppCodec().MustMarshal(&oldPlan) + store.Set(upgradetypes.PlanKey(), bz) + + bz, err := types.MarshalClientState(suite.chainA.App.AppCodec(), upgradedClientState) + suite.Require().NoError(err) + + suite.Require().NoError(suite.chainA.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainA.GetContext(), oldPlan.Height, bz)) + } + + err := suite.chainA.App.GetIBCKeeper().ClientKeeper.ScheduleIBCSoftwareUpgrade(suite.chainA.GetContext(), plan, upgradedClientState) + + if tc.expError == nil { + suite.Require().NoError(err) + + // check that the correct plan is returned + storedPlan, err := suite.chainA.GetSimApp().UpgradeKeeper.GetUpgradePlan(suite.chainA.GetContext()) + suite.Require().NoError(err) + suite.Require().Equal(plan, storedPlan) + + // check that old upgraded client state is cleared + cs, err := suite.chainA.GetSimApp().UpgradeKeeper.GetUpgradedClient(suite.chainA.GetContext(), oldPlan.Height) + suite.Require().ErrorIs(err, upgradetypes.ErrNoUpgradedClientFound) + suite.Require().Empty(cs) + + // check that client state was set + storedClientState, err := suite.chainA.GetSimApp().UpgradeKeeper.GetUpgradedClient(suite.chainA.GetContext(), plan.Height) + suite.Require().NoError(err) + clientState, err := types.UnmarshalClientState(suite.chainA.App.AppCodec(), storedClientState) + suite.Require().NoError(err) + suite.Require().Equal(upgradedClientState, clientState) + } else { + // check that the new plan wasn't stored + storedPlan, err := suite.chainA.GetSimApp().UpgradeKeeper.GetUpgradePlan(suite.chainA.GetContext()) + if oldPlan.Height != 0 { + // NOTE: this is only true if the ScheduleUpgrade function + // returns an error before clearing the old plan + suite.Require().NoError(err) + suite.Require().Equal(oldPlan, storedPlan) + } else { + suite.Require().ErrorIs(err, upgradetypes.ErrNoUpgradePlanFound) + suite.Require().Empty(storedPlan) + } + + // check that client state was not set + cs, err := suite.chainA.GetSimApp().UpgradeKeeper.GetUpgradedClient(suite.chainA.GetContext(), plan.Height) + suite.Require().Empty(cs) + suite.Require().ErrorIs(err, upgradetypes.ErrNoUpgradedClientFound) + } + }) + } +} diff --git a/modules/core/02-client/keeper/proposal.go b/modules/core/02-client/keeper/proposal.go deleted file mode 100644 index a8748542d1e..00000000000 --- a/modules/core/02-client/keeper/proposal.go +++ /dev/null @@ -1,102 +0,0 @@ -package keeper - -import ( - metrics "github.com/hashicorp/go-metrics" - - errorsmod "cosmossdk.io/errors" - - "github.com/cosmos/cosmos-sdk/telemetry" - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v8/modules/core/exported" -) - -// ClientUpdateProposal will retrieve the subject and substitute client. -// A callback will occur to the subject client state with the client -// prefixed store being provided for both the subject and the substitute client. -// The IBC client implementations are responsible for validating the parameters of the -// subtitute (enusring they match the subject's parameters) as well as copying -// the necessary consensus states from the subtitute to the subject client -// store. The substitute must be Active and the subject must not be Active. -func (k Keeper) ClientUpdateProposal(ctx sdk.Context, p *types.ClientUpdateProposal) error { - subjectClientState, found := k.GetClientState(ctx, p.SubjectClientId) - if !found { - return errorsmod.Wrapf(types.ErrClientNotFound, "subject client with ID %s", p.SubjectClientId) - } - - subjectClientStore := k.ClientStore(ctx, p.SubjectClientId) - - if status := k.GetClientStatus(ctx, subjectClientState, p.SubjectClientId); status == exported.Active { - return errorsmod.Wrap(types.ErrInvalidUpdateClientProposal, "cannot update Active subject client") - } - - substituteClientState, found := k.GetClientState(ctx, p.SubstituteClientId) - if !found { - return errorsmod.Wrapf(types.ErrClientNotFound, "substitute client with ID %s", p.SubstituteClientId) - } - - if subjectClientState.GetLatestHeight().GTE(substituteClientState.GetLatestHeight()) { - return errorsmod.Wrapf(types.ErrInvalidHeight, "subject client state latest height is greater or equal to substitute client state latest height (%s >= %s)", subjectClientState.GetLatestHeight(), substituteClientState.GetLatestHeight()) - } - - substituteClientStore := k.ClientStore(ctx, p.SubstituteClientId) - - if status := k.GetClientStatus(ctx, substituteClientState, p.SubstituteClientId); status != exported.Active { - return errorsmod.Wrapf(types.ErrClientNotActive, "substitute client is not Active, status is %s", status) - } - - if err := subjectClientState.CheckSubstituteAndUpdateState(ctx, k.cdc, subjectClientStore, substituteClientStore, substituteClientState); err != nil { - return err - } - - k.Logger(ctx).Info("client updated after governance proposal passed", "client-id", p.SubjectClientId) - - defer telemetry.IncrCounterWithLabels( - []string{"ibc", "client", "update"}, - 1, - []metrics.Label{ - telemetry.NewLabel(types.LabelClientType, substituteClientState.ClientType()), - telemetry.NewLabel(types.LabelClientID, p.SubjectClientId), - telemetry.NewLabel(types.LabelUpdateType, "proposal"), - }, - ) - - // emitting events in the keeper for proposal updates to clients - emitUpdateClientProposalEvent(ctx, p.SubjectClientId, substituteClientState.ClientType()) - - return nil -} - -// HandleUpgradeProposal sets the upgraded client state in the upgrade store. It clears -// an IBC client state and consensus state if a previous plan was set. Then it -// will schedule an upgrade and finally set the upgraded client state in upgrade -// store. -func (k Keeper) HandleUpgradeProposal(ctx sdk.Context, p *types.UpgradeProposal) error { - clientState, err := types.UnpackClientState(p.UpgradedClientState) - if err != nil { - return errorsmod.Wrap(err, "could not unpack UpgradedClientState") - } - - // zero out any custom fields before setting - cs := clientState.ZeroCustomFields() - bz, err := types.MarshalClientState(k.cdc, cs) - if err != nil { - return errorsmod.Wrap(err, "could not marshal UpgradedClientState") - } - - if err := k.upgradeKeeper.ScheduleUpgrade(ctx, p.Plan); err != nil { - return err - } - - // sets the new upgraded client in last height committed on this chain is at plan.Height, - // since the chain will panic at plan.Height and new chain will resume at plan.Height - if err = k.upgradeKeeper.SetUpgradedClient(ctx, p.Plan.Height, bz); err != nil { - return err - } - - // emitting an event for handling client upgrade proposal - emitUpgradeClientProposalEvent(ctx, p.Title, p.Plan.Height) - - return nil -} diff --git a/modules/core/02-client/keeper/proposal_test.go b/modules/core/02-client/keeper/proposal_test.go deleted file mode 100644 index 5e5a44e068d..00000000000 --- a/modules/core/02-client/keeper/proposal_test.go +++ /dev/null @@ -1,270 +0,0 @@ -package keeper_test - -import ( - upgradetypes "cosmossdk.io/x/upgrade/types" - - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" - - "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v8/modules/core/exported" - ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" - ibctesting "github.com/cosmos/ibc-go/v8/testing" -) - -func (suite *KeeperTestSuite) TestClientUpdateProposal() { - var ( - subject, substitute string - subjectClientState, substituteClientState exported.ClientState - content govtypes.Content - ) - - testCases := []struct { - name string - malleate func() - expPass bool - }{ - { - "valid update client proposal", func() { - content = types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, subject, substitute) - }, true, - }, - { - "subject and substitute use different revision numbers", func() { - tmClientState, ok := substituteClientState.(*ibctm.ClientState) - suite.Require().True(ok) - consState, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientConsensusState(suite.chainA.GetContext(), substitute, tmClientState.LatestHeight) - suite.Require().True(found) - newRevisionNumber := tmClientState.GetLatestHeight().GetRevisionNumber() + 1 - - tmClientState.LatestHeight = types.NewHeight(newRevisionNumber, tmClientState.GetLatestHeight().GetRevisionHeight()) - - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), substitute, tmClientState.LatestHeight, consState) - clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), substitute) - ibctm.SetProcessedTime(clientStore, tmClientState.LatestHeight, 100) - ibctm.SetProcessedHeight(clientStore, tmClientState.LatestHeight, types.NewHeight(0, 1)) - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), substitute, tmClientState) - - content = types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, subject, substitute) - }, true, - }, - { - "cannot use solomachine as substitute for tendermint client", func() { - solomachine := ibctesting.NewSolomachine(suite.T(), suite.cdc, "solo machine", "", 1) - solomachine.Sequence = subjectClientState.GetLatestHeight().GetRevisionHeight() + 1 - substituteClientState = solomachine.ClientState() - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), substitute, substituteClientState) - content = types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, subject, substitute) - }, false, - }, - { - "subject client does not exist", func() { - content = types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, ibctesting.InvalidID, substitute) - }, false, - }, - { - "substitute client does not exist", func() { - content = types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, subject, ibctesting.InvalidID) - }, false, - }, - { - "subject and substitute have equal latest height", func() { - tmClientState, ok := subjectClientState.(*ibctm.ClientState) - suite.Require().True(ok) - tmClientState.LatestHeight = substituteClientState.GetLatestHeight().(types.Height) - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), subject, tmClientState) - - content = types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, subject, substitute) - }, false, - }, - { - "update fails, client is not frozen or expired", func() { - tmClientState, ok := subjectClientState.(*ibctm.ClientState) - suite.Require().True(ok) - tmClientState.FrozenHeight = types.ZeroHeight() - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), subject, tmClientState) - - content = types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, subject, substitute) - }, false, - }, - { - "substitute is frozen", func() { - tmClientState, ok := substituteClientState.(*ibctm.ClientState) - suite.Require().True(ok) - tmClientState.FrozenHeight = types.NewHeight(0, 1) - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), substitute, tmClientState) - - content = types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, subject, substitute) - }, false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() // reset - - subjectPath := ibctesting.NewPath(suite.chainA, suite.chainB) - suite.coordinator.SetupClients(subjectPath) - subject = subjectPath.EndpointA.ClientID - subjectClientState = suite.chainA.GetClientState(subject) - - substitutePath := ibctesting.NewPath(suite.chainA, suite.chainB) - suite.coordinator.SetupClients(substitutePath) - substitute = substitutePath.EndpointA.ClientID - - // update substitute twice - err := substitutePath.EndpointA.UpdateClient() - suite.Require().NoError(err) - err = substitutePath.EndpointA.UpdateClient() - suite.Require().NoError(err) - substituteClientState = suite.chainA.GetClientState(substitute) - - tmClientState, ok := subjectClientState.(*ibctm.ClientState) - suite.Require().True(ok) - tmClientState.AllowUpdateAfterMisbehaviour = true - tmClientState.AllowUpdateAfterExpiry = true - tmClientState.FrozenHeight = tmClientState.LatestHeight - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), subject, tmClientState) - - tmClientState, ok = substituteClientState.(*ibctm.ClientState) - suite.Require().True(ok) - tmClientState.AllowUpdateAfterMisbehaviour = true - tmClientState.AllowUpdateAfterExpiry = true - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), substitute, tmClientState) - - tc.malleate() - - updateProp, ok := content.(*types.ClientUpdateProposal) - suite.Require().True(ok) - err = suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientUpdateProposal(suite.chainA.GetContext(), updateProp) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -} - -func (suite *KeeperTestSuite) TestHandleUpgradeProposal() { - var ( - upgradedClientState *ibctm.ClientState - oldPlan, plan upgradetypes.Plan - content govtypes.Content - err error - ) - - testCases := []struct { - name string - malleate func() - expPass bool - }{ - { - "valid upgrade proposal", func() { - content, err = types.NewUpgradeProposal(ibctesting.Title, ibctesting.Description, plan, upgradedClientState) - suite.Require().NoError(err) - }, true, - }, - { - "valid upgrade proposal with previous IBC state", func() { - oldPlan = upgradetypes.Plan{ - Name: "upgrade IBC clients", - Height: 100, - } - - content, err = types.NewUpgradeProposal(ibctesting.Title, ibctesting.Description, plan, upgradedClientState) - suite.Require().NoError(err) - }, true, - }, - { - "cannot unpack client state", func() { - protoAny, err := types.PackConsensusState(&ibctm.ConsensusState{}) - suite.Require().NoError(err) - content = &types.UpgradeProposal{ - Title: ibctesting.Title, - Description: ibctesting.Description, - Plan: plan, - UpgradedClientState: protoAny, - } - }, false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() // reset - oldPlan.Height = 0 // reset - - path := ibctesting.NewPath(suite.chainA, suite.chainB) - suite.coordinator.SetupClients(path) - upgradedClientState = suite.chainA.GetClientState(path.EndpointA.ClientID).ZeroCustomFields().(*ibctm.ClientState) - - // use height 1000 to distinguish from old plan - plan = upgradetypes.Plan{ - Name: "upgrade IBC clients", - Height: 1000, - } - - tc.malleate() - - // set the old plan if it is not empty - if oldPlan.Height != 0 { - // set upgrade plan in the upgrade store - store := suite.chainA.GetContext().KVStore(suite.chainA.GetSimApp().GetKey(upgradetypes.StoreKey)) - bz := suite.chainA.App.AppCodec().MustMarshal(&oldPlan) - store.Set(upgradetypes.PlanKey(), bz) - - bz, err := types.MarshalClientState(suite.chainA.App.AppCodec(), upgradedClientState) - suite.Require().NoError(err) - - suite.chainA.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainA.GetContext(), oldPlan.Height, bz) //nolint:errcheck - } - - upgradeProp, ok := content.(*types.UpgradeProposal) - suite.Require().True(ok) - err = suite.chainA.App.GetIBCKeeper().ClientKeeper.HandleUpgradeProposal(suite.chainA.GetContext(), upgradeProp) - - if tc.expPass { - suite.Require().NoError(err) - - // check that the correct plan is returned - storedPlan, err := suite.chainA.GetSimApp().UpgradeKeeper.GetUpgradePlan(suite.chainA.GetContext()) - suite.Require().NoError(err) - suite.Require().Equal(plan, storedPlan) - - // check that old upgraded client state is cleared - _, err = suite.chainA.GetSimApp().UpgradeKeeper.GetUpgradedClient(suite.chainA.GetContext(), oldPlan.Height) - suite.Require().ErrorIs(err, upgradetypes.ErrNoUpgradedClientFound) - - // check that client state was set - storedClientState, err := suite.chainA.GetSimApp().UpgradeKeeper.GetUpgradedClient(suite.chainA.GetContext(), plan.Height) - suite.Require().NoError(err) - clientState, err := types.UnmarshalClientState(suite.chainA.App.AppCodec(), storedClientState) - suite.Require().NoError(err) - suite.Require().Equal(upgradedClientState, clientState) - } else { - suite.Require().Error(err) - - // check that the new plan wasn't stored - storedPlan, err := suite.chainA.GetSimApp().UpgradeKeeper.GetUpgradePlan(suite.chainA.GetContext()) - if oldPlan.Height != 0 { - // NOTE: this is only true if the ScheduleUpgrade function - // returns an error before clearing the old plan - suite.Require().NoError(err) - suite.Require().Equal(oldPlan, storedPlan) - } else { - suite.Require().ErrorIs(err, upgradetypes.ErrNoUpgradePlanFound) - suite.Require().Empty(storedPlan) - } - - // check that client state was not set - _, err = suite.chainA.GetSimApp().UpgradeKeeper.GetUpgradedClient(suite.chainA.GetContext(), plan.Height) - suite.Require().ErrorIs(err, upgradetypes.ErrNoUpgradedClientFound) - } - }) - } -} diff --git a/modules/core/02-client/proposal_handler.go b/modules/core/02-client/proposal_handler.go deleted file mode 100644 index 2b08d47144e..00000000000 --- a/modules/core/02-client/proposal_handler.go +++ /dev/null @@ -1,27 +0,0 @@ -package client - -import ( - errorsmod "cosmossdk.io/errors" - - sdk "github.com/cosmos/cosmos-sdk/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" - - "github.com/cosmos/ibc-go/v8/modules/core/02-client/keeper" - "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" - ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" -) - -// NewClientProposalHandler defines the 02-client proposal handler -func NewClientProposalHandler(k keeper.Keeper) govtypes.Handler { - return func(ctx sdk.Context, content govtypes.Content) error { - switch c := content.(type) { - case *types.ClientUpdateProposal: - return k.ClientUpdateProposal(ctx, c) - case *types.UpgradeProposal: - return k.HandleUpgradeProposal(ctx, c) - - default: - return errorsmod.Wrapf(ibcerrors.ErrUnknownRequest, "unrecognized ibc proposal content type: %T", c) - } - } -} diff --git a/modules/core/02-client/proposal_handler_test.go b/modules/core/02-client/proposal_handler_test.go deleted file mode 100644 index 79e34ceaa85..00000000000 --- a/modules/core/02-client/proposal_handler_test.go +++ /dev/null @@ -1,94 +0,0 @@ -package client_test - -import ( - sdkmath "cosmossdk.io/math" - - sdk "github.com/cosmos/cosmos-sdk/types" - distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" - - client "github.com/cosmos/ibc-go/v8/modules/core/02-client" - clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" - ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" - ibctesting "github.com/cosmos/ibc-go/v8/testing" -) - -func (suite *ClientTestSuite) TestNewClientUpdateProposalHandler() { - var ( - content govtypes.Content - err error - ) - - testCases := []struct { - name string - malleate func() - expPass bool - }{ - { - "valid update client proposal", func() { - subjectPath := ibctesting.NewPath(suite.chainA, suite.chainB) - suite.coordinator.SetupClients(subjectPath) - subjectClientState := suite.chainA.GetClientState(subjectPath.EndpointA.ClientID) - - substitutePath := ibctesting.NewPath(suite.chainA, suite.chainB) - suite.coordinator.SetupClients(substitutePath) - - // update substitute twice - err = substitutePath.EndpointA.UpdateClient() - suite.Require().NoError(err) - err = substitutePath.EndpointA.UpdateClient() - suite.Require().NoError(err) - substituteClientState := suite.chainA.GetClientState(substitutePath.EndpointA.ClientID) - - tmClientState, ok := subjectClientState.(*ibctm.ClientState) - suite.Require().True(ok) - tmClientState.AllowUpdateAfterMisbehaviour = true - tmClientState.FrozenHeight = tmClientState.LatestHeight - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), subjectPath.EndpointA.ClientID, tmClientState) - - // replicate changes to substitute (they must match) - tmClientState, ok = substituteClientState.(*ibctm.ClientState) - suite.Require().True(ok) - tmClientState.AllowUpdateAfterMisbehaviour = true - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), substitutePath.EndpointA.ClientID, tmClientState) - - content = clienttypes.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, subjectPath.EndpointA.ClientID, substitutePath.EndpointA.ClientID) - }, true, - }, - { - "nil proposal", func() { - content = nil - }, false, - }, - { - "unsupported proposal type", func() { - content = &distributiontypes.CommunityPoolSpendProposal{ //nolint:staticcheck - Title: ibctesting.Title, - Description: ibctesting.Description, - Recipient: suite.chainA.SenderAccount.GetAddress().String(), - Amount: sdk.NewCoins(sdk.NewCoin("communityfunds", sdkmath.NewInt(10))), - } - }, false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() // reset - - tc.malleate() - - proposalHandler := client.NewClientProposalHandler(suite.chainA.App.GetIBCKeeper().ClientKeeper) - - err = proposalHandler(suite.chainA.GetContext(), content) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -} diff --git a/modules/core/02-client/types/client.pb.go b/modules/core/02-client/types/client.pb.go index 94f4ea8e5a5..954b4aba6d6 100644 --- a/modules/core/02-client/types/client.pb.go +++ b/modules/core/02-client/types/client.pb.go @@ -4,9 +4,7 @@ package types import ( - types1 "cosmossdk.io/x/upgrade/types" 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" @@ -194,102 +192,6 @@ func (m *ClientConsensusStates) GetConsensusStates() []ConsensusStateWithHeight return nil } -// 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). -type ClientUpdateProposal struct { - // the title of the update 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 client identifier for the client to be updated if the proposal passes - SubjectClientId string `protobuf:"bytes,3,opt,name=subject_client_id,json=subjectClientId,proto3" json:"subject_client_id,omitempty"` - // the substitute client identifier for the client standing in for the subject - // client - SubstituteClientId string `protobuf:"bytes,4,opt,name=substitute_client_id,json=substituteClientId,proto3" json:"substitute_client_id,omitempty"` -} - -func (m *ClientUpdateProposal) Reset() { *m = ClientUpdateProposal{} } -func (m *ClientUpdateProposal) String() string { return proto.CompactTextString(m) } -func (*ClientUpdateProposal) ProtoMessage() {} -func (*ClientUpdateProposal) Descriptor() ([]byte, []int) { - return fileDescriptor_b6bc4c8185546947, []int{3} -} -func (m *ClientUpdateProposal) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *ClientUpdateProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_ClientUpdateProposal.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 *ClientUpdateProposal) XXX_Merge(src proto.Message) { - xxx_messageInfo_ClientUpdateProposal.Merge(m, src) -} -func (m *ClientUpdateProposal) XXX_Size() int { - return m.Size() -} -func (m *ClientUpdateProposal) XXX_DiscardUnknown() { - xxx_messageInfo_ClientUpdateProposal.DiscardUnknown(m) -} - -var xxx_messageInfo_ClientUpdateProposal proto.InternalMessageInfo - -// UpgradeProposal is a gov Content type for initiating an IBC breaking -// upgrade. -type UpgradeProposal struct { - Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` - Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` - Plan types1.Plan `protobuf:"bytes,3,opt,name=plan,proto3" json:"plan"` - // 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 - UpgradedClientState *types.Any `protobuf:"bytes,4,opt,name=upgraded_client_state,json=upgradedClientState,proto3" json:"upgraded_client_state,omitempty"` -} - -func (m *UpgradeProposal) Reset() { *m = UpgradeProposal{} } -func (*UpgradeProposal) ProtoMessage() {} -func (*UpgradeProposal) Descriptor() ([]byte, []int) { - return fileDescriptor_b6bc4c8185546947, []int{4} -} -func (m *UpgradeProposal) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *UpgradeProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_UpgradeProposal.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 *UpgradeProposal) XXX_Merge(src proto.Message) { - xxx_messageInfo_UpgradeProposal.Merge(m, src) -} -func (m *UpgradeProposal) XXX_Size() int { - return m.Size() -} -func (m *UpgradeProposal) XXX_DiscardUnknown() { - xxx_messageInfo_UpgradeProposal.DiscardUnknown(m) -} - -var xxx_messageInfo_UpgradeProposal proto.InternalMessageInfo - // Height is a monotonically increasing data type // that can be compared against another Height for the purposes of updating and // freezing clients @@ -310,7 +212,7 @@ type Height struct { func (m *Height) Reset() { *m = Height{} } func (*Height) ProtoMessage() {} func (*Height) Descriptor() ([]byte, []int) { - return fileDescriptor_b6bc4c8185546947, []int{5} + return fileDescriptor_b6bc4c8185546947, []int{3} } func (m *Height) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -351,7 +253,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_b6bc4c8185546947, []int{6} + return fileDescriptor_b6bc4c8185546947, []int{4} } func (m *Params) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -391,8 +293,6 @@ func init() { proto.RegisterType((*IdentifiedClientState)(nil), "ibc.core.client.v1.IdentifiedClientState") proto.RegisterType((*ConsensusStateWithHeight)(nil), "ibc.core.client.v1.ConsensusStateWithHeight") proto.RegisterType((*ClientConsensusStates)(nil), "ibc.core.client.v1.ClientConsensusStates") - proto.RegisterType((*ClientUpdateProposal)(nil), "ibc.core.client.v1.ClientUpdateProposal") - proto.RegisterType((*UpgradeProposal)(nil), "ibc.core.client.v1.UpgradeProposal") proto.RegisterType((*Height)(nil), "ibc.core.client.v1.Height") proto.RegisterType((*Params)(nil), "ibc.core.client.v1.Params") } @@ -400,82 +300,37 @@ func init() { func init() { proto.RegisterFile("ibc/core/client/v1/client.proto", fileDescriptor_b6bc4c8185546947) } var fileDescriptor_b6bc4c8185546947 = []byte{ - // 635 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x54, 0x4f, 0x6b, 0xd4, 0x4e, - 0x18, 0x4e, 0xda, 0xfd, 0x2d, 0xdd, 0xc9, 0x8f, 0xae, 0xc6, 0x2d, 0xac, 0xab, 0x64, 0x97, 0x20, - 0xb8, 0x14, 0x9b, 0x74, 0x57, 0xd0, 0x52, 0xf0, 0x60, 0x7b, 0x69, 0x2f, 0x52, 0x22, 0x45, 0x10, - 0x64, 0x49, 0x26, 0xd3, 0xec, 0x48, 0x32, 0x13, 0x32, 0x93, 0x48, 0xbf, 0x81, 0x47, 0xc1, 0x8b, - 0xc7, 0x7e, 0x08, 0x3f, 0x44, 0xf1, 0xb4, 0x47, 0x4f, 0x22, 0xbb, 0x17, 0xbf, 0x81, 0x57, 0xc9, - 0xcc, 0xc4, 0xdd, 0xf8, 0xa7, 0x0a, 0xde, 0xe6, 0x7d, 0xdf, 0x67, 0xde, 0xf7, 0x79, 0x5e, 0x9e, - 0x19, 0xd0, 0xc7, 0x01, 0x74, 0x21, 0xcd, 0x90, 0x0b, 0x63, 0x8c, 0x08, 0x77, 0x8b, 0x91, 0x3a, - 0x39, 0x69, 0x46, 0x39, 0x35, 0x4d, 0x1c, 0x40, 0xa7, 0x04, 0x38, 0x2a, 0x5d, 0x8c, 0x7a, 0x9d, - 0x88, 0x46, 0x54, 0x94, 0xdd, 0xf2, 0x24, 0x91, 0xbd, 0x9b, 0x11, 0xa5, 0x51, 0x8c, 0x5c, 0x11, - 0x05, 0xf9, 0x99, 0xeb, 0x93, 0x73, 0x55, 0xba, 0x03, 0x29, 0x4b, 0x28, 0x73, 0xf3, 0x34, 0xca, - 0xfc, 0x10, 0xb9, 0xc5, 0x28, 0x40, 0xdc, 0x1f, 0x55, 0x71, 0xd5, 0x40, 0xa2, 0x26, 0xb2, 0xb3, - 0x0c, 0x64, 0xc9, 0x4e, 0xc0, 0xd6, 0x71, 0x88, 0x08, 0xc7, 0x67, 0x18, 0x85, 0x87, 0x82, 0xc8, - 0x53, 0xee, 0x73, 0x64, 0xde, 0x02, 0x2d, 0xc9, 0x6b, 0x82, 0xc3, 0xae, 0x3e, 0xd0, 0x87, 0x2d, - 0x6f, 0x43, 0x26, 0x8e, 0x43, 0xf3, 0x21, 0xf8, 0x5f, 0x15, 0x59, 0x09, 0xee, 0xae, 0x0d, 0xf4, - 0xa1, 0x31, 0xee, 0x38, 0x92, 0xa8, 0x53, 0x11, 0x75, 0x1e, 0x93, 0x73, 0xcf, 0x80, 0xcb, 0xae, - 0xf6, 0x5b, 0x1d, 0x74, 0x0f, 0x29, 0x61, 0x88, 0xb0, 0x9c, 0x89, 0xd4, 0x33, 0xcc, 0xa7, 0x47, - 0x08, 0x47, 0x53, 0x6e, 0xee, 0x81, 0xe6, 0x54, 0x9c, 0xc4, 0x3c, 0x63, 0xdc, 0x73, 0x7e, 0x5e, - 0x91, 0x23, 0xb1, 0x07, 0x8d, 0xcb, 0x4f, 0x7d, 0xcd, 0x53, 0x78, 0xf3, 0x11, 0x68, 0xc3, 0xaa, - 0xeb, 0x5f, 0x50, 0xda, 0x84, 0x35, 0x0a, 0x25, 0xab, 0x2d, 0xa9, 0xbd, 0xce, 0x8d, 0x5d, 0xbd, - 0x85, 0x17, 0xe0, 0xda, 0x0f, 0x53, 0x59, 0x77, 0x6d, 0xb0, 0x3e, 0x34, 0xc6, 0xf7, 0x7e, 0xc5, - 0xfc, 0x77, 0xba, 0x95, 0x96, 0x76, 0x9d, 0x14, 0xb3, 0x67, 0x3a, 0xe8, 0x48, 0x56, 0xa7, 0x69, - 0xe8, 0x73, 0x74, 0x92, 0xd1, 0x94, 0x32, 0x3f, 0x36, 0x3b, 0xe0, 0x3f, 0x8e, 0x79, 0x8c, 0x14, - 0x21, 0x19, 0x98, 0x03, 0x60, 0x84, 0x88, 0xc1, 0x0c, 0xa7, 0x1c, 0x53, 0x22, 0xf4, 0xb7, 0xbc, - 0xd5, 0x94, 0xb9, 0x0d, 0xae, 0xb3, 0x3c, 0x78, 0x89, 0x20, 0x9f, 0x2c, 0x45, 0xad, 0x0b, 0x5c, - 0x5b, 0x15, 0x0e, 0x2b, 0x6d, 0xbb, 0xa0, 0xc3, 0xf2, 0x80, 0x71, 0xcc, 0x73, 0x8e, 0x56, 0xe0, - 0x0d, 0x01, 0x37, 0x97, 0xb5, 0xea, 0xc6, 0xbe, 0xfd, 0xfa, 0xa2, 0xaf, 0x7d, 0x78, 0xbf, 0xd3, - 0x53, 0xfe, 0x8a, 0x68, 0xe1, 0x28, 0x3b, 0x96, 0xd2, 0x39, 0x22, 0xdc, 0xfe, 0xaa, 0x83, 0xf6, - 0xa9, 0xb4, 0xe6, 0x3f, 0xab, 0x79, 0x00, 0x1a, 0x69, 0xec, 0x13, 0x21, 0xc0, 0x18, 0xdf, 0x76, - 0xd4, 0xd8, 0xca, 0xf9, 0xd5, 0xe8, 0x93, 0xd8, 0x27, 0x6a, 0xc3, 0x02, 0x6f, 0x1e, 0x81, 0x2d, - 0x85, 0x09, 0x27, 0x35, 0x13, 0x37, 0xae, 0x70, 0xcc, 0x8d, 0xea, 0xca, 0xca, 0x13, 0xd9, 0xdf, - 0x2e, 0x15, 0xbf, 0xbb, 0xe8, 0x6b, 0x5f, 0x2e, 0xfa, 0xfa, 0x1f, 0x94, 0x87, 0xa0, 0xa9, 0x5c, - 0x7e, 0x17, 0xb4, 0x33, 0x54, 0x60, 0x86, 0x29, 0x99, 0x90, 0x3c, 0x09, 0x50, 0x26, 0x94, 0x37, - 0xbc, 0xcd, 0x2a, 0xfd, 0x44, 0x64, 0x6b, 0x40, 0xf5, 0x2e, 0xd6, 0xea, 0x40, 0xd9, 0x71, 0x7f, - 0xa3, 0xe2, 0x61, 0x8f, 0x40, 0xf3, 0xc4, 0xcf, 0xfc, 0x84, 0x95, 0x97, 0xfd, 0x38, 0xa6, 0xaf, - 0xbe, 0x8b, 0x64, 0x5d, 0x7d, 0xb0, 0x3e, 0x6c, 0x79, 0x9b, 0x2a, 0x2d, 0x85, 0xb0, 0x03, 0xef, - 0x72, 0x6e, 0xe9, 0xb3, 0xb9, 0xa5, 0x7f, 0x9e, 0x5b, 0xfa, 0x9b, 0x85, 0xa5, 0xcd, 0x16, 0x96, - 0xf6, 0x71, 0x61, 0x69, 0xcf, 0xf7, 0x22, 0xcc, 0xa7, 0x79, 0xe0, 0x40, 0x9a, 0xa8, 0x3f, 0xc3, - 0xc5, 0x01, 0xdc, 0x89, 0xa8, 0x5b, 0xec, 0xb9, 0x09, 0x0d, 0xf3, 0x18, 0x31, 0xf9, 0xc3, 0xed, - 0x8e, 0x77, 0xd4, 0x27, 0xc7, 0xcf, 0x53, 0xc4, 0x82, 0xa6, 0xd8, 0xdd, 0xfd, 0x6f, 0x01, 0x00, - 0x00, 0xff, 0xff, 0x3a, 0xf9, 0x45, 0x71, 0x04, 0x05, 0x00, 0x00, + // 439 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x52, 0xcf, 0x8b, 0xd3, 0x40, + 0x14, 0xce, 0x74, 0x97, 0xb2, 0x9d, 0x4a, 0x2b, 0x61, 0x17, 0x62, 0x85, 0xb4, 0xe4, 0x62, 0x0e, + 0xee, 0x8c, 0x8d, 0x07, 0x8b, 0xe0, 0xc1, 0xdd, 0x8b, 0x7b, 0x11, 0x89, 0x07, 0x41, 0x90, 0x92, + 0x4c, 0x66, 0x93, 0x81, 0x64, 0x66, 0xc9, 0x4c, 0x22, 0xfd, 0x0f, 0x3c, 0x0a, 0x5e, 0x3c, 0xee, + 0x9f, 0xb3, 0xc7, 0x3d, 0x7a, 0x12, 0x69, 0xff, 0x11, 0xc9, 0xcc, 0x14, 0x89, 0xbf, 0xd8, 0xdb, + 0xcb, 0xf7, 0xbe, 0x7c, 0xef, 0x7b, 0xdf, 0x3c, 0x38, 0x67, 0x29, 0xc1, 0x44, 0xd4, 0x14, 0x93, + 0x92, 0x51, 0xae, 0x70, 0xbb, 0xb4, 0x15, 0xba, 0xaa, 0x85, 0x12, 0xae, 0xcb, 0x52, 0x82, 0x3a, + 0x02, 0xb2, 0x70, 0xbb, 0x9c, 0x1d, 0xe7, 0x22, 0x17, 0xba, 0x8d, 0xbb, 0xca, 0x30, 0x67, 0x0f, + 0x72, 0x21, 0xf2, 0x92, 0x62, 0xfd, 0x95, 0x36, 0x97, 0x38, 0xe1, 0x1b, 0xd3, 0x0a, 0x2a, 0x78, + 0x72, 0x91, 0x51, 0xae, 0xd8, 0x25, 0xa3, 0xd9, 0xb9, 0xd6, 0x79, 0xab, 0x12, 0x45, 0xdd, 0x87, + 0x70, 0x64, 0x64, 0xd7, 0x2c, 0xf3, 0xc0, 0x02, 0x84, 0xa3, 0xf8, 0xc8, 0x00, 0x17, 0x99, 0xfb, + 0x0c, 0xde, 0xb3, 0x4d, 0xd9, 0x91, 0xbd, 0xc1, 0x02, 0x84, 0xe3, 0xe8, 0x18, 0x99, 0x39, 0x68, + 0x3f, 0x07, 0xbd, 0xe4, 0x9b, 0x78, 0x4c, 0x7e, 0xa9, 0x06, 0x5f, 0x00, 0xf4, 0xce, 0x05, 0x97, + 0x94, 0xcb, 0x46, 0x6a, 0xe8, 0x1d, 0x53, 0xc5, 0x2b, 0xca, 0xf2, 0x42, 0xb9, 0x2b, 0x38, 0x2c, + 0x74, 0xa5, 0xe7, 0x8d, 0xa3, 0x19, 0xfa, 0x73, 0x43, 0x64, 0xb8, 0x67, 0x87, 0x37, 0xdf, 0xe7, + 0x4e, 0x6c, 0xf9, 0xee, 0x0b, 0x38, 0x25, 0x7b, 0xd5, 0x3b, 0x58, 0x9a, 0x90, 0x9e, 0x85, 0xce, + 0xd5, 0x89, 0xd9, 0xbd, 0xef, 0x4d, 0xfe, 0x3f, 0x85, 0x0f, 0xf0, 0xfe, 0x6f, 0x53, 0xa5, 0x37, + 0x58, 0x1c, 0x84, 0xe3, 0xe8, 0xf1, 0xdf, 0x9c, 0xff, 0x6b, 0x6f, 0xbb, 0xcb, 0xb4, 0x6f, 0x4a, + 0x06, 0x19, 0x1c, 0xda, 0x60, 0x1e, 0xc1, 0x69, 0x4d, 0x5b, 0x26, 0x99, 0xe0, 0x6b, 0xde, 0x54, + 0x29, 0xad, 0xb5, 0x97, 0xc3, 0x78, 0xb2, 0x87, 0x5f, 0x6b, 0xb4, 0x47, 0xb4, 0x51, 0x0e, 0xfa, + 0x44, 0xa3, 0xf8, 0xfc, 0xe8, 0xd3, 0xf5, 0xdc, 0xf9, 0x7a, 0x3d, 0x77, 0x82, 0x25, 0x1c, 0xbe, + 0x49, 0xea, 0xa4, 0x92, 0xdd, 0xcf, 0x49, 0x59, 0x8a, 0x8f, 0x34, 0x5b, 0x1b, 0xd3, 0xd2, 0x03, + 0x8b, 0x83, 0x70, 0x14, 0x4f, 0x2c, 0x6c, 0x22, 0x92, 0x67, 0xf1, 0xcd, 0xd6, 0x07, 0xb7, 0x5b, + 0x1f, 0xfc, 0xd8, 0xfa, 0xe0, 0xf3, 0xce, 0x77, 0x6e, 0x77, 0xbe, 0xf3, 0x6d, 0xe7, 0x3b, 0xef, + 0x57, 0x39, 0x53, 0x45, 0x93, 0x22, 0x22, 0x2a, 0x4c, 0x84, 0xac, 0x84, 0xc4, 0x2c, 0x25, 0xa7, + 0xb9, 0xc0, 0xed, 0x0a, 0x57, 0x22, 0x6b, 0x4a, 0x2a, 0xcd, 0x4d, 0x3f, 0x89, 0x4e, 0xed, 0x59, + 0xab, 0xcd, 0x15, 0x95, 0xe9, 0x50, 0x3f, 0xd0, 0xd3, 0x9f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x17, + 0x37, 0x3f, 0x66, 0xf6, 0x02, 0x00, 0x00, } -func (this *UpgradeProposal) Equal(that interface{}) bool { - if that == nil { - return this == nil - } - - that1, ok := that.(*UpgradeProposal) - if !ok { - that2, ok := that.(UpgradeProposal) - if ok { - that1 = &that2 - } else { - return false - } - } - if that1 == nil { - return this == nil - } else if this == nil { - return false - } - if this.Title != that1.Title { - return false - } - if this.Description != that1.Description { - return false - } - if !this.Plan.Equal(&that1.Plan) { - return false - } - if !this.UpgradedClientState.Equal(that1.UpgradedClientState) { - return false - } - return true -} func (m *IdentifiedClientState) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -607,116 +462,6 @@ func (m *ClientConsensusStates) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *ClientUpdateProposal) 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 *ClientUpdateProposal) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *ClientUpdateProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.SubstituteClientId) > 0 { - i -= len(m.SubstituteClientId) - copy(dAtA[i:], m.SubstituteClientId) - i = encodeVarintClient(dAtA, i, uint64(len(m.SubstituteClientId))) - i-- - dAtA[i] = 0x22 - } - if len(m.SubjectClientId) > 0 { - i -= len(m.SubjectClientId) - copy(dAtA[i:], m.SubjectClientId) - i = encodeVarintClient(dAtA, i, uint64(len(m.SubjectClientId))) - i-- - dAtA[i] = 0x1a - } - if len(m.Description) > 0 { - i -= len(m.Description) - copy(dAtA[i:], m.Description) - i = encodeVarintClient(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 = encodeVarintClient(dAtA, i, uint64(len(m.Title))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *UpgradeProposal) 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 *UpgradeProposal) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *UpgradeProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.UpgradedClientState != nil { - { - size, err := m.UpgradedClientState.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintClient(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x22 - } - { - size, err := m.Plan.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintClient(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - if len(m.Description) > 0 { - i -= len(m.Description) - copy(dAtA[i:], m.Description) - i = encodeVarintClient(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 = encodeVarintClient(dAtA, i, uint64(len(m.Title))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - func (m *Height) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -844,54 +589,6 @@ func (m *ClientConsensusStates) Size() (n int) { return n } -func (m *ClientUpdateProposal) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Title) - if l > 0 { - n += 1 + l + sovClient(uint64(l)) - } - l = len(m.Description) - if l > 0 { - n += 1 + l + sovClient(uint64(l)) - } - l = len(m.SubjectClientId) - if l > 0 { - n += 1 + l + sovClient(uint64(l)) - } - l = len(m.SubstituteClientId) - if l > 0 { - n += 1 + l + sovClient(uint64(l)) - } - return n -} - -func (m *UpgradeProposal) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Title) - if l > 0 { - n += 1 + l + sovClient(uint64(l)) - } - l = len(m.Description) - if l > 0 { - n += 1 + l + sovClient(uint64(l)) - } - l = m.Plan.Size() - n += 1 + l + sovClient(uint64(l)) - if m.UpgradedClientState != nil { - l = m.UpgradedClientState.Size() - n += 1 + l + sovClient(uint64(l)) - } - return n -} - func (m *Height) Size() (n int) { if m == nil { return 0 @@ -1281,367 +978,6 @@ func (m *ClientConsensusStates) Unmarshal(dAtA []byte) error { } return nil } -func (m *ClientUpdateProposal) 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 ErrIntOverflowClient - } - 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: ClientUpdateProposal: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: ClientUpdateProposal: 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 ErrIntOverflowClient - } - 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 ErrInvalidLengthClient - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthClient - } - 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 ErrIntOverflowClient - } - 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 ErrInvalidLengthClient - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthClient - } - 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 SubjectClientId", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowClient - } - 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 ErrInvalidLengthClient - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthClient - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.SubjectClientId = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field SubstituteClientId", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowClient - } - 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 ErrInvalidLengthClient - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthClient - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.SubstituteClientId = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipClient(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthClient - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *UpgradeProposal) 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 ErrIntOverflowClient - } - 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: UpgradeProposal: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: UpgradeProposal: 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 ErrIntOverflowClient - } - 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 ErrInvalidLengthClient - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthClient - } - 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 ErrIntOverflowClient - } - 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 ErrInvalidLengthClient - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthClient - } - 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 Plan", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowClient - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthClient - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthClient - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Plan.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field UpgradedClientState", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowClient - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthClient - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthClient - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.UpgradedClientState == nil { - m.UpgradedClientState = &types.Any{} - } - if err := m.UpgradedClientState.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipClient(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthClient - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func (m *Height) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/modules/core/02-client/types/codec.go b/modules/core/02-client/types/codec.go index a0a9b8fd176..f115fa39ea7 100644 --- a/modules/core/02-client/types/codec.go +++ b/modules/core/02-client/types/codec.go @@ -8,7 +8,6 @@ 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/v1beta1" ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" "github.com/cosmos/ibc-go/v8/modules/core/exported" @@ -37,17 +36,14 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { "ibc.core.client.v1.Misbehaviour", (*exported.ClientMessage)(nil), ) - registry.RegisterImplementations( - (*govtypes.Content)(nil), - &ClientUpdateProposal{}, - &UpgradeProposal{}, - ) registry.RegisterImplementations( (*sdk.Msg)(nil), &MsgCreateClient{}, &MsgUpdateClient{}, &MsgUpgradeClient{}, &MsgSubmitMisbehaviour{}, + &MsgRecoverClient{}, + &MsgIBCSoftwareUpgrade{}, &MsgUpdateParams{}, ) diff --git a/modules/core/02-client/types/errors.go b/modules/core/02-client/types/errors.go index cdc84871ca0..3a726378cbc 100644 --- a/modules/core/02-client/types/errors.go +++ b/modules/core/02-client/types/errors.go @@ -28,7 +28,7 @@ var ( ErrFailedNextSeqRecvVerification = errorsmod.Register(SubModuleName, 21, "next sequence receive verification failed") ErrSelfConsensusStateNotFound = errorsmod.Register(SubModuleName, 22, "self consensus state not found") ErrUpdateClientFailed = errorsmod.Register(SubModuleName, 23, "unable to update light client") - ErrInvalidUpdateClientProposal = errorsmod.Register(SubModuleName, 24, "invalid update client proposal") + ErrInvalidRecoveryClient = errorsmod.Register(SubModuleName, 24, "invalid recovery client") ErrInvalidUpgradeClient = errorsmod.Register(SubModuleName, 25, "invalid client upgrade") ErrInvalidHeight = errorsmod.Register(SubModuleName, 26, "invalid height") ErrInvalidSubstitute = errorsmod.Register(SubModuleName, 27, "invalid client state substitute") diff --git a/modules/core/02-client/types/events.go b/modules/core/02-client/types/events.go index 9fbf7fbb052..f729106e01c 100644 --- a/modules/core/02-client/types/events.go +++ b/modules/core/02-client/types/events.go @@ -21,13 +21,13 @@ const ( // IBC client events vars var ( - EventTypeCreateClient = "create_client" - EventTypeUpdateClient = "update_client" - EventTypeUpgradeClient = "upgrade_client" - EventTypeSubmitMisbehaviour = "client_misbehaviour" - EventTypeUpdateClientProposal = "update_client_proposal" - EventTypeUpgradeChain = "upgrade_chain" - EventTypeUpgradeClientProposal = "upgrade_client_proposal" + EventTypeCreateClient = "create_client" + EventTypeUpdateClient = "update_client" + EventTypeUpgradeClient = "upgrade_client" + EventTypeSubmitMisbehaviour = "client_misbehaviour" + EventTypeRecoverClient = "recover_client" + EventTypeScheduleIBCSoftwareUpgrade = "schedule_ibc_software_upgrade" + EventTypeUpgradeChain = "upgrade_chain" AttributeValueCategory = fmt.Sprintf("%s_%s", ibcexported.ModuleName, SubModuleName) ) diff --git a/modules/core/02-client/types/msgs.go b/modules/core/02-client/types/msgs.go index 95cf016c10a..b0d4528bd87 100644 --- a/modules/core/02-client/types/msgs.go +++ b/modules/core/02-client/types/msgs.go @@ -2,6 +2,7 @@ package types import ( errorsmod "cosmossdk.io/errors" + upgradetypes "cosmossdk.io/x/upgrade/types" codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -17,11 +18,14 @@ var ( _ sdk.Msg = (*MsgSubmitMisbehaviour)(nil) _ sdk.Msg = (*MsgUpgradeClient)(nil) _ sdk.Msg = (*MsgUpdateParams)(nil) + _ sdk.Msg = (*MsgIBCSoftwareUpgrade)(nil) + _ sdk.Msg = (*MsgRecoverClient)(nil) _ codectypes.UnpackInterfacesMessage = (*MsgCreateClient)(nil) _ codectypes.UnpackInterfacesMessage = (*MsgUpdateClient)(nil) _ codectypes.UnpackInterfacesMessage = (*MsgSubmitMisbehaviour)(nil) _ codectypes.UnpackInterfacesMessage = (*MsgUpgradeClient)(nil) + _ codectypes.UnpackInterfacesMessage = (*MsgIBCSoftwareUpgrade)(nil) ) // NewMsgCreateClient creates a new MsgCreateClient instance @@ -259,6 +263,92 @@ func (msg MsgSubmitMisbehaviour) UnpackInterfaces(unpacker codectypes.AnyUnpacke return unpacker.UnpackAny(msg.Misbehaviour, &misbehaviour) } +// NewMsgRecoverClient creates a new MsgRecoverClient instance +func NewMsgRecoverClient(signer, subjectClientID, substituteClientID string) *MsgRecoverClient { + return &MsgRecoverClient{ + Signer: signer, + SubjectClientId: subjectClientID, + SubstituteClientId: substituteClientID, + } +} + +// ValidateBasic performs basic checks on a MsgRecoverClient. +func (msg *MsgRecoverClient) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(msg.Signer); err != nil { + return errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err) + } + + if err := host.ClientIdentifierValidator(msg.SubjectClientId); err != nil { + return err + } + + if err := host.ClientIdentifierValidator(msg.SubstituteClientId); err != nil { + return err + } + + if msg.SubjectClientId == msg.SubstituteClientId { + return errorsmod.Wrapf(ErrInvalidSubstitute, "subject and substitute clients must be different") + } + + return nil +} + +// GetSigners returns the expected signers for a MsgRecoverClient message. +func (msg *MsgRecoverClient) GetSigners() []sdk.AccAddress { + accAddr, err := sdk.AccAddressFromBech32(msg.Signer) + if err != nil { + panic(err) + } + return []sdk.AccAddress{accAddr} +} + +// NewMsgIBCSoftwareUpgrade creates a new MsgIBCSoftwareUpgrade instance +func NewMsgIBCSoftwareUpgrade(signer string, plan upgradetypes.Plan, upgradedClientState exported.ClientState) (*MsgIBCSoftwareUpgrade, error) { + anyClient, err := PackClientState(upgradedClientState) + if err != nil { + return nil, err + } + + return &MsgIBCSoftwareUpgrade{ + Signer: signer, + Plan: plan, + UpgradedClientState: anyClient, + }, nil +} + +// ValidateBasic performs basic checks on a MsgIBCSoftwareUpgrade. +func (msg *MsgIBCSoftwareUpgrade) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(msg.Signer); err != nil { + return errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err) + } + + clientState, err := UnpackClientState(msg.UpgradedClientState) + if err != nil { + return err + } + + // for the time being, we should implicitly be on tendermint when using ibc-go + if clientState.ClientType() != exported.Tendermint { + return errorsmod.Wrapf(ErrInvalidUpgradeClient, "upgraded client state must be a Tendermint client") + } + + return msg.Plan.ValidateBasic() +} + +// GetSigners returns the expected signers for a MsgIBCSoftwareUpgrade message. +func (msg *MsgIBCSoftwareUpgrade) GetSigners() []sdk.AccAddress { + accAddr, err := sdk.AccAddressFromBech32(msg.Signer) + if err != nil { + panic(err) + } + return []sdk.AccAddress{accAddr} +} + +// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces +func (msg *MsgIBCSoftwareUpgrade) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { + return unpacker.UnpackAny(msg.UpgradedClientState, new(exported.ClientState)) +} + // NewMsgUpdateParams creates a new instance of MsgUpdateParams. func NewMsgUpdateParams(signer string, params Params) *MsgUpdateParams { return &MsgUpdateParams{ diff --git a/modules/core/02-client/types/msgs_test.go b/modules/core/02-client/types/msgs_test.go index eda16a705e0..0c9d881300a 100644 --- a/modules/core/02-client/types/msgs_test.go +++ b/modules/core/02-client/types/msgs_test.go @@ -1,6 +1,7 @@ package types_test import ( + "errors" "testing" "time" @@ -8,10 +9,17 @@ import ( "github.com/stretchr/testify/require" testifysuite "github.com/stretchr/testify/suite" + upgradetypes "cosmossdk.io/x/upgrade/types" + + codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" + ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" + "github.com/cosmos/ibc-go/v8/modules/core/exported" solomachine "github.com/cosmos/ibc-go/v8/modules/light-clients/06-solomachine" ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v8/testing" @@ -613,6 +621,278 @@ func (suite *TypesTestSuite) TestMsgSubmitMisbehaviour_ValidateBasic() { } } +// TestMsgRecoverClientValidateBasic tests ValidateBasic for MsgRecoverClient +func (suite *TypesTestSuite) TestMsgRecoverClientValidateBasic() { + var msg *types.MsgRecoverClient + + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "success: valid signer and client identifiers", + func() {}, + nil, + }, + { + "failure: invalid signer address", + func() { + msg.Signer = "invalid" + }, + ibcerrors.ErrInvalidAddress, + }, + { + "failure: invalid subject client ID", + func() { + msg.SubjectClientId = "" + }, + host.ErrInvalidID, + }, + { + "failure: invalid substitute client ID", + func() { + msg.SubstituteClientId = "" + }, + host.ErrInvalidID, + }, + { + "failure: subject and substribute client IDs are the same", + func() { + msg.SubstituteClientId = ibctesting.FirstClientID + }, + types.ErrInvalidSubstitute, + }, + } + + for _, tc := range testCases { + msg = types.NewMsgRecoverClient( + ibctesting.TestAccAddress, + ibctesting.FirstClientID, + ibctesting.SecondClientID, + ) + + tc.malleate() + + err := msg.ValidateBasic() + expPass := tc.expError == nil + if expPass { + suite.Require().NoError(err, "valid case %s failed", tc.name) + } else { + suite.Require().Error(err, "invalid case %s passed", tc.name) + suite.Require().ErrorIs(err, tc.expError, "invalid case %s passed", tc.name) + } + } +} + +// TestMsgRecoverClientGetSigners tests GetSigners for MsgRecoverClient +func TestMsgRecoverClientGetSigners(t *testing.T) { + testCases := []struct { + name string + address sdk.AccAddress + expPass bool + }{ + {"success: valid address", sdk.AccAddress(ibctesting.TestAccAddress), true}, + {"failure: nil address", nil, false}, + } + + for _, tc := range testCases { + // Leave subject client ID and substitute client ID as empty strings + msg := types.MsgRecoverClient{ + Signer: tc.address.String(), + } + if tc.expPass { + require.Equal(t, []sdk.AccAddress{tc.address}, msg.GetSigners()) + } else { + require.Panics(t, func() { + msg.GetSigners() + }) + } + } +} + +// TestMsgIBCSoftwareUpgrade_NewMsgIBCSoftwareUpgrade tests NewMsgIBCSoftwareUpgrade +func (suite *TypesTestSuite) TestMsgIBCSoftwareUpgrade_NewMsgIBCSoftwareUpgrade() { + testCases := []struct { + name string + upgradedClientState exported.ClientState + expPass bool + }{ + { + "success", + ibctm.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath), + true, + }, + { + "fail: failed to pack ClientState", + nil, + false, + }, + } + + for _, tc := range testCases { + plan := upgradetypes.Plan{ + Name: "upgrade IBC clients", + Height: 1000, + } + msg, err := types.NewMsgIBCSoftwareUpgrade( + ibctesting.TestAccAddress, + plan, + tc.upgradedClientState, + ) + + if tc.expPass { + suite.Require().NoError(err) + suite.Assert().Equal(ibctesting.TestAccAddress, msg.Signer) + suite.Assert().Equal(plan, msg.Plan) + unpackedClientState, err := types.UnpackClientState(msg.UpgradedClientState) + suite.Require().NoError(err) + suite.Assert().Equal(tc.upgradedClientState, unpackedClientState) + } else { + suite.Require().True(errors.Is(err, ibcerrors.ErrPackAny)) + } + } +} + +// TestMsgIBCSoftwareUpgrade_GetSigners tests GetSigners for MsgIBCSoftwareUpgrade +func (suite *TypesTestSuite) TestMsgIBCSoftwareUpgrade_GetSigners() { + testCases := []struct { + name string + address sdk.AccAddress + expPass bool + }{ + { + "success: valid address", + sdk.AccAddress(ibctesting.TestAccAddress), + true, + }, + { + "failure: nil address", + nil, + false, + }, + } + + for _, tc := range testCases { + clientState := ibctm.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath) + plan := upgradetypes.Plan{ + Name: "upgrade IBC clients", + Height: 1000, + } + msg, err := types.NewMsgIBCSoftwareUpgrade( + tc.address.String(), + plan, + clientState, + ) + suite.Require().NoError(err) + + if tc.expPass { + suite.Require().Equal([]sdk.AccAddress{tc.address}, msg.GetSigners()) + } else { + suite.Require().Panics(func() { msg.GetSigners() }) + } + } +} + +// TestMsgIBCSoftwareUpgrade_ValidateBasic tests ValidateBasic for MsgIBCSoftwareUpgrade +func (suite *TypesTestSuite) TestMsgIBCSoftwareUpgrade_ValidateBasic() { + var ( + signer string + plan upgradetypes.Plan + anyClient *codectypes.Any + ) + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "success", + func() {}, + nil, + }, + { + "failure: invalid authority address", + func() { + signer = "invalid" + }, + ibcerrors.ErrInvalidAddress, + }, + { + "failure: error unpacking client state", + func() { + anyClient = &codectypes.Any{} + }, + ibcerrors.ErrUnpackAny, + }, + { + "failure: error validating upgrade plan, height is not greater than zero", + func() { + plan.Height = 0 + }, + sdkerrors.ErrInvalidRequest, + }, + } + + for _, tc := range testCases { + signer = ibctesting.TestAccAddress + plan = upgradetypes.Plan{ + Name: "upgrade IBC clients", + Height: 1000, + } + upgradedClientState := ibctm.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath) + var err error + anyClient, err = types.PackClientState(upgradedClientState) + suite.Require().NoError(err) + + tc.malleate() + + msg := types.MsgIBCSoftwareUpgrade{ + plan, + anyClient, + signer, + } + + err = msg.ValidateBasic() + expPass := tc.expError == nil + + if expPass { + suite.Require().NoError(err) + } + if tc.expError != nil { + suite.Require().True(errors.Is(err, tc.expError)) + } + } +} + +// tests a MsgIBCSoftwareUpgrade can be marshaled and unmarshaled, and the +// client state can be unpacked +func (suite *TypesTestSuite) TestMarshalMsgIBCSoftwareUpgrade() { + cdc := suite.chainA.App.AppCodec() + + // create proposal + plan := upgradetypes.Plan{ + Name: "upgrade ibc", + Height: 1000, + } + + msg, err := types.NewMsgIBCSoftwareUpgrade(ibctesting.TestAccAddress, plan, &ibctm.ClientState{}) + suite.Require().NoError(err) + + // marshal message + bz, err := cdc.MarshalJSON(msg) + suite.Require().NoError(err) + + // unmarshal proposal + newMsg := &types.MsgIBCSoftwareUpgrade{} + err = cdc.UnmarshalJSON(bz, newMsg) + suite.Require().NoError(err) + + // unpack client state + _, err = types.UnpackClientState(newMsg.UpgradedClientState) + suite.Require().NoError(err) +} + // TestMsgUpdateParamsValidateBasic tests ValidateBasic for MsgUpdateParams func (suite *TypesTestSuite) TestMsgUpdateParamsValidateBasic() { signer := suite.chainA.App.GetIBCKeeper().GetAuthority() diff --git a/modules/core/02-client/types/proposal.go b/modules/core/02-client/types/proposal.go deleted file mode 100644 index 929eff8feb0..00000000000 --- a/modules/core/02-client/types/proposal.go +++ /dev/null @@ -1,148 +0,0 @@ -package types - -import ( - "fmt" - "reflect" - - errorsmod "cosmossdk.io/errors" - upgradetypes "cosmossdk.io/x/upgrade/types" - - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" - - "github.com/cosmos/ibc-go/v8/modules/core/exported" -) - -const ( - // ProposalTypeClientUpdate defines the type for a ClientUpdateProposal - ProposalTypeClientUpdate = "ClientUpdate" - ProposalTypeUpgrade = "IBCUpgrade" -) - -var ( - _ govtypes.Content = (*ClientUpdateProposal)(nil) - _ govtypes.Content = (*UpgradeProposal)(nil) - _ codectypes.UnpackInterfacesMessage = (*UpgradeProposal)(nil) -) - -func init() { - govtypes.RegisterProposalType(ProposalTypeClientUpdate) - govtypes.RegisterProposalType(ProposalTypeUpgrade) -} - -// NewClientUpdateProposal creates a new client update proposal. -func NewClientUpdateProposal(title, description, subjectClientID, substituteClientID string) govtypes.Content { - return &ClientUpdateProposal{ - Title: title, - Description: description, - SubjectClientId: subjectClientID, - SubstituteClientId: substituteClientID, - } -} - -// GetTitle returns the title of a client update proposal. -func (cup *ClientUpdateProposal) GetTitle() string { return cup.Title } - -// GetDescription returns the description of a client update proposal. -func (cup *ClientUpdateProposal) GetDescription() string { return cup.Description } - -// ProposalRoute returns the routing key of a client update proposal. -func (*ClientUpdateProposal) ProposalRoute() string { return RouterKey } - -// ProposalType returns the type of a client update proposal. -func (*ClientUpdateProposal) ProposalType() string { return ProposalTypeClientUpdate } - -// ValidateBasic runs basic stateless validity checks -func (cup *ClientUpdateProposal) ValidateBasic() error { - err := govtypes.ValidateAbstract(cup) - if err != nil { - return err - } - - if cup.SubjectClientId == cup.SubstituteClientId { - return errorsmod.Wrap(ErrInvalidSubstitute, "subject and substitute client identifiers are equal") - } - if _, _, err := ParseClientIdentifier(cup.SubjectClientId); err != nil { - return err - } - if _, _, err := ParseClientIdentifier(cup.SubstituteClientId); err != nil { - return err - } - - return nil -} - -// NewUpgradeProposal creates a new IBC breaking upgrade proposal. -func NewUpgradeProposal(title, description string, plan upgradetypes.Plan, upgradedClientState exported.ClientState) (govtypes.Content, error) { - protoAny, err := PackClientState(upgradedClientState) - if err != nil { - return nil, err - } - - return &UpgradeProposal{ - Title: title, - Description: description, - Plan: plan, - UpgradedClientState: protoAny, - }, nil -} - -// GetTitle returns the title of a upgrade proposal. -func (up *UpgradeProposal) GetTitle() string { return up.Title } - -// GetDescription returns the description of a upgrade proposal. -func (up *UpgradeProposal) GetDescription() string { return up.Description } - -// ProposalRoute returns the routing key of a upgrade proposal. -func (*UpgradeProposal) ProposalRoute() string { return RouterKey } - -// ProposalType returns the upgrade proposal type. -func (*UpgradeProposal) ProposalType() string { return ProposalTypeUpgrade } - -// ValidateBasic runs basic stateless validity checks -func (up *UpgradeProposal) ValidateBasic() error { - if err := govtypes.ValidateAbstract(up); err != nil { - return err - } - - if err := up.Plan.ValidateBasic(); err != nil { - return err - } - - if up.UpgradedClientState == nil { - return errorsmod.Wrap(ErrInvalidUpgradeProposal, "upgraded client state cannot be nil") - } - - clientState, err := UnpackClientState(up.UpgradedClientState) - if err != nil { - return errorsmod.Wrap(err, "failed to unpack upgraded client state") - } - - if !reflect.DeepEqual(clientState, clientState.ZeroCustomFields()) { - return errorsmod.Wrap(ErrInvalidUpgradeProposal, "upgraded client state is not zeroed out") - } - - return nil -} - -// String returns the string representation of the UpgradeProposal. -func (up UpgradeProposal) String() string { - var upgradedClientStr string - upgradedClient, err := UnpackClientState(up.UpgradedClientState) - if err != nil { - upgradedClientStr = "invalid IBC Client State" - } else { - upgradedClientStr = upgradedClient.String() - } - - return fmt.Sprintf(`IBC Upgrade Proposal - Title: %s - Description: %s - %s - Upgraded IBC Client: %s`, up.Title, up.Description, up.Plan.String(), upgradedClientStr) -} - -// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces -func (up UpgradeProposal) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { - return unpacker.UnpackAny(up.UpgradedClientState, new(exported.ClientState)) -} diff --git a/modules/core/02-client/types/proposal_test.go b/modules/core/02-client/types/proposal_test.go deleted file mode 100644 index 73904b37f2e..00000000000 --- a/modules/core/02-client/types/proposal_test.go +++ /dev/null @@ -1,227 +0,0 @@ -package types_test - -import ( - "fmt" - - upgradetypes "cosmossdk.io/x/upgrade/types" - - "github.com/cosmos/cosmos-sdk/codec" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" - - "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" - ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" - ibctesting "github.com/cosmos/ibc-go/v8/testing" -) - -func (suite *TypesTestSuite) TestValidateBasic() { - subjectPath := ibctesting.NewPath(suite.chainA, suite.chainB) - suite.coordinator.SetupClients(subjectPath) - subject := subjectPath.EndpointA.ClientID - - substitutePath := ibctesting.NewPath(suite.chainA, suite.chainB) - suite.coordinator.SetupClients(substitutePath) - substitute := substitutePath.EndpointA.ClientID - - testCases := []struct { - name string - proposal govtypes.Content - expPass bool - }{ - { - "success", - types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, subject, substitute), - true, - }, - { - "fails validate abstract - empty title", - types.NewClientUpdateProposal("", ibctesting.Description, subject, substitute), - false, - }, - { - "subject and substitute use the same identifier", - types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, subject, subject), - false, - }, - { - "invalid subject clientID", - types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, ibctesting.InvalidID, substitute), - false, - }, - { - "invalid substitute clientID", - types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, subject, ibctesting.InvalidID), - false, - }, - } - - for _, tc := range testCases { - - err := tc.proposal.ValidateBasic() - - if tc.expPass { - suite.Require().NoError(err, tc.name) - } else { - suite.Require().Error(err, tc.name) - } - } -} - -// tests a client update proposal can be marshaled and unmarshaled -func (suite *TypesTestSuite) TestMarshalClientUpdateProposalProposal() { - // create proposal - proposal := types.NewClientUpdateProposal("update IBC client", "description", "subject", "substitute") - - // create codec - ir := codectypes.NewInterfaceRegistry() - types.RegisterInterfaces(ir) - govtypes.RegisterInterfaces(ir) - cdc := codec.NewProtoCodec(ir) - - // marshal message - content := proposal.(*types.ClientUpdateProposal) - bz, err := cdc.MarshalJSON(content) - suite.Require().NoError(err) - - // unmarshal proposal - newProposal := &types.ClientUpdateProposal{} - err = cdc.UnmarshalJSON(bz, newProposal) - suite.Require().NoError(err) -} - -func (suite *TypesTestSuite) TestUpgradeProposalValidateBasic() { - var ( - proposal govtypes.Content - err error - ) - - path := ibctesting.NewPath(suite.chainA, suite.chainB) - suite.coordinator.SetupClients(path) - cs := suite.chainA.GetClientState(path.EndpointA.ClientID) - plan := upgradetypes.Plan{ - Name: "ibc upgrade", - Height: 1000, - } - - testCases := []struct { - name string - malleate func() - expPass bool - }{ - { - "success", func() { - proposal, err = types.NewUpgradeProposal(ibctesting.Title, ibctesting.Description, plan, cs.ZeroCustomFields()) - suite.Require().NoError(err) - }, true, - }, - { - "fails validate abstract - empty title", func() { - proposal, err = types.NewUpgradeProposal("", ibctesting.Description, plan, cs.ZeroCustomFields()) - suite.Require().NoError(err) - }, false, - }, - { - "non zeroed fields", func() { - proposal, err = types.NewUpgradeProposal(ibctesting.Title, ibctesting.Description, plan, &ibctm.ClientState{ - FrozenHeight: types.Height{ - RevisionHeight: 10, - }, - }) - suite.Require().NoError(err) - }, false, - }, - { - "plan height is zero", func() { - invalidPlan := upgradetypes.Plan{Name: "ibc upgrade", Height: 0} - proposal, err = types.NewUpgradeProposal(ibctesting.Title, ibctesting.Description, invalidPlan, cs.ZeroCustomFields()) - suite.Require().NoError(err) - }, false, - }, - { - "client state is nil", func() { - proposal = &types.UpgradeProposal{ - Title: ibctesting.Title, - Description: ibctesting.Description, - Plan: plan, - UpgradedClientState: nil, - } - }, false, - }, - { - "failed to unpack client state", func() { - protoAny, err := types.PackConsensusState(&ibctm.ConsensusState{}) - suite.Require().NoError(err) - - proposal = &types.UpgradeProposal{ - Title: ibctesting.Title, - Description: ibctesting.Description, - Plan: plan, - UpgradedClientState: protoAny, - } - }, false, - }, - } - - for _, tc := range testCases { - - tc.malleate() - - err := proposal.ValidateBasic() - - if tc.expPass { - suite.Require().NoError(err, tc.name) - } else { - suite.Require().Error(err, tc.name) - } - } -} - -// tests an upgrade proposal can be marshaled and unmarshaled, and the -// client state can be unpacked -func (suite *TypesTestSuite) TestMarshalUpgradeProposal() { - // create proposal - plan := upgradetypes.Plan{ - Name: "upgrade ibc", - Height: 1000, - } - content, err := types.NewUpgradeProposal("title", "description", plan, &ibctm.ClientState{}) - suite.Require().NoError(err) - - up, ok := content.(*types.UpgradeProposal) - suite.Require().True(ok) - - // create codec - ir := codectypes.NewInterfaceRegistry() - types.RegisterInterfaces(ir) - govtypes.RegisterInterfaces(ir) - ibctm.RegisterInterfaces(ir) - cdc := codec.NewProtoCodec(ir) - - // marshal message - bz, err := cdc.MarshalJSON(up) - suite.Require().NoError(err) - - // unmarshal proposal - newUp := &types.UpgradeProposal{} - err = cdc.UnmarshalJSON(bz, newUp) - suite.Require().NoError(err) - - // unpack client state - _, err = types.UnpackClientState(newUp.UpgradedClientState) - suite.Require().NoError(err) -} - -func (suite *TypesTestSuite) TestUpgradeString() { - plan := upgradetypes.Plan{ - Name: "ibc upgrade", - Info: "https://foo.bar/baz", - Height: 1000, - } - - proposal, err := types.NewUpgradeProposal(ibctesting.Title, ibctesting.Description, plan, &ibctm.ClientState{}) - suite.Require().NoError(err) - - expect := fmt.Sprintf("IBC Upgrade Proposal\n Title: title\n Description: description\n name:\"ibc upgrade\" time: height:1000 info:\"https://foo.bar/baz\" \n Upgraded IBC Client: %s", &ibctm.ClientState{}) - - suite.Require().Equal(expect, proposal.String()) -} diff --git a/modules/core/02-client/types/tx.pb.go b/modules/core/02-client/types/tx.pb.go index fba1e65a080..41954fe8f29 100644 --- a/modules/core/02-client/types/tx.pb.go +++ b/modules/core/02-client/types/tx.pb.go @@ -5,6 +5,7 @@ package types import ( context "context" + types1 "cosmossdk.io/x/upgrade/types" fmt "fmt" types "github.com/cosmos/cosmos-sdk/codec/types" _ "github.com/cosmos/cosmos-sdk/types/msgservice" @@ -365,6 +366,194 @@ func (m *MsgSubmitMisbehaviourResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgSubmitMisbehaviourResponse proto.InternalMessageInfo +// MsgRecoverClient defines the message used to recover a frozen or expired client. +type MsgRecoverClient struct { + // the client identifier for the client to be updated if the proposal passes + SubjectClientId string `protobuf:"bytes,1,opt,name=subject_client_id,json=subjectClientId,proto3" json:"subject_client_id,omitempty"` + // the substitute client identifier for the client which will replace the subject + // client + SubstituteClientId string `protobuf:"bytes,2,opt,name=substitute_client_id,json=substituteClientId,proto3" json:"substitute_client_id,omitempty"` + // signer address (it may be the the address that controls the module, which defaults to x/gov unless overwritten). + Signer string `protobuf:"bytes,3,opt,name=signer,proto3" json:"signer,omitempty"` +} + +func (m *MsgRecoverClient) Reset() { *m = MsgRecoverClient{} } +func (m *MsgRecoverClient) String() string { return proto.CompactTextString(m) } +func (*MsgRecoverClient) ProtoMessage() {} +func (*MsgRecoverClient) Descriptor() ([]byte, []int) { + return fileDescriptor_cb5dc4651eb49a04, []int{8} +} +func (m *MsgRecoverClient) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRecoverClient) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRecoverClient.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 *MsgRecoverClient) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRecoverClient.Merge(m, src) +} +func (m *MsgRecoverClient) XXX_Size() int { + return m.Size() +} +func (m *MsgRecoverClient) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRecoverClient.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRecoverClient proto.InternalMessageInfo + +// MsgRecoverClientResponse defines the Msg/RecoverClient response type. +type MsgRecoverClientResponse struct { +} + +func (m *MsgRecoverClientResponse) Reset() { *m = MsgRecoverClientResponse{} } +func (m *MsgRecoverClientResponse) String() string { return proto.CompactTextString(m) } +func (*MsgRecoverClientResponse) ProtoMessage() {} +func (*MsgRecoverClientResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_cb5dc4651eb49a04, []int{9} +} +func (m *MsgRecoverClientResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRecoverClientResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRecoverClientResponse.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 *MsgRecoverClientResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRecoverClientResponse.Merge(m, src) +} +func (m *MsgRecoverClientResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgRecoverClientResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRecoverClientResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRecoverClientResponse proto.InternalMessageInfo + +// MsgIBCSoftwareUpgrade defines the message used to schedule an upgrade of an IBC client using a v1 governance proposal +type MsgIBCSoftwareUpgrade struct { + Plan types1.Plan `protobuf:"bytes,1,opt,name=plan,proto3" json:"plan"` + // 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. Correspondingly, the UpgradedClientState field has been + // deprecated in the Cosmos SDK to allow for this logic to exist solely in + // the 02-client module. + UpgradedClientState *types.Any `protobuf:"bytes,2,opt,name=upgraded_client_state,json=upgradedClientState,proto3" json:"upgraded_client_state,omitempty"` + // signer defaults to the governance account address unless otherwise specified. + Signer string `protobuf:"bytes,3,opt,name=signer,proto3" json:"signer,omitempty"` +} + +func (m *MsgIBCSoftwareUpgrade) Reset() { *m = MsgIBCSoftwareUpgrade{} } +func (m *MsgIBCSoftwareUpgrade) String() string { return proto.CompactTextString(m) } +func (*MsgIBCSoftwareUpgrade) ProtoMessage() {} +func (*MsgIBCSoftwareUpgrade) Descriptor() ([]byte, []int) { + return fileDescriptor_cb5dc4651eb49a04, []int{10} +} +func (m *MsgIBCSoftwareUpgrade) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgIBCSoftwareUpgrade) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgIBCSoftwareUpgrade.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 *MsgIBCSoftwareUpgrade) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgIBCSoftwareUpgrade.Merge(m, src) +} +func (m *MsgIBCSoftwareUpgrade) XXX_Size() int { + return m.Size() +} +func (m *MsgIBCSoftwareUpgrade) XXX_DiscardUnknown() { + xxx_messageInfo_MsgIBCSoftwareUpgrade.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgIBCSoftwareUpgrade proto.InternalMessageInfo + +func (m *MsgIBCSoftwareUpgrade) GetPlan() types1.Plan { + if m != nil { + return m.Plan + } + return types1.Plan{} +} + +func (m *MsgIBCSoftwareUpgrade) GetUpgradedClientState() *types.Any { + if m != nil { + return m.UpgradedClientState + } + return nil +} + +func (m *MsgIBCSoftwareUpgrade) GetSigner() string { + if m != nil { + return m.Signer + } + return "" +} + +// MsgIBCSoftwareUpgradeResponse defines the Msg/IBCSoftwareUpgrade response type. +type MsgIBCSoftwareUpgradeResponse struct { +} + +func (m *MsgIBCSoftwareUpgradeResponse) Reset() { *m = MsgIBCSoftwareUpgradeResponse{} } +func (m *MsgIBCSoftwareUpgradeResponse) String() string { return proto.CompactTextString(m) } +func (*MsgIBCSoftwareUpgradeResponse) ProtoMessage() {} +func (*MsgIBCSoftwareUpgradeResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_cb5dc4651eb49a04, []int{11} +} +func (m *MsgIBCSoftwareUpgradeResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgIBCSoftwareUpgradeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgIBCSoftwareUpgradeResponse.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 *MsgIBCSoftwareUpgradeResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgIBCSoftwareUpgradeResponse.Merge(m, src) +} +func (m *MsgIBCSoftwareUpgradeResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgIBCSoftwareUpgradeResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgIBCSoftwareUpgradeResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgIBCSoftwareUpgradeResponse proto.InternalMessageInfo + // MsgUpdateParams defines the sdk.Msg type to update the client parameters. type MsgUpdateParams struct { // signer address (it may be the the address that controls the module, which defaults to x/gov unless overwritten). @@ -379,7 +568,7 @@ func (m *MsgUpdateParams) Reset() { *m = MsgUpdateParams{} } func (m *MsgUpdateParams) String() string { return proto.CompactTextString(m) } func (*MsgUpdateParams) ProtoMessage() {} func (*MsgUpdateParams) Descriptor() ([]byte, []int) { - return fileDescriptor_cb5dc4651eb49a04, []int{8} + return fileDescriptor_cb5dc4651eb49a04, []int{12} } func (m *MsgUpdateParams) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -416,7 +605,7 @@ func (m *MsgUpdateParamsResponse) Reset() { *m = MsgUpdateParamsResponse func (m *MsgUpdateParamsResponse) String() string { return proto.CompactTextString(m) } func (*MsgUpdateParamsResponse) ProtoMessage() {} func (*MsgUpdateParamsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_cb5dc4651eb49a04, []int{9} + return fileDescriptor_cb5dc4651eb49a04, []int{13} } func (m *MsgUpdateParamsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -454,6 +643,10 @@ func init() { proto.RegisterType((*MsgUpgradeClientResponse)(nil), "ibc.core.client.v1.MsgUpgradeClientResponse") proto.RegisterType((*MsgSubmitMisbehaviour)(nil), "ibc.core.client.v1.MsgSubmitMisbehaviour") proto.RegisterType((*MsgSubmitMisbehaviourResponse)(nil), "ibc.core.client.v1.MsgSubmitMisbehaviourResponse") + proto.RegisterType((*MsgRecoverClient)(nil), "ibc.core.client.v1.MsgRecoverClient") + proto.RegisterType((*MsgRecoverClientResponse)(nil), "ibc.core.client.v1.MsgRecoverClientResponse") + proto.RegisterType((*MsgIBCSoftwareUpgrade)(nil), "ibc.core.client.v1.MsgIBCSoftwareUpgrade") + proto.RegisterType((*MsgIBCSoftwareUpgradeResponse)(nil), "ibc.core.client.v1.MsgIBCSoftwareUpgradeResponse") proto.RegisterType((*MsgUpdateParams)(nil), "ibc.core.client.v1.MsgUpdateParams") proto.RegisterType((*MsgUpdateParamsResponse)(nil), "ibc.core.client.v1.MsgUpdateParamsResponse") } @@ -461,47 +654,58 @@ func init() { func init() { proto.RegisterFile("ibc/core/client/v1/tx.proto", fileDescriptor_cb5dc4651eb49a04) } var fileDescriptor_cb5dc4651eb49a04 = []byte{ - // 639 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x95, 0xbf, 0x6f, 0xd3, 0x40, - 0x14, 0xc7, 0x73, 0xfd, 0x11, 0x91, 0x6b, 0xda, 0x80, 0x15, 0x68, 0xea, 0xaa, 0x4e, 0x14, 0x18, - 0x42, 0xa1, 0x76, 0x13, 0x06, 0x22, 0x10, 0x43, 0xdb, 0x89, 0x21, 0x12, 0x72, 0xc5, 0xc2, 0x12, - 0x6c, 0xe7, 0x72, 0xb5, 0x14, 0xfb, 0x2c, 0x9f, 0x1d, 0x91, 0x0d, 0x31, 0x31, 0x82, 0xc4, 0xc2, - 0xc6, 0x9f, 0x50, 0xf1, 0x3f, 0x20, 0x75, 0xec, 0xc8, 0x84, 0x50, 0x32, 0xf4, 0xdf, 0x40, 0xf6, - 0x5d, 0x8c, 0xed, 0xc6, 0x26, 0x15, 0x9b, 0xed, 0xf7, 0x79, 0xef, 0xfb, 0x7d, 0xcf, 0xef, 0x6c, - 0xb8, 0x6b, 0xea, 0x86, 0x62, 0x10, 0x17, 0x29, 0xc6, 0xc8, 0x44, 0xb6, 0xa7, 0x8c, 0xdb, 0x8a, - 0xf7, 0x4e, 0x76, 0x5c, 0xe2, 0x11, 0x41, 0x30, 0x75, 0x43, 0x0e, 0x82, 0x32, 0x0b, 0xca, 0xe3, - 0xb6, 0xb8, 0x6d, 0x10, 0x6a, 0x11, 0xaa, 0x58, 0x14, 0x07, 0xac, 0x45, 0x31, 0x83, 0xc5, 0x2a, - 0x26, 0x98, 0x84, 0x97, 0x4a, 0x70, 0xc5, 0x9f, 0xee, 0x60, 0x42, 0xf0, 0x08, 0x29, 0xe1, 0x9d, - 0xee, 0x0f, 0x15, 0xcd, 0x9e, 0xf0, 0x50, 0x7d, 0x81, 0x34, 0xd7, 0x09, 0x81, 0xe6, 0x77, 0x00, - 0x2b, 0x3d, 0x8a, 0x4f, 0x5c, 0xa4, 0x79, 0xe8, 0x24, 0x8c, 0x08, 0x4f, 0x61, 0x99, 0x31, 0x7d, - 0xea, 0x69, 0x1e, 0xaa, 0x81, 0x06, 0x68, 0x6d, 0x74, 0xaa, 0x32, 0x93, 0x91, 0xe7, 0x32, 0xf2, - 0x91, 0x3d, 0x51, 0x37, 0x18, 0x79, 0x1a, 0x80, 0xc2, 0x0b, 0x58, 0x31, 0x88, 0x4d, 0x91, 0x4d, - 0x7d, 0xca, 0x73, 0x57, 0x72, 0x72, 0xb7, 0x22, 0x98, 0xa5, 0xdf, 0x83, 0x45, 0x6a, 0x62, 0x1b, - 0xb9, 0xb5, 0xd5, 0x06, 0x68, 0x95, 0x54, 0x7e, 0xf7, 0xac, 0xf2, 0xf1, 0x5b, 0xbd, 0xf0, 0xe1, - 0xea, 0x7c, 0x9f, 0x3f, 0x68, 0xee, 0xc0, 0xed, 0x94, 0x67, 0x15, 0x51, 0x27, 0x28, 0xd6, 0xfc, - 0xc2, 0xfa, 0x79, 0xed, 0x0c, 0xfe, 0xf6, 0xb3, 0x0b, 0x4b, 0xbc, 0x1f, 0x73, 0x10, 0x36, 0x53, - 0x52, 0x6f, 0xb1, 0x07, 0x2f, 0x07, 0xc2, 0x73, 0xb8, 0xc5, 0x83, 0x16, 0xa2, 0x54, 0xc3, 0xf9, - 0x96, 0x37, 0x19, 0xdb, 0x63, 0xe8, 0x4d, 0x1d, 0xc7, 0x5d, 0x45, 0x8e, 0x7f, 0xac, 0xc0, 0xdb, - 0x61, 0x0c, 0xbb, 0xda, 0x60, 0x29, 0xcb, 0xe9, 0xf7, 0xb3, 0xf2, 0x1f, 0xef, 0x67, 0xf5, 0x06, - 0xef, 0xe7, 0x10, 0x56, 0x1d, 0x97, 0x90, 0x61, 0xdf, 0x67, 0x5e, 0xfb, 0xac, 0x76, 0x6d, 0xad, - 0x01, 0x5a, 0x65, 0x55, 0x08, 0x63, 0xc9, 0x36, 0x8e, 0xe0, 0x5e, 0x2a, 0x23, 0x25, 0xbf, 0x1e, - 0xa6, 0x8a, 0x89, 0xd4, 0xac, 0xa5, 0x28, 0xe6, 0x8f, 0x58, 0x84, 0xb5, 0xf4, 0x18, 0xa3, 0x19, - 0x7f, 0x05, 0xf0, 0x6e, 0x8f, 0xe2, 0x53, 0x5f, 0xb7, 0x4c, 0xaf, 0x67, 0x52, 0x1d, 0x9d, 0x69, - 0x63, 0x93, 0xf8, 0x6e, 0xfe, 0xa0, 0xbb, 0xb0, 0x6c, 0xc5, 0xe0, 0xdc, 0x41, 0x27, 0xc8, 0xcc, - 0xc5, 0xb8, 0x93, 0x72, 0x5d, 0x03, 0xcd, 0x3a, 0xdc, 0x5b, 0x68, 0x2d, 0x32, 0xef, 0xc5, 0x36, - 0xfa, 0x95, 0xe6, 0x6a, 0x16, 0x8d, 0x95, 0x07, 0xf1, 0xf2, 0x42, 0x17, 0x16, 0x9d, 0x90, 0xe0, - 0x56, 0x45, 0xf9, 0xfa, 0xd7, 0x45, 0x66, 0x35, 0x8e, 0xd7, 0x2e, 0x7e, 0xd5, 0x0b, 0x2a, 0xe7, - 0xf3, 0x37, 0x96, 0x65, 0xcc, 0x0d, 0x75, 0x3e, 0xaf, 0xc1, 0xd5, 0x1e, 0xc5, 0xc2, 0x5b, 0x58, - 0x4e, 0x7c, 0x37, 0xee, 0x2f, 0x52, 0x4b, 0x1d, 0x54, 0xf1, 0xd1, 0x12, 0xd0, 0x5c, 0x29, 0x50, - 0x48, 0x9c, 0xe4, 0x2c, 0x85, 0x38, 0x94, 0xa9, 0xb0, 0xe8, 0xf4, 0x09, 0x06, 0xdc, 0x4c, 0xae, - 0xec, 0x83, 0xcc, 0xec, 0x18, 0x25, 0x3e, 0x5e, 0x86, 0x8a, 0x44, 0x5c, 0x28, 0x2c, 0x58, 0xbd, - 0x87, 0x19, 0x35, 0xae, 0xa3, 0x62, 0x7b, 0x69, 0x34, 0xd2, 0x1c, 0x42, 0x21, 0xde, 0x30, 0x5f, - 0x9c, 0xfc, 0x01, 0x32, 0xe8, 0x1f, 0x03, 0x4c, 0x2e, 0x83, 0xb8, 0xfe, 0xfe, 0xea, 0x7c, 0x1f, - 0x1c, 0xab, 0x17, 0x53, 0x09, 0x5c, 0x4e, 0x25, 0xf0, 0x7b, 0x2a, 0x81, 0x4f, 0x33, 0xa9, 0x70, - 0x39, 0x93, 0x0a, 0x3f, 0x67, 0x52, 0xe1, 0x4d, 0x17, 0x9b, 0xde, 0x99, 0xaf, 0xcb, 0x06, 0xb1, - 0x14, 0xfe, 0x5f, 0x33, 0x75, 0xe3, 0x00, 0x13, 0x65, 0xdc, 0x55, 0x2c, 0x32, 0xf0, 0x47, 0x88, - 0xb2, 0x5f, 0xd4, 0x61, 0xe7, 0x80, 0xff, 0xa5, 0xbc, 0x89, 0x83, 0xa8, 0x5e, 0x0c, 0x0f, 0xd8, - 0x93, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xe4, 0x3c, 0xd8, 0xef, 0x40, 0x07, 0x00, 0x00, + // 809 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x56, 0xb1, 0x6f, 0xd3, 0x4e, + 0x14, 0x8e, 0xd3, 0x36, 0xfa, 0xf5, 0x9a, 0x36, 0xbf, 0x1e, 0x29, 0x4d, 0x5d, 0x9a, 0x54, 0xa1, + 0x43, 0x29, 0xd4, 0x6e, 0x8a, 0x04, 0x11, 0x88, 0xa1, 0xcd, 0x42, 0x87, 0x48, 0x95, 0x2b, 0x16, + 0x96, 0x60, 0x3b, 0x97, 0xab, 0x51, 0xec, 0xb3, 0x7c, 0xe7, 0x40, 0x37, 0xc4, 0xc4, 0xc8, 0xc0, + 0xc2, 0xc6, 0x9f, 0x50, 0xf1, 0x07, 0xb0, 0x21, 0x75, 0xec, 0xc8, 0x84, 0x50, 0x3b, 0x54, 0xe2, + 0xaf, 0x40, 0xf6, 0x5d, 0x52, 0xdb, 0x89, 0x43, 0x2a, 0xb6, 0xd8, 0xef, 0x7b, 0xf7, 0xbe, 0xef, + 0xdd, 0x7b, 0x5f, 0x0c, 0x56, 0x2d, 0xc3, 0x54, 0x4d, 0xe2, 0x21, 0xd5, 0xec, 0x5a, 0xc8, 0x61, + 0x6a, 0xaf, 0xa6, 0xb2, 0xb7, 0x8a, 0xeb, 0x11, 0x46, 0x20, 0xb4, 0x0c, 0x53, 0x09, 0x82, 0x0a, + 0x0f, 0x2a, 0xbd, 0x9a, 0xbc, 0x6c, 0x12, 0x6a, 0x13, 0xaa, 0xda, 0x14, 0x07, 0x58, 0x9b, 0x62, + 0x0e, 0x96, 0x37, 0x44, 0xc0, 0x77, 0xb1, 0xa7, 0xb7, 0x91, 0xda, 0xab, 0x19, 0x88, 0xe9, 0xb5, + 0xfe, 0xb3, 0x40, 0x15, 0x31, 0xc1, 0x24, 0xfc, 0xa9, 0x06, 0xbf, 0xc4, 0xdb, 0x15, 0x4c, 0x08, + 0xee, 0x22, 0x35, 0x7c, 0x32, 0xfc, 0x8e, 0xaa, 0x3b, 0x27, 0x22, 0x54, 0x19, 0x41, 0x50, 0xb0, + 0x09, 0x01, 0xd5, 0xaf, 0x12, 0x28, 0x34, 0x29, 0x6e, 0x78, 0x48, 0x67, 0xa8, 0x11, 0x46, 0xe0, + 0x63, 0x90, 0xe7, 0x98, 0x16, 0x65, 0x3a, 0x43, 0x25, 0x69, 0x5d, 0xda, 0x9c, 0xdb, 0x2d, 0x2a, + 0xbc, 0x8c, 0xd2, 0x2f, 0xa3, 0xec, 0x39, 0x27, 0xda, 0x1c, 0x47, 0x1e, 0x05, 0x40, 0xf8, 0x0c, + 0x14, 0x4c, 0xe2, 0x50, 0xe4, 0x50, 0x9f, 0x8a, 0xdc, 0xec, 0x98, 0xdc, 0x85, 0x01, 0x98, 0xa7, + 0xdf, 0x06, 0x39, 0x6a, 0x61, 0x07, 0x79, 0xa5, 0xa9, 0x75, 0x69, 0x73, 0x56, 0x13, 0x4f, 0x4f, + 0x0a, 0x1f, 0xbe, 0x54, 0x32, 0xef, 0xaf, 0x4e, 0xb7, 0xc4, 0x8b, 0xea, 0x0a, 0x58, 0x4e, 0x70, + 0xd6, 0x10, 0x75, 0x83, 0xc3, 0xaa, 0x9f, 0xb8, 0x9e, 0x17, 0x6e, 0xfb, 0x5a, 0xcf, 0x2a, 0x98, + 0x15, 0x7a, 0xac, 0x76, 0x28, 0x66, 0x56, 0xfb, 0x8f, 0xbf, 0x38, 0x68, 0xc3, 0xa7, 0x60, 0x41, + 0x04, 0x6d, 0x44, 0xa9, 0x8e, 0xc7, 0x53, 0x9e, 0xe7, 0xd8, 0x26, 0x87, 0xde, 0x94, 0x71, 0x94, + 0xd5, 0x80, 0xf1, 0xf7, 0x2c, 0xf8, 0x3f, 0x8c, 0x85, 0x17, 0x3d, 0x09, 0xe5, 0xe4, 0xfd, 0x64, + 0xff, 0xe1, 0x7e, 0xa6, 0x6e, 0x70, 0x3f, 0x3b, 0xa0, 0xe8, 0x7a, 0x84, 0x74, 0x5a, 0x62, 0x28, + 0x5b, 0xfc, 0xec, 0xd2, 0xf4, 0xba, 0xb4, 0x99, 0xd7, 0x60, 0x18, 0x8b, 0xcb, 0xd8, 0x03, 0x6b, + 0x89, 0x8c, 0x44, 0xf9, 0x99, 0x30, 0x55, 0x8e, 0xa5, 0xa6, 0x0d, 0x45, 0x6e, 0x7c, 0x8b, 0x65, + 0x50, 0x4a, 0xb6, 0x71, 0xd0, 0xe3, 0xcf, 0x12, 0x58, 0x6a, 0x52, 0x7c, 0xe4, 0x1b, 0xb6, 0xc5, + 0x9a, 0x16, 0x35, 0xd0, 0xb1, 0xde, 0xb3, 0x88, 0xef, 0x8d, 0x6f, 0x74, 0x1d, 0xe4, 0xed, 0x08, + 0x78, 0x6c, 0xa3, 0x63, 0xc8, 0xd4, 0xc1, 0x58, 0x4c, 0xb0, 0x2e, 0x49, 0xd5, 0x0a, 0x58, 0x1b, + 0x49, 0x2d, 0x4a, 0x3e, 0x18, 0x10, 0x0d, 0x99, 0xa4, 0x87, 0x3c, 0xd1, 0xd9, 0x2d, 0xb0, 0x48, + 0x7d, 0xe3, 0x35, 0x32, 0x59, 0x2b, 0xc9, 0xbf, 0x20, 0x02, 0x8d, 0xbe, 0x8c, 0x1d, 0x50, 0xa4, + 0xbe, 0x41, 0x99, 0xc5, 0x7c, 0x86, 0x22, 0xf0, 0x6c, 0x08, 0x87, 0xd7, 0xb1, 0x41, 0xc6, 0xc4, + 0x73, 0xcd, 0x9b, 0x1e, 0xa3, 0x36, 0xe0, 0xfd, 0x8d, 0x37, 0xfd, 0x60, 0xbf, 0x71, 0x44, 0x3a, + 0xec, 0x8d, 0xee, 0x21, 0x71, 0x39, 0xf0, 0x11, 0x98, 0x76, 0xbb, 0xba, 0x23, 0x8c, 0xe5, 0x8e, + 0xc2, 0xbd, 0x4f, 0xe9, 0x7b, 0x9d, 0xf0, 0x3e, 0xe5, 0xb0, 0xab, 0x3b, 0xfb, 0xd3, 0x67, 0x3f, + 0x2b, 0x19, 0x2d, 0xc4, 0xc3, 0xe7, 0x60, 0x49, 0x60, 0xda, 0xad, 0x89, 0x37, 0xe0, 0x56, 0x3f, + 0xa5, 0x11, 0xd9, 0x84, 0x34, 0x81, 0x73, 0x51, 0x71, 0xfc, 0x66, 0x86, 0xf9, 0x0f, 0x14, 0xb2, + 0x88, 0xd7, 0x1c, 0xea, 0x9e, 0x6e, 0xd3, 0xc8, 0xc1, 0x52, 0xf4, 0x60, 0x58, 0x07, 0x39, 0x37, + 0x44, 0x08, 0xae, 0xb2, 0x32, 0xfc, 0xef, 0xa0, 0xf0, 0x33, 0x84, 0x64, 0x81, 0x1f, 0xef, 0x25, + 0x3c, 0xa3, 0x4f, 0x68, 0xf7, 0xf7, 0x0c, 0x98, 0x6a, 0x52, 0x0c, 0x5f, 0x81, 0x7c, 0xcc, 0xd1, + 0xef, 0x8e, 0xaa, 0x96, 0xb0, 0x50, 0xf9, 0xfe, 0x04, 0xa0, 0x7e, 0xa5, 0xa0, 0x42, 0xcc, 0x63, + 0xd3, 0x2a, 0x44, 0x41, 0xa9, 0x15, 0x46, 0xf9, 0x22, 0x34, 0xc1, 0x7c, 0xdc, 0x4c, 0x36, 0x52, + 0xb3, 0x23, 0x28, 0xf9, 0xc1, 0x24, 0xa8, 0x41, 0x11, 0x0f, 0xc0, 0x11, 0xa6, 0x70, 0x2f, 0xe5, + 0x8c, 0x61, 0xa8, 0x5c, 0x9b, 0x18, 0x1a, 0x15, 0x16, 0xdf, 0xe5, 0x34, 0x61, 0x31, 0x54, 0xaa, + 0xb0, 0x91, 0xcb, 0x17, 0x08, 0x1b, 0xb1, 0x78, 0x69, 0xc2, 0x86, 0xa1, 0xa9, 0xc2, 0xd2, 0xd7, + 0x01, 0x76, 0x00, 0x8c, 0xde, 0xa4, 0xd8, 0x88, 0xf1, 0x93, 0xc1, 0x41, 0x7f, 0x99, 0x8c, 0xf8, + 0x94, 0xcb, 0x33, 0xef, 0xae, 0x4e, 0xb7, 0xa4, 0x7d, 0xed, 0xec, 0xa2, 0x2c, 0x9d, 0x5f, 0x94, + 0xa5, 0x5f, 0x17, 0x65, 0xe9, 0xe3, 0x65, 0x39, 0x73, 0x7e, 0x59, 0xce, 0xfc, 0xb8, 0x2c, 0x67, + 0x5e, 0xd6, 0xb1, 0xc5, 0x8e, 0x7d, 0x43, 0x31, 0x89, 0xad, 0x8a, 0xef, 0x2a, 0xcb, 0x30, 0xb7, + 0x31, 0x51, 0x7b, 0x75, 0xd5, 0x26, 0x6d, 0xbf, 0x8b, 0x28, 0xff, 0x2a, 0xda, 0xd9, 0xdd, 0x16, + 0x1f, 0x46, 0xec, 0xc4, 0x45, 0xd4, 0xc8, 0x85, 0xd6, 0xf1, 0xf0, 0x4f, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xa3, 0x68, 0xc1, 0x10, 0xd9, 0x09, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -524,6 +728,10 @@ type MsgClient interface { UpgradeClient(ctx context.Context, in *MsgUpgradeClient, opts ...grpc.CallOption) (*MsgUpgradeClientResponse, error) // SubmitMisbehaviour defines a rpc handler method for MsgSubmitMisbehaviour. SubmitMisbehaviour(ctx context.Context, in *MsgSubmitMisbehaviour, opts ...grpc.CallOption) (*MsgSubmitMisbehaviourResponse, error) + // RecoverClient defines a rpc handler method for MsgRecoverClient. + RecoverClient(ctx context.Context, in *MsgRecoverClient, opts ...grpc.CallOption) (*MsgRecoverClientResponse, error) + // IBCSoftwareUpgrade defines a rpc handler method for MsgIBCSoftwareUpgrade. + IBCSoftwareUpgrade(ctx context.Context, in *MsgIBCSoftwareUpgrade, opts ...grpc.CallOption) (*MsgIBCSoftwareUpgradeResponse, error) // UpdateClientParams defines a rpc handler method for MsgUpdateParams. UpdateClientParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) } @@ -572,6 +780,24 @@ func (c *msgClient) SubmitMisbehaviour(ctx context.Context, in *MsgSubmitMisbeha return out, nil } +func (c *msgClient) RecoverClient(ctx context.Context, in *MsgRecoverClient, opts ...grpc.CallOption) (*MsgRecoverClientResponse, error) { + out := new(MsgRecoverClientResponse) + err := c.cc.Invoke(ctx, "/ibc.core.client.v1.Msg/RecoverClient", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) IBCSoftwareUpgrade(ctx context.Context, in *MsgIBCSoftwareUpgrade, opts ...grpc.CallOption) (*MsgIBCSoftwareUpgradeResponse, error) { + out := new(MsgIBCSoftwareUpgradeResponse) + err := c.cc.Invoke(ctx, "/ibc.core.client.v1.Msg/IBCSoftwareUpgrade", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *msgClient) UpdateClientParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) { out := new(MsgUpdateParamsResponse) err := c.cc.Invoke(ctx, "/ibc.core.client.v1.Msg/UpdateClientParams", in, out, opts...) @@ -591,6 +817,10 @@ type MsgServer interface { UpgradeClient(context.Context, *MsgUpgradeClient) (*MsgUpgradeClientResponse, error) // SubmitMisbehaviour defines a rpc handler method for MsgSubmitMisbehaviour. SubmitMisbehaviour(context.Context, *MsgSubmitMisbehaviour) (*MsgSubmitMisbehaviourResponse, error) + // RecoverClient defines a rpc handler method for MsgRecoverClient. + RecoverClient(context.Context, *MsgRecoverClient) (*MsgRecoverClientResponse, error) + // IBCSoftwareUpgrade defines a rpc handler method for MsgIBCSoftwareUpgrade. + IBCSoftwareUpgrade(context.Context, *MsgIBCSoftwareUpgrade) (*MsgIBCSoftwareUpgradeResponse, error) // UpdateClientParams defines a rpc handler method for MsgUpdateParams. UpdateClientParams(context.Context, *MsgUpdateParams) (*MsgUpdateParamsResponse, error) } @@ -611,6 +841,12 @@ func (*UnimplementedMsgServer) UpgradeClient(ctx context.Context, req *MsgUpgrad func (*UnimplementedMsgServer) SubmitMisbehaviour(ctx context.Context, req *MsgSubmitMisbehaviour) (*MsgSubmitMisbehaviourResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method SubmitMisbehaviour not implemented") } +func (*UnimplementedMsgServer) RecoverClient(ctx context.Context, req *MsgRecoverClient) (*MsgRecoverClientResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RecoverClient not implemented") +} +func (*UnimplementedMsgServer) IBCSoftwareUpgrade(ctx context.Context, req *MsgIBCSoftwareUpgrade) (*MsgIBCSoftwareUpgradeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method IBCSoftwareUpgrade not implemented") +} func (*UnimplementedMsgServer) UpdateClientParams(ctx context.Context, req *MsgUpdateParams) (*MsgUpdateParamsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method UpdateClientParams not implemented") } @@ -691,6 +927,42 @@ func _Msg_SubmitMisbehaviour_Handler(srv interface{}, ctx context.Context, dec f return interceptor(ctx, in, info, handler) } +func _Msg_RecoverClient_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgRecoverClient) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).RecoverClient(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.core.client.v1.Msg/RecoverClient", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).RecoverClient(ctx, req.(*MsgRecoverClient)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_IBCSoftwareUpgrade_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgIBCSoftwareUpgrade) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).IBCSoftwareUpgrade(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.core.client.v1.Msg/IBCSoftwareUpgrade", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).IBCSoftwareUpgrade(ctx, req.(*MsgIBCSoftwareUpgrade)) + } + return interceptor(ctx, in, info, handler) +} + func _Msg_UpdateClientParams_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(MsgUpdateParams) if err := dec(in); err != nil { @@ -729,6 +1001,14 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ MethodName: "SubmitMisbehaviour", Handler: _Msg_SubmitMisbehaviour_Handler, }, + { + MethodName: "RecoverClient", + Handler: _Msg_RecoverClient_Handler, + }, + { + MethodName: "IBCSoftwareUpgrade", + Handler: _Msg_IBCSoftwareUpgrade_Handler, + }, { MethodName: "UpdateClientParams", Handler: _Msg_UpdateClientParams_Handler, @@ -1057,7 +1337,7 @@ func (m *MsgSubmitMisbehaviourResponse) MarshalToSizedBuffer(dAtA []byte) (int, return len(dAtA) - i, nil } -func (m *MsgUpdateParams) Marshal() (dAtA []byte, err error) { +func (m *MsgRecoverClient) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -1067,37 +1347,41 @@ func (m *MsgUpdateParams) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *MsgUpdateParams) MarshalTo(dAtA []byte) (int, error) { +func (m *MsgRecoverClient) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *MsgUpdateParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *MsgRecoverClient) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - { - size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 if len(m.Signer) > 0 { i -= len(m.Signer) copy(dAtA[i:], m.Signer) i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) i-- + dAtA[i] = 0x1a + } + if len(m.SubstituteClientId) > 0 { + i -= len(m.SubstituteClientId) + copy(dAtA[i:], m.SubstituteClientId) + i = encodeVarintTx(dAtA, i, uint64(len(m.SubstituteClientId))) + i-- + dAtA[i] = 0x12 + } + if len(m.SubjectClientId) > 0 { + i -= len(m.SubjectClientId) + copy(dAtA[i:], m.SubjectClientId) + i = encodeVarintTx(dAtA, i, uint64(len(m.SubjectClientId))) + i-- dAtA[i] = 0xa } return len(dAtA) - i, nil } -func (m *MsgUpdateParamsResponse) Marshal() (dAtA []byte, err error) { +func (m *MsgRecoverClientResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -1107,12 +1391,12 @@ func (m *MsgUpdateParamsResponse) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *MsgUpdateParamsResponse) MarshalTo(dAtA []byte) (int, error) { +func (m *MsgRecoverClientResponse) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *MsgUpdateParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *MsgRecoverClientResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -1120,56 +1404,194 @@ func (m *MsgUpdateParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) return len(dAtA) - i, nil } -func encodeVarintTx(dAtA []byte, offset int, v uint64) int { - offset -= sovTx(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ +func (m *MsgIBCSoftwareUpgrade) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } - dAtA[offset] = uint8(v) - return base + return dAtA[:n], nil } -func (m *MsgCreateClient) Size() (n int) { - if m == nil { - return 0 - } + +func (m *MsgIBCSoftwareUpgrade) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgIBCSoftwareUpgrade) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - if m.ClientState != nil { - l = m.ClientState.Size() - n += 1 + l + sovTx(uint64(l)) + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0x1a } - if m.ConsensusState != nil { - l = m.ConsensusState.Size() - n += 1 + l + sovTx(uint64(l)) + if m.UpgradedClientState != nil { + { + size, err := m.UpgradedClientState.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 } - l = len(m.Signer) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + { + size, err := m.Plan.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) } - return n + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil } -func (m *MsgCreateClientResponse) Size() (n int) { - if m == nil { - return 0 +func (m *MsgIBCSoftwareUpgradeResponse) 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 *MsgIBCSoftwareUpgradeResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgIBCSoftwareUpgradeResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - return n + return len(dAtA) - i, nil } -func (m *MsgUpdateClient) Size() (n int) { - if m == nil { - return 0 +func (m *MsgUpdateParams) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } - var l int - _ = l - l = len(m.ClientId) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + return dAtA[:n], nil +} + +func (m *MsgUpdateParams) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgUpdateParamsResponse) 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 *MsgUpdateParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateParamsResponse) 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 + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgCreateClient) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ClientState != nil { + l = m.ClientState.Size() + n += 1 + l + sovTx(uint64(l)) + } + if m.ConsensusState != nil { + l = m.ConsensusState.Size() + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgCreateClientResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgUpdateClient) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ClientId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) } if m.ClientMessage != nil { l = m.ClientMessage.Size() @@ -1263,6 +1685,64 @@ func (m *MsgSubmitMisbehaviourResponse) Size() (n int) { return n } +func (m *MsgRecoverClient) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.SubjectClientId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.SubstituteClientId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgRecoverClientResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgIBCSoftwareUpgrade) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Plan.Size() + n += 1 + l + sovTx(uint64(l)) + if m.UpgradedClientState != nil { + l = m.UpgradedClientState.Size() + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgIBCSoftwareUpgradeResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + func (m *MsgUpdateParams) Size() (n int) { if m == nil { return 0 @@ -2201,6 +2681,403 @@ func (m *MsgSubmitMisbehaviourResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *MsgRecoverClient) 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: MsgRecoverClient: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRecoverClient: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SubjectClientId", 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.SubjectClientId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SubstituteClientId", 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.SubstituteClientId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signer", 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.Signer = 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 *MsgRecoverClientResponse) 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: MsgRecoverClientResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRecoverClientResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgIBCSoftwareUpgrade) 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: MsgIBCSoftwareUpgrade: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgIBCSoftwareUpgrade: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Plan", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Plan.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UpgradedClientState", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.UpgradedClientState == nil { + m.UpgradedClientState = &types.Any{} + } + if err := m.UpgradedClientState.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signer", 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.Signer = 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 *MsgIBCSoftwareUpgradeResponse) 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: MsgIBCSoftwareUpgradeResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgIBCSoftwareUpgradeResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *MsgUpdateParams) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index ab4a5874000..922c365842b 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -100,6 +100,39 @@ func (k Keeper) SubmitMisbehaviour(goCtx context.Context, msg *clienttypes.MsgSu return &clienttypes.MsgSubmitMisbehaviourResponse{}, nil } +// RecoverClient defines a rpc handler method for MsgRecoverClient. +func (k Keeper) RecoverClient(goCtx context.Context, msg *clienttypes.MsgRecoverClient) (*clienttypes.MsgRecoverClientResponse, error) { + if k.GetAuthority() != msg.Signer { + return nil, errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "expected %s, got %s", k.GetAuthority(), msg.Signer) + } + + ctx := sdk.UnwrapSDKContext(goCtx) + if err := k.ClientKeeper.RecoverClient(ctx, msg.SubjectClientId, msg.SubstituteClientId); err != nil { + return nil, errorsmod.Wrap(err, "client recovery failed") + } + + return &clienttypes.MsgRecoverClientResponse{}, nil +} + +// IBCSoftwareUpgrade defines a rpc handler method for MsgIBCSoftwareUpgrade. +func (k Keeper) IBCSoftwareUpgrade(goCtx context.Context, msg *clienttypes.MsgIBCSoftwareUpgrade) (*clienttypes.MsgIBCSoftwareUpgradeResponse, error) { + if k.GetAuthority() != msg.Signer { + return nil, errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "expected %s, got %s", k.GetAuthority(), msg.Signer) + } + + ctx := sdk.UnwrapSDKContext(goCtx) + upgradedClientState, err := clienttypes.UnpackClientState(msg.UpgradedClientState) + if err != nil { + return nil, errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "cannot unpack client state: %s", err) + } + + if err = k.ClientKeeper.ScheduleIBCSoftwareUpgrade(ctx, msg.Plan, upgradedClientState); err != nil { + return nil, errorsmod.Wrap(err, "failed to schedule upgrade") + } + + return &clienttypes.MsgIBCSoftwareUpgradeResponse{}, nil +} + // ConnectionOpenInit defines a rpc handler method for MsgConnectionOpenInit. func (k Keeper) ConnectionOpenInit(goCtx context.Context, msg *connectiontypes.MsgConnectionOpenInit) (*connectiontypes.MsgConnectionOpenInitResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) diff --git a/modules/core/keeper/msg_server_test.go b/modules/core/keeper/msg_server_test.go index 2be0075097b..84298ae0481 100644 --- a/modules/core/keeper/msg_server_test.go +++ b/modules/core/keeper/msg_server_test.go @@ -1,13 +1,18 @@ package keeper_test import ( + "errors" + upgradetypes "cosmossdk.io/x/upgrade/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" + ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" "github.com/cosmos/ibc-go/v8/modules/core/exported" "github.com/cosmos/ibc-go/v8/modules/core/keeper" ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" @@ -775,6 +780,165 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { } } +func (suite *KeeperTestSuite) TestRecoverClient() { + var msg *clienttypes.MsgRecoverClient + + testCases := []struct { + name string + malleate func() + expErr error + }{ + { + "success: recover client", + func() {}, + nil, + }, + { + "signer doesn't match authority", + func() { + msg.Signer = ibctesting.InvalidID + }, + ibcerrors.ErrUnauthorized, + }, + { + "invalid subject client", + func() { + msg.SubjectClientId = ibctesting.InvalidID + }, + clienttypes.ErrClientNotFound, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + subjectPath := ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.SetupClients(subjectPath) + subject := subjectPath.EndpointA.ClientID + subjectClientState := suite.chainA.GetClientState(subject) + + substitutePath := ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.SetupClients(substitutePath) + substitute := substitutePath.EndpointA.ClientID + + // update substitute twice + err := substitutePath.EndpointA.UpdateClient() + suite.Require().NoError(err) + err = substitutePath.EndpointA.UpdateClient() + suite.Require().NoError(err) + + tmClientState, ok := subjectClientState.(*ibctm.ClientState) + suite.Require().True(ok) + tmClientState.FrozenHeight = tmClientState.LatestHeight + suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), subject, tmClientState) + + msg = clienttypes.NewMsgRecoverClient(suite.chainA.App.GetIBCKeeper().GetAuthority(), subject, substitute) + + tc.malleate() + + _, err = keeper.Keeper.RecoverClient(*suite.chainA.App.GetIBCKeeper(), suite.chainA.GetContext(), msg) + + expPass := tc.expErr == nil + if expPass { + suite.Require().NoError(err) + + // Assert that client status is now Active + clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), subjectPath.EndpointA.ClientID) + tmClientState := subjectPath.EndpointA.GetClientState().(*ibctm.ClientState) + suite.Require().Equal(tmClientState.Status(suite.chainA.GetContext(), clientStore, suite.chainA.App.AppCodec()), exported.Active) + } else { + suite.Require().Error(err) + suite.Require().ErrorIs(err, tc.expErr) + } + }) + } +} + +// TestIBCSoftwareUpgrade tests the IBCSoftwareUpgrade rpc handler +func (suite *KeeperTestSuite) TestIBCSoftwareUpgrade() { + var msg *clienttypes.MsgIBCSoftwareUpgrade + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "success: valid authority and client upgrade", + func() {}, + nil, + }, + { + "failure: invalid authority address", + func() { + msg.Signer = suite.chainA.SenderAccount.GetAddress().String() + }, + ibcerrors.ErrUnauthorized, + }, + { + "failure: invalid clientState", + func() { + msg.UpgradedClientState = nil + }, + clienttypes.ErrInvalidClientType, + }, + { + "failure: failed to schedule client upgrade", + func() { + msg.Plan.Height = 0 + }, + sdkerrors.ErrInvalidRequest, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + path := ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.SetupClients(path) + validAuthority := suite.chainA.App.GetIBCKeeper().GetAuthority() + plan := upgradetypes.Plan{ + Name: "upgrade IBC clients", + Height: 1000, + } + // update trusting period + clientState := path.EndpointB.GetClientState() + clientState.(*ibctm.ClientState).TrustingPeriod += 100 + + var err error + msg, err = clienttypes.NewMsgIBCSoftwareUpgrade( + validAuthority, + plan, + clientState, + ) + + suite.Require().NoError(err) + + tc.malleate() + + _, err = keeper.Keeper.IBCSoftwareUpgrade(*suite.chainA.App.GetIBCKeeper(), suite.chainA.GetContext(), msg) + + if tc.expError == nil { + suite.Require().NoError(err) + // upgrade plan is stored + storedPlan, err := suite.chainA.GetSimApp().UpgradeKeeper.GetUpgradePlan(suite.chainA.GetContext()) + suite.Require().NoError(err) + suite.Require().Equal(plan, storedPlan) + + // upgraded client state is stored + bz, err := suite.chainA.GetSimApp().UpgradeKeeper.GetUpgradedClient(suite.chainA.GetContext(), plan.Height) + suite.Require().NoError(err) + upgradedClientState, err := clienttypes.UnmarshalClientState(suite.chainA.App.AppCodec(), bz) + suite.Require().NoError(err) + suite.Require().Equal(clientState.ZeroCustomFields(), upgradedClientState) + } else { + suite.Require().True(errors.Is(err, tc.expError)) + } + }) + } +} + // TestUpdateClientParams tests the UpdateClientParams rpc handler func (suite *KeeperTestSuite) TestUpdateClientParams() { signer := suite.chainA.App.GetIBCKeeper().GetAuthority() diff --git a/modules/core/module.go b/modules/core/module.go index 65d59272829..a90d6c30fe4 100644 --- a/modules/core/module.go +++ b/modules/core/module.go @@ -36,6 +36,7 @@ var ( _ module.AppModule = (*AppModule)(nil) _ module.AppModuleBasic = (*AppModuleBasic)(nil) _ module.AppModuleSimulation = (*AppModule)(nil) + _ module.HasProposalMsgs = (*AppModule)(nil) _ appmodule.HasBeginBlocker = (*AppModule)(nil) _ appmodule.AppModule = (*AppModule)(nil) ) @@ -195,6 +196,11 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) { simulation.RandomizedGenState(simState) } +// ProposalMsgs returns msgs used for governance proposals for simulations. +func (AppModule) ProposalMsgs(simState module.SimulationState) []simtypes.WeightedProposalMsg { + return simulation.ProposalMsgs() +} + // RegisterStoreDecoder registers a decoder for ibc module's types func (am AppModule) RegisterStoreDecoder(sdr simtypes.StoreDecoderRegistry) { sdr[exported.StoreKey] = simulation.NewDecodeStore(*am.keeper) diff --git a/modules/core/simulation/proposals.go b/modules/core/simulation/proposals.go new file mode 100644 index 00000000000..2607ba1dd1c --- /dev/null +++ b/modules/core/simulation/proposals.go @@ -0,0 +1,60 @@ +package simulation + +import ( + "math/rand" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/simulation" + + "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" +) + +// Simulation operation weights constants +const ( + DefaultWeightMsgUpdateParams int = 100 + + OpWeightMsgUpdateParams = "op_weight_msg_update_params" // #nosec +) + +// ProposalMsgs defines the module weighted proposals' contents +func ProposalMsgs() []simtypes.WeightedProposalMsg { + return []simtypes.WeightedProposalMsg{ + simulation.NewWeightedProposalMsg( + OpWeightMsgUpdateParams, + DefaultWeightMsgUpdateParams, + SimulateClientMsgUpdateParams, + ), + simulation.NewWeightedProposalMsg( + OpWeightMsgUpdateParams, + DefaultWeightMsgUpdateParams, + SimulateConnectionMsgUpdateParams, + ), + } +} + +// SimulateClientMsgUpdateParams returns a random MsgUpdateParams for 02-client +func SimulateClientMsgUpdateParams(r *rand.Rand, _ sdk.Context, _ []simtypes.Account) sdk.Msg { + var signer sdk.AccAddress = address.Module("gov") + params := types.DefaultParams() + params.AllowedClients = []string{"06-solomachine", "07-tendermint"} + + return &types.MsgUpdateParams{ + Signer: signer.String(), + Params: params, + } +} + +// SimulateConnectionMsgUpdateParams returns a random MsgUpdateParams 03-connection +func SimulateConnectionMsgUpdateParams(r *rand.Rand, _ sdk.Context, _ []simtypes.Account) sdk.Msg { + var signer sdk.AccAddress = address.Module("gov") + params := connectiontypes.DefaultParams() + params.MaxExpectedTimePerBlock = uint64(100) + + return &connectiontypes.MsgUpdateParams{ + Signer: signer.String(), + Params: params, + } +} diff --git a/modules/core/simulation/proposals_test.go b/modules/core/simulation/proposals_test.go new file mode 100644 index 00000000000..285f440fa0f --- /dev/null +++ b/modules/core/simulation/proposals_test.go @@ -0,0 +1,57 @@ +package simulation_test + +import ( + "math/rand" + "testing" + + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + + cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" + + "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" + "github.com/cosmos/ibc-go/v8/modules/core/simulation" +) + +func TestProposalMsgs(t *testing.T) { + // initialize parameters + s := rand.NewSource(1) + r := rand.New(s) + + ctx := sdk.NewContext(nil, cmtproto.Header{}, true, nil) + accounts := simtypes.RandomAccounts(r, 3) + + // execute ProposalMsgs function + weightedProposalMsgs := simulation.ProposalMsgs() + require.Equal(t, 2, len(weightedProposalMsgs)) + + w0 := weightedProposalMsgs[0] + + // tests w0 interface: + require.Equal(t, simulation.OpWeightMsgUpdateParams, w0.AppParamsKey()) + require.Equal(t, simulation.DefaultWeightMsgUpdateParams, w0.DefaultWeight()) + + msg := w0.MsgSimulatorFn()(r, ctx, accounts) + msgUpdateParams, ok := msg.(*types.MsgUpdateParams) + require.True(t, ok) + + require.Equal(t, sdk.AccAddress(address.Module("gov")).String(), msgUpdateParams.Signer) + require.EqualValues(t, []string{"06-solomachine", "07-tendermint"}, msgUpdateParams.Params.AllowedClients) + + w1 := weightedProposalMsgs[1] + + // tests w1 interface: + require.Equal(t, simulation.OpWeightMsgUpdateParams, w1.AppParamsKey()) + require.Equal(t, simulation.DefaultWeightMsgUpdateParams, w1.DefaultWeight()) + + msg1 := w1.MsgSimulatorFn()(r, ctx, accounts) + msgUpdateConnectionParams, ok := msg1.(*connectiontypes.MsgUpdateParams) + require.True(t, ok) + + require.Equal(t, sdk.AccAddress(address.Module("gov")).String(), msgUpdateParams.Signer) + require.EqualValues(t, uint64(100), msgUpdateConnectionParams.Params.MaxExpectedTimePerBlock) +} diff --git a/proto/ibc/core/client/v1/client.proto b/proto/ibc/core/client/v1/client.proto index afb22be397d..5da8f86a3a2 100644 --- a/proto/ibc/core/client/v1/client.proto +++ b/proto/ibc/core/client/v1/client.proto @@ -6,8 +6,6 @@ option go_package = "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"; import "gogoproto/gogo.proto"; import "google/protobuf/any.proto"; -import "cosmos/upgrade/v1beta1/upgrade.proto"; -import "cosmos_proto/cosmos.proto"; // IdentifiedClientState defines a client state with an additional client // identifier field. @@ -36,45 +34,6 @@ message ClientConsensusStates { repeated ConsensusStateWithHeight consensus_states = 2 [(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; - option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content"; - // 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; - // the substitute client identifier for the client standing in for the subject - // client - string substitute_client_id = 4; -} - -// 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; - option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content"; - - 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; -} - // Height is a monotonically increasing data type // that can be compared against another Height for the purposes of updating and // freezing clients diff --git a/proto/ibc/core/client/v1/tx.proto b/proto/ibc/core/client/v1/tx.proto index c3f8deeda96..d7f8e2f97a0 100644 --- a/proto/ibc/core/client/v1/tx.proto +++ b/proto/ibc/core/client/v1/tx.proto @@ -5,6 +5,7 @@ package ibc.core.client.v1; option go_package = "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"; import "cosmos/msg/v1/msg.proto"; +import "cosmos/upgrade/v1beta1/upgrade.proto"; import "gogoproto/gogo.proto"; import "google/protobuf/any.proto"; import "ibc/core/client/v1/client.proto"; @@ -25,6 +26,12 @@ service Msg { // SubmitMisbehaviour defines a rpc handler method for MsgSubmitMisbehaviour. rpc SubmitMisbehaviour(MsgSubmitMisbehaviour) returns (MsgSubmitMisbehaviourResponse); + // RecoverClient defines a rpc handler method for MsgRecoverClient. + rpc RecoverClient(MsgRecoverClient) returns (MsgRecoverClientResponse); + + // IBCSoftwareUpgrade defines a rpc handler method for MsgIBCSoftwareUpgrade. + rpc IBCSoftwareUpgrade(MsgIBCSoftwareUpgrade) returns (MsgIBCSoftwareUpgradeResponse); + // UpdateClientParams defines a rpc handler method for MsgUpdateParams. rpc UpdateClientParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); } @@ -111,6 +118,44 @@ message MsgSubmitMisbehaviour { // type. message MsgSubmitMisbehaviourResponse {} +// MsgRecoverClient defines the message used to recover a frozen or expired client. +message MsgRecoverClient { + option (gogoproto.goproto_getters) = false; + option (cosmos.msg.v1.signer) = "signer"; + + // the client identifier for the client to be updated if the proposal passes + string subject_client_id = 1; + // the substitute client identifier for the client which will replace the subject + // client + string substitute_client_id = 2; + + // signer address (it may be the the address that controls the module, which defaults to x/gov unless overwritten). + string signer = 3; +} + +// MsgRecoverClientResponse defines the Msg/RecoverClient response type. +message MsgRecoverClientResponse {} + +// MsgIBCSoftwareUpgrade defines the message used to schedule an upgrade of an IBC client using a v1 governance proposal +message MsgIBCSoftwareUpgrade { + option (cosmos.msg.v1.signer) = "signer"; + cosmos.upgrade.v1beta1.Plan plan = 1 [(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. Correspondingly, the UpgradedClientState field has been + // deprecated in the Cosmos SDK to allow for this logic to exist solely in + // the 02-client module. + google.protobuf.Any upgraded_client_state = 2; + // signer defaults to the governance account address unless otherwise specified. + string signer = 3; +} + +// MsgIBCSoftwareUpgradeResponse defines the Msg/IBCSoftwareUpgrade response type. +message MsgIBCSoftwareUpgradeResponse {} + // MsgUpdateParams defines the sdk.Msg type to update the client parameters. message MsgUpdateParams { option (cosmos.msg.v1.signer) = "signer"; @@ -127,4 +172,4 @@ message MsgUpdateParams { } // MsgUpdateParamsResponse defines the MsgUpdateParams response type. -message MsgUpdateParamsResponse {} \ No newline at end of file +message MsgUpdateParamsResponse {} diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 491e796e350..3fd6110046b 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -121,9 +121,6 @@ import ( ibctransferkeeper "github.com/cosmos/ibc-go/v8/modules/apps/transfer/keeper" ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" ibc "github.com/cosmos/ibc-go/v8/modules/core" - ibcclient "github.com/cosmos/ibc-go/v8/modules/core/02-client" - ibcclientclient "github.com/cosmos/ibc-go/v8/modules/core/02-client/client" - ibcclienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" ibckeeper "github.com/cosmos/ibc-go/v8/modules/core/keeper" @@ -414,9 +411,7 @@ func NewSimApp( // See: https://docs.cosmos.network/main/modules/gov#proposal-messages govRouter := govv1beta1.NewRouter() govRouter.AddRoute(govtypes.RouterKey, govv1beta1.ProposalHandler). - AddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(app.ParamsKeeper)). - AddRoute(ibcclienttypes.RouterKey, ibcclient.NewClientProposalHandler(app.IBCKeeper.ClientKeeper)) - + AddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(app.ParamsKeeper)) govConfig := govtypes.DefaultConfig() /* Example of setting gov params: @@ -612,8 +607,6 @@ func NewSimApp( govtypes.ModuleName: gov.NewAppModuleBasic( []govclient.ProposalHandler{ paramsclient.ProposalHandler, - ibcclientclient.UpdateClientProposalHandler, - ibcclientclient.UpgradeProposalHandler, }, ), }) diff --git a/testing/values.go b/testing/values.go index 6459112a1cd..2741b1a5fed 100644 --- a/testing/values.go +++ b/testing/values.go @@ -21,6 +21,7 @@ import ( const ( FirstClientID = "07-tendermint-0" + SecondClientID = "07-tendermint-1" FirstChannelID = "channel-0" FirstConnectionID = "connection-0"