# 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 Protocol (IBC) 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).
# Connections
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 counterparty 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.
# Version negotiation
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
OpenInit
orOpenTry
has 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 Counterparty
definition:
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:
- OpenInit
- OpenTry
- OpenAck
- OpenConfirm
Colin Axnér of the Interchain Foundation gives an overview of how IBC Connections work (ICS-03), along with a code walkthrough, in the context of the Inter-Blockchain Communications Protocol (IBC).
A high level overview of a successful four-way handshake is as follows:
# Handshake step 1 - ConnOpenInit
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 a MsgUpdateClient
with chain A as the source chain before this handshake. MsgUpdateClient
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 INIT
.
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 ConnOpenInit
:
This function creates a unique connectionID
. It adds the connection to a list of connections associated with a specific client.
It creates a new ConnectionEnd
:
With the following proto definition:
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 ConnOpenInit
:
# Handshake step 2 - ConnOpenTry
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 MsgUpdateClient
s 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 TRYOPEN
.
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 (opens new window) is as follows:
# Handshake step 3 - ConnOpenAck
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 MsgUpdateClient
s 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 TRYOPEN
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.
The OpenAck
code (opens new window) is very similar to OpenTry
:
Both functions do the same checks, except that OpenTry
takes proofInit
as a parameter, and OpenAck
takes proofTry
:
Therefore, each chain verifies the ConnectionState
, the ClientState
, and the ConsensusState
of the other chain. Note that after this step the connection state on chain A updates from INIT
to OPEN
.
# Handshake step 4 - ConnOpenConfirm
OpenConfirm
is the final handshake, in which chain B confirms that both self-identification and counterparty identification were successful.
The conclusion of this handshake (opens new window) results in the successful establishing of an IBC connection:
The initiation of this handshake from chain B updates its connection state from TRYOPEN
to 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 edge 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.
While still discussed in the video earlier, crossing hellos have been removed from ibc-go v4 onward, as referenced in this PR (opens new window). The PreviousConnectionId
in MsgConnectionOpenTry
has been deprecated.
# An imposter
What if an imposter tried to open a connection pretending to be another chain?
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 Client/Connection/ConsensusState
.
To summarize, this section has explored:
- How a connection between two blockchains with IBC is established by a four-way handshake, thereby establishing the identity of the counterparty chain and preventing any malicious entity from pretending to be the counterparty.
- How versioning is important to establish, to ensure that only compatible protocol versions attempt to connect.