-
Couldn't load subscription status.
- Fork 729
Connection handshake
This document attempts to explore IBC's connection handshake in detail. The goals of this tutorial are:
- Explore the code of hermes and ibc-go that makes connection handshake possible.
- Understand the data passed in the connection handshake messages and how/where it is obtained.
Some other useful resources:
- Transport, Authentication, and Ordering Layer - Connections in Cosmos Developer Portal.
- Hermes ADR 002.
- Setup
- Assumptions
- ICS-03 store paths
- Connection handshake
- Two chains (
chain1andchain2) running ib-go'ssimdbinary. -
chain1's RPC endpoint runs onhttp://localhost:27000and REST API runs onhttp://localhost:27001. -
chain2's RPC endpoint runs onhttp://localhost:27010and REST API runs onhttp://localhost:27011. - hermes relayer.
This document is updated for ibc-go v4.0.0 and hermes 1.0.0.
This tutorial assumes that both chains have already gone through the creation of a light client for the counterparty chain. In this tutorial the client ID of the light client on both chains is 07-tendermint-0.
Connection-related information is stored in the IBC store:
| key | value |
|---|---|
[]byte("nextConnectionSequence") |
Next available connection sequence |
[]byte("connections/" + {connection-id}) |
Connection end |
[]byte("clients/" + {clientID} + "/connections") |
Set of connection IDs associated with a particular client ID |
Before creating a connection between chain1 and chain2 we need to create the light client on each chain tracking the counterparty's consensus state (see hermes documentation for more details):
> hermes --config config.toml create client \
--host-chain chain2 \
--reference-chain chain1
SUCCESS CreateClient(
CreateClient(
Attributes {
client_id: ClientId(
"07-tendermint-0",
),
client_type: Tendermint,
consensus_height: Height {
revision: 0,
height: 120,
},
},
),
)> hermes --config config.toml create client \
--host-chain chain1 \
--reference-chain chain2
SUCCESS CreateClient(
CreateClient(
Attributes {
client_id: ClientId(
"07-tendermint-0",
),
client_type: Tendermint,
consensus_height: Height {
revision: 0,
height: 58,
},
},
),
)It's possible to trigger a connection handshake between chain1 and chain2 with just executing:
> hermes --config config.toml create connection \
--a-chain chain1 \
--a-client 07-tendermint-0 \
--b-client 07-tendermint-0
But in this guide we will execute each step of the handshake independently.
All the connection handshake logic in hermes happens in the handshake function.
At a high level the process looks like the following:
In the first step of the connection handshake the relayer submits MsgConnectionOpenInit on chain1 (see the message proto definition).
In hermes the MsgConnectionOpenInit is constructed and sent in function build_conn_init_and_send. More specifically, the message is constructed in build_conn_init.
The parameters needed to construct MsgConnectionOpenInit are:
It's the client ID of the light client on chain1 (07-tendermint-0 in this tutorial).
It is constructed here:
-
client_idis the client ID of the light client onchain2(07-tendermint-0in this tutorial). -
connection_idis empty, sincechain2does not have a connection end with a connection ID yet. -
prefixis assigned at the moment the value read from the config file of hermes. In the future this value could be queried fromchain2. This prefix is the store prefix used by the on-chain IBC module for Cosmos-SDK chains and at the moment isibc.
It is assigned the default value. In the future this value could also be queried from chain2. This default value matches ibc-go's DefaultIBCVersion ("identifier": "1", "features": ["ORDER_ORDERED", "ORDER_UNORDERED"]).
It is assigned the value entered in the command line parameter of the create connection command of hermes, if any; otherwise it takes the default value 0. The delay period is the time that must pass before a consensus state can be used for packet verification.
It is the address of the relayer that submits the message.
Using hermes to submit this message on chain1 we execute the following command:
> hermes --config config.toml tx conn-init \
--dst-chain chain1 \
--src-chain chain2 \
--dst-client 07-tendermint-0 \
--src-client 07-tendermint-0
From the hermes log we can retrieve the hash of the transaction that executed MsgConnectionOpenInit:
2022-09-24T19:23:18.561753Z DEBUG ThreadId(13) send_tx_commit{id=ConnectionOpenInit}:send_tx_with_account_sequence_retry{id=chain1}: broadcast_tx_sync: Response { code: Ok, data: Data([]), log: Log("[]"), hash: transaction::Hash(7B2B567446610826C7F523632E03FB7DD919C82A41F21C6886DD369B90CBCD1B) }
And we can use this hash to get the transaction information using Tendermint's /tx RPC endpoint:
http://localhost:27000/tx?hash=0x7B2B567446610826C7F523632E03FB7DD919C82A41F21C6886DD369B90CBCD1B
See sample JSON result.
The transaction was successfully executed and included in the block at height 142. The value in the field result.tx is a base64-encoded string of the bytes of the messages that were executed as part of the transaction. This transaction contains only one message (MsgConnectionOpenInit) and if we decode these bytes we can retrieve back the message data that the relayer submitted:
> simd tx decode CusBCrABCi0vaWJjLmNvcmUuY29ubmVjdGlvbi52MS5Nc2dDb25uZWN0aW9uT3BlbkluaXQSfwoPMDctdGVuZGVybWludC0wEhgKDzA3LXRlbmRlcm1pbnQtMBoFCgNpYmMaIwoBMRINT1JERVJfT1JERVJFRBIPT1JERVJfVU5PUkRFUkVEKi1jb3Ntb3MxOWVuZXB6M3B3eGQ1ZGd1Y3EycXAycjhsNXlubTkwZ3B0ZjUybnYSNmhlcm1lcyAxLjAuMCtlZDRkZDhjIChodHRwczovL2hlcm1lcy5pbmZvcm1hbC5zeXN0ZW1zKRJlClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiEC4bLJKTkOe1oQftx4VX/S1yuAvSno3Z7WiJKEGqqQuAwSBAoCCAEYARIRCgsKBXN0YWtlEgI3NxDs1wQaQNKA9LVye1hnc09Vsga8fqjaXpGciuz/SrAKOvF11dCFXFqb5ogZREQOMx83FlfLVxkI/5VLVV8D3Mxyk3FFlSw=
See sample JSON result.
In particular the MsgConnectionOpenInit looks like this:
{
"@type":"/ibc.core.connection.v1.MsgConnectionOpenInit",
"client_id":"07-tendermint-0",
"counterparty":{
"client_id":"07-tendermint-0",
"connection_id":"",
"prefix":{
"key_prefix":"aWJj"
}
},
"version":{
"identifier":"1",
"features":[
"ORDER_ORDERED",
"ORDER_UNORDERED"
]
},
"delay_period":"0",
"signer":"cosmos19enepz3pwxd5dgucq2qp2r8l5ynm90gptf52nv"
}The key prefix is the string ibc in base64 format. The counterparty here is chain2, which does not have a connection ID yet.
After the message reaches the message server the execution continues in ConnectionKeeper's ConnOpenInit function, to which the message fields are passed in. The steps in ConnOpenInit consist of:
-
types.GetCompatibleVersionsreturns the latest supported version of IBC used in connection version negotiation. These versions will be used in the creation of the connection end if the message does not provide any or the one provided is not supported.types.IsSupportedVersionreturnstrueif the proposed version has a matching version in the list of compatible versions. - A new connection identifier is generated by retrieving the next connection sequence from the store. In this tutorial, the generated connection ID is
connection-0. - A new
ConnectionEndis instantiated with the information from the message and with the stateSTATE_INIT. The connection end is stored under the keyconnections/connection-0. The connection ID is also added to the set of connections associated with the client (which is stored under keyclients/07-tendermint-0/connectionsin this tutorial). - An event is emitted signalling that the connection open init has finished successfully. From the event information (which can also be found in the field
result.tx_result.logof the transaction that includedMsgConnectionOpenInit) it is possible to figure out what connection ID this new connection end has:
[
{
"events":[
{
"type":"connection_open_init",
"attributes":[
{
"key":"connection_id",
"value":"connection-0"
},
{
"key":"client_id",
"value":"07-tendermint-0"
},
{
"key":"counterparty_client_id",
"value":"07-tendermint-0"
},
{
"key":"counterparty_connection_id"
}
]
},
{
"type":"message",
"attributes":[
{
"key":"action",
"value":"/ibc.core.connection.v1.MsgConnectionOpenInit"
},
{
"key":"module",
"value":"ibc_connection"
}
]
}
]
}
]After MsgConnectionOpenInit successfully executes, there is a connection end stored on chain1. We can use ibc-go's REST interface to check the existence of the connection end with connection ID connection-0 by simply entering http://localhost:27001/ibc/core/connection/v1/connections/connection-0 and check that the state of the connection is STATE_INIT:
{
"connection": {
"client_id": "07-tendermint-0",
"versions": [
{
"identifier": "1",
"features": [
"ORDER_ORDERED",
"ORDER_UNORDERED"
]
}
],
"state": "STATE_INIT",
"counterparty": {
"client_id": "07-tendermint-0",
"connection_id": "",
"prefix": {
"key_prefix": "aWJj"
}
},
"delay_period": "0"
},
"proof": null,
"proof_height": {
"revision_number": "0",
"revision_height": "151"
}
}After MsgConnectionOpenInit succeeds on chain1, then the relayer submits MsgConnectionOpenTry on chain2 (see the message proto definition).
In hermes MsgConnectionOpenTry is constructed and sent in function build_conn_try_and_send. More specifically, the message is constructed in build_conn_try.
To build MsgConnectionOpenInit hermes queries chain1 at a certain height to get proofs for the following things:
- A proof that
chain1has stored a connection end with connection IDconnection-0and stateSTATE_INIT. - A proof that
chain1has stored for the light client with client ID07-tendermint-0the client state forchain2. - A proof that
chain1has stored for the light client with client ID07-tendermint-0the consensus state forchain2.
In this tutorial the height at which hermes is going to query chain1 for these proofs is 174 (we know this because we will see that hermes has submitted together with MsgConnectionOpenTry a MsgUpdateClient that updates the client state of chain1 on chain2 to the height 175, this is because the hash after applying all transactions in block 174 is included in block at height 175). The query height is obtained here by querying Tendermint's /status RPC endpoint and
reading the values for result.node_info.network (which is the revision number, chain1) and result.sync_info.latest_block_height (which is the revision height, 174).
The parameters needed to construct MsgConnectionOpenTry are:
it is the client ID of the light client on chain2 (07-tendermint-0 in this tutorial).
It is the connection ID for the connection end on chain2 in case there exists a connection already in state STATE_INIT. The way hermes figures this out is by sending a query request to ibc-go's gRPC query endpoint for a single connection. This query returns the connection end on chain1, which includes the counterparty information with its respective connection_id (for chain2). In this tutorial the previous_connection_id is empty, since there is no connection on chain2 in state STATE_INIT and therefore there is no connection end on chain2.
Note: This field is now unused. Crossing hellos are no longer supported in core IBC.
It is the client state for chain2 that chain1 has stored. It is retrieved here by performing an ABCI RPC query to the ibc store of chain1. The query uses the query height (174 in this tutorial). We will see a sample of the client state data in the proof_client item a bit further down.
It is constructed here:
-
client_idis the client ID of the light client onchain1(07-tendermint-0in this tutorial). -
connection_idis the connection ID for the connection end onchain1, which isconnection-0in this tutorial. -
prefixis determined here at the moment in a similar way as it was done forMsgConnectionOpenInit(i.e. reading the valueibcfrom the config file of hermes).
It is determined here.
It gets assigned here the versions from the connection end on chain1, if they exist; or the default, otherwise (as done similarly for MsgConnectionOpenInit).
It is the height for the commitment root for proving the proofs for init, client and consensus. When creating these proofs, chain1 is queried at height proof_height - 1 (174 in this tutorial). The reason why proof_height (175 in this tutorial) is query_height + 1 is because for Tendermint chains the hash after applying all transactions in block n is included in block at height n + 1.
It is obtained by performing an ABCI RPC query to the ibc store of chain1. This proof is used to verify that chain1 has stored a connection end with state STATE_INIT at the query height (174 in this tutorial). We can make the same ABCI RPC query on the browser by simply using Tendermint's /abci_query REST endpoint:
path: "store/ibc/key"
data: "connections/connection-0" (in hex: 0x636f6e6e656374696f6e732f636f6e6e656374696f6e2d30)
prove: true (so that the response contains the merkle proof)
height: 174
URL: http://localhost:27000/abci_query?path="store/ibc/key"&data=0x636f6e6e656374696f6e732f636f6e6e656374696f6e2d30&prove=true&height=174
See sample JSON response.
The response to this ABCI RPC query contains both the value stored at the queried path (connections/connection-0) and the proof needed to verify it. If we take the base64-encoded byte string from the value for the field result.response.value and we decode it, then we can inspect the information for the connection end stored in chain1:
{
ClientId:07-tendermint-0
Versions:[
identifier:"1"
features:"ORDER_ORDERED"
features:"ORDER_UNORDERED"
]
State:STATE_INIT
Counterparty:{
ClientId:07-tendermint-0
ConnectionId:
Prefix: {
KeyPrefix:[105 98 99]
}
}
DelayPeriod:0
}
We see that the connection end is in state STATE_INIT. The key_prefix is the byte representation of the string ibc.
It is obtained by performing an ABCI RPC query to the ibc store of chain1. This proof is used to verify that that chain1 has stored at the query height (174 in this tutorial) for the light client with client ID 07-tendermint-0 the client state for chain2 (the same client state that is submitted as part of MsgConnectionOpenTry in the client_state field). We can make the same ABCI RPC query on the browser by simply using Tendermint's /abci_query REST endpoint:
path: "store/ibc/key"
data: "clients/07-tendermint-0/clientState" (in hex: 0x636c69656e74732f30372d74656e6465726d696e742d302f636c69656e745374617465)
prove: true (so that the response contains the merkle proof)
height: 174
URL: http://localhost:27000/abci_query?path="store/ibc/key"&data=0x636c69656e74732f30372d74656e6465726d696e742d302f636c69656e745374617465&prove=true&height=174
See sample JSON response.
If we take base64-encoded byte string from the value for the field result.response.value and we decode it, then we can inspect the information for the client state of chain2 stored in chain1:
chain_id:"chain2"
trust_level:<numerator:1 denominator:3 >
trusting_period:<seconds:1209600 >
unbonding_period:<seconds:1814400 >
max_clock_drift:<seconds:40 >
frozen_height:<>
latest_height:<revision_height:106 >
proof_specs:<leaf_spec:<hash:SHA256 prehash_value:SHA256 length:VAR_PROTO prefix:"\000" > inner_spec:<child_order:0 child_order:1 child_size:33 min_prefix_length:4 max_prefix_length:12 hash:SHA256 > >
proof_specs:<leaf_spec:<hash:SHA256 prehash_value:SHA256 length:VAR_PROTO prefix:"\000" > inner_spec:<child_order:0 child_order:1 child_size:32 min_prefix_length:1 max_prefix_length:1 hash:SHA256 > >
upgrade_path:"upgrade"
upgrade_path:"upgradedIBCState"
allow_update_after_expiry:true
allow_update_after_misbehaviour:true
We see that the latest_height has a revision_height of 106, which means that the client state for chain2 on chain1 was last updated for block height 106 of chain2.
It is obtained by performing an ABCI RPC query to the ibc store of chain1. This proof is used to verify that chain1 has stored at the query height (174 in this tutorial) for the light client with client ID 07-tendermint-0 the consensus state at the consensus_height of chain2 (106 in this tutorial). We can make the same ABCI RPC query on the browser by simply using Tendermint's /abci_query REST endpoint. The data query parameter follows the format clients/{client-id}/consensusStates/{epoch}-{height}. epoch is the revision number (0 in this tutorial) and height is the revision height (106 in this tutorial), both retrieved from the latest_height field of the client state stored on chain1.
path: "store/ibc/key"
data: "clients/07-tendermint-0/consensusStates/0-106" (in hex 0x636c69656e74732f30372d74656e6465726d696e742d302f636f6e73656e7375735374617465732f302d313036)
prove: true
height: 174
URL: http://localhost:27000/abci_query?path="store/ibc/key"&data=0x636c69656e74732f30372d74656e6465726d696e742d302f636f6e73656e7375735374617465732f302d313036&prove=true&height=174
See sample JSON response.
If we take base64-encoded byte string from the value for the field result.response.value and we decode it, then we can inspect the information for the consensus state of chain2 (at block height 106) stored in chain1 (at block height 174):
timestamp:<seconds:1664047549 nanos:509581000 >
root:<hash:"i\307\025\205\335n\363\2758\302\201}?\006\334H?\273\033V\023|]f\022\206\217j;F\004\334" > next_validators_hash:"=\231\271\250\261I\024\366W\353\031_\256yI1\005\355!-\311I\327\317\342G\277E\177/l\322"
The timestamp corresponds to the block height in which the consensus state was stored. root is the app hash for block height 106 of chain2 and next_validators_hash is the hash of the next validator set. The root hash is the byte representation of the hex string 69c71585dd6ef3bd38c2817d3f06dc483fbb1b56137c5d6612868f6a3b4604dc. If we query chain2 locally for the block at height 106 by entering http://localhost:27010/block?height=106 on the browser, we can check that the value in the response for the field result.block.header.app_hash (69C71585DD6EF3BD38C2817D3F06DC483FBB1B56137C5D6612868F6A3B4604DC) matches the root hash from the consensus state (see the sample JSON response).
It is the latest height of chain2 which chain1 has stored in its chain2 light client. In this tutorial it is 106 (i.e. the value for latest_height in the stored client state).
It is the address of the relayer that submits the message.
Using hermes to submit this message we execute the following command:
> hermes --config config.toml tx conn-try \
--dst-chain chain2 \
--src-chain chain1 \
--dst-client 07-tendermint-0 \
--src-client 07-tendermint-0 \
--src-connection connection-0
From the hermes log we can retrieve the hash of the transaction that executed MsgConnectionOpenTry:
2022-09-24T19:26:07.221153Z DEBUG ThreadId(13) send_tx_commit{id=ConnectionOpenTry}:send_tx_with_account_sequence_retry{id=chain2}: broadcast_tx_sync: Response { code: Ok, data: Data([]), log: Log("[]"), hash: transaction::Hash(86F785AEA29C21BA41DE929796EF76ADAE242237B33D96C873517DA588B58E5D) }
And we can use this hash to get the transaction information using Tendermint's /tx RPC endpoint:
http://localhost:27010/tx?hash=0x86F785AEA29C21BA41DE929796EF76ADAE242237B33D96C873517DA588B58E5D
See sample JSON result.
The transaction was successfully executed and included in the block at height 109. The value in the field result.tx is a base64-encoded string of the bytes of the messages that were executed as part of the transaction. This transaction contains two messages: MsgUpdateClient and MsgConnectionOpenTry; and if we decode these bytes we can retrieve back the message data that the relayer submitted:
> simd tx decode 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
See sample JSON result.
In particular the MsgUpdateClient and MsgConnectionOpenTry look like this:
{
"@type":"/ibc.core.client.v1.MsgUpdateClient",
"client_id":"07-tendermint-0",
"header":{
"@type":"/ibc.lightclients.tendermint.v1.Header",
"signed_header":{
"header":{
"version":{
"block":"11",
"app":"0"
},
"chain_id":"chain1",
"height":"175",
"time":"2022-09-24T19:26:01.963771Z",
"last_block_id":{
"hash":"98Q8QAKv578FGriFYC0DujgfCnoqHcGu4m7B+MUkYY4=",
"part_set_header":{
"total":1,
"hash":"0flk4LAfjuWiOMYbMq3UdhMbXg2UBcdI3Emim+mGI0M="
}
},
"last_commit_hash":"radnI2wx3aSVmlUm1o9iVyArM7PW0zqayOM4jRa2DmQ=",
"data_hash":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
"validators_hash":"lGCNkT5hD2Ieag9s+6qfYt873x14YOJnVK1lLcyKWJw=",
"next_validators_hash":"lGCNkT5hD2Ieag9s+6qfYt873x14YOJnVK1lLcyKWJw=",
"consensus_hash":"BICRvH3cKD93v7+R1zxE2ljD34qcvIZ0Bdi389qtoi8=",
"app_hash":"rUxdlBQuYq/WohFEw3FVETLkjilva4ROP9xyYRmzp1Q=",
"last_results_hash":"kb39N2n68MhFXjSISUqdC9XZQow436Cc2mAvdj65Nf8=",
"evidence_hash":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
"proposer_address":"/KFlfQw/mhsgX7gFKSYhHuxsUak="
},
"commit":{
"height":"175",
"round":0,
"block_id":{
"hash":"q1I62Ejs3MfsoRhI/GcTn9AGiPssInumn69Sntu4uQg=",
"part_set_header":{
"total":1,
"hash":"AfaHie8LCuht9jDBVWconce5XXb7gZjHQYlCbX6kcik="
}
},
"signatures":[
{
"block_id_flag":"BLOCK_ID_FLAG_COMMIT",
"validator_address":"/KFlfQw/mhsgX7gFKSYhHuxsUak=",
"timestamp":"2022-09-24T19:26:07.050146Z",
"signature":"YUIr9AuQ2ifSbp2fAbdRwLN+6ckXuaA6QyyOaCd/W1Zg6oVift2+VCFWoJERG36eaxYY56l0zHtpWWIWYphVBQ=="
}
]
}
},
"validator_set":{
"validators":[
{
"address":"/KFlfQw/mhsgX7gFKSYhHuxsUak=",
"pub_key":{
"ed25519":"Vf2Pj3yaGBnAtQLbKCb9tWC7WpLyn8u9nWkoNKB7PbU="
},
"voting_power":"10",
"proposer_priority":"0"
}
],
"proposer":{
"address":"/KFlfQw/mhsgX7gFKSYhHuxsUak=",
"pub_key":{
"ed25519":"Vf2Pj3yaGBnAtQLbKCb9tWC7WpLyn8u9nWkoNKB7PbU="
},
"voting_power":"10",
"proposer_priority":"0"
},
"total_voting_power":"10"
},
"trusted_height":{
"revision_number":"0",
"revision_height":"120"
},
"trusted_validators":{
"validators":[
{
"address":"/KFlfQw/mhsgX7gFKSYhHuxsUak=",
"pub_key":{
"ed25519":"Vf2Pj3yaGBnAtQLbKCb9tWC7WpLyn8u9nWkoNKB7PbU="
},
"voting_power":"10",
"proposer_priority":"0"
}
],
"proposer":{
"address":"/KFlfQw/mhsgX7gFKSYhHuxsUak=",
"pub_key":{
"ed25519":"Vf2Pj3yaGBnAtQLbKCb9tWC7WpLyn8u9nWkoNKB7PbU="
},
"voting_power":"10",
"proposer_priority":"0"
},
"total_voting_power":"10"
}
},
"signer":"cosmos1flqvlaum0drg089fhzqq3n042sdlvukj8dae3z"
},
{
"@type":"/ibc.core.connection.v1.MsgConnectionOpenTry",
"client_id":"07-tendermint-0",
"previous_connection_id":"",
"client_state":{
"@type":"/ibc.lightclients.tendermint.v1.ClientState",
"chain_id":"chain2",
"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":"106"
},
"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
},
"counterparty":{
"client_id":"07-tendermint-0",
"connection_id":"connection-0",
"prefix":{
"key_prefix":"aWJj"
}
},
"delay_period":"0",
"counterparty_versions":[
{
"identifier":"1",
"features":[
"ORDER_ORDERED",
"ORDER_UNORDERED"
]
}
],
"proof_height":{
"revision_number":"0",
"revision_height":"175"
},
"proof_init":"CrECCq4CChhjb25uZWN0aW9ucy9jb25uZWN0aW9uLTASUgoPMDctdGVuZGVybWludC0wEiMKATESDU9SREVSX09SREVSRUQSD09SREVSX1VOT1JERVJFRBgBIhgKDzA3LXRlbmRlcm1pbnQtMBoFCgNpYmMaDAgBGAEgASoEAAKcAiIqCAESJgQG3AIgvX8E6AMbidgDi02Kr3BF4Mj2VpRpuUGI7xMvtl11fdkgIioIARImBgrcAiAGzIuCGnFlWI/cGfYPsgK6e8M4DQG1xpi7prYrDwDCbCAiLAgBEgUIENwCIBohIAt3eDLbhXORqk3PJTKizvcNqyQ4Woy6cHk8N7T7NuOoIioIARImChzcAiBO5xWJKpuALcyDpN7b0NIagPgH/eftgg8seyn9g2m93yAK/gEK+wEKA2liYxIgfbjt6JwOubUqy5RzRZstRfi9EUDslbURak/jB/6acokaCQgBGAEgASoBACIlCAESIQFGsg9bKg+Td5KCS6A+Qnp6eIVOcOR7NdKpisvlOJb5EyInCAESAQEaIKplBAbqDXbjndQ9LqapHj/aockI/CGnymjl5izIEVY5IicIARIBARogBbQQZKCtw0RxqRDcQ/p/9m7pUJ2wMDSouvR/Azr4aa4iJQgBEiEBk3pdrZNYsYXuTXdXl9HBwTwKYeOscKBrP/2hGRHwVF4iJwgBEgEBGiDgk7AN2ZqlJAGBS7smchl8P5DIdt5U6uyuO14q6dol+g==",
"proof_client":"CusCCugCCiNjbGllbnRzLzA3LXRlbmRlcm1pbnQtMC9jbGllbnRTdGF0ZRKoAQorL2liYy5saWdodGNsaWVudHMudGVuZGVybWludC52MS5DbGllbnRTdGF0ZRJ5CgZjaGFpbjISBAgBEAMaBAiA6kkiBAiA324qAggoMgA6AhBqQhkKCQgBGAEgASoBABIMCgIAARAhGAQgDDABQhkKCQgBGAEgASoBABIMCgIAARAgGAEgATABSgd1cGdyYWRlShB1cGdyYWRlZElCQ1N0YXRlUAFYARoMCAEYASABKgQAAtwCIiwIARIFAgTcAiAaISD3YamIPneGyeAq1zMxKusV+BIS5Bi4hV/pV5w2EBH3myIsCAESBQYM3AIgGiEg7l5FIeXsDkOwplSfr3XFPQjgYnB+6EHFW3K3TN6+tx4iLAgBEgUKHNwCIBohIKxAb6RIvWFaEMtX0P5QGbeYSuzsZ821la8KaAK9FWC/Cv4BCvsBCgNpYmMSIH247eicDrm1KsuUc0WbLUX4vRFA7JW1EWpP4wf+mnKJGgkIARgBIAEqAQAiJQgBEiEBRrIPWyoPk3eSgkugPkJ6eniFTnDkezXSqYrL5TiW+RMiJwgBEgEBGiCqZQQG6g12453UPS6mqR4/2qHJCPwhp8po5eYsyBFWOSInCAESAQEaIAW0EGSgrcNEcakQ3EP6f/Zu6VCdsDA0qLr0fwM6+GmuIiUIARIhAZN6Xa2TWLGF7k13V5fRwcE8CmHjrHCgaz/9oRkR8FReIicIARIBARog4JOwDdmapSQBgUu7JnIZfD+QyHbeVOrsrjteKunaJfo=",
"proof_consensus":"Cv8CCvwCCi1jbGllbnRzLzA3LXRlbmRlcm1pbnQtMC9jb25zZW5zdXNTdGF0ZXMvMC0xMDYShgEKLi9pYmMubGlnaHRjbGllbnRzLnRlbmRlcm1pbnQudjEuQ29uc2Vuc3VzU3RhdGUSVAoMCL2zvZkGEMit/vIBEiIKIGnHFYXdbvO9OMKBfT8G3Eg/uxtWE3xdZhKGj2o7RgTcGiA9mbmosUkU9lfrGV+ueUkxBe0hLclJ18/iR79Ffy9s0hoMCAEYASABKgQAAtwCIiwIARIFAgTcAiAaISDwqm/y+VkCtd6CaW840BwW13RXUr6KOSFFTUk7td6gtSIsCAESBQQI3AIgGiEgn3k4CSY7YNV27j16HEr+iP4vBflYRyX4MgpxFRzF5dQiKggBEiYGDNwCIOHsqWVJSlq9tF94IHHRkfScWkZkDyCs7I7ShpgLvUgKICIsCAESBQoc3AIgGiEgrEBvpEi9YVoQy1fQ/lAZt5hK7OxnzbWVrwpoAr0VYL8K/gEK+wEKA2liYxIgfbjt6JwOubUqy5RzRZstRfi9EUDslbURak/jB/6acokaCQgBGAEgASoBACIlCAESIQFGsg9bKg+Td5KCS6A+Qnp6eIVOcOR7NdKpisvlOJb5EyInCAESAQEaIKplBAbqDXbjndQ9LqapHj/aockI/CGnymjl5izIEVY5IicIARIBARogBbQQZKCtw0RxqRDcQ/p/9m7pUJ2wMDSouvR/Azr4aa4iJQgBEiEBk3pdrZNYsYXuTXdXl9HBwTwKYeOscKBrP/2hGRHwVF4iJwgBEgEBGiDgk7AN2ZqlJAGBS7smchl8P5DIdt5U6uyuO14q6dol+g==",
"consensus_height":{
"revision_number":"0",
"revision_height":"106"
},
"signer":"cosmos1flqvlaum0drg089fhzqq3n042sdlvukj8dae3z"
}After the message reaches the message server the execution continues in ConnectionKeeper's ConnOpenTry function, to which the message fields are passed in. The steps in ConnOpenTry consist of:
- A new connection identifier is generated by retrieving the next connection sequence from the store. In this tutorial, the generated connection ID is
connection-0. - Check to make sure that the height of
chain2is greater than the latest height ofchain2thatchain1has stored in itschain2client state. - Validate that the parameters for the client state of
chain2stored onchain1are correct. -
Construct the expected consensus state and connection end that
chain2expectschain1to have stored in its state. The expected consensus state ischain2's consensus state atconsensusHeight(106 in this tutorial), which is retrieved bychain2self-inspecting its own consensus state; the expected connection end ischain1's connection end created during theConnectionOpenInitstep. -
A connection end is created that
chain2will store in state. -
Verify against the app hash at height
proofHeightthatchain1stored in state the expected connection end. This verification checks thatchain1has stored in the pathconnections/connection-0of theibcstore the expected connection end with stateSTATE_INITcreated during the execution ofMsgConnectionOpenInit. It does this by computing the merkle root hash usingproofInitand the expected connection end and checking that it matches the root hash atproofHeightof the consensus state stored for the light client ofchain1. -
Verify against the app hash at height
proofHeightthatchain1stored in state theclientStateforchain2. This verification checks thatchain1has stored in the pathclients/07-tendermint-0/clientStateof theibcstore theclientStatesubmitted inMsgConnectionOpenTry. It does this by computing the merkle root hash usingproofClientand theclientStateand checking that it matches the root hash atproofHeightof the consensus state stored for the light client ofchain1. -
Verify against the app hash at height
proofHeightthatchain1stored in state the consensus state forchain2. This verification checks thatchain1has stored in the pathclients/07-tendermint-0/consensusStates/106of theibcstore the consensus state forchain2atconsensus_height(106 in this tutorial). It does this by computing the merkle root hash usingproofConsensusand the expected consensus state and checking that it matches the root hash atproofHeightof the consensus state stored for the light client ofchain1. - The connection ID is also added to the set of connections associated with a client (which is stored under key
clients/07-tendermint-0/connectionsin this tutorial). And the connection end is stored under the keyconnections/connection-0. - An event is emitted signalling that the connection open try has finished successfully. From the event information (which can also be found in the field
result.tx_result.logof the transaction that includedMsgConnectionOpenTry) it is possible to figure out what connection ID this new connection end has:
[
{
"events":[
{
"type":"message",
"attributes":[
{
"key":"action",
"value":"/ibc.core.client.v1.MsgUpdateClient"
},
{
"key":"module",
"value":"ibc_client"
}
]
},
{
"type":"update_client",
"attributes":[
{
"key":"client_id",
"value":"07-tendermint-0"
},
{
"key":"client_type",
"value":"07-tendermint"
},
{
"key":"consensus_height",
"value":"0-175"
},
{
"key":"header",
"value":"0a262f6962632e6c69676874636c69656e74732e74656e6465726d696e742e76312e48656164657212d0060ac9040a8d030a02080b1206636861696e3118af01220c08c9b3bd990610f8f4c7cb032a480a20f7c43c4002afe7bf051ab885602d03ba381f0a7a2a1dc1aee26ec1f8c524618e122408011220d1f964e0b01f8ee5a238c61b32add476131b5e0d9405c748dc49a29be98623433220ada767236c31dda4959a5526d68f6257202b33b3d6d33a9ac8e3388d16b60e643a20e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855422094608d913e610f621e6a0f6cfbaa9f62df3bdf1d7860e26754ad652dcc8a589c4a2094608d913e610f621e6a0f6cfbaa9f62df3bdf1d7860e26754ad652dcc8a589c5220048091bc7ddc283f77bfbf91d73c44da58c3df8a9cbc867405d8b7f3daada22f5a20ad4c5d94142e62afd6a21144c371551132e48e296f6b844e3fdc726119b3a754622091bdfd3769faf0c8455e3488494a9d0bd5d9428c38dfa09cda602f763eb935ff6a20e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8557214fca1657d0c3f9a1b205fb8052926211eec6c51a912b60108af011a480a20ab523ad848ecdcc7eca11848fc67139fd00688fb2c227ba69faf529edbb8b90812240801122001f68789ef0b0ae86df630c15567289dc7b95d76fb8198c74189426d7ea47229226708021214fca1657d0c3f9a1b205fb8052926211eec6c51a91a0b08cfb3bd990610d0d5f417224061422bf40b90da27d26e9d9f01b751c0b37ee9c917b9a03a432c8e68277f5b5660ea85627eddbe542156a091111b7e9e6b1618e7a974cc7b6959621662985505127e0a3c0a14fca1657d0c3f9a1b205fb8052926211eec6c51a912220a2055fd8f8f7c9a1819c0b502db2826fdb560bb5a92f29fcbbd9d692834a07b3db5180a123c0a14fca1657d0c3f9a1b205fb8052926211eec6c51a912220a2055fd8f8f7c9a1819c0b502db2826fdb560bb5a92f29fcbbd9d692834a07b3db5180a180a1a021078227e0a3c0a14fca1657d0c3f9a1b205fb8052926211eec6c51a912220a2055fd8f8f7c9a1819c0b502db2826fdb560bb5a92f29fcbbd9d692834a07b3db5180a123c0a14fca1657d0c3f9a1b205fb8052926211eec6c51a912220a2055fd8f8f7c9a1819c0b502db2826fdb560bb5a92f29fcbbd9d692834a07b3db5180a180a"
}
]
}
]
},
{
"msg_index":1,
"events":[
{
"type":"connection_open_try",
"attributes":[
{
"key":"connection_id",
"value":"connection-0"
},
{
"key":"client_id",
"value":"07-tendermint-0"
},
{
"key":"counterparty_client_id",
"value":"07-tendermint-0"
},
{
"key":"counterparty_connection_id",
"value":"connection-0"
}
]
},
{
"type":"message",
"attributes":[
{
"key":"action",
"value":"/ibc.core.connection.v1.MsgConnectionOpenTry"
},
{
"key":"module",
"value":"ibc_connection"
}
]
}
]
}
]After MsgConnectionOpenTry successfully executes, there is a connection end stored on chain2. We can use ibc-go's REST interface to check the existence of the connection end with connection ID connection-0 by simply entering http://localhost:27011/ibc/core/connection/v1/connections/connection-0 and check that the state of the connection is STATE_TRYOPEN:
{
"connection": {
"client_id": "07-tendermint-0",
"versions": [
{
"identifier": "1",
"features": [
"ORDER_ORDERED",
"ORDER_UNORDERED"
]
}
],
"state": "STATE_TRYOPEN",
"counterparty": {
"client_id": "07-tendermint-0",
"connection_id": "connection-0",
"prefix": {
"key_prefix": "aWJj"
}
},
"delay_period": "0"
},
"proof": null,
"proof_height": {
"revision_number": "0",
"revision_height": "114"
}
}After MsgConnectionOpenTry succeeds on chain2, then the relayer submits MsgConnectionOpenAck on chain1 (see the message proto definition.
In hermes MsgConnectionOpenTry is constructed and sent in function build_conn_ack_and_send. More specifically, the message is constructed in build_conn_ack.
To build MsgConnectionOpenAck hermes queries chain2 at a certain height to get proofs for the following things:
- A proof that
chain2has stored a connection end with connection IDconnection-0and stateSTATE_TRY. - A proof that
chain2has stored for the light client with client ID07-tendermint-0the client state forchain1. - A proof that
chain2has stored for the light client with client ID07-tendermint-0the consensus state forchain1.
In this tutorial the height at which hermes is going to query chain2 for these proofs is 144 (we know this because we will see that hermes has submitted together with MsgConnectionOpenAck a MsgUpdateClient that updates the client state of chain2 on chain1 to the height 145). The query height is obtained here by querying Tendermint's /status RPC endpoint and reading the values for result.node_info.network (which is the revision number, chain1) and result.sync_info.latest_block_height (which is the revision height, 144).
The parameters needed to construct MsgConnectionOpenAck are:
It is the connection ID for the connection end on chain1 (connection-0 in this tutorial).
It is the connection ID for the connection end on chain2.
It is the version selected by chain2.
It is the client state for chain1 that chain2 has stored. It is retrieved here by performing an ABCI RPC query to the ibc store of chain2. The query uses the query height (144 in this tutorial). We will see a sample of the client state data in the proof_client item a bit further down.
It is the height for the commitment root for proving the proofs for try, client and consensus. When creating these proofs, chain2 is queried at height proof_height - 1 (144 in this tutorial). The reason why proof_height (145 in this tutorial) is query_height + 1 is because for Tendermint chains the app hash after applying all transactions in block n is included in block at height n + 1.
It is obtained by performing an ABCI RPC query to the ibc store of chain2. This proof is used to verify that chain2 has stored a connection end with state STATE_TRYOPEN at the query height (144 in this tutorial). We can make the same ABCI RPC query on the browser by simply using Tendermint's /abci_query REST endpoint:
path: "store/ibc/key"
data: "connections/connection-0" (in hex: 0x636f6e6e656374696f6e732f636f6e6e656374696f6e2d30)
prove: true (so that the response contains the merkle proof)
height: 144
URL: http://localhost:27010/abci_query?path="store/ibc/key"&data=0x636f6e6e656374696f6e732f636f6e6e656374696f6e2d30&prove=true&height=144
See sample JSON response.
The response to this ABCI RPC query contains both the value stored at the queried path (connections/connection-0) and the proof needed to verify it. If we take the base64-encoded byte string from the value for the field result.response.value and we decode it, then we can inspect the information for the connection end stored in chain2:
{
ClientId:07-tendermint-0
Versions:[
identifier:"1"
features:"ORDER_ORDERED"
features:"ORDER_UNORDERED"
]
State:STATE_TRYOPEN
Counterparty:{
ClientId:07-tendermint-0
ConnectionId:connection-0
Prefix:{
KeyPrefix:[105 98 99]
}
}
DelayPeriod:0
}
We see that the connection end is in state STATE_TRYOPEN. The key_prefix is the byte representation of the string ibc.
It is obtained by performing an ABCI RPC query to the ibc store of chain1. This proof is used to check that chain2 has stored at the query height (144 in this tutorial) for the light client with client ID 07-tendermint-0 the client state for chain1 (the same client state that is submitted in MsgConnectionOpenAck in the client_state field). We can make the same ABCI RPC query on the browser by simply using Tendermint's /abci_query REST endpoint:
path: "store/ibc/key"
data: "clients/07-tendermint-0/clientState" (in hex: 0x636c69656e74732f30372d74656e6465726d696e742d302f636c69656e745374617465)
prove: true (so that the response contains the merkle proof)
height: 144
URL: http://localhost:27010/abci_query?path="store/ibc/key"&data=0x636c69656e74732f30372d74656e6465726d696e742d302f636c69656e745374617465&prove=true&height=144
See sample JSON response.
If we take base64-encoded byte string from the value for the field result.response.value and we decode it, then we can inspect the information for the client state of chain1 stored in chain2:
chain_id:"chain1"
trust_level:<numerator:1 denominator:3 >
trusting_period:<seconds:1209600 >
unbonding_period:<seconds:1814400 >
max_clock_drift:<seconds:40 >
frozen_height:<>
latest_height:<revision_height:209 >
proof_specs:<leaf_spec:<hash:SHA256 prehash_value:SHA256 length:VAR_PROTO prefix:"\000" > inner_spec:<child_order:0 child_order:1 child_size:33 min_prefix_length:4 max_prefix_length:12 hash:SHA256 > >
proof_specs:<leaf_spec:<hash:SHA256 prehash_value:SHA256 length:VAR_PROTO prefix:"\000" > inner_spec:<child_order:0 child_order:1 child_size:32 min_prefix_length:1 max_prefix_length:1 hash:SHA256 > >
upgrade_path:"upgrade"
upgrade_path:"upgradedIBCState"
allow_update_after_expiry:true
allow_update_after_misbehaviour:true
We see that the latest_height has a revision_height of 209, which means that the client state for chain1 on chain2 was last updated for block height 209 of chain1.
It is obtained by performing an ABCI RPC query to the ibc store of chain2. This proof is used to check that chain2 has stored at the query height (144 in this tutorial) for the light client with client ID 07-tendermint-0 the consensus state at the consensus_height (209 in this tutorial) of chain1. We can make the same ABCI RPC query on the browser by simply using Tendermint's /abci_query REST endpoint. The data query parameter follows the format clients/{client-id}/consensusStates/{epoch}-{height}. epoch is the revision number (0 in this tutorial) and height is the revision height (209 in this tutorial), both retrieved from the latest_height field of the client state stored on chain2.
path: "store/ibc/key"
data: "clients/07-tendermint-0/consensusStates/0-209" (in hex 0x636c69656e74732f30372d74656e6465726d696e742d302f636f6e73656e7375735374617465732f302d323039)
prove: true
height: 174
URL: http://localhost:27010/abci_query?path="store/ibc/key"&data=0x636c69656e74732f30372d74656e6465726d696e742d302f636f6e73656e7375735374617465732f302d323039&prove=true&height=174
See sample JSON response.
If we take base64-encoded byte string from the value for the field result.response.value and we decode it, then we can inspect the information for the consensus state of chain1 (at block height 209) stored in chain2 (at block height 174):
timestamp:<seconds:1664047735 nanos:238479000 >
root:<hash:".\345?@\244\305\303&8\n\246c\271\351\320\t\255\007m\275\334\226\247/x\020\306\273\357\273|*" > next_validators_hash:"\224`\215\221>a\017b\036j\017l\373\252\237b\337;\337\035x`\342gT\255e-\314\212X\234"
The timestamp corresponds to the block height in which the consensus state was stored. root is the app hash for block height 209 of chain2 and next_validators_hash is the hash of the next validator set. The root hash is the byte representation of the hex string 2ee53f40a4c5c326380aa663b9e9d009ad076dbddc96a72f7810c6bbefbb7c2a. If we query chain1 locally for block at height 209 by entering http://localhost:27000/block?height=209 on the browser, we can check that the value in the response for the field result.block.header.app_hash (2EE53F40A4C5C326380AA663B9E9D009AD076DBDDC96A72F7810C6BBEFBB7C2A) matches the root hash from the consensus state (see the sample JSON response).
It is the latest height of chain1 which chain2 has stored in its chain1 light client. In this tutorial it is 209 (i.e. the value for latest_height in the stored client state).
It is the address of the relayer that submits the message.
Using hermes to submit this message we execute the following command:
> hermes --config config.toml tx conn-ack \
--dst-chain chain1 \
--src-chain chain2 \
--dst-client 07-tendermint-0 \
--src-client 07-tendermint-0 \
--dst-connection connection-0 \
--src-connection connection-0
From the hermes log we can retrieve the hash of the transaction that executed MsgConnectionOpenAck:
2022-09-24T19:29:13.362255Z DEBUG ThreadId(13) send_tx_commit{id=ConnectionOpenAck}:send_tx_with_account_sequence_retry{id=chain1}: broadcast_tx_sync: Response { code: Ok, data: Data([]), log: Log("[]"), hash: transaction::Hash(6127DCDF7C2FAFE234ED69A377DE0B3682E947AE2BAC7D4697C352FC74441375) }
And we can use this hash to get the transaction information using Tendermint's /tx RPC endpoint:
http://localhost:27000/tx?hash=0x6127DCDF7C2FAFE234ED69A377DE0B3682E947AE2BAC7D4697C352FC74441375
See sample JSON result.
The transaction was successfully executed and included in the block at height 212. The value in the field result.tx is a base64-encoded string of the bytes of the messages that were executed as part of the transaction. This transaction contains two messages: MsgUpdateClient and MsgConnectionOpenAck; and if we decode these bytes we can retrieve back the message data that the relayer submitted:
> simd tx decode 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
See sample JSON result.
In particular the MsgUpdateClient and MsgConnectionOpenAck look like this:
{
"@type":"/ibc.core.client.v1.MsgUpdateClient",
"client_id":"07-tendermint-0",
"header":{
"@type":"/ibc.lightclients.tendermint.v1.Header",
"signed_header":{
"header":{
"version":{
"block":"11",
"app":"0"
},
"chain_id":"chain2",
"height":"145",
"time":"2022-09-24T19:29:08.106934Z",
"last_block_id":{
"hash":"VVJjWIG9i8TfuE0eRB01W0Og7WH3zxwqbE2aT/yDwug=",
"part_set_header":{
"total":1,
"hash":"RX+BotISwovJ1SHkyYYl5nZqCYO8AyHgjWKsG10ZtaQ="
}
},
"last_commit_hash":"9RBJCeXS5+4T6XbKn/M/gvqJGAnMSySILsC1o0mUZ6I=",
"data_hash":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
"validators_hash":"PZm5qLFJFPZX6xlfrnlJMQXtIS3JSdfP4ke/RX8vbNI=",
"next_validators_hash":"PZm5qLFJFPZX6xlfrnlJMQXtIS3JSdfP4ke/RX8vbNI=",
"consensus_hash":"BICRvH3cKD93v7+R1zxE2ljD34qcvIZ0Bdi389qtoi8=",
"app_hash":"ck9kuZEDQFWscI1qnvW/kjFh/Wx2oyrZ+Spemc2CUUA=",
"last_results_hash":"0z6NkrMeAFNh1m1enUoHzbkaiyL/Htok0jLIAYUGrVM=",
"evidence_hash":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
"proposer_address":"FKTxW3cu3Uzgr4aGZpg6/vni9DU="
},
"commit":{
"height":"145",
"round":0,
"block_id":{
"hash":"cWELs6N8+bFvOVKV9fqY8/6s9e9ThjAGmeFv0+xWEs8=",
"part_set_header":{
"total":1,
"hash":"Urpz4RLyq54rDkMBVmUkd00ove020ikWeU+fttUbQAQ="
}
},
"signatures":[
{
"block_id_flag":"BLOCK_ID_FLAG_COMMIT",
"validator_address":"FKTxW3cu3Uzgr4aGZpg6/vni9DU=",
"timestamp":"2022-09-24T19:29:13.190280Z",
"signature":"l1/xvEBl40sHHdXsiFaNH7oI+qtXRGD1JF5cSqCfBN9CC4C8dHVyYcwCyqLwtNOuZF8Hxu+s+/egT+FsTQi/BQ=="
}
]
}
},
"validator_set":{
"validators":[
{
"address":"FKTxW3cu3Uzgr4aGZpg6/vni9DU=",
"pub_key":{
"ed25519":"bbHID9h8mDVBW5UwkVTuMqy0kRDcCTO9k/x2XgbHEfs="
},
"voting_power":"10",
"proposer_priority":"0"
}
],
"proposer":{
"address":"FKTxW3cu3Uzgr4aGZpg6/vni9DU=",
"pub_key":{
"ed25519":"bbHID9h8mDVBW5UwkVTuMqy0kRDcCTO9k/x2XgbHEfs="
},
"voting_power":"10",
"proposer_priority":"0"
},
"total_voting_power":"10"
},
"trusted_height":{
"revision_number":"0",
"revision_height":"106"
},
"trusted_validators":{
"validators":[
{
"address":"FKTxW3cu3Uzgr4aGZpg6/vni9DU=",
"pub_key":{
"ed25519":"bbHID9h8mDVBW5UwkVTuMqy0kRDcCTO9k/x2XgbHEfs="
},
"voting_power":"10",
"proposer_priority":"0"
}
],
"proposer":{
"address":"FKTxW3cu3Uzgr4aGZpg6/vni9DU=",
"pub_key":{
"ed25519":"bbHID9h8mDVBW5UwkVTuMqy0kRDcCTO9k/x2XgbHEfs="
},
"voting_power":"10",
"proposer_priority":"0"
},
"total_voting_power":"10"
}
},
"signer":"cosmos19enepz3pwxd5dgucq2qp2r8l5ynm90gptf52nv"
},
{
"@type":"/ibc.core.connection.v1.MsgConnectionOpenAck",
"connection_id":"connection-0",
"counterparty_connection_id":"connection-0",
"version":{
"identifier":"1",
"features":[
"ORDER_ORDERED",
"ORDER_UNORDERED"
]
},
"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":"209"
},
"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_height":{
"revision_number":"0",
"revision_height":"145"
},
"proof_try":"CusCCugCChhjb25uZWN0aW9ucy9jb25uZWN0aW9uLTASYAoPMDctdGVuZGVybWludC0wEiMKATESDU9SREVSX09SREVSRUQSD09SREVSX1VOT1JERVJFRBgCIiYKDzA3LXRlbmRlcm1pbnQtMBIMY29ubmVjdGlvbi0wGgUKA2liYxoMCAEYASABKgQAAtoBIioIARImAgSgAiC7KbNtxKFD+r7iLI7JQWTZ6PjEYWs11j2iLqAEUJ73oyAiKggBEiYECKACIO1PFmu3WPO8pqrDfHYT+fCVBEPWY0qppagnclfCYJlYICIsCAESBQYOoAIgGiEgS6K+ecLdX6ZH5y2FrZndDEvXZ5Y5tjBk2/Ge2nYsW/0iKggBEiYIGqACIIarz5iUxw8ostqGeTAW5iGqO5wMBHeZm8NtTDlY+EwHICIqCAESJgokoAIgtXBh7ekb0PmkVQ5ZfKjFSUBVFeuGJaNDF/+4gTMh1ZMgCv4BCvsBCgNpYmMSIAAa9ewRHR5FoTlsd5YI6YecY+1Z3d6U1khyzyQDJOCFGgkIARgBIAEqAQAiJQgBEiEBRrIPWyoPk3eSgkugPkJ6eniFTnDkezXSqYrL5TiW+RMiJwgBEgEBGiCqZQQG6g12453UPS6mqR4/2qHJCPwhp8po5eYsyBFWOSInCAESAQEaIMrCGJEl1NdHHTxSzLwezLjNlPb72glzUmWL6nM0GATQIiUIARIhAYqRDaJu600nq4vouKC8s36d4cpdqHQEUAxPd0DfZWzqIicIARIBARoggOS6HQIBFTr04W7CL3Dwnd4+SO5LXsefXeMTDMVv70I=",
"proof_client":"CpoDCpcDCiNjbGllbnRzLzA3LXRlbmRlcm1pbnQtMC9jbGllbnRTdGF0ZRKpAQorL2liYy5saWdodGNsaWVudHMudGVuZGVybWludC52MS5DbGllbnRTdGF0ZRJ6CgZjaGFpbjESBAgBEAMaBAiA6kkiBAiA324qAggoMgA6AxDRAUIZCgkIARgBIAEqAQASDAoCAAEQIRgEIAwwAUIZCgkIARgBIAEqAQASDAoCAAEQIBgBIAEwAUoHdXBncmFkZUoQdXBncmFkZWRJQkNTdGF0ZVABWAEaDAgBGAEgASoEAAKgAiIsCAESBQIEoAIgGiEgjh06ooepFXF11U91hB6FrO3lMaf7bC9FfVPw61wpeYQiLAgBEgUEBqACIBohIAm8255Xx3u4a1XuYL7KCwSuJ6WUSyt9B0EXePDC7Vf7IiwIARIFBgqgAiAaISBhOfhdRUYG3kAJMRfVe8RUgx3H1Kn9kO3fOijkfF4HKyIsCAESBQokoAIgGiEgYBv2UIjzjpPsRnbcplJ1dH/rzyVRP5cyhO8JclNaJucK/gEK+wEKA2liYxIgABr17BEdHkWhOWx3lgjph5xj7Vnd3pTWSHLPJAMk4IUaCQgBGAEgASoBACIlCAESIQFGsg9bKg+Td5KCS6A+Qnp6eIVOcOR7NdKpisvlOJb5EyInCAESAQEaIKplBAbqDXbjndQ9LqapHj/aockI/CGnymjl5izIEVY5IicIARIBARogysIYkSXU10cdPFLMvB7MuM2U9vvaCXNSZYvqczQYBNAiJQgBEiEBipENom7rTSeri+i4oLyzfp3hyl2odARQDE93QN9lbOoiJwgBEgEBGiCA5LodAgEVOvThbsIvcPCd3j5I7ktex59d4xMMxW/vQg==",
"proof_consensus":"CqgDCqUDCi1jbGllbnRzLzA3LXRlbmRlcm1pbnQtMC9jb25zZW5zdXNTdGF0ZXMvMC0yMDkShQEKLi9pYmMubGlnaHRjbGllbnRzLnRlbmRlcm1pbnQudjEuQ29uc2Vuc3VzU3RhdGUSUwoLCPe0vZkGEJjN23ESIgogLuU/QKTFwyY4CqZjuenQCa0Hbb3clqcveBDGu++7fCoaIJRgjZE+YQ9iHmoPbPuqn2LfO98deGDiZ1StZS3MilicGgwIARgBIAEqBAACoAIiKggBEiYCBKACICGIYuy9XMiupqWwXWqMKQfDNhJM/+lQRWL/gkLGskrJICIsCAESBQQIoAIgGiEgfxivhs5VQapRljQRhCUhqMQayqBDj6BpGEV6KwgChV8iKggBEiYGDKACIIqPfYNTkgrabCH/tx+B0D3Hrc036fUxQ/mLNYCj+/rnICIsCAESBQgaoAIgGiEgSxennFZ/rIYsaPJtru95KUi4KKyJ0fMFAydsrQz1fCoiKggBEiYKJKACILVwYe3pG9D5pFUOWXyoxUlAVRXrhiWjQxf/uIEzIdWTIAr+AQr7AQoDaWJjEiAAGvXsER0eRaE5bHeWCOmHnGPtWd3elNZIcs8kAyTghRoJCAEYASABKgEAIiUIARIhAUayD1sqD5N3koJLoD5Cenp4hU5w5Hs10qmKy+U4lvkTIicIARIBARogqmUEBuoNduOd1D0upqkeP9qhyQj8IafKaOXmLMgRVjkiJwgBEgEBGiDKwhiRJdTXRx08Usy8Hsy4zZT2+9oJc1Jli+pzNBgE0CIlCAESIQGKkQ2ibutNJ6uL6LigvLN+neHKXah0BFAMT3dA32Vs6iInCAESAQEaIIDkuh0CARU69OFuwi9w8J3ePkjuS17Hn13jEwzFb+9C",
"consensus_height":{
"revision_number":"0",
"revision_height":"209"
},
"signer":"cosmos19enepz3pwxd5dgucq2qp2r8l5ynm90gptf52nv"
}After the message reaches the message server the execution continues in ConnectionKeeper's ConnOpenAck function, to which the message fields are passed in. The steps in ConnOpenAck consist of:
- Check to make sure that the height of
chain1is greater than the latest height ofchain1thatchain2has stored in itschain1client. -
Retrieve the connection end previously stored during execution of
ConnOpenInitand check that the state isSTATE_INIT. -
Make sure that the version selected by
chain2is supported bychain1. - Validate that the parameters for the client state of
chain1stored onchain2are correct. -
Construct the expected consensus state and connection end that
chain1expectschain2to have stored in its state. The expected consensus state ischain1's consensus state atconsensusHeight(209 in this example), which is retrieved bychain1self-inspecting its own consensus state; the expected connection end ischain2's connection end created during theConnectionOpenTrystep. -
Verify against the app hash at height
proofHeightthatchain2stored in state the expected connection end. This verification checks thatchain2has stored in the pathconnections/connection-0of theibcstore the expected connection end with stateSTATE_TRYcreated during the execution ofMsgConnectionOpenTry. It does this by computing the merkle root hash usingproofTryand the expected connection end and checking that it matches the root hash atproofHeightof the consensus state stored for the light client ofchain2. -
Verify against the app hash at height
proofHeightthatchain2stored in state theclientStateforchain1. This verification checks thatchain2has stored in the pathclients/07-tendermint-0/clientStateof theibcstore theclientStatesubmitted inMsgConnectionOpenTrymessage at block heightproofHeightand it does this by computing the merkle root hash usingproofClientand theclientStateand checking that it matches the root hash atproofHeightof the consensus state stored for the light client ofchain2. -
Verify against the app hash at height
proofHeightthatchain2stored in state the consensus state forchain1. This verification checks thatchain2has stored in the pathclients/07-tendermint-0/consensusStates/84of theibcstore the consensus state forchain1atconsensus_height(209 in this tutorial). It does this by computing the merkle root hash usingproofConsensusand the expected consensus state and checking that it matches the root hash atproofHeightof the consensus state stored for the light client ofchain2. -
Update the state of the connection end on
chain1toSTATE_OPEN, the versions and the counterparty connection ID. - An event is emitted signalling that the connection open ack has finished successfully:
[[
{
"events":[
{
"type":"message",
"attributes":[
{
"key":"action",
"value":"/ibc.core.client.v1.MsgUpdateClient"
},
{
"key":"module",
"value":"ibc_client"
}
]
},
{
"type":"update_client",
"attributes":[
{
"key":"client_id",
"value":"07-tendermint-0"
},
{
"key":"client_type",
"value":"07-tendermint"
},
{
"key":"consensus_height",
"value":"0-145"
},
{
"key":"header",
"value":"0a262f6962632e6c69676874636c69656e74732e74656e6465726d696e742e76312e48656164657212cf060ac8040a8c030a02080b1206636861696e32189101220b0884b5bd990610f0ddfe322a480a205552635881bd8bc4dfb84d1e441d355b43a0ed61f7cf1c2a6c4d9a4ffc83c2e8122408011220457f81a2d212c28bc9d521e4c98625e6766a0983bc0321e08d62ac1b5d19b5a43220f5104909e5d2e7ee13e976ca9ff33f82fa891809cc4b24882ec0b5a3499467a23a20e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b85542203d99b9a8b14914f657eb195fae79493105ed212dc949d7cfe247bf457f2f6cd24a203d99b9a8b14914f657eb195fae79493105ed212dc949d7cfe247bf457f2f6cd25220048091bc7ddc283f77bfbf91d73c44da58c3df8a9cbc867405d8b7f3daada22f5a20724f64b991034055ac708d6a9ef5bf923161fd6c76a32ad9f92a5e99cd8251406220d33e8d92b31e005361d66d5e9d4a07cdb91a8b22ff1eda24d232c8018506ad536a20e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855721414a4f15b772edd4ce0af868666983afef9e2f43512b6010891011a480a2071610bb3a37cf9b16f395295f5fa98f3feacf5ef5386300699e16fd3ec5612cf12240801122052ba73e112f2ab9e2b0e4301566524774d28bded36d22916794f9fb6d51b400422670802121414a4f15b772edd4ce0af868666983afef9e2f4351a0b0889b5bd990610c0e2dd5a2240975ff1bc4065e34b071dd5ec88568d1fba08faab574460f5245e5c4aa09f04df420b80bc74757261cc02caa2f0b4d3ae645f07c6efacfbf7a04fe16c4d08bf05127e0a3c0a1414a4f15b772edd4ce0af868666983afef9e2f43512220a206db1c80fd87c9835415b95309154ee32acb49110dc0933bd93fc765e06c711fb180a123c0a1414a4f15b772edd4ce0af868666983afef9e2f43512220a206db1c80fd87c9835415b95309154ee32acb49110dc0933bd93fc765e06c711fb180a180a1a02106a227e0a3c0a1414a4f15b772edd4ce0af868666983afef9e2f43512220a206db1c80fd87c9835415b95309154ee32acb49110dc0933bd93fc765e06c711fb180a123c0a1414a4f15b772edd4ce0af868666983afef9e2f43512220a206db1c80fd87c9835415b95309154ee32acb49110dc0933bd93fc765e06c711fb180a180a"
}
]
}
]
},
{
"msg_index":1,
"events":[
{
"type":"connection_open_ack",
"attributes":[
{
"key":"connection_id",
"value":"connection-0"
},
{
"key":"client_id",
"value":"07-tendermint-0"
},
{
"key":"counterparty_client_id",
"value":"07-tendermint-0"
},
{
"key":"counterparty_connection_id",
"value":"connection-0"
}
]
},
{
"type":"message",
"attributes":[
{
"key":"action",
"value":"/ibc.core.connection.v1.MsgConnectionOpenAck"
},
{
"key":"module",
"value":"ibc_connection"
}
]
}
]
}
]After MsgConnectionOpenAck successfully executes, the connection end stored on chain1 is now in state STATE_OPEN. We can use ibc-go's REST interface to check by simply entering http://localhost:27001/ibc/core/connection/v1/connections/connection-0 and check that the state of the connection is indeed STATE_OPEN:
{
"connection": {
"client_id": "07-tendermint-0",
"versions": [
{
"identifier": "1",
"features": [
"ORDER_ORDERED",
"ORDER_UNORDERED"
]
}
],
"state": "STATE_OPEN",
"counterparty": {
"client_id": "07-tendermint-0",
"connection_id": "connection-0",
"prefix": {
"key_prefix": "aWJj"
}
},
"delay_period": "0"
},
"proof": null,
"proof_height": {
"revision_number": "0",
"revision_height": "220"
}
}After MsgConnectionOpenAck succeeds on chain1, then the relayer submits MsgConnectionOpenConfirm on chain2 (see the message proto definition.
In hermes MsgConnectionOpenConfirm is constructed and sent in function build_conn_confirm_and_send. More specifically, the message is constructed in build_conn_confirm.
To build MsgConnectionOpenConfirm hermes queries chain1 at a certain height to get proof for the following thing:
- A proof that
chain1has updated the state of its connection end with connection IDconnection-0toSTATE_OPEN.
In this tutorial the height at which hermes is going to query chain1 for this proof is 242 (we know this because we will see that hermes has submitted together with MsgConnectionOpenConfirm a MsgUpdateClient that updates the client state of chain1 on chain2 to the height 243). The query height is obtained here by querying Tendermint's /status RPC endpoint and reading the values for result.node_info.network (which is the revision number, chain1) and result.sync_info.latest_block_height (which is the revision height, 242).
The parameters needed to construct MsgConnectionOpenConfirm are:
It is the connection ID for the connection end on chain2 (connection-0 in this tutorial).
It is obtained by performing an ABCI RPC query to the ibc store of chain1. This proof is used to verify that chain1 has stored a connection end with state STATE_OPEN at the query height (242 in this tutorial). We can make the same ABCI RPC query on the browser by simply using Tendermint's /abci_query REST endpoint:
path: "store/ibc/key"
data: "connections/connection-0" (in hex: 0x636f6e6e656374696f6e732f636f6e6e656374696f6e2d30)
prove: true (so that the response contains the merkle proof)
height: 242
URL: http://localhost:27000/abci_query?path="store/ibc/key"&data=0x636f6e6e656374696f6e732f636f6e6e656374696f6e2d30&prove=true&height=242
See sample JSON response.
The response to this ABCI RPC query contains both the value stored at the queried path (connections/connection-0) and the proof needed to verify it. If we take the base64-encoded byte string from the value for the field result.response.value and we decode it, then we can inspect the information for the connection end stored in chain1:
{
ClientId:07-tendermint-0
Versions:[
identifier:"1"
features:"ORDER_ORDERED"
features:"ORDER_UNORDERED"
]
State:STATE_OPEN
Counterparty:{
ClientId:07-tendermint-0
ConnectionId:connection-0
Prefix:{
KeyPrefix:[105 98 99]
}
}
DelayPeriod:0
}
We see that the connection end is in state STATE_OPEN. The key_prefix is the byte representation of the string ibc.
It is the height for the commitment root for proving the proof for ack. When creating this proof, chain1 is queried at height proof_height - 1 (242 in this tutorial). The reason why proof_height (243 in this tutorial) is query_height + 1 is because for Tendermint chains the app hash after applying all transactions in block n is included in block at height n + 1.
It is the address of the relayer that submits the message.
Using hermes to submit this message we execute the following command:
> hermes --config config.toml tx conn-confirm \
--dst-chain chain2 \
--src-chain chain1 \
--dst-client 07-tendermint-0 \
--src-client 07-tendermint-0 \
--dst-connection connection-0 \
--src-connection connection-0
From the hermes log we can retrieve the hash of the transaction that executed MsgConnectionOpenConfirm:
2022-09-24T19:31:53.480574Z DEBUG ThreadId(13) send_tx_commit{id=ConnectionOpenConfirm}:send_tx_with_account_sequence_retry{id=chain2}: broadcast_tx_sync: Response { code: Ok, data: Data([]), log: Log("[]"), hash: transaction::Hash(DED572F1C2930C49C43C057C6D1D959472F7027DE24704E3464483DED83C8DDD) }
And we can use this hash to get the transaction information using Tendermint's /tx RPC endpoint:
http://localhost:27010/tx?hash=0xDED572F1C2930C49C43C057C6D1D959472F7027DE24704E3464483DED83C8DDD
See sample JSON result.
The transaction was successfully executed and included in the block at height 177. The value in the field result.tx is a base64-encoded string of the bytes of the messages that were executed as part of the transaction. This transaction contains two messages: MsgUpdateClient and MsgConnectionOpenConfirm; and if we decode these bytes we can retrieve back the message data that the relayer submitted:
> simd tx decode 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
See sample JSON result.
In particular the MsgUpdateClient and MsgConnectionOpenConfirm look like this:
{
"@type":"/ibc.core.client.v1.MsgUpdateClient",
"client_id":"07-tendermint-0",
"header":{
"@type":"/ibc.lightclients.tendermint.v1.Header",
"signed_header":{
"header":{
"version":{
"block":"11",
"app":"0"
},
"chain_id":"chain1",
"height":"243",
"time":"2022-09-24T19:31:48.249022Z",
"last_block_id":{
"hash":"2fqqgJHqD6OcRsDPjWt/FXp8e4bAFbReM1j/JSXZFCk=",
"part_set_header":{
"total":1,
"hash":"oGwfj/3awy+HM57pdHshs5BtbkYI5pExLeH6Xz2dfDk="
}
},
"last_commit_hash":"Q6xU2wQlJNI8Knmf+33MlAJeO6Nqy2JJ5cOZdgO7wg8=",
"data_hash":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
"validators_hash":"lGCNkT5hD2Ieag9s+6qfYt873x14YOJnVK1lLcyKWJw=",
"next_validators_hash":"lGCNkT5hD2Ieag9s+6qfYt873x14YOJnVK1lLcyKWJw=",
"consensus_hash":"BICRvH3cKD93v7+R1zxE2ljD34qcvIZ0Bdi389qtoi8=",
"app_hash":"l9p2DWT0ypIf/AKrS2vCMGvV6tSMK5Jjt1VUOFeYWN0=",
"last_results_hash":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
"evidence_hash":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
"proposer_address":"/KFlfQw/mhsgX7gFKSYhHuxsUak="
},
"commit":{
"height":"243",
"round":0,
"block_id":{
"hash":"/pwSlut6yNiK62vk752aepcgkag2QO7n1L3fqwM3uew=",
"part_set_header":{
"total":1,
"hash":"sxPVv/RFfr/inkb5OeATcq2fYKneyGEFnCMW8l7cnY4="
}
},
"signatures":[
{
"block_id_flag":"BLOCK_ID_FLAG_COMMIT",
"validator_address":"/KFlfQw/mhsgX7gFKSYhHuxsUak=",
"timestamp":"2022-09-24T19:31:53.311985Z",
"signature":"A7t/oLH8qs8+1fJWorXFpAlB3DHL2GhVrHYxnyI9aR++xeR2Qu5VZrd/JqJwmXSI6jQDrts07NhaPCKyc4l9AQ=="
}
]
}
},
"validator_set":{
"validators":[
{
"address":"/KFlfQw/mhsgX7gFKSYhHuxsUak=",
"pub_key":{
"ed25519":"Vf2Pj3yaGBnAtQLbKCb9tWC7WpLyn8u9nWkoNKB7PbU="
},
"voting_power":"10",
"proposer_priority":"0"
}
],
"proposer":{
"address":"/KFlfQw/mhsgX7gFKSYhHuxsUak=",
"pub_key":{
"ed25519":"Vf2Pj3yaGBnAtQLbKCb9tWC7WpLyn8u9nWkoNKB7PbU="
},
"voting_power":"10",
"proposer_priority":"0"
},
"total_voting_power":"10"
},
"trusted_height":{
"revision_number":"0",
"revision_height":"209"
},
"trusted_validators":{
"validators":[
{
"address":"/KFlfQw/mhsgX7gFKSYhHuxsUak=",
"pub_key":{
"ed25519":"Vf2Pj3yaGBnAtQLbKCb9tWC7WpLyn8u9nWkoNKB7PbU="
},
"voting_power":"10",
"proposer_priority":"0"
}
],
"proposer":{
"address":"/KFlfQw/mhsgX7gFKSYhHuxsUak=",
"pub_key":{
"ed25519":"Vf2Pj3yaGBnAtQLbKCb9tWC7WpLyn8u9nWkoNKB7PbU="
},
"voting_power":"10",
"proposer_priority":"0"
},
"total_voting_power":"10"
}
},
"signer":"cosmos1flqvlaum0drg089fhzqq3n042sdlvukj8dae3z"
},
{
"@type":"/ibc.core.connection.v1.MsgConnectionOpenConfirm",
"connection_id":"connection-0",
"proof_ack":"CusCCugCChhjb25uZWN0aW9ucy9jb25uZWN0aW9uLTASYAoPMDctdGVuZGVybWludC0wEiMKATESDU9SREVSX09SREVSRUQSD09SREVSX1VOT1JERVJFRBgDIiYKDzA3LXRlbmRlcm1pbnQtMBIMY29ubmVjdGlvbi0wGgUKA2liYxoMCAEYASABKgQAAqgDIioIARImAgSoAyDlbr3KBdkhO9gmoe5A0xaatAsH8Kk9yc5vwABz70CLuCAiKggBEiYECKgDIIppJtp7gjOIwGGhf7Xv5STrvNVgzIlUw2wTAGUU+66zICIqCAESJgYMqAMgBsyLghpxZViP3Bn2D7ICunvDOA0BtcaYu6a2Kw8AwmwgIiwIARIFCBKoAyAaISALd3gy24VzkapNzyUyos73DaskOFqMunB5PDe0+zbjqCIqCAESJgokqAMgUNKdevm8B/IUbQRYaZUxhXXVTyI4zR8I8ltYwiwIP08gCv4BCvsBCgNpYmMSIMQoajHoCPnsqtJK36RxsYCbtrJ706zB4FnuDG/dP9gTGgkIARgBIAEqAQAiJQgBEiEBRrIPWyoPk3eSgkugPkJ6eniFTnDkezXSqYrL5TiW+RMiJwgBEgEBGiCqZQQG6g12453UPS6mqR4/2qHJCPwhp8po5eYsyBFWOSInCAESAQEaII1jsf/SXAG2WkIS5ZCEqfA0nd8JgIjeauLJEaIr5/99IiUIARIhAQZ0ZeeWt9xWHkd3kghUybRanh6FiJS3BHHHZDSBPo6PIicIARIBARogmwRTLRVy5fnOCdMBg7OSc+eu49EqwQmx+RyG6Ek/u90=",
"proof_height":{
"revision_number":"0",
"revision_height":"243"
},
"signer":"cosmos1flqvlaum0drg089fhzqq3n042sdlvukj8dae3z"
}After the message reaches the message server the execution continues in ConnectionKeeper's ConnOpenConfirm function, to which the message fields are passed in. The steps in ConnOpenConfirm consist of:
-
Retrieve the connection end previously stored during execution of
ConnOpenTryand check that the state isSTATE_TRYOPEN. -
Construct the expected connection end that
chain2expectschain1to have stored in its state. The expected connection end ischain1's connection end updated during theConnectionOpenAckstep (i.e. the state was updated fromSTATE_INITtoSTATE_OPEN). -
Verify against the app hash at height
proofHeightthatchain1stored in state the expected connection end. This verification checks thatchain1has stored in the pathconnections/connection-0of theibcstore the expected connection end with stateSTATE_OPENupdated during the execution ofMsgConnectionOpenAck. It does this by computing the merkle root hash usingproofAckand the expected connection end and checking that it matches the root hash atproofHeightof the consensus state stored for the light client ofchain1. -
Update the state of the connection end on
chain2toSTATE_OPEN. - An event is emitted signalling that the connection open confirm has finished successfully:
[
{
"events":[
{
"type":"message",
"attributes":[
{
"key":"action",
"value":"/ibc.core.client.v1.MsgUpdateClient"
},
{
"key":"module",
"value":"ibc_client"
}
]
},
{
"type":"update_client",
"attributes":[
{
"key":"client_id",
"value":"07-tendermint-0"
},
{
"key":"client_type",
"value":"07-tendermint"
},
{
"key":"consensus_height",
"value":"0-243"
},
{
"key":"header",
"value":"0a262f6962632e6c69676874636c69656e74732e74656e6465726d696e742e76312e48656164657212d1060ac9040a8c030a02080b1206636861696e3118f301220b08a4b6bd990610b08cdf762a480a20d9faaa8091ea0fa39c46c0cf8d6b7f157a7c7b86c015b45e3358ff2525d91429122408011220a06c1f8ffddac32f87339ee9747b21b3906d6e4608e691312de1fa5f3d9d7c39322043ac54db042524d23c2a799ffb7dcc94025e3ba36acb6249e5c3997603bbc20f3a20e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855422094608d913e610f621e6a0f6cfbaa9f62df3bdf1d7860e26754ad652dcc8a589c4a2094608d913e610f621e6a0f6cfbaa9f62df3bdf1d7860e26754ad652dcc8a589c5220048091bc7ddc283f77bfbf91d73c44da58c3df8a9cbc867405d8b7f3daada22f5a2097da760d64f4ca921ffc02ab4b6bc2306bd5ead48c2b9263b7555438579858dd6220e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8556a20e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8557214fca1657d0c3f9a1b205fb8052926211eec6c51a912b70108f3011a480a20fe9c1296eb7ac8d88aeb6be4ef9d9a7a972091a83640eee7d4bddfab0337b9ec122408011220b313d5bff4457ebfe29e46f939e01372ad9f60a9dec861059c2316f25edc9d8e226808021214fca1657d0c3f9a1b205fb8052926211eec6c51a91a0c08a9b6bd990610e886e29401224003bb7fa0b1fcaacf3ed5f256a2b5c5a40941dc31cbd86855ac76319f223d691fbec5e47642ee5566b77f26a270997488ea3403aedb34ecd85a3c22b273897d01127e0a3c0a14fca1657d0c3f9a1b205fb8052926211eec6c51a912220a2055fd8f8f7c9a1819c0b502db2826fdb560bb5a92f29fcbbd9d692834a07b3db5180a123c0a14fca1657d0c3f9a1b205fb8052926211eec6c51a912220a2055fd8f8f7c9a1819c0b502db2826fdb560bb5a92f29fcbbd9d692834a07b3db5180a180a1a0310d101227e0a3c0a14fca1657d0c3f9a1b205fb8052926211eec6c51a912220a2055fd8f8f7c9a1819c0b502db2826fdb560bb5a92f29fcbbd9d692834a07b3db5180a123c0a14fca1657d0c3f9a1b205fb8052926211eec6c51a912220a2055fd8f8f7c9a1819c0b502db2826fdb560bb5a92f29fcbbd9d692834a07b3db5180a180a"
}
]
}
]
},
{
"msg_index":1,
"events":[
{
"type":"connection_open_confirm",
"attributes":[
{
"key":"connection_id",
"value":"connection-0"
},
{
"key":"client_id",
"value":"07-tendermint-0"
},
{
"key":"counterparty_client_id",
"value":"07-tendermint-0"
},
{
"key":"counterparty_connection_id",
"value":"connection-0"
}
]
},
{
"type":"message",
"attributes":[
{
"key":"action",
"value":"/ibc.core.connection.v1.MsgConnectionOpenConfirm"
},
{
"key":"module",
"value":"ibc_connection"
}
]
}
]
}
]After MsgConnectionOpenConfirm successfully executes, the connection end on both chain1 and chain2 is in state STATE_OPEN. We can use ibc-go's REST interface to check; first for chain1 by simply entering http://localhost:27001/ibc/core/connection/v1/connections/connection-0:
{
"connection": {
"client_id": "07-tendermint-0",
"versions": [
{
"identifier": "1",
"features": [
"ORDER_ORDERED",
"ORDER_UNORDERED"
]
}
],
"state": "STATE_OPEN",
"counterparty": {
"client_id": "07-tendermint-0",
"connection_id": "connection-0",
"prefix": {
"key_prefix": "aWJj"
}
},
"delay_period": "0"
},
"proof": null,
"proof_height": {
"revision_number": "0",
"revision_height": "251"
}
}And then also for chain2 by simply entering http://localhost:27011/ibc/core/connection/v1/connections/connection-0:
{
"connection": {
"client_id": "07-tendermint-0",
"versions": [
{
"identifier": "1",
"features": [
"ORDER_ORDERED",
"ORDER_UNORDERED"
]
}
],
"state": "STATE_OPEN",
"counterparty": {
"client_id": "07-tendermint-0",
"connection_id": "connection-0",
"prefix": {
"key_prefix": "aWJj"
}
},
"delay_period": "0"
},
"proof": null,
"proof_height": {
"revision_number": "0",
"revision_height": "189"
}
}The sequence diagram was generated with the following code:
sequenceDiagram
participant chain1
participant hermes
participant chain2
critical ConnectionOpenInit
hermes->>chain1: MsgConnectionOpenInit
Note over chain1: ConnOpenInit succeeds at height 142
end
critical ConnectionOpenTry
hermes->>chain1: MsgUpdateClient
Note over chain1: chain2's consensus state updated to height 106
Note over chain1: UpdateClient succeeds at height 174
hermes-->>chain1: query chain2's client_state (height 174)
hermes-->>chain1: query proof_init (height 174)
hermes-->>chain1: query proof_client (height 174)
hermes-->>chain1: query proof_consensus (height 174)
hermes->>chain2: MsgUpdateClient
Note over chain2: chain1's consensus state updated to height 175
hermes->>chain2: MsgConnectionOpenTry
Note over chain2: Verify proofs against chain1's consensus state at height 175
Note over chain2: UpdateClient and ConnOpenTry succeed at height 109
end
critical ConnectionOpenAck
hermes->>chain2: MsgUpdateClient
Note over chain2: chain1's consensus state updated to height 209
Note over chain2: UpdateClient succeeds at height 144
hermes-->>chain2: query chain1's client_state (height 144)
hermes-->>chain2: query proof_try (height 144)
hermes-->>chain2: query proof_client (height 144)
hermes-->>chain2: query proof_consensus (height 144)
hermes->>chain1: MsgUpdateClient
Note over chain1: chain2's consensus state updated to height 145
hermes->>chain1: MsgConnectionOpenAck
Note over chain1: Verify proofs against chain2's consensus state at height 145
Note over chain1: UpdateClient and ConnOpenAck succeed at height 212
end
critical ConnectionOpenConfirm
hermes-->>chain1: query proof_ack (height 242)
hermes->>chain2: MsgUpdateClient
Note over chain2: chain1's consensus state updated to height 243
hermes->>chain2: MsgConnectionOpenConfirm
Note over chain2: Verify proof against chain1's consensus state at height 243
Note over chain2: UpdateClient and ConnOpenConfirm succeed at height 177
end
using Mermaid's live editor.