Skip to content

IBC Notes

Yang SONG edited this page Dec 8, 2021 · 3 revisions

IBC Overview

When an IBC Transfer is triggered, it is just the beginning.

A user signed a transaction containing a MsgTransfer message, and broadcast it to the network.

Later, when the transaction succeeds and is written into a block, the network will generate related events. These events will be caught by Relayers, and they will sign other corresponding transactions to do the communication between two networks.

A full IBC Transfer lifecycle could be:

Success case:

  1. MsgTransfer msg detected on Chain A:
    • A user signs a transaction on Chain A, and the transaction is executed and is written to a block.
  2. MsgRecvPacket msg detected on Chain B:
    • Relayer signs a transaction containing MsgRecvPacket msg on Chain B. It tells Chain B that one IBC Transfer has triggered on Chain A.
    • The IBC Transfer packet is received and handled on Chain B.
    • The IBC Transfer could be either succeed or fail.
  3. MsgAcknowledgement msg detected on Chain A:
    • Relayer signs a transaction containing MsgAcknowledgement msg on Chain A. It tells Chain A that the IBC Transfer is handled on Chain B.
    • The IBC Transfer could be either succeed or fail.
    • The IBC Transfer is finished.

Failure case:

  1. MsgTransfer msg detected on Chain A:
    • A user signs a transaction on Chain A, and the transaction is executed and is written to a block.
  2. MsgTimeout msg detected on Chain A:
    • Relayer signs a transaction containing MsgTimeout msg on Chain A. It tells Chain A that the IBC Transfer timeouts.

Multiple Relays For A Single Packet

Problem

One problem is that for each IBC Channel, there could be multiple relayers monitoring it. Therefore, there is a race condition between relayers. Each IBC Transfer could be relayed by multiple relayers.

For example, when one tx containing MsgTransfer is on Chain A, you might see multiple corresponding txs containing MsgRecvPacket on Chain B.

Although there will be multiple MsgRecvPacket msg for one MsgTransfer, only one of the MsgRecvPacket will be executed. Others will be ignored by CosmosSDK, they will do no-operation to the duplicate relayed msgs.

Similar behavior also exists on MsgAcknowledgement and MsgTimeout.

Code references on CosmosSDK:

Solution

From an indexing perspective, we are not interested in those multiple relayed msgs, and we want to ignore them.

In order to do that, we introduced a set of customized Msgs, which is defined by ourselves:

  • MsgAlreadyRelayedIBCRecvPacket
  • MsgAlreadyRelayedIBCAcknowledgement
  • MsgAlreadyRelayedIBCTimeout
  • MsgAlreadyRelayedIBCTimeoutOnClose

During the parsing of block and block_results, when those multiple relayed msgs are detected, they will be converted to the above-mentioned customized Msgs.

Our existing projections will not handle these messages, which fulfills the target of ignoring them.

Determining Success for MsgRecvPacket and MsgAcknowledgement

For MsgRecvPacket:

  • If success:
    • msgIBCRecvPacket.Params.MaybeFungibleTokenPacketData.Success should be true.
    • msgIBCRecvPacket.Params.PacketAck.MaybeError should be nil.
  • If failure:
    • msgIBCRecvPacket.Params.MaybeFungibleTokenPacketData.Success should be false.
    • msgIBCRecvPacket.Params.PacketAck.MaybeError should contain error message.

For MsgAcknowledgement:

  • If success:
    • msgIBCAcknowledgement.Params.MaybeFungibleTokenPacketData.Success should be true.
    • msgIBCAcknowledgement.Params.MaybeFungibleTokenPacketData.MaybeError should be nil.
  • If failure:
    • msgIBCAcknowledgement.Params.MaybeFungibleTokenPacketData.Success should be false.
    • msgIBCAcknowledgement.Params.MaybeFungibleTokenPacketData.MaybeError should contain error message.

IBC Denom

A good reference from Cosmos: https://tutorials.cosmos.network/understanding-ibc-denoms/

An IBC Denom has two formats:

  • [<port-id>/<channel-id>/]<original-denom>:
    • e.g. transfer/channel-0/basecro, basecro
  • ibc/XXXX: (ibc/ followed by a sha256 hash)
    • e.g. ibc/6411AE2ADA1E73DB59DB151A8988F9B7D5E7E233D8414DB6817F8F1A01611F86

The two formats are representing the same thing:

ibc/ + sha256("transfer/channel-0/basecro") = ibc/6411AE2ADA1E73DB59DB151A8988F9B7D5E7E233D8414DB6817F8F1A01611F86

Problem

One problem caused by the formats is in tx raw MsgTransfer messages, its token denom could be in [<port-id>/<channel-id>/]<original-denom> format or ibc/XXXX format.

As we need to calculate the bonded_tokens for each IBC Channel, we want to always represent denom in [<port-id>/<channel-id>/]<original-denom> format in our system.

Solution

To keep the denom consistent when doing related calculation, for MsgTransfer message:

  • Always use: msgIBCTransferTransfer.Params.PacketData.Denom, as it is always in [<port-id>/<channel-id>/]<original-denom> format.
  • Not recommend to use: msgIBCTransferTransfer.Params.Token.Denom, as it is possible in ibc/XXXX format.