# Go Relayer

Before you dive into Go relayers, make sure to:

  • Install Go.
  • Install Docker.
  • Install Rust.

For all installations, please see the setup page.

Have you considered running a relayer?

In this section, you will learn:

  • How to get started with the Go relayer.
  • Basic Go relayer commands.

The Go relayer (opens new window) is a relayer implementation written in Golang. It can create clients, connections, and channels, as well as relay packets and update and upgrade clients.

The Go relayer aims to get your relayer up and running with minimal manual configuration and abstracts away a lot of the more complex Inter-Blockchain Communication Protocol (IBC) concepts. The objective is that users can spin up their own relayer and relay packets. To provide this functionality, it automates a lot of work to fetch configuration data from the chain registry (opens new window).

After the installation, you will get started with relaying on mainnet chains and do some local testing.

# Installation and getting started

The repository offers a script to start two chains, which you need to test the relayer.

The most up-to-date major version of the Go relayer is v2. This version delivered major updates and improvements, including the introduction of a provider interface to accommodate chains with different consensus types than Tendermint and event-based processing that results in performance improvements.

It is recommended to use this latest version, and the following commands assume you are using v2.

  1. First, create a folder for this section:
Copy $ mkdir relay-go-test $ cd relay-go-test
  1. Clone the Go relayer repository (opens new window):
Copy $ git clone https://github.com/cosmos/relayer.git
  1. Now build the Go relayer:
Copy $ cd relayer $ make install

Make sure that your $GOPATH is set correctly and $GOPATH/bin is included in your $PATH.

To check the available commands, run the help command on the rly binary.

Copy $ rly -h

Which returns:

Copy rly has: 1. Configuration management for Chains and Paths 2. Key management for managing multiple keys for multiple chains 3. Query and transaction functionality for IBC NOTE: Most of the commands have aliases that make typing them much quicker (i.e. 'rly tx', 'rly q', etc...) Usage: rly [command] Available Commands: config Manage configuration file chains Manage chain configurations paths Manage path configurations keys Manage keys held by the relayer for each chain transact IBC transaction commands query IBC query commands start Start the listening relayer on a given path version Print the relayer version info help Help about any command completion Generate the autocompletion script for the specified shell Flags: -d, --debug debug output -h, --help help for rly --home string set home directory (default "/Users/<userName>/.relayer") --log-format string log output format (auto, logfmt, json, or console) (default "auto") Use "rly [command] --help" for more information about a command.

Notice how the categories reflect the requirements you saw in the last section: to manage chain and path information, manage keys, query, and transact. The configuration data is added to the config file, stored at $HOME/.relayer/config/config.yaml by default. If this is the first time you run the relayer, first initialize the config with the following command:

Copy $ rly config init

And check the config with:

Copy $ rly config show

By default, transactions will be relayed with a memo of rly(VERSION) - for example, rly(v2.0.0).

To customize the memo for all relaying, use the --memo flag when initializing the configuration.

Copy $ rly config init --memo "My custom memo"



Custom memos will have rly(VERSION) appended. For example, a memo of My custom memo running on relayer version v2.0.0 would result in a transaction memo of My custom memo | rly(v2.0.0).

The --memo flag is also available for other rly commands that involve sending transactions, such as rly tx link and rly start. It can be passed there to override the config.yaml value if desired.

To omit the memo entirely, including the default value of rly(VERSION), use - for the memo.

Now you are all set to add the chains and paths you want to relay on, add your keys and start relaying. You will investigate two different scenarios: setting up a relayer between two chains on the mainnet (this would enable you to start relaying in production), and setting up two local chains for testing purposes.

# Relaying in production

As stated earlier, the Go relayer strives to get your relayer up and running in a short amount of time. You will follow the tutorial from the Github repository (opens new window) to start relaying between the Cosmos Hub and Osmosis, one of the most popular paths.

  1. Configure the chains you want to relay between.

In this example, you will configure the relayer to operate on the canonical path between the Cosmos Hub and Osmosis.

The rly chains add command fetches chain metadata from the chain registry (opens new window) and adds it to your config file:

Copy $ rly chains add cosmoshub osmosis

Adding chains from the chain registry randomly selects a publicly available RPC address from the registry entry. If you are running your own node (which is recommended if you are running relaying services professionally), manually go into the config and adjust the rpc-addr setting to the RPC endpoint you have exposed.

rly chains add will check the liveliness of the available RPC endpoints for that chain in the chain registry. The command may fail if none of these RPC endpoints are available. In this case, you will want to manually add the chain config.

To add the chain config files manually, example config files have been included in the Cosmos relayer documentation (opens new window).

Copy $ rly chains add --url https://raw.githubusercontent.com/cosmos/relayer/main/docs/example-configs/cosmoshub-4.json $ rly chains add --url https://raw.githubusercontent.com/cosmos/relayer/main/docs/example-configs/osmosis-1.json
  1. Import OR create new keys for the relayer to use when signing and relaying transactions.

key-name is an identifier of your choosing.

  • If you need to generate a new private key you can use the add subcommand:

    Copy $ rly keys add cosmoshub [key-name] $ rly keys add osmosis [key-name]
  • If you already have a private key and want to restore it from your mnemonic you can use the restore subcommand:

    Copy $ rly keys restore cosmoshub [key-name] "mnemonic words here" $ rly keys restore osmosis [key-name] "mnemonic words here"
  1. Edit the relayer's key values in the config file to match the key-names chosen above.

This step is necessary if you chose a key-name other than "default".

Example:

Copy - type: cosmos value: key: YOUR-KEY-NAME-HERE chain-id: cosmoshub-4 rpc-addr: http://localhost:26657
  1. Ensure the keys associated with the configured chains are funded.

ATTENTION: Your configured addresses will need to contain some of the respective native tokens to pay relayer fees.

You can query the balance of each configured key by running:

Copy $ rly q balance cosmoshub $ rly q balance osmosis
  1. Configure path metadata in the config file.

You configured the chain metadata, now you need path metadata. This scenario assumes that there is already a canonical channel, so there is no need for light client creation, nor connection and channel handshakes to set these up.

There is one easy command to get this path information - initially from the Interchain folder (opens new window) in the Go relayer repository, but this is being replaced by IBC data in the chain registry (opens new window).

Copy $ rly paths fetch

Do not see the path metadata for paths you want to relay on? Please open a Push Request (PR) to add this metadata to the GitHub repository!

  1. Configure the channel filter.

By default, the relayer will relay packets over all channels on a given connection.

Each path has an src-channel-filter, which you can utilize to specify which channels you would like to relay on.

The rule can be one of three values:

  • allowlist, which tells the relayer to relay on only the channels in channel-list.
  • denylist, which tells the relayer to relay on all channels except the channels in channel-list.
  • Empty value, which is the default setting and tells the relayer to relay on all channels.

Since you should only be worried about the canonical channel between the Cosmos Hub and Osmosis, our filter settings would look like the following:

Example:

Copy hubosmo: src: chain-id: cosmoshub-4 client-id: 07-tendermint-259 connection-id: connection-257 dst: chain-id: osmosis-1 client-id: 07-tendermint-1 connection-id: connection-1 src-channel-filter: rule: allowlist channel-list: [channel-141]

Because two channels between chains are tightly coupled, there is no need to specify the dst channels.

  1. Do a status check.

Before starting to relay and after making some changes to the config, you can check the status of the chains and paths in the config:

Copy $ rly chains list

Which returns this output when healthy:

Copy 0: cosmoshub-4 -> type(cosmos) key(✔) bal(✔) path(✔) 1: osmosis-1 -> type(cosmos) key(✔) bal(✔) path(✔) Copy $ rly paths list

Which returns this output when healthy:

Copy 0: cosmoshub-osmosis -> chns(✔) clnts(✔) conn(✔) (cosmoshub-4<>osmosis-1)

In case one of the checks receives a instead of , you will need to check if you completed all the previous steps correctly.

  1. Finally, start the relayer on the desired path.

The relayer will periodically update the clients and listen for IBC messages to relay.

Copy $ rly start [path]

The relayer now has an event processor added to respond to emitted events signaling an IBC packet event. You can use it by adding an additional flag:

Copy $ rly start [path] -p events

You will need to start a separate shell instance for each path you wish to relay over.

When running multiple instances of rly start, you will need to use the --debug-addr flag and provide an address:port. You can also pass an empty string '' to turn off this feature, or pass localhost:0 to randomly select a port.

# Testing locally

Besides running a relayer between mainnet chains, you can also run a relayer between public testnet chains, or run chains locally to do some testing of particular scenarios. Here you will use a docker-compose network with two local checkers chains and a relayer between them.

The example presented is based on the demo in the b9lab/cosmos-ibc-docker (opens new window) repository.

Start by cloning the repository:

Copy $ git clone https://github.com/b9lab/cosmos-ibc-docker.git

Make sure that you have installed Docker Compose (opens new window) and Docker (opens new window) before continuing.

Then build the images for the checkers blockchain:

Copy $ cd cosmos-ibc-docker/tokentransfer/checkers $ ./build-images.sh

You can build the relayer image manually, or just start the network via docker-compose and let it build the missing image for the ibc-go relayer:

Copy $ cd cosmos-ibc-docker/tokentransfer $ docker-compose -f tokentransfer.yml --profile go up

Observe the output of docker-compose until the chains are ready - the chains will take some time.

When the chains are ready, start the relayer process. In a new terminal, jump into the relayer container:

Copy $ docker exec -it relayer bash

The demo includes a script to start the relayer, but do the steps manually to practice a bit.

First, initialize the configuration:

Copy $ rly config init $ rly chains add-dir configs $ rly paths add-dir paths

You can find the configs and paths folders in the folder cosmos-ibc-docker/tokentransfer/relayer_go. In the checkersa.json and checkersb.json, you can find the endpoints of the chains and a default key alias.

Populate the aliases:

Copy $ rly keys restore checkersa alice "cinnamon legend sword giant master simple visit action level ancient day rubber pigeon filter garment hockey stay water crawl omit airport venture toilet oppose" $ rly keys restore checkersb bob "define envelope federal move soul panel purity language memory illegal little twin borrow menu mule vote alter bright must deal sight muscle weather rug"

The mnemonics are set in the checkers blockchains, take alice from checkersa and bob from checkersb.

Now check if the chains and path(s) are ready to relay over:

Copy $ rly chains list $ rly paths list

You can now connect the two chains with the link command.

The relayer will check if any clients, connections, and channels are present for the given path. If not, the link command will attempt to create the missing objects.

You can also check rly tx -h to find the separate commands for these actions.

Copy $ rly tx link demo -d -t 3s

Next, check the token balances on both chains:

Copy $ rly q balance checkersa $ rly q bal checkersb

Finally, send some tokens between the chains:

Copy $ rly tx transfer checkersa checkersb 10token $(rly chains address checkersb) channel-0

The default key used for checkersa is alice.

$(rly chains address checkersb) will give the address of bob.

You created the commitment proof on checkersa to send the packet, but no relaying has taken place yet.

# Relay packets/acknowledgments

Running rly start demo would essentially loop these two commands:

Copy $ rly tx relay-pkts demo channel-0 -d $ rly tx relay-acks demo channel-0 -d

Check that the transfer was completed:

Copy $ rly q bal checkersa $ rly q bal checkersb

You can see that the tokens have a denom on the checkersb chain because they are not native tokens of checkersb. Send the tokens back to the account on checkersa by replacing $denom (this will be something like ibc/D11F61D9F5E49A31348A7CD2DECE888D4DFEE1DADA343F7D8D4502BFA9496936):

Copy $ rly tx transfer checkersb checkersa 10$denom $(rly chains addr checkersa) channel-0 $ rly tx relay-pkts demo channel-0 -d $ rly tx relay-acks demo channel-0 -d

Check that the return trip was completed:

Copy $ rly q bal checkersa $ rly q bal checkersb

You can see that the stake balances decreased on each chain because of the set fees in the configuration.

If you are finished with the tests, make sure to shut down your network with:

Copy $ docker-compose -f tokentransfer.yml --profile go down
synopsis

To summarize, this section has explored:

  • The Go relayer, a relayer implementation written in Golang that can create clients, connections, and channels, as well as relay packets, and update and upgrade clients.
  • How the Go relayer requires minimal manual configuration and abstracts away many more complex IBC concepts by automating a lot of work to fetch configuration data from the chain registry.
  • How to install and configure the Go relayer, and how to run it between public testnet chains or locally run chains to conveniently test particular scenarios.