IBC between Cradle sessions

Being a direct fork of a Mainnet, Cradle sessions support IBC. Unlike testnet/local devnet, you can leverage existing IBC connections and channels on Mainnet, making it easier to directly test IBC interactions as if you were doing transactions on Mainnet. This is extremely useful if you want to test, for example, a cross-chain contract migrations or token transfers.

This document will guide you through the process of using IBC between Cradle sessions.

Note

This feature is experimental and may not work as expected. Let us know if it's broken!


Configuring Cradle sessions for IBC

To use IBC between Cradle sessions, you should have at least two Cradle sessions running. If you haven't already, you can follow the Getting Started to set up your Cradle sessions.

Make sure you're creating sessions that are close by, time-wise!

IBC relayers assume both chains are running within a certain time difference called clock drift. If the time difference between the two chains is too large, the relayer will fail to send transactions.

  • The best way to ensure that the time difference is minimal is to create the sessions at the latest available block height, at the same time.
  • If you're creating a fork of a certain block height, make sure you find and create the other session at around the same time.

Configuring IBC Relayers for Cradle sessions

You will need to setup your own relayer between Cradle sessions. In this tutorial, we will be using hermes. We will assume that you have already installed hermes, and wallets are setup.

If this is your first time, you can follow the Hermes Quick Start.

Configure source and destination chains

First, you will need to configure the source and destination chains in the hermes configuration file. The configuration file is usually located at ~/.hermes/config.toml.

Below is an example configuration (essential parts only):

[[chains]]
# Source chain ID as shown in the Cradle session's config
id = "{SRC_CHAIN_ID}"

# Source RPC address as shown in the Cradle session's config
rpc_addr = "https://...."

# Source gRPC address as shown in the Cradle session's config.
# IMPORTANT: use http://
grpc_addr = "http://{session_id}.cradle-grpc.ec1-prod.newmetric.xyz:80"

# Cradle doesn't support websocket yet, so you'll need to use `pull` mode
event_source = { mode = 'pull', interval = '10s' }

[[chains]]
# Destination chain ID as shown in the Cradle session's config
id = "{DST_CHAIN_ID}"

# Destination RPC address as shown in the Cradle session's config
# IMPORTANT: use http://
rpc_addr = "https://...." # Destination RPC address

# Destination gRPC address as shown in the Cradle session's config
grpc_addr = "{session_id}.cradle-grpc.ec1-prod.newmetric.xyz:80"

# Cradle doesn't support websocket yet, so you'll need to use `pull` mode
event_source = { mode = 'pull', interval = '10s' }
See if relayer can connect to both sessions

Run the following command to see if the relayer can connect to both chains:

$ hermes health-check

# If the relayer can connect to both chains, you should see logs similar to the following:
2024-02-19T19:06:38.486663Z  INFO ThreadId(01) health_check{chain=src}: chain is healthy
2024-02-19T19:06:41.486663Z  INFO ThreadId(01) health_check{chain=dst}: chain is healthy
SUCCESS performed health check for all chains in the config
(optional) Applying packet filters to make things quicker

By default, hermes will check all packets across all channels. Sometimes, this may cause the relayer to take a long time to start, especially for Cradle sessions.

You can apply packet filters to make the relayer start faster.

[[chains]]

# allow only channel-25 and channel-229
[chains.packet_filter]
policy = 'allow'
list = [
    ['transfer', 'channel-25'],
    ['transfer', 'channel-229'],
]
🚀 Done!

That's it! You have successfully configured hermes to work with Cradle sessions. You can now proceed to send IBC transactions between the Cradle sessions.


Sending IBC transactions

For Cradle sessions, the steps to send an IBC transaction are similar to the steps for Mainnet. The only difference is that it's manual; since Cradle sessions don't propose blocks automatically, you will need to propose blocks at the right timing to ensure that the IBC transactions are sent and received correctly.

This is largely due to relayers depending on the chain states to determine what steps to take next. IBC, being a trustless protocol, mandates certain level of observable security before it proceeds with the next step. Usually, this is done by checking the trusted height of the chain, which is the height at which the chain is considered to be in a stable state.

Below are the step-by-step instructions to send an IBC transaction between Cradle sessions, using the hermes relayer.

Propose at least 1 block for each session

You will need to propose at least 1 block for each session to ensure that the application is ready for IBC transactions.

This is because certain permissions required for IBC transaction are only initialized in the first run of block proposal. Without this, relayer may fail with failed to simulate tx error.

Click on Propose Block on each session's dashboard.

Start the relayer

Start the relayer with the following command:

$ hermes start

Check the logs to ensure that the relayer is running without any errors. Both chains should report chain is healthy in the logs.

Send an IBC transaction to the source chain

Send an IBC transaction to the source chain. In this tutorial, we will create a fungible ICS20 transfer between two chains. For any other IBC transaction, you can send your own transaction with the appropriate messages.

$ hermes tx ft-transfer --dst-chain {DST_CHAIN_ID} --src-chain {SRC_CHAIN_ID} --src-port {SRC_PORT_ID} --src-channel {SRC_CHANNEL_ID} --amount {AMOUNT}

Replace the placeholders with the actual values for your chains.

Propose a block on the source chain

Once the transaction is sent, you should be able to see the transaction in the source chain's mempool. Propose a block on the source chain to finalize the transaction.

Propose again on the source chain

Propose another block on the source chain to reach the trusted height. This is required by relayers to ensure that the transaction is indeed finalized.

After this step, the relayer should be sending the counterparty transaction to the destination chain.

Check the destination chain's mempool

The relayer should have sent the counterparty transaction to the destination chain. Check the destination chain's mempool to ensure that the transaction is received.

Note

If you forgot to propose at least 1 block for destination chain, this is the step where you will see failed to simulate tx error. If you see this error, propose a block on the destination chain now, and repeat from Step 4.

Propose a block on the destination chain

Propose a block on the destination chain to finalize the transaction.

You can check the result of the transaction by navigating to the Cradle's block explorer for the destination chain. The transaction may fail due to invariants of the IBC protocol, and any errors will be displayed in the logs.

Propose again on the destination chain

Now it's time to send back the acknowledgement to the source chain! Propose a block on the destination chain to reach the trusted height. Much like Step 5, this is required by relayers to ensure that the transaction is finalized.

After this step, the relayer should be sending the acknowledgement to the source chain.

Check the source chain's mempool

The relayer should have sent the acknowledgement to the source chain. Check the source chain's mempool to ensure that the transaction is received.

Propose a block on the source chain to finalize

Propose a block on the source chain to finalize the transaction.

🚀 Done!

That's it! You have successfully done a full cycle of IBC transaction between Cradle sessions.


Important things you should know... maybe

IBC protocol makes heavy use of proofs and verifications involving commitments. While Cradle is a fork of Mainnet, it's a simulation; as such, it is not capable of committing to its resulting state. This means that any proof generated by Cradle is not valid in the context of the IBC protocol, therefore the destination chain will simply reject the transaction.

To overcome this limitation, Cradle bypasses certain security verifications that the IBC protocol specifies. Namely, merkle proofs for packets and light client header verification.

At this point, IBC on Cradle is essentially an insecure cross-chain messaging. However, this is fine for most testing purposes, as the focus is on the application level, not the protocol level.

If your test scenario makes any assumption of the commitment verification at the application level, there maybe discrepancies between the expected and actual results. If this is the case, you should consider using the Mainnet for your tests.