Skip to main content

Run an IBC Relayer

What is an IBC Relayer?

It is possible to communicate between two different blockchain networks that accept the Inter-Blockchain Communication (IBC) protocol using an IBC relayer, which is a software component. IBC protocol is a standard for the safe and reliable movement of digital assets and data between various blockchain networks.

IBC packets are used to transport messages and data between two distinct blockchain networks, and an IBC relayer is in charge of relaying these packets. After confirming their validity and authenticity, it sends the packets to the receiving chain after receiving them from one chain.

In this guide, we will be relaying between Humans (channel-4) and Osmosis (channel-20082). When setting up your Humans and Osmosis full nodes, be sure to offset the ports being used in both the app.toml and config.toml files of the respective chains.

Steps can be also found in the validator guide created by Huggin Tech.

Minimum Requirements

  • 8 core (4 physical core), x86_64 architecture processor
  • 32 GB RAM (or equivalent swap file set up)
  • 1 TB+ nVME drives
  • Tested in Ubuntu Server 22.04 / Rocky Linux 8 x64

When using a single VM to run several nodes, ensure your open files limit is increased.

Prerequisites

Humans Daemon Settings​

First, set grpc server on port 9090 in the app.toml file from the $HOME/.humansd/config directory:

nano $HOME/.humansd/config/app.toml
[grpc]

# Enable defines if the gRPC server should be enabled.
enable = true

# Address defines the gRPC server address to bind to.
address = "0.0.0.0:9090"

Then, set the pprof_laddr to port 6060, rpc laddr to port 26657, and prp laddr to 26656 in the config.toml file from the $HOME/.humansd/config directory:

nano $HOME/.humansd/config/config.toml
# pprof listen address (https://golang.org/pkg/net/http/pprof)
pprof_laddr = "localhost:6060"
[rpc]

# TCP or UNIX socket address for the RPC server to listen on
laddr = "tcp://127.0.0.1:26657"
[p2p]

# Address to listen for incoming connections
laddr = "tcp://0.0.0.0:26656"

Osmosis Daemon Settings

First, set grpc server to port 9092 in the app.toml file from the $HOME/.osmosisd/config directory:

nano $HOME/.osmosisd/config/app.toml
[grpc]

# Enable defines if the gRPC server should be enabled.
enable = true

# Address defines the gRPC server address to bind to.
address = "0.0.0.0:9092"

Then, set the pprof_laddr to port 6062, rpc laddr to port 26757, and prp laddr to 26756 in the config.toml file from the $HOME/.osmosisd/config directory:

nano $HOME/.osmosisd/config/config.toml
# pprof listen address (https://golang.org/pkg/net/http/pprof)
pprof_laddr = "localhost:6062"
[rpc]

# TCP or UNIX socket address for the RPC server to listen on
laddr = "tcp://127.0.0.1:26757"
[p2p]

# Address to listen for incoming connections
laddr = "tcp://0.0.0.0:26756"

Make the updates and install the necessary packages

sudo apt update && sudo apt upgrade

Install Rust Dependencies

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

source $HOME/.cargo/env

sudo apt-get install pkg-config libssl-dev

sudo apt install librust-openssl-dev build-essential git

Install Hermes via Cargo

The official Hermes (IBC Relayer CLI) Documentation can be found here.

cargo install ibc-relayer-cli --bin hermes --locked

export PATH="$HOME/.cargo/bin:$PATH"

# Check hermes version
hermes version
hermes v1.7.4

Make the hermes directory, keys and create config.toml and save this config:

mkdir -p $HOME/.hermes
mkdir -p $HOME/.hermes/keys
cd .hermes
nano config.toml
[global]
log_level = "info"

[mode.clients]
enabled = true
refresh = true
misbehaviour = false

[mode.connections]
enabled = false

[mode.channels]
enabled = false

[mode.packets]
enabled = true
clear_interval = 200
clear_on_start = true
tx_confirmation = true
auto_register_counterparty_payee = false

[rest]
enabled = false
host = "127.0.0.1"
port = 3000

[telemetry]
enabled = false
host = "127.0.0.1"
port = 3001

[telemetry.buckets.latency_submitted]
start = 500
end = 20000
buckets = 10

[telemetry.buckets.latency_confirmed]
start = 1000
end = 30000
buckets = 10

[[chains]]
id = "osmosis-1"
type = "CosmosSdk"
rpc_addr = "http://127.0.0.1:26757"
grpc_addr = "http://127.0.0.1:9092"
rpc_timeout = "10s"
trusted_node = false
account_prefix = "osmo"
key_name = "osmosis"
key_store_type = "Test"
store_prefix = "ibc"
default_gas = 500000
max_gas = 120000000
gas_multiplier = 1.4
max_msg_num = 30
max_tx_size = 180000
max_grpc_decoding_size = 33554432
clock_drift = "15s"
max_block_time = "30s"
ccv_consumer_chain = false
memo_prefix = "Relayed by Huginn | https://huginn.tech"
sequential_batch_tx = false

[chains.event_source]
mode = "push"
url = "wss://127.0.0.1:26757/websocket"
batch_delay = "500ms"

[chains.trust_threshold]
numerator = "1"
denominator = "3"

[chains.gas_price]
price = 0.0050
denom = "uosmo"

[chains.packet_filter]
policy = "allow"
list = [
['transfer', 'channel-20082'], # humans
]

[chains.packet_filter.min_fees]

[chains.address_type]
derivation = "cosmos"


[[chains]]
id = "humans_1089-1"
type = "CosmosSdk"
rpc_addr = "http://127.0.0.1:26657"
grpc_addr = "http://127.0.0.1:9090"
rpc_timeout = "10s"
trusted_node = false
account_prefix = "human"
key_name = "human"
key_store_type = "Test"
store_prefix = "ibc"
default_gas = 200000
max_gas = 10000000
gas_multiplier = 1.3
max_msg_num = 30
max_tx_size = 2097152
max_grpc_decoding_size = 33554432
clock_drift = "25s"
max_block_time = "30s"
ccv_consumer_chain = false
memo_prefix = "Relayed by validator name | validator.website"
sequential_batch_tx = false

[chains.event_source]
mode = "push"
url = "wss://127.0.0.1:26657/websocket"
batch_delay = "500ms"

[chains.trust_threshold]
numerator = "1"
denominator = "3"

[chains.gas_price]
price = 100000000000
denom = "aheart"

[chains.packet_filter]
policy = "allow"
list = [
['transfer', 'channel-4'], # osmosis
]

[chains.packet_filter.min_fees]

[chains.address_type]
derivation = "ethermint"
proto_type = { pk_type = '/ethermint.crypto.v1.ethsecp256k1.PubKey' }

Edit the hermes configuration (use ports according the port configuration set above, adding only chains that will be relayed) and save the file.

The best practice is to use the same mnemonic over all networks. Do not use your relaying-addresses for anything else, because it will lead to account sequence errors.

MNEMONIC_B='24-word mnemonic seed'
CHAIN_ID_B='humans_1089-1'
sudo tee $HOME/.hermes/${CHAIN_ID_A}.mnemonic > /dev/null <<EOF
${MNEMONIC_A}
EOF
hermes keys add --chain ${CHAIN_ID_A} --mnemonic-file $HOME/.hermes/${CHAIN_ID_A}.mnemonic
MNEMONIC_B='24-word mnemonic seed'
CHAIN_ID_B='osmosis-1'
sudo tee $HOME/.hermes/${CHAIN_ID_B}.mnemonic > /dev/null <<EOF
${MNEMONIC_A}
EOF
hermes keys add --chain ${CHAIN_ID_B} --mnemonic-file $HOME/.hermes/${CHAIN_ID_B}.mnemonic

Ensure this wallet has funds in both HEART and OSMO in order to pay the fees required to relay.

Final Checks

Validate your hermes configuration file:

hermes config validate
INFO ThreadId(01) using default configuration from '/root/.hermes/config.toml'
INFO ThreadId(01) running Hermes v1.7.4
SUCCESS "configuration is valid"

Perform the hermes health-check to see if all connected nodes are up and synced:

hermes health-check
INFO ThreadId(01) using default configuration from '/root/.hermes/config.toml'
INFO ThreadId(01) running Hermes v1.7.4
INFO ThreadId(01) health_check{chain=osmosis-1}: performing health check...
WARN ThreadId(06) health_check{chain=osmosis-1}: Will use fallback value for max_block_time: `30s`. Error: response error: Internal error: genesis response is large, please use the genesis_chunked API instead (code: -32603)
INFO ThreadId(01) health_check{chain=osmosis-1}: chain is healthy
INFO ThreadId(01) health_check{chain=humans_1089-1}: performing health check...
INFO ThreadId(11) health_check{chain=humans_1089-1}: Updated `max_block_time` using /genesis endpoint. Old value: `30s`, new value: `30s`
INFO ThreadId(01) health_check{chain=humans_1089-1}: chain is healthy
SUCCES performed health check for all chains in the config

When your nodes are fully synced, you can start the hermes daemon:

sudo tee /etc/systemd/system/hermesd.service > /dev/null <<EOF
[Unit]
Description=Hermes
After=network.target

[Service]
User=root
Type=simple
ExecStart=/root/.cargo/bin/hermes start
Restart=on-failure
LimitNOFILE=4096

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload

systemctl enable hermesd

systemctl start hermesd

Watch hermes's output for successfully relayed packets, or any errors. It will try and clear any unreceived packets after startup has completed.

journalctl -u hermesd -fo cat