# Transport, Authentication, and Ordering Layer - Connections
IBC in depth. Discover the IBC protocol in detail:
- Learn more about connection negotiation.
- Explore connection states.
- How IBC repels hostile connection attempts.
Now that you covered the introduction and have a better understanding of how different Inter-Blockchain Communication (IBC) Protocol components and Interchain Standards (ICS) relate to each other, take a deep dive into IBC/TAO (transport, authentication, and ordering) and the IBC module (opens new window).
If you want to connect two blockchains with IBC, you will need to establish an IBC connection. Connections, established by a four-way handshake, are responsible for:
- Establishing the identity of the counterparty chain.
- Preventing a malicious entity from forging incorrect information by pretending to be the counter party chain. IBC connections are established by on-chain ledger code and therefore do not require interaction with off-chain (trusted) third-party processes.
The connection semantics are described in ICS-3 (opens new window).
In the IBC stack, connections are built on top of clients, so technically there could be multiple connections for each client if the client is interacting with multiple versions of the IBC protocol. For now, the setup should connote one connection for each client.
Note that versioning here refers to the IBC protocol spec and not the ibc-go module. A backwards incompatible update is currently not planned.
Protocol versioning is important to establish, as different protocol versions may not be compatible, for example due to proofs being stored on a different path. There are three types of protocol version negotiation:
- Default, no selection: only one protocol version is supported. This is default to propose.
- With selection: two protocol versions can be proposed, such that the chain initiating
OpenTryhas a choice of which version to go with.
- Impossible communication: a backwards incompatible IBC protocol version. For example, if an IBC module changes where it stores its proofs (proof paths), errors result. There are no plans to upgrade to a backwards incompatible IBC protocol version.
As discussed previously, the opening handshake protocol allows each chain to verify the identifier used to reference the connection on the other chain, enabling modules on each chain to reason about the reference of the other chain.
With regards to the connection on the other side, the connection protobufs (opens new window) contains the
In this definition,
connection-id is used as a key to map and retrieve connections associated with a certain client from the store.
prefix is used by the clients to construct merkle prefix paths which are then used to verify proofs.
# Connection handshakes and states
Establishing an IBC connection (for example, between chain A and chain B) requires four handshakes:
A high level overview of a successful four-way handshake is as follows:
# Handshake 1: OpenInit
OpenInit initializes any connection which may occur, while still necessitating agreement from both sides. It is like an identifying announcement from the IBC module on chain A which is submitted by a relayer. The relayer should also submit an
UpdateClient with chain A as the source chain before this handshake.
UpdateClient updates the client on the initializing chain A with the latest consensus state of chain B.
The initiation of this handshake from chain A updates its connection state to
OpenInit proposes a protocol version to be used for the IBC connection. A relayer-submitted
OpenInit which contains a protocol version that is not supported by chain A will be expected to fail.
The reference implementation for the connection handshake is found in the IBC module repository (opens new window). Examine
This function creates a unique
connectionID. It adds the connection to a list of connections associated with a specific client.
It creates a new
ConnOpenInit is triggered by the relayer, which constructs the message and sends it to the SDK that uses the
msg_server.go (opens new window) previously seen to call
# Handshake 2: OpenTry
OpenInit is followed by an
OpenTry response, in which chain B verifies the identity of chain A according to information that chain B has about chain A in its light client (the algorithm and the last snapshot of the consensus state containing the root hash of the latest height as well as the next validator set). It also responds to some of the information about its own identity in the
OpenInit announcement from chain A.
The purpose of this step of the handshake is double verification: not only for chain B to verify that chain A is the expected counterparty identity, but also to verify that the counterparty has accurate information about chain B's identity. The relayer also submits two
UpdateClients with chain A and chain B as source chains before this handshake. These update the light clients of both chain A and chain B in order to make sure that the state verifications in this step are successful.
The initiation of this handshake from chain B updates its connection state to
With regards to IBC protocol versioning,
OpenTry either accepts the protocol version which has been proposed in
OpenInit or proposes another protocol version from the versions available to chain A to be used for the IBC connection. A relayer-submitted
OpenTry which contains an unsupported protocol version will be expected to fail.
The implementation of OpenTry is as follows:
# Handshake 3: OpenAck
OpenAck is very similar to the functionality of
OpenInit, except that the information verification now occurs for chain A. As in
OpenTry, the relayer also submits two
UpdateClients with chain A and chain B as source chains before this handshake. These update the light clients of both chain A and chain B, in order to make sure that the state verifications in this step are successful.
The initiation of this handshake from chain A updates its connection state to
OPEN. It is important to note that the counterparty chain must have a
TRY connection state in order for the handshake and connection state update to be successful.
With regards to version negotiation,
OpenAck must confirm the protocol version which has been proposed in
OpenTry. It ends the connection handshake process if the version is unwanted or unsupported.
OpenAck code is very similar to
Both functions do the same checks, except that
proofInit as a parameter, and
Therefore, each chain verifies the
ClientState, and the
ConsensusState of the other chain. Note that after this step the connection state on chain A updates from
# Handshake 4: OpenConfirm
OpenConfirm is the final handshake, in which chain B confirms that both self-identification and counterparty identification were successful.
The conclusion of this handshake results in the successful establishing of an IBC connection:
The initiation of this handshake from chain B updates its connection state from
OPEN. The counterparty chain must have an
OPEN connection state in order for the handshake and connection state update to be successful.
The successful four-way handshake described establishes an IBC connection between the two chains. Now consider two related circumstances: simultaneous attempts by the chains to perform the same handshake, and attempts by an imposter to interfere.
# Crossing hellos
"Crossing Hellos" refers to when both chains attempt the same handshake step at the same time.
If both chains submit
OpenTry at same time, there should be no error. In this case, both sides still need to confirm with a successful
OpenAck, but no
OpenConfirm is required because both ConnectionEnds will update to an OPEN state.
# An imposter
In fact this is not an issue. Any attempted
OpenInit from an imposter will fail on
OpenTry, because it will not contain valid proofs of
# Next up
Now that you finished having a look at connections in IBC/TAO, it is now time to switch your focus to channels in the next section.