Overview
Learn about IBC, its components, and IBC use cases.
What is the Interblockchain Communication Protocol (IBC)?
This document serves as a guide for developers who want to write their own Inter-Blockchain Communication protocol (IBC) applications for custom use cases.
IBC applications must be written as self-contained modules.
Due to the modular design of the IBC protocol, IBC application developers do not need to be concerned with the low-level details of clients, connections, and proof verification.
This brief explanation of the lower levels of the
stack gives application developers a broad understanding of the IBC
protocol. Abstraction layer details for channels and ports are most relevant for application developers and describe how to define custom packets and IBCModule
callbacks.
The requirements to have your module interact over IBC are:
- Bind to a port or ports.
- Define your packet data.
- Use the default acknowledgment struct provided by core IBC or optionally define a custom acknowledgment struct.
- Standardize an encoding of the packet data.
- Implement the
IBCModule
interface.
Read on for a detailed explanation of how to write a self-contained IBC application module.
Components Overview
Clients
IBC clients are on-chain light clients. Each light client is identified by a unique client-id.
IBC clients track the consensus states of other blockchains, along with the proof spec necessary to
properly verify proofs against the client's consensus state. A client can be associated with any number
of connections to the counterparty chain. The client identifier is auto generated using the client type
and the global client counter appended in the format: {client-type}-{N}
.
A ClientState
should contain chain specific and light client specific information necessary for verifying updates
and upgrades to the IBC client. The ClientState
may contain information such as chain-id, latest height, proof specs,
unbonding periods or the status of the light client. The ClientState
should not contain information that
is specific to a given block at a certain height, this is the function of the ConsensusState
. Each ConsensusState
should be associated with a unique block and should be referenced using a height. IBC clients are given a
client identifier prefixed store to store their associated client state and consensus states along with
any metadata associated with the consensus states. Consensus states are stored using their associated height.
The supported IBC clients are:
- Solo Machine light client: Devices such as phones, browsers, or laptops.
- Tendermint light client: The default for Cosmos SDK-based chains.
- Localhost (loopback) client: Useful for testing, simulation, and relaying packets to modules on the same application.
IBC Client Heights
IBC Client Heights are represented by the struct:
type Height struct {
RevisionNumber uint64
RevisionHeight uint64
}
The RevisionNumber
represents the revision of the chain that the height is representing.
A revision typically represents a continuous, monotonically increasing range of block-heights.
The RevisionHeight
represents the height of the chain within the given revision.
On any reset of the RevisionHeight
—for example, when hard-forking a Tendermint chain—
the RevisionNumber
will get incremented. This allows IBC clients to distinguish between a
block-height n
of a previous revision of the chain (at revision p
) and block-height n
of the current
revision of the chain (at revision e
).
Height
s that share the same revision number can be compared by simply comparing their respective RevisionHeight
s.
Height
s that do not share the same revision number will only be compared using their respective RevisionNumber
s.
Thus a height h
with revision number e+1
will always be greater than a height g
with revision number e
,
REGARDLESS of the difference in revision heights.
Ex:
Height{RevisionNumber: 3, RevisionHeight: 0} > Height{RevisionNumber: 2, RevisionHeight: 100000000000}
When a Tendermint chain is running a particular revision, relayers can simply submit headers and proofs with the revision number
given by the chain's chainID
, and the revision height given by the Tendermint block height. When a chain updates using a hard-fork
and resets its block-height, it is responsible for updating its chainID
to increment the revision number.
IBC Tendermint clients then verifies the revision number against their chainID
and treat the RevisionHeight
as the Tendermint block-height.
Tendermint chains wishing to use revisions to maintain persistent IBC connections even across height-resetting upgrades must format their chainID
s
in the following manner: {chainID}-{revision_number}
. On any height-resetting upgrade, the chainID
MUST be updated with a higher revision number
than the previous value.
Ex:
- Before upgrade
chainID
:gaiamainnet-3
- After upgrade
chainID
:gaiamainnet-4
Clients that do not require revisions, such as the solo-machine client, simply hardcode 0
into the revision number whenever they
need to return an IBC height when implementing IBC interfaces and use the RevisionHeight
exclusively.
Other client-types can implement their own logic to verify the IBC heights that relayers provide in their Update
, Misbehavior
, and
Verify
functions respectively.
The IBC interfaces expect an ibcexported.Height
interface, however all clients must use the concrete implementation provided in
02-client/types
and reproduced above.
Connections
Connections encapsulate two ConnectionEnd
objects on two separate blockchains. Each
ConnectionEnd
is associated with a client of the other blockchain (for example, the counterparty blockchain).
The connection handshake is responsible for verifying that the light clients on each chain are
correct for their respective counterparties. Connections, once established, are responsible for
facilitating all cross-chain verifications of IBC state. A connection can be associated with any
number of channels.