高价值 IBC 客户端能够与其底层链一同升级,对于避免 IBC 生态系统中断至关重要。因此,IBC 客户端开发者应实现升级功能,使客户端即使在链升级期间也能维持连接和通道。

实现 VerifyUpgradeAndUpdateState

IBC 协议允许客户端实现在给定升级后的 ClientState、升级后的 ConsensusState 以及两者各自证明的情况下,提供一条升级客户端的路径。该路径由 VerifyUpgradeAndUpdateState 方法提供:
/ 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.
/ If the upgrade is verified, the upgraded client and consensus states must be set in the client store.
func (l LightClientModule)

VerifyUpgradeAndUpdateState(
  ctx sdk.Context,
  clientID string,
  newClient []byte,
  newConsState []byte,
  upgradeClientProof,
  upgradeConsensusStateProof []byte,
)

error
请参考 Tendermint 轻客户端实现 作为实现示例。
需要特别注意的是,轻客户端必须自行处理客户端状态和共识状态的全部管理工作,包括在客户端存储中设置更新后的 ClientState 和 ConsensusState。这可以包括:验证提交的升级后 ClientState 是否为有效的 ClientState 类型;验证升级后客户端的高度不大于当前客户端的高度(以保持 BFT 单调时间);以及验证某些不应被修改的参数在升级后的 ClientState 中没有被更改。 开发者必须确保 MsgUpgradeClient 在旧链的最后一个高度提交之前不能通过;在链升级之后,MsgUpgradeClient 应当在所有对手方客户端上通过一次且仅通过一次。

升级路径

客户端应当预先知道用于升级后客户端状态和升级后共识状态的 merkle 路径。升级发生的高度也应编码进证明中。
Tendermint 客户端实现通过在 ClientState 本身中包含 UpgradePath 来实现这一点,并结合升级高度构造提交客户端状态和共识状态所使用的 merkle 路径。

链特定参数与客户端特定参数

开发者应保持清晰区分两类客户端参数:一类是在某条链上的所有有效轻客户端之间都一致的参数(由链选择的参数),另一类是每个客户端可单独自定义的参数(由客户端选择的参数)。 在升级客户端时,开发者必须确保新客户端采用所有必须在某条链上的每个有效轻客户端之间保持一致的新客户端参数(由链选择的参数),同时保留前一个版本客户端中那些可由各个客户端单独自定义的参数(由客户端选择的参数)。

安全性

升级必须遵循 IBC 安全模型。IBC 的正确性并不依赖诚实中继者这一假设。因此,用户不应依赖中继者来维持客户端的正确性和安全性(尽管为了维持中继活性,必须存在诚实的中继者)。虽然中继者在创建新的 ClientState 时可以选择任意一组客户端参数,但这依然符合安全模型,因为用户始终可以选择一个由中继者创建且满足其安全性与正确性需求的客户端;如果不存在这样的客户端,用户也可以使用自己期望的参数创建一个客户端。 然而,在升级现有客户端时,必须牢记已经有许多用户依赖该客户端的特定参数。一旦这些参数已经被选定,我们就不能让执行升级的中继者对这些参数拥有自由选择权。这会违反安全模型,因为依赖该客户端的用户将不得不依赖升级中继者来维持相同级别的安全性。 因此,开发者必须确保其升级机制允许客户端在链升级改变这些参数时升级由链指定的参数(Tendermint 客户端中的示例包括 UnbondingPeriod、TrustingPeriod、ChainID、UpgradePath 等),同时确保提交 MsgUpgradeClient 的中继者不能修改用户所依赖的那些由客户端选择的参数(Tendermint 客户端中的示例包括 TrustLevel、MaxClockDrift 等)。

在升级期间记录潜在的客户端参数冲突

对手方客户端可以通过采用链上已提交的 UpgradedClient 中所有由链选择的参数,并保留所有旧的由客户端选择的参数,来实现安全升级。这使链能够在不依赖诚实中继者的情况下安全升级;但在某些情况下,如果新的由链选择的参数与旧的由客户端选择的参数发生冲突,也可能导致最终的 ClientState 无效。在 Tendermint 客户端的场景中,如果执行升级的链将 UnbondingPeriod(由链选择)降低到低于某个对手方客户端的 TrustingPeriod(由客户端选择)的时长,就可能发生这种情况。开发者应清晰记录这些情形,以便各条链了解应避免哪些升级,从而防止出现该问题。在 VerifyUpgradeAndUpdateState 返回之前,也应验证最终升级后的客户端,以确保客户端不会升级到无效的 ClientState。
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.

Implementing VerifyUpgradeAndUpdateState

The IBC protocol allows client implementations to provide a path to upgrading clients given the upgraded ClientState, upgraded ConsensusState and proofs for each. This path is provided in the VerifyUpgradeAndUpdateState method:
/ 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.
/ If the upgrade is verified, the upgraded client and consensus states must be set in the client store.
func (l LightClientModule)

VerifyUpgradeAndUpdateState(
  ctx sdk.Context,
  clientID string,
  newClient []byte,
  newConsState []byte,
  upgradeClientProof,
  upgradeConsensusStateProof []byte,
)

error
Please refer to the Tendermint light client implementation as an example for implementation.
It is important to note that light clients must handle all management of client and consensus states including the setting of updated ClientState and ConsensusState in the client store. This can include verifying that the submitted upgraded ClientState is of a valid ClientState type, that the height of the upgraded client is not greater than the height of the current client (in order to preserve BFT monotonic time), or that certain parameters which should not be changed have not been altered in the upgraded ClientState. Developers must ensure that the MsgUpgradeClient does not pass until the last height of the old chain has been committed, and after the chain upgrades, the MsgUpgradeClient should pass once and only once on all counterparty clients.

Upgrade path

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.
The Tendermint client implementation accomplishes this by including an UpgradePath in the ClientState itself, which is used along with the upgrade height to construct the merkle path under which the client state and consensus state are committed.

Chain specific vs client specific client parameters

Developers should maintain the 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). When upgrading a client, developers must ensure that the new client adopts all of the new client parameters that must be uniform across every valid light client of a chain (chain-chosen parameters), while maintaining the client parameters that are customizable by each individual client (client-chosen parameters) from the previous version of the client.

Security

Upgrades must adhere to the IBC Security Model. IBC does not rely on the assumption of honest relayers for correctness. Thus users should not have to rely on relayers to maintain client correctness and security (though honest relayers must exist to maintain relayer liveness). While relayers may choose any set of client parameters while creating a new ClientState, this still holds under the security 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 if no such client exists. 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. We cannot give the upgrading relayer free choice over these parameters once they have already been chosen. This would violate the security model since users who rely on the client would have to rely on the upgrading relayer to maintain the same level of security. Thus, 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, TrustingPeriod, ChainID, UpgradePath, etc), while ensuring that the relayer submitting the MsgUpgradeClient cannot alter the client-chosen parameters that the users are relying upon (examples in Tendermint client include TrustLevel, MaxClockDrift, etc).

Document potential client parameter conflicts during upgrades

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.