Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IBC Upgrade docs #8298

Merged
merged 12 commits into from
Jan 20, 2021
40 changes: 40 additions & 0 deletions docs/ibc/upgrades/developer-guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# IBC Client Developer Guide to Upgrades
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# IBC Client Developer Guide to Upgrades
# IBC Client Upgrade Guide

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This document is specifically for developers who are trying to implement an IBC client. It is not relevant for end users. Is there a better title you had in mind that makes it clear this is for developers?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, it's just that client developer sounds like wallets, exchanges, etc. Maybe light client devs?

AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

As mentioned in the [overview](./overview.md), it is vital that high-value IBC clients can upgrade along with their underlying chains to avoid disruption to the IBC ecosystem. Thus, IBC client developers will want to implement upgrade functionality to enable clients to maintain connections and channels even across chain upgrades.

The IBC protocol allows client implementations to provide a path to upgrading clients given the upgraded client state, upgraded consensus state and proofs for each.

```go
// Upgrade functions
// NOTE: proof heights are not included as upgrade to a new revision is expected to pass only on the last
// height committed by the current revision. Clients are responsible for ensuring that the planned last
// height of the current revision is somehow encoded in the proof verification process.
// This is to ensure that no premature upgrades occur, since upgrade plans committed to by the counterparty
// may be cancelled or modified before the last planned height.
VerifyUpgradeAndUpdateState(
ctx sdk.Context,
cdc codec.BinaryMarshaler,
store sdk.KVStore,
newClient ClientState,
newConsState ConsensusState,
proofUpgradeClient,
proofUpgradeConsState []byte,
) (upgradedClient ClientState, upgradedConsensus ConsensusState, err error)
```

Note that the clients should have prior knowledge of the merkle path that the upgraded client and upgraded consensus states will use. The height at which the upgrade has occurred should also be encoded in the proof. In the Tendermint client implementation, the upgrade height is encoded in the proof key.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that the clients should have prior knowledge of the merkle path that the upgraded client and upgraded consensus states will use

where do clients know this info? I'd be nice to add that


Developers must ensure that the `UpgradeClientMsg` does not pass until the last height of the old chain has been committed, and after the chain upgrades, the `UpgradeClientMsg` should pass once and only once on all counterparty clients.

Upgrades must also adhere to the IBC Security Model. IBC does not rely on the assumption of honest relayers. While relayers may choose any set of client parameters while creating a new `Client`, this still holds under the model since users can always choose a relayer-created client that suits their security and correctness needs or create a Client with their desired parameters. However, when upgrading an existing client, one must keep in mind that there are already many users who depend on this client's particular parameters. Thus, we cannot give the upgrading relayer free choice over these parameters once they have already been chosen. Developers must make sure that their upgrade mechanism allows clients to upgrade the chain-specified parameters whenever a chain upgrade changes these parameters (examples in the Tendermint client include `UnbondingPeriod`, `ChainID`, `UpgradePath`, etc.), while ensuring that the relayer submitting the `UpgradeClientMsg` cannot alter the client-chosen parameters that the users are relying upon (examples in Tendermint client include `TrustingPeriod`, `TrustLevel`, `MaxClockDrift`, etc).
colin-axner marked this conversation as resolved.
Show resolved Hide resolved
colin-axner marked this conversation as resolved.
Show resolved Hide resolved
colin-axner marked this conversation as resolved.
Show resolved Hide resolved

Developers should maintain this distinction between Client parameters that are uniform across every valid light client of a chain (chain-chosen parameters), and Client parameters that are customizable by each individual client (client-chosen parameters); since this distinction is necessary to implement the `ZeroCustomFields` method in the `ClientState` interface:
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

```go
// Utility function that zeroes out any client customizable fields in client state
// Ledger enforced fields are maintained while all custom fields are zero values
// Used to verify upgrades
ZeroCustomFields() ClientState
```

Counterparty clients can upgrade securely by using all of the chain-chosen parameters from the chain-committed `UpgradedClient` and preserving all of the old client-chosen parameters. This enables chains to securely upgrade without relying on an honest relayer, however it can in some cases lead to an invalid final `ClientState` if the new chain-chosen parameters clash with the old client-chosen parameter. This can happen in the Tendermint client case if the upgrading chain lowers the `UnbondingPeriod` (chain-chosen) to a duration below that of a counterparty client's `TrustingPeriod` (client-chosen). Such cases should be clearly documented by developers, so that chains know which upgrades should be avoided to prevent this problem. The final upgraded client should also be validated in `VerifyUpgradeAndUpdateState` before returning to ensure that the client does not upgrade to an invalid `ClientState`.
8 changes: 8 additions & 0 deletions docs/ibc/upgrades/overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
### Upgrading IBC Chains Overview
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto


This directory contains information on how to upgrade an IBC chain without breaking counterparty clients and connections.

IBC-connnected chains must be able to upgrade without breaking connections to other chains. Otherwise there would be a massive disincentive towards upgrading and disrupting high-value IBC connections, thus preventing chains in the IBC ecosystem from evolving and improving. Many chain upgrades may be irrelevant to IBC, however some upgrades could potentially break counterparty clients if not handled correctly. Thus, any IBC chain that wishes to perform a IBC-client-breaking upgrade must perform an IBC upgrade in order to allow counterparty clients to securely upgrade to the new light client.

1. The [quick-guide](./quick-guide.md) describes how IBC-connected chains can perform client-breaking upgrades and how relayers can securely upgrade counterparty clients using the SDK.
2. The [developer-guide](./developer-guide.md) is a guide for developers intending to develop IBC client implementations with upgrade functionality.
44 changes: 44 additions & 0 deletions docs/ibc/upgrades/quick-guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# How to Upgrade IBC Chains and their Clients
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand the difference with the first doc from this title

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doc is intended for the end users of the upgrade process. Relayers and stake holders of the upgrading chain.


The information in this doc for upgrading chains is relevant to SDK chains. However, the guide for counterparty clients is relevant to any Tendermint client that enables upgrades.

## Upgrading Chains
colin-axner marked this conversation as resolved.
Show resolved Hide resolved


### IBC Client Breaking Upgrades
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should outline the types of upgrades that clients could encounter (planned, unplanned) and with breaking an non-breaking state machine changes. This doc should also document the recommended steps for each of the 4 combinations

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup good point. Currently unplanned upgrades are not supported. All of the cases given only apply if they are planned.

Will write this point in.


IBC-connected chains must perform an IBC upgrade if their upgrade will break counterparty IBC clients. The current IBC protocol supports upgrading tendermint chains for a specific subset of IBC-client-breaking upgrades. Here is the exhaustive list of IBC client-breaking upgrades and whether the IBC protocol currently supports such upgrades.
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

Note: Since upgrades are only implemented for Tendermint clients, this doc only discusses upgrades on Tendermint chains that would break counterparty IBC Tendermint Clients.

1. Changing the Chain-ID: **Supported**
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Future improvements may turn this list to a flowchart

2. Changing the UnbondingPeriod: **Partially Supported**, chains may increase the unbonding period with no issues. However, decreasing the unbonding period may irreversibly break some counterparty clients. Thus, it is **not recommended** that chains reduce the unbonding period.
3. Changing the height (resetting to 0): **Supported**, so long as chains remember to increment the revision number in their chain-id.
4. Changing the ProofSpecs: **Supported**, this should be changed if the proof structure needed to verify IBC proofs is changed across the upgrade. Ex: Switching from an IAVL store, to a SimpleTree Store
5. Changing the UpgradePath: **Supported**, this might involve changing the key under which upgraded clients and consensus states are stored in the upgrade store, or even migrating the upgrade store itself.
6. Migrating the IBC store: **Unsupported**, as the IBC store location is negotiated by the connection.
7. Upgrading to a IBC path-breaking version of IBC: **Unsupported**, as IBC version is negotiated on connection handshake.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't it supported so long as the old versions use the old path? Adding support for a new version with new path should be supported

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider chainA and chainB are connected by an IBC channel. chainA decides to upgrade to a different version of IBC such that the paths in 24-host have changed. The client on chainB needs to upgrade its Verification methods to use the new paths.

This is theoretically possible by using the upgraded client state and then "converting" it into a new type that implements the different Verification method.

However, the IBC version that is used is negotiated in the connection. So that field needs to change as well which isn't supported with client upgrades.

Upgrading and breaking IBC paths is theoretically possible, it just isn't implemented yet and client upgrades alone will not upgrade the connection.

Technically the new IBC version could also store information in the old paths as well, and thus create "backwards-compatibility" for old connections, but this wouldn't be path breaking.

cc: @cwgoes

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer to avoid duplicating storage, though it is possible. Generally upgrading the version of IBC is a completely separate concern from upgrading a particular light client algorithm, and it should be treated as such - for example, the IBC version needs to be agreed on by both ends, while the light client versions are independent.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(sorry, I may have misunderstood the original comment - the light client upgrades should support changing paths used by the light client algorithm, but not IBC protocol paths in general, I think)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could add this for clarity. It may not be immediately clear what a IBC path-breaking version of IBC is. But it's really just a non-backwards compatible version of IBC (IBC 2.0) ie we cannot upgrade IBC connection or channel versions with this upgrade mechanism

8. Changing the Tendermint LightClient algorithm: **Partially Supported**. Changes to the light client algorithm that do not change the ClientState or ConsensusState struct may be supported, provided that the counterparty is also upgraded to support the new light client algorithm. Changes that require updating the ClientState and ConsensusState structs themselves are theoretically possible by providing a path to translate an older ClientState struct into the new ClientState struct; however this is not currently implemented.

### Upgrade Process for SDK chains

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 `SoftwareUpgradeProposal` with an `UpgradePlan` that includes the new IBC ClientState in the `UpgradedClientState`. 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).

Upon the `SoftwareUpgradeProposal` 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`.

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.

### Upgrade Process for Relayers Upgrading Counterparty Clients

Once the upgrading chain has committed to upgrading, relayers must wait till the chain halts at the upgrade height before upgrading counterparty clients. This is because chains may reschedule or cancel upgrade plans before they occur. Thus, relayers must wait till the chain reaches the upgrade height and halts before they can be sure the upgrade will take place.

Thus, the upgrade process for relayers trying to upgrade the counterparty clients is as follows:

1. Wait for the upgrading chain to reach the upgrade height and halt
2. Query a full node for the proofs of `UpgradedClient` and `UpgradedConsensusState` at the last height of the old chain.
3. Update the counterparty client to the last height of the old chain using the `UpdateClient` msg.
4. Submit an `UpgradeClient` msg to the counterpart chain with the `UpgradedClient`, `UpgradedConsensusState` and their respective proofs.
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

The Tendermint client on the counterparty chain will verify that the upgrading chain did indeed commit to the upgraded client and upgraded consensus state at the upgrade height (since the upgrade height is included in the key). If the proofs are verified against the upgrade height, then the client will upgrade to the new client while retaining all of its client-customized fields. Thus, it will retain its old TrustingPeriod, TrustLevel, MaxClockDrift, etc; while adopting the new chain-specified fields such as UnbondingPeriod, ChainId, UpgradePath, etc. Note, this can lead to an invalid client since the old client-chosen fields may no longer be valid given the new chain-chosen fields. Upgrading chains should try to avoid these situations by not altering parameters that can break old clients. For an example, see the UnbondingPeriod example in the supported upgrades section.
colin-axner marked this conversation as resolved.
Show resolved Hide resolved