upgrade-client.md
4.52 Kb · 123 lines
1# UpgradeClient
2
3`core.UpgradeClient` follows a counterparty chain through a **breaking**
4upgrade — an upgrade that `UpdateClient` cannot absorb because the chain
5itself changes shape. Typical triggers:
6
7- `ChainID` change (signed in every header).
8- Revision-number bump (encoded in `Height`, propagates into header
9 signing).
10- Validator-set discontinuity (a hard fork that doesn't preserve the
11 trust graph).
12- Security-parameter changes the client carries — `UnbondingPeriod`,
13 `ProofSpecs`, `UpgradePath`.
14
15```gno
16core.UpgradeClient(cross, clientID,
17 upgradedClient, upgradedConsState,
18 proofUpgradeClient, proofUpgradeConsState)
19```
20
21Gated by `ensureAuthorizedRelayer()`.
22
23## Lifecycle
24
25### 1. Counterparty schedules the upgrade
26
27Before the upgrade height the counterparty chain commits the upgraded
28`ClientState` and `ConsensusState` to its upgrade store at well-known
29paths derived from the client's `UpgradePath` (the SDK upgrade module
30default is `["upgrade", "upgradedIBCState"]`):
31
32- `{UpgradePath[0]}/{UpgradePath[1]}/{H}/upgradedClient`
33- `{UpgradePath[0]}/{UpgradePath[1]}/{H}/upgradedConsState`
34
35`H` is the upgrade plan height (just the height number, not a revision
36pair). The committed bytes are `cdc.MarshalInterface(...)`-style:
37wrapped in `google.protobuf.Any` with the corresponding type URL.
38
39The committed `ClientState` has its client-customizable fields
40(`TrustLevel`, `TrustingPeriod`, `MaxClockDrift`, `FrozenHeight`) zeroed
41out — only the chain-specified fields (`ChainID`, `UnbondingPeriod`,
42`LatestHeight`, `ProofSpecs`, `UpgradePath`) are committed. The
43committed `ConsensusState` carries a sentinel `Root` because the
44upgraded chain hasn't produced any blocks yet at commit time.
45
46### 2. Relayer reads and submits
47
48Once the chain has reached the upgrade height, a relayer reads the
49committed states and the corresponding ICS-23 membership proofs and
50calls `UpgradeClient`. Each proof is a chained `[]ics23.CommitmentProof`
51matching the client's `ProofSpecs` (typically 2 proofs: an IAVL
52existence proof for the inner key and a multistore existence proof for
53the store name).
54
55### 3. Verification
56
57The realm checks:
58
59- `UpgradePath` on the current client is non-empty.
60- `LatestHeight` of the upgraded client is greater than the current
61 latest height.
62- The relayer's submitted client/consensus states reconstruct the bytes
63 the chain committed: the `ClientState` is wrapped in
64 `google.protobuf.Any` with its customizable fields zeroed
65 (`ZeroCustomFields`), the `ConsensusState` is wrapped in `Any` as-is.
66- Both chained proofs verify membership under the current client's
67 latest consensus root.
68
69### 4. State transition
70
71A new `ClientState` is built by mixing fields (see below). The stored
72consensus state has its `Root` overwritten with the sentinel value so it
73cannot be used to verify packet proofs — by construction. Real roots
74arrive afterwards via `UpdateClient` once the new chain is producing
75headers.
76
77### 5. Resume
78
79Subsequent `UpdateClient` calls bring real headers from the new chain;
80packet flow resumes against those real consensus states.
81
82## Preconditions
83
84- The client exists and the caller is in the relayer whitelist.
85- The client's `UpgradePath` is set.
86- The client's status is `Active`.
87- The upgraded client's `LatestHeight` is greater than the current
88 latest height.
89- Both proofs verify membership of the upgraded client and consensus
90 state at the upgrade path under the current latest consensus root.
91
92## Field mapping
93
94On success the new `ClientState` is built by combining:
95
96- **Taken from the upgraded client** (chain-specified): `ChainID`,
97 `UnbondingPeriod`, `LatestHeight`, `ProofSpecs`, `UpgradePath`.
98- **Preserved from the current client** (customizable): `TrustLevel`,
99 `TrustingPeriod`, `MaxClockDrift`.
100- **Reset**: `FrozenHeight`.
101
102If the unbonding period shrank, `TrustingPeriod` is scaled
103proportionally so the security ratio is preserved:
104
105 newTrusting = trusting * newUnbonding / currentUnbonding (truncated)
106
107The math is performed in seconds; sub-second precision is irrelevant for
108trusting periods which are measured in days.
109
110## Generating proofs for testing
111
112`cmd/gen-proof` provides an `upgrade` subcommand that mounts an
113`upgrade` IAVL store, commits the upgraded client/consensus state at
114the SDK upgrade keys (`upgradedIBCState/{H}/upgradedClient`,
115`upgradedIBCState/{H}/upgradedConsState`), and dumps Go literals for the
116chained proofs:
117
118```bash
119go run -C ./cmd/gen-proof . upgrade
120```
121
122The output is suitable for embedding in a filetest. See
123`z10c_upgrade_client_filetest.gno` for the full happy-path scenario.