-
Notifications
You must be signed in to change notification settings - Fork 616
How to upgrade a client
This is a step-by-step guide of how to upgrade an IBC client. The example explained in this guide assumes the following:
- Two chains (with chain IDs
chain1
andchain2
):- running locally with a single validator node,
- that start from clean state,
- with 2 accounts (1 validator, 1 wallet).
-
chain1
's REST API runs onhttp://localhost:27001
andchain2
's REST API runs onhttp://localhost:27011
. - The chain binary for both chains is the
simd
binary of ibc-go forv5.0.0-rc1
. - The relayer used is hermes v1.0.0.
Therefore based on your own situation, you might need to adjust the parameters or commands presented here.
We are going to upgrade the client state on chain1
with a change to the unbonding period. The light client of the counterparty chain2
will be updated with the new unbonding period.
This guide is relevant only for Tendermint chains that would break counterparty IBC Tendermint Clients.
Some other useful resources:
- How to Upgrade IBC Chains and their Clients for the ibc-go documentation.
- Testing Client Upgrade from hermes documentation.
For the purposes of this example we are going to change some of the gov
parameters in the genesis.json
file, so that we can complete the upgrade faster. These are the changes needed in the genesis.json
of chain1
:
"gov": {
"starting_proposal_id": "1",
"deposits": [],
"votes": [],
"proposals": [],
"deposit_params": {
"min_deposit": [
{
"denom": "stake",
- "amount": "10000000"
+ "amount": "100"
}
],
"max_deposit_period": "172800s"
},
"voting_params": {
- "voting_period": "172800s"
+ "voting_period": "180s"
},
"tally_params": {
"quorum": "0.334000000000000000",
- "threshold": "0.500000000000000000",
+ "threshold": "0.300000000000000000",
"veto_threshold": "0.334000000000000000"
}
},
When we upgrade the client state of chain1
, light clients for chain1
on counterparty chains will need to be updated. So we create a light client on chain2
using hermes:
> hermes create client --host-chain chain2 --reference-chain chain1
The light client creation succeeds and it is initialized with the consensus state of chain1
at height 28:
SUCCESS CreateClient(
CreateClient(
Attributes {
height: Height {
revision: 0,
height: 29,
},
client_id: ClientId(
"07-tendermint-0",
),
client_type: Tendermint,
consensus_height: Height {
revision: 0,
height: 28,
},
},
),
)
We can use now ibc-go's REST interface to check the existence of the client state for chain1
by simply entering
http://localhost:27011/ibc/core/client/v1/client_states/07-tendermint-0
on the browser address bar (note that, in my case, the REST API for chain2
is running on localhost:27011
):
{
"client_state": {
"@type": "/ibc.lightclients.tendermint.v1.ClientState",
"chain_id": "chain1",
"trust_level": {
"numerator": "1",
"denominator": "3"
},
"trusting_period": "1209600s",
"unbonding_period": "1814400s",
"max_clock_drift": "40s",
"frozen_height": {
"revision_number": "0",
"revision_height": "0"
},
"latest_height": {
"revision_number": "0",
"revision_height": "28"
},
"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"
],
"allow_update_after_expiry": true,
"allow_update_after_misbehaviour": true
},
"proof": null,
"proof_height": {
"revision_number": "0",
"revision_height": "37"
}
}
We need now to prepare an UpgradeProposal
with an upgrade plan that contains the new IBC client state in the upgraded_client_state
field. The upgrade plan must specify an upgrade height only (no upgrade time), and the client state should only include the fields common to all valid clients and zero out any client-customizable fields (such as the trusting period). Using the client state retrieved from chain2
's REST API, we create the following upgraded client state with a new unbonding_period
of
2419200s
:
{
"@type": "/ibc.lightclients.tendermint.v1.ClientState",
"chain_id": "chain1",
"unbonding_period": "2419200s",
"latest_height": {
"revision_number": "0",
"revision_height": "201"
},
"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"
]
}
And we store this in a file called upgraded_client_state.json
.
We use the CLI command to submit an upgrade proposal to plan the upgrade to happen at height 200:
simd tx gov submit-legacy-proposal ibc-upgrade increase-unbonding-period 200 ./upgraded_client_state.json \
--title increase-unbonding-period \
--description increase-unbonding-period \
--deposit 100stake \
--from validator \
--chain-id chain1 \
--keyring-backend test \
--home ../../gm/chain1 \
--node http://localhost:27000
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.
And now we can check that the proposal has been accepted and it has entered the voting period:
> simd q gov proposals --node http://localhost:27000
pagination:
next_key: null
total: "0"
proposals:
- deposit_end_time: "2022-09-17T18:46:25.607417Z"
final_tally_result:
abstain_count: "0"
no_count: "0"
no_with_veto_count: "0"
yes_count: "0"
id: "1"
messages:
- '@type': /cosmos.gov.v1.MsgExecLegacyContent
authority: cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn
content:
'@type': /ibc.core.client.v1.UpgradeProposal
description: increase-unbonding-period
plan:
height: "200"
info: ""
name: increase-unbonding-period
time: "0001-01-01T00:00:00Z"
upgraded_client_state: null
title: increase-unbonding-period
upgraded_client_state:
'@type': /ibc.lightclients.tendermint.v1.ClientState
allow_update_after_expiry: false
allow_update_after_misbehaviour: false
chain_id: chain1
frozen_height:
revision_height: "0"
revision_number: "0"
latest_height:
revision_height: "201"
revision_number: "0"
max_clock_drift: 0s
proof_specs:
- inner_spec:
child_order:
- 0
- 1
child_size: 33
empty_child: null
hash: SHA256
max_prefix_length: 12
min_prefix_length: 4
leaf_spec:
hash: SHA256
length: VAR_PROTO
prefix: AA==
prehash_key: NO_HASH
prehash_value: SHA256
max_depth: 0
min_depth: 0
- inner_spec:
child_order:
- 0
- 1
child_size: 32
empty_child: null
hash: SHA256
max_prefix_length: 1
min_prefix_length: 1
leaf_spec:
hash: SHA256
length: VAR_PROTO
prefix: AA==
prehash_key: NO_HASH
prehash_value: SHA256
max_depth: 0
min_depth: 0
trust_level:
denominator: "0"
numerator: "0"
trusting_period: 0s
unbonding_period: 2419200s
upgrade_path:
- upgrade
- upgradedIBCState
metadata: ""
status: PROPOSAL_STATUS_VOTING_PERIOD
submit_time: "2022-09-15T18:46:25.607417Z"
total_deposit:
- amount: "100"
denom: stake
voting_end_time: "2022-09-15T18:48:25.607417Z"
voting_start_time: "2022-09-15T18:46:25.607417Z"
Now we vote for the proposal:
simd tx gov vote 1 yes \
--from validator \
--chain-id chain1 \
--keyring-backend test \
--home ../../gm/chain1 \
--node http://localhost:27000
And we wait for the voting period to end. Once it ends we can check that the proposal has passed (i.e. the status has changed from PROPOSAL_STATUS_VOTING_PERIOD
to PROPOSAL_STATUS_PASSED
):
> simd q gov proposals --node http://localhost:27000
pagination:
next_key: null
total: "0"
proposals:
- deposit_end_time: "2022-09-17T18:46:25.607417Z"
final_tally_result:
abstain_count: "0"
no_count: "0"
no_with_veto_count: "0"
yes_count: "10000000"
id: "1"
messages:
- '@type': /cosmos.gov.v1.MsgExecLegacyContent
authority: cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn
content:
'@type': /ibc.core.client.v1.UpgradeProposal
description: increase-unbonding-period
plan:
height: "200"
info: ""
name: increase-unbonding-period
time: "0001-01-01T00:00:00Z"
upgraded_client_state: null
title: increase-unbonding-period
upgraded_client_state:
'@type': /ibc.lightclients.tendermint.v1.ClientState
allow_update_after_expiry: false
allow_update_after_misbehaviour: false
chain_id: chain1
frozen_height:
revision_height: "0"
revision_number: "0"
latest_height:
revision_height: "201"
revision_number: "0"
max_clock_drift: 0s
proof_specs:
- inner_spec:
child_order:
- 0
- 1
child_size: 33
empty_child: null
hash: SHA256
max_prefix_length: 12
min_prefix_length: 4
leaf_spec:
hash: SHA256
length: VAR_PROTO
prefix: AA==
prehash_key: NO_HASH
prehash_value: SHA256
max_depth: 0
min_depth: 0
- inner_spec:
child_order:
- 0
- 1
child_size: 32
empty_child: null
hash: SHA256
max_prefix_length: 1
min_prefix_length: 1
leaf_spec:
hash: SHA256
length: VAR_PROTO
prefix: AA==
prehash_key: NO_HASH
prehash_value: SHA256
max_depth: 0
min_depth: 0
trust_level:
denominator: "0"
numerator: "0"
trusting_period: 0s
unbonding_period: 2419200s
upgrade_path:
- upgrade
- upgradedIBCState
metadata: ""
status: PROPOSAL_STATUS_PASSED
submit_time: "2022-09-15T18:46:25.607417Z"
total_deposit:
- amount: "100"
denom: stake
voting_end_time: "2022-09-15T18:48:25.607417Z"
voting_start_time: "2022-09-15T18:46:25.607417Z"
Before we can create a connection between chain1
and chain2
we need to update the unbonding_time
of the staking params. This is needed because chain1
will validate, during connection creation, that the counterparty chain2
has stored the correct values for the client state (which includes the unbonding period). To be able to perform the validation for the value of the unbonding period, chain1
will retrieve the unbonding_time
from the staking keeper and therefore this value needs to match the unbonding_period
in the client state stored on chain2
(which will be updated after the upgrade succeeds).
We use the REST interface to query the staking params of chain1
by simply entering http://localhost:27001/cosmos/staking/v1beta1/params
on the address bar of the browser:
{
"params": {
"unbonding_time": "1814400s",
"max_validators": 100,
"max_entries": 7,
"historical_entries": 10000,
"bond_denom": "stake",
"min_commission_rate": "0.000000000000000000"
}
}
We submit a proposal to perform a param change:
simd tx gov submit-legacy-proposal param-change ./params_change.json \
--from validator \
--chain-id chain1 \
--keyring-backend test \
--home ../../gm/chain1 \
--node http://localhost:27000
with the following content in the param_change.json
file:
{
"title": "Staking Param Change",
"description": "Update unbonding period",
"changes": [
{
"subspace": "staking",
"key": "UnbondingTime",
"value": "2419200000000000"
}
],
"deposit": "100stake"
}
We check that the proposal has been accepted and it has entered the voting period:
> simd q gov proposals --node http://localhost:27000
- deposit_end_time: "2022-09-17T18:50:53.755022Z"
final_tally_result:
abstain_count: "0"
no_count: "0"
no_with_veto_count: "0"
yes_count: "0"
id: "2"
messages:
- '@type': /cosmos.gov.v1.MsgExecLegacyContent
authority: cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn
content:
'@type': /cosmos.params.v1beta1.ParameterChangeProposal
changes:
- key: UnbondingTime
subspace: staking
value: '"2419200000000000"'
description: Update unbonding period
title: Staking Param Change
metadata: ""
status: PROPOSAL_STATUS_VOTING_PERIOD
submit_time: "2022-09-15T18:50:53.755022Z"
total_deposit:
- amount: "100"
denom: stake
voting_end_time: "2022-09-15T18:52:53.755022Z"
voting_start_time: "2022-09-15T18:50:53.755022Z"
Once the voting period ends, we check again and see that the proposal has passed:
> simd q gov proposals --node http://localhost:27000
- deposit_end_time: "2022-09-17T18:50:53.755022Z"
final_tally_result:
abstain_count: "0"
no_count: "0"
no_with_veto_count: "0"
yes_count: "10000000"
id: "2"
messages:
- '@type': /cosmos.gov.v1.MsgExecLegacyContent
authority: cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn
content:
'@type': /cosmos.params.v1beta1.ParameterChangeProposal
changes:
- key: UnbondingTime
subspace: staking
value: '"2419200000000000"'
description: Update unbonding period
title: Staking Param Change
metadata: ""
status: PROPOSAL_STATUS_PASSED
submit_time: "2022-09-15T18:50:53.755022Z"
total_deposit:
- amount: "100"
denom: stake
voting_end_time: "2022-09-15T18:52:53.755022Z"
voting_start_time: "2022-09-15T18:50:53.755022Z"
If we make a query for the staking params of chain1
using the REST API http://localhost:27001/cosmos/staking/v1beta1/params
we can see that the unbonding_time
has been updated to 2419200 seconds:
{
"params": {
"unbonding_time": "2419200s",
"max_validators": 100,
"max_entries": 7,
"historical_entries": 10000,
"bond_denom": "stake",
"min_commission_rate": "0.000000000000000000"
}
}
We can now instruct hermes to wait for chain1
to halt and then it will perform the upgrade for client 07-tendermint-0
on chain2
.
hermes upgrade client --host-chain chain2 --client 07-tendermint-0 --upgrade-height 200
When chain1
halts we can check the logs of the chain and see that it has panicked at the expected block height:
[90m8:59PM[0m [1m[31mERR[0m[0m UPGRADE "increase-unbonding-period" NEEDED at height: 200:
[90m8:59PM[0m [1m[31mERR[0m[0m CONSENSUS FAILURE!!! [36merr=[0m"UPGRADE \"increase-unbonding-period\" NEEDED at height: 200: " [36mmodule=[0mconsensus [36mstack=[0m"goroutine 88 [running]:\nruntime/debug.Stack()\n\truntime/debug/stack.go:24 +0x65\ngit.luolix.top/tendermint/tendermint/consensus.(*State).receiveRoutine.func2()\n\tgit.luolix.top/tendermint/tendermint@v0.34.21/consensus/state.go:727 +0x4c\npanic({0x575a120, 0xc001413d10})\n\truntime/panic.go:838 +0x207\ngit.luolix.top/cosmos/cosmos-sdk/x/upgrade.BeginBlocker({{0x7ffeefbff6b0, 0x34}, 0xc00112ed20, {0x6478950, 0xc000e17210}, {0x6498f88, 0xc0005de420}, 0xc0013d33e0, {0x64716e0, 0xc000555180}, ...}, ...)\n\tgit.luolix.top/cosmos/cosmos-sdk@v0.46.1/x/upgrade/abci.go:56 +0xf94\ngit.luolix.top/cosmos/cosmos-sdk/x/upgrade.AppModule.BeginBlock(...)\n\tgit.luolix.top/cosmos/cosmos-sdk@v0.46.1/x/upgrade/module.go:134\ngit.luolix.top/cosmos/cosmos-sdk/types/module.(*Manager).BeginBlock(_, {{0x648d340, 0xc000126008}, {0x649a880, 0xc0075838c0}, {{0xb, 0x0}, {0xc001360470, 0x6}, 0xc8, ...}, ...}, ...)\n\tgit.luolix.top/cosmos/cosmos-sdk@v0.46.1/types/module/module.go:481 +0x398\ngit.luolix.top/cosmos/ibc-go/v5/testing/simapp.(*SimApp).BeginBlocker(_, {{0x648d340, 0xc000126008}, {0x649a880, 0xc0075838c0}, {{0xb, 0x0}, {0xc001360470, 0x6}, 0xc8, ...}, ...}, ...)\n\tgit.luolix.top/cosmos/ibc-go/v5/testing/simapp/app.go:649 +0x7b\ngit.luolix.top/cosmos/cosmos-sdk/baseapp.(*BaseApp).BeginBlock(_, {{0xc00715e580, 0x20, 0x20}, {{0xb, 0x0}, {0xc001360470, 0x6}, 0xc8, {0x107e2b0, ...}, ...}, ...})\n\tgit.luolix.top/cosmos/cosmos-sdk@v0.46.1/baseapp/abci.go:200 +0x843\ngit.luolix.top/tendermint/tendermint/abci/client.(*localClient).BeginBlockSync(_, {{0xc00715e580, 0x20, 0x20}, {{0xb, 0x0}, {0xc001360470, 0x6}, 0xc8, {0x107e2b0, ...}, ...}, ...})\n\tgit.luolix.top/tendermint/tendermint@v0.34.21/abci/client/local_client.go:280 +0x118\ngit.luolix.top/tendermint/tendermint/proxy.(*appConnConsensus).BeginBlockSync(_, {{0xc00715e580, 0x20, 0x20}, {{0xb, 0x0}, {0xc001360470, 0x6}, 0xc8, {0x107e2b0, ...}, ...}, ...})\n\tgit.luolix.top/tendermint/tendermint@v0.34.21/proxy/app_conn.go:81 +0x55\ngit.luolix.top/tendermint/tendermint/state.execBlockOnProxyApp({0x648e338?, 0xc0010d3440}, {0x6493d18, 0xc00141c410}, 0xc002fe1e00, {0x649a108, 0xc00000e1f8}, 0xc7?)\n\tgit.luolix.top/tendermint/tendermint@v0.34.21/state/execution.go:307 +0x3dd\ngit.luolix.top/tendermint/tendermint/state.(*BlockExecutor).ApplyBlock(_, {{{0xb, 0x0}, {0xc000de28f0, 0x7}}, {0xc000de28f8, 0x6}, 0x1, 0xc7, {{0xc007ac1920, ...}, ...}, ...}, ...)\n\tgit.luolix.top/tendermint/tendermint@v0.34.21/state/execution.go:140 +0x171\ngit.luolix.top/tendermint/tendermint/consensus.(*State).finalizeCommit(0xc00121ee00, 0xc8)\n\tgit.luolix.top/tendermint/tendermint@v0.34.21/consensus/state.go:1659 +0xafd\ngit.luolix.top/tendermint/tendermint/consensus.(*State).tryFinalizeCommit(0xc00121ee00, 0xc8)\n\tgit.luolix.top/tendermint/tendermint@v0.34.21/consensus/state.go:1568 +0x2ff\ngit.luolix.top/tendermint/tendermint/consensus.(*State).enterCommit.func1()\n\tgit.luolix.top/tendermint/tendermint@v0.34.21/consensus/state.go:1503 +0x87\ngit.luolix.top/tendermint/tendermint/consensus.(*State).enterCommit(0xc00121ee00, 0xc8, 0x0)\n\tgit.luolix.top/tendermint/tendermint@v0.34.21/consensus/state.go:1541 +0xcb7\ngit.luolix.top/tendermint/tendermint/consensus.(*State).addVote(0xc00121ee00, 0xc006757360, {0x0, 0x0})\n\tgit.luolix.top/tendermint/tendermint@v0.34.21/consensus/state.go:2155 +0xb7c\ngit.luolix.top/tendermint/tendermint/consensus.(*State).tryAddVote(0xc00121ee00, 0xc006757360, {0x0?, 0x4079c66?})\n\tgit.luolix.top/tendermint/tendermint@v0.34.21/consensus/state.go:1953 +0x2c\ngit.luolix.top/tendermint/tendermint/consensus.(*State).handleMsg(0xc00121ee00, {{0x64727a0?, 0xc0000bbd88?}, {0x0?, 0x0?}})\n\tgit.luolix.top/tendermint/tendermint@v0.34.21/consensus/state.go:856 +0x44b\ngit.luolix.top/tendermint/tendermint/consensus.(*State).receiveRoutine(0xc00121ee00, 0x0)\n\tgit.luolix.top/tendermint/tendermint@v0.34.21/consensus/state.go:783 +0x512\ncreated by github.com/tendermint/tendermint/consensus.(*State).OnStart\n\tgit.luolix.top/tendermint/tendermint@v0.34.21/consensus/state.go:379 +0x12d\n"
And hermes has performed the upgrade successfully:
SUCCESS [
UpdateClient(
h: 0-200, cs_h: 07-tendermint-0(0-200),
),
UpgradeClient(
UpgradeClient(
Attributes {
height: Height {
revision: 0,
height: 200,
},
client_id: ClientId(
"07-tendermint-0",
),
client_type: Tendermint,
consensus_height: Height {
revision: 0,
height: 201,
},
},
),
),
]
We use ibc-go's REST interface to check the client state for chain1
on chain2
by simply entering
http://localhost:27011/ibc/core/client/v1/client_states/07-tendermint-0
on the browser address bar:
{
"client_state": {
"@type": "/ibc.lightclients.tendermint.v1.ClientState",
"chain_id": "chain1",
"trust_level": {
"numerator": "1",
"denominator": "3"
},
"trusting_period": "1209600s",
"unbonding_period": "2419200s",
"max_clock_drift": "40s",
"frozen_height": {
"revision_number": "0",
"revision_height": "0"
},
"latest_height": {
"revision_number": "0",
"revision_height": "201"
},
"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"
],
"allow_update_after_expiry": true,
"allow_update_after_misbehaviour": true
},
"proof": null,
"proof_height": {
"revision_number": "0",
"revision_height": "230"
}
}
And we can see that the unbonding_period
has correctly been updated to 2419200s
.
We know prepare a new binary for chain1
that include the following upgrade handler:
app.UpgradeKeeper.SetUpgradeHandler("increase-unbonding-period",
func(ctx sdk.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
return app.mm.RunMigrations(ctx, app.configurator, fromVM)
})
We swap the binary for chain1
and restart:
[90m9:03PM[0m [32mINF[0m applying upgrade "increase-unbonding-period" at height: 200
The upgrade has concluded and chain1
is running again.
We create a light client for chain2
on chain1
:
hermes create client --host-chain chain1 --reference-chain chain2
SUCCESS CreateClient(
CreateClient(
Attributes {
height: Height {
revision: 0,
height: 225,
},
client_id: ClientId(
"07-tendermint-0",
),
client_type: Tendermint,
consensus_height: Height {
revision: 0,
height: 260,
},
},
),
)
Now both chain1
and chain2
have a light client of each other and we can now create a connection:
hermes --config config.toml create connection --a-chain chain1 --a-client 07-tendermint-0 --b-client 07-tendermint-0
SUCCESS Connection {
delay_period: 0ns,
a_side: ConnectionSide {
chain: BaseChainHandle {
chain_id: ChainId {
id: "chain1",
version: 0,
},
runtime_sender: Sender { .. },
},
client_id: ClientId(
"07-tendermint-0",
),
connection_id: Some(
ConnectionId(
"connection-0",
),
),
},
b_side: ConnectionSide {
chain: BaseChainHandle {
chain_id: ChainId {
id: "chain2",
version: 0,
},
runtime_sender: Sender { .. },
},
client_id: ClientId(
"07-tendermint-0",
),
connection_id: Some(
ConnectionId(
"connection-0",
),
),
},
}
The connection creation succeeded, which means that chain1
's validation for its client state stored on chain2
passed.