ブロックチェーンをつなげるIBCとは 〜Relayerを用いたトークン転送〜


:::note
本記事では、Cosmos Network のテストネットを利用して Relayer の立ち上げ・利用方法、IBC によるトークン転送の方法を解説します。
:::

## はじめに

2022 年以降、Web3.0 に注目が集まっています。その基盤であるパブリックブロックチェーンには、記録されているデータの完全性を保ちつつ、トラストレスにデータを流通させるという役割が期待されています。

しかし、現在のブロックチェーンの利用は独自の仕様をもつチェーンが乱立している状態にあり、データの完全性を維持することはできていても、その利用範囲は記録したブロックチェーンの中に留まっています。

個々のブロックチェーンが分断した状態ではデータの相互利用が見込めず、各ユーザが異なるブロックチェーンに依存しているとトラストレスに利用可能なデータ流通基盤としての役割は果たせません。

現状、スマートコントラクトを提供するブロックチェーンとして最も利用されている Ethereum はさまざまなアプリケーションの基盤として利用されています。しかし、このような汎用ブロックチェーンですべての処理を実行するには性能が不足するため、汎用チェーンから処理の一部を切り出し、Layer2 と呼ばれるブロックチェーン外部のソリューションがみられます。Ethereum は分散管理されている一方、Layer2 は必ずしも分散運営になっているわけではなく、特定の運営者への信頼を前提とすることがあります。

従って、トラストレスに利用できるデータ流通基盤を実現するために今後必要性が高まってくると考えられるのが、相互運用性という考え方です。

## ブロックチェーンにおける相互運用性とは

相互運用性という言葉は他領域でも用いられていますが、ブロックチェーン領域では**異なるブロックチェーン同士を接続し、相互にデータを読み書きできる性質**を指します。

ブロックチェーン間でデータを転送するには、片方のブロックチェーンに記録されているトランザクション（TX）をもう一方のブロックチェーンへ書き込む必要があります。

２つのブロックチェーンで仕様が異なる場合はまったく同じデータを書き込むのではなく、同じ意味を表すデータを書き込むことになりますが、この際には TX の内容が改ざんされずに記録されなければなりません。

トークンの相互運用が利用され始めた当初は AtomicSwap や InterLedger Protocol など、アルゴリズムによる検証によって異なるブロックチェーン同士の取引を可能にしていました。

しかし、これらのアルゴリズムは２つのブロックチェーンが同じハッシュ関数を利用していることやタイムロック制御可能であることなど、実装上の制約があります。

そのため、現在に至るまで多く用いられているのは、オフチェーンの検証者による検証です。この手法は一般にブリッジと呼ばれています。

ブリッジはブロックチェーンの仕様が異なっていてもデータが転送できるというメリットがある一方で、仲介者を信頼しなければなりません。

もともと、パブリックブロックチェーンはトラストレスな利用を想定しています。できるだけ第三者への信頼を必要としない検証が望ましく、オンチェーンの検証者が検証することでこれを実現する仕組みが考案されています。その一つが IBC と呼ばれる仕組みです。

### IBC とは

IBC（Inter-Blockchain Communication）とは、オンチェーンで検証することで相互運用性を実現する手法です。その構成技術は、ICS（Interchain Standards）という規格として整理されています。

IBC では、接続する２つのブロックチェーン上で互いの Light Client をもち、他方のブロックチェーン宛の TX が記録されると、Light Client はそのステートの変化を検知して Relayer 経由で TX を転送します。

（参考）[Chapter Overview - The Interchain, Its Ecosystem, and ATOM | Developer Portal](https://tutorials.cosmos.network/academy/1-what-is-cosmos/)

:::note
Light Client とは、ブロックチェーン上で動作するソフトウェアの一つ[^1]。

[^1]: コンセンサスエンジンを提供するソフトウェアCometBFTに実装されています。

フルノードは、TX の実行・検証機能をもち、ブロックや TX などの情報をすべて保持しています。これに対し、Light Client はフルノードからデータを取得して検証する機能のみをもち、最近のブロックヘッダー（ハッシュ）のみを保持しています。

（参考）[Everything you need to know about the Tendermint Light Client | by Anton Kaliaev | Tendermint Blog | Medium](https://medium.com/tendermint/everything-you-need-to-know-about-the-tendermint-light-client-f80d03856f98)
:::

通信を中継する Relayer は、既に Light Client で検証済みの TX を転送するのみで通信内容を書き換えないため、第三者への信頼を必要としない仕組みを実現しています。

![image2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633547/fe5c8d36-8d96-590b-5262-3aa998715a0b.png)

IBC はパブリックブロックチェーンである Cosmos 内の通信方法として提案されたものですが、ノードのネットワーク構造やコンセンサスアルゴリズムに依存しないため、さまざまなブロックチェーンで利用できます。

### Cosmos とは

Cosmos とは、Cosmos SDK[^2]を用いて開発したブロックチェーン同士を接続して構築されるエコシステムです。

[^2]: フレームワークは他にも存在しますが、Cosmos SDK が最も利用されています。

単一のブロックチェーンではなく、個々のサービスの基盤として利用される Zone と、Zone と Zone を繋ぐ役割をもつ Hub で構成され、Cosmos Network とも呼ばれます。

## IBC の動作検証

### 検証目的

IBCは各ブロックチェーン上にライトクライアントが待機し、異なる仕組みをもつブロックチェーン間でも通信できる。独自の仕様で開発してきたブロックチェーンが乱立し、相互運用に対する需要が高まるなかで、ブロックチェーンの仕様に依存しないIBCは有望な技術の一つである。

本検証は、パブリックテストネットを用いてIBCの通信方法やトークン転送の基礎を理解し、今後の活用に向けた知見の獲得を目的とする。

### 動作環境

Cosmos Network 内のテストネット間で IBC 転送する方法を検証するため、ローカル環境に Relayer を構築します。

動作環境は以下のとおりです。

- macOS Ventura 13.2.1
- Intel Core i5 2.0GHz
- 16GB Memory

また、Go v1.20.2 がインストールされています（goenv 利用）。

### 利用したテストネット

| Chain name | Chain ID          |
| ---------- | ----------------- |
| Archway    | contantine-2      |
| Cosmos Hub | theta-testnet-001 |
| Juno       | uni-6             |

:::note warn
Osmosis (osmo-test-4)はクライアントインスタンスが作成できなかったため、利用しませんでした。
:::

### 環境構築

Relayer のパッケージをインストールします。前提として Go v1.18 以上が必要です。

```sh :terminal
$ git clone https://github.com/cosmos/relayer.git
$ cd ./relayer && git switch -c v2.3.0
$ make install
```

インストール後、設定を保存するディレクトリ/ファイルを作成します。

```sh :terminal
$ rly config init
```

#### テストネットの追加

テストネットはチェーン名称を指定しても設定を読み込めないため、別途設定ファイルを作成しておきます。

```sh :terminal
$ rly chains add --file <path_to_config.json> <chain_name>
```

<details><summary>実際のコマンド</summary>

```sh :terminal
$ rly chains add --file ./custom-configs/archwaytestnet.json archwaytestnet
$ rly chains add --file ./custom-configs/cosmoshubtestnet.json cosmoshubtestnet
$ rly chains add --file ./custom-configs/junotestnet.json junotestnet
```

</details>

上記で用いる設定ファイルの例は以下のとおりです。

```json :./custom-configs/cosmoshubtestnet.json
{
  "type": "cosmos",
  "value": {
    "key": "thetakey",
    "chain-id": "theta-testnet-001",
    "rpc-addr": "http://state-sync-01.theta-testnet.polypore.xyz:26657",
    "account-prefix": "cosmos",
    "keyring-backend": "test",
    "gas-adjustment": 1.2,
    "gas-prices": "0.0025uatom",
    "debug": true,
    "timeout": "20s",
    "output-format": "json",
    "sign-mode": "direct"
  }
}
```

パラメータはブロックチェーンごとに異なります。以下ディレクトリ内の chain.json を参考にできます。

[chain-registry/testnets at master · cosmos/chain-registry · GitHub](https://github.com/cosmos/chain-registry/tree/master/testnets)

:::note warn
chain.json に記載がある RPC の中には現在稼働していないものも含まれている可能性があります。その際は、各チェーンのドキュメントで確認が必要です。
:::

chain.json には記載されていませんが、RPC の URL にはポート番号をつける必要があります。Tendermint RPC は HTTP1.1 で通信しており，ポート番号は 26657 を指定します。HTTPS による通信を行う場合は，Well-known ポートの 443 を指定します。

ポート番号を指定していない、あるいは入力した RPC が稼働していない場合、RPC 接続時に以下のようなエラーメッセージが表示されます。

```sh
// The port number is not specified.
Error: post failed: Post "https://public-cosmos-theta.w3node.com": dial tcp: address public-cosmos-theta.w3node.com: missing port in address

// RPC node is not working or the RPC URL is wrong.
Error: post failed: Post "https://rpc.malaga-420.cosmwasm:443": dial tcp: lookup rpc.malaga-420.cosmwasm: no such host
```

#### 秘密鍵の作成

Relayer が署名や TX 転送の際に使用する秘密鍵を作成します。利用するテストネットの分だけ生成します。

```sh :terminal
$ rly keys add <chain_name> <key-name>
```

<details><summary>実際のコマンド</summary>

```sh :terminal
$ rly keys add cosmoshubtestnet thetakey
{"mnemonic":"xxx xxx xxx ...","address":"cosmos1rxa3g70qg5vmkn7dk9xqn8kcgat39sh6a7ncmz"}
$ rly keys add archwaytestnet constantinekey
$ rly keys add junotestnet unikey
```

</details>

mnemonic から復元することもできます。

```sh :terminal
$ rly keys restore <chain_name> <key_name> "<mnemonic>"
```

<details><summary>実際のコマンド</summary>

```sh :terminal
$ rly keys restore cosmoshubtestnet thetakey "xxx xxx xxx ..."
```

</details>

設定が正常に完了すれば、各アドレスのトークン残高を確認するコマンドが動作します。

```sh :terminal
$ rly q balance <chain_name>
```

<details><summary>実際のコマンド</summary>

```sh :terminal
$ rly q balance cosmoshubtestnet
address {cosmos1rxa3g70qg5vmkn7dk9xqn8kcgat39sh6a7ncmz} balance {}
```

</details>

#### Path の作成

Relayer が通信を中継するための設定を行います。今回はテストネットを利用するため、新規に作成します。

```sh :terminal
$ rly paths new <src_chain_id> <dst_chain_id> <path_name>
```

<details><summary>実際のコマンド</summary>

```sh :terminal
$ rly paths new constantine-2 uni-6 archwaytestnet-junotestnet
$ rly paths new uni-6 theta-testnet-001 junotestnet-cosmoshubtestnet
```

</details>

既に確立している Client，Connection を利用する場合は、以下のコマンドで path を読み込めます。

```sh :terminal
$ rly paths add <src_chain_id> <dst_chain_id> <path_name>
```

また、メインネットを利用する場合は chain-registry からフェッチすることで path を取得できます。

```sh :terminal
$ rly paths fetch
```

:::note
接続する２つのブロックチェーンのうち、転送元となるブロックチェーンを Source chain（src_chain），転送先となるブロックチェーンを Destination chain（dst_chain）と呼びます。
:::

最終的に、設定ファイルは以下のようになります。

<details><summary>config.yaml</summary>

`paths` の情報はConnectionが確立した後に入力されます。

```yaml :config.yaml
global:
  api-listen-addr: :5183
  timeout: 10s
  memo: ''
  light-cache-size: 20
chains:
  archwaytestnet:
    type: cosmos
    value:
      key-directory: /Users/<username>/.relayer/keys/constantine-2
      key: constantinekey
      chain-id: constantine-2
      rpc-addr: https://rpc.constantine-2.archway.tech:443
      account-prefix: archway
      keyring-backend: test
      gas-adjustment: 1.3
      gas-prices: 0.01uconst
      min-gas-amount: 0
      debug: true
      timeout: 20s
      block-timeout: ''
      output-format: json
      sign-mode: direct
      extra-codecs: []
      coin-type: null
      broadcast-mode: batch
      min-loop-duration: 0s
  cosmoshubtestnet:
    type: cosmos
    value:
      key-directory: /Users/<username>/.relayer/keys/theta-testnet-001
      key: thetakey
      chain-id: theta-testnet-001
      rpc-addr: http://state-sync-01.theta-testnet.polypore.xyz:26657
      account-prefix: cosmos
      keyring-backend: test
      gas-adjustment: 1.2
      gas-prices: 0.0025uatom
      min-gas-amount: 0
      debug: true
      timeout: 20s
      block-timeout: ''
      output-format: json
      sign-mode: direct
      extra-codecs: []
      coin-type: null
      broadcast-mode: batch
      min-loop-duration: 0s
  junotestnet:
    type: cosmos
    value:
      key-directory: /Users/<username>/.relayer/keys/uni-6
      key: unikey
      chain-id: uni-6
      rpc-addr: https://rpc.uni.junonetwork.io:443
      account-prefix: juno
      keyring-backend: test
      gas-adjustment: 1.3
      gas-prices: 0.1ujunox
      min-gas-amount: 0
      debug: true
      timeout: 20s
      block-timeout: ''
      output-format: json
      sign-mode: direct
      extra-codecs: []
      coin-type: null
      broadcast-mode: batch
      min-loop-duration: 0s
paths:
  archwaytestnet-junotestnet:
    src:
      chain-id: constantine-2
      client-id: 07-tendermint-106
      connection-id: connection-63
    dst:
      chain-id: uni-6
      client-id: 07-tendermint-178
      connection-id: connection-201
    src-channel-filter:
      rule: ''
      channel-list: []
  junotestnet-cosmoshubtestnet:
    src:
      chain-id: uni-6
      client-id: 07-tendermint-188
      connection-id: connection-320
    dst:
      chain-id: theta-testnet-001
      client-id: 07-tendermint-1978
      connection-id: connection-2357
    src-channel-filter:
      rule: ''
      channel-list: []
```

</details>

#### Faucet

テストネットでの実行にもガス代の支払いが必要です。

テストネットごとに Faucet 方法は異なりますが、今回利用したテストネットはすべて Discord で依頼できます。以下、参考リンクです。

- Archway: [Requesting Testnet Tokens](https://docs.archway.io/developers/guides/faucet)
- Cosmos Hub: [Joining Testnet | Cosmos Hub](https://hub.cosmos.network/main/hub-tutorials/join-testnet.html)
- Juno: [Joining Testnet - Junø](https://docs.junonetwork.io/validators/joining-the-testnets)

### IBC による通信の確立

Relayer を用いて通信を確立する際、以下の順に処理が進みます。

1. Light Client インスタンスの作成
2. Connection の確立
3. Channel の確立

#### 1. Light Client インスタンスの作成

各ブロックチェーンに対して TX を送信することで、通信を確立するための処理を行います。

双方のブロックチェーンに Light Client を用意する必要があるため、それぞれに対して TX を送信しています。

```sh :terminal
$ rly tx clients <path_name>
```

<details><summary>実際のコマンド</summary>

```sh :terminal
$ rly tx clients junotestnet-cosmoshubtestnet
2023-04-18T07:00:36.413704Z	info	Successful transaction	{"provider_type": "cosmos", "chain_id": "uni-6", "gas_used": 100418, "fees": "11201ujunox", "fee_payer": "juno19y6lwhdzcwdar69tyfkyjedhldc5jpqg2phskr", "height": 1047477, "msg_types": ["/ibc.core.client.v1.MsgCreateClient"], "tx_hash": "2A808183A1B3BB45CB80C9C7181E6D00CBC036EBEFE9D3DE9793FD9F01A90C9D"}
2023-04-18T07:00:36.413795Z	info	Client Created	{"src_chain_id": "uni-6", "src_client_id": "07-tendermint-173", "dst_chain_id": "theta-testnet-001"}
2023-04-18T07:02:34.202860Z	info	Successful transaction	{"provider_type": "cosmos", "chain_id": "theta-testnet-001", "gas_used": 101446, "fees": "273uatom", "fee_payer": "cosmos1rxa3g70qg5vmkn7dk9xqn8kcgat39sh6a7ncmz", "height": 15549287, "msg_types": ["/ibc.core.client.v1.MsgCreateClient"], "tx_hash": "D81B7C20FE37C46F53F03383B25F78380C061CD3A16BF94726CB3D197D0BD560"}
2023-04-18T07:02:34.202937Z	info	Client Created	{"src_chain_id": "theta-testnet-001", "src_client_id": "07-tendermint-1971", "dst_chain_id": "uni-6"}
2023-04-18T07:02:34.203043Z	info	Clients created	{"src_client_id": "07-tendermint-173", "src_chain_id": "uni-6", "dst_client_id": "07-tendermint-1971", "dst_chain_id": "theta-testnet-001"}
```

</details>

:::note
IBCのセキュリティはLight Clientに依存します。IBCの接続を確立する際には、クライアントの保持している情報が正しいかどうか、最新の情報を同期しているかを検証します。

そのため、ConnectionやChannelを確立するためのTXを実行する際には、`MsgUpdateClient` というTXを先に実行して最新の状態に更新します。
:::

#### 2. Connection の確立

Light Client インスタンスの作成後、3way ハンドシェイクによって Connection を確立します。

双方のブロックチェーンで、接続先のブロックチェーンに関する情報（最新のステートや利用しているLight Clientのバージョンなど）の整合性を確認します。

![Handshake for Connection](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633547/2294d7bf-832f-fc8c-8d23-0eaa3c935789.png)

```sh :terminal
$ rly tx connection <path_name>
```

<details><summary>実際のコマンド</summary>

```sh :terminal
$ rly tx connection junotestnet-cosmoshubtestnet
2023-04-18T07:04:53.197062Z	info	Clients created	{"src_client_id": "07-tendermint-173", "src_chain_id": "uni-6", "dst_client_id": "07-tendermint-1971", "dst_chain_id": "theta-testnet-001"}
2023-04-18T07:04:53.197211Z	info	Starting event processor for connection handshake	{"src_chain_id": "uni-6", "src_client_id": "07-tendermint-173", "dst_chain_id": "theta-testnet-001", "dst_client_id": "07-tendermint-1971"}
2023-04-18T07:04:54.754798Z	info	Chain is not yet in sync	{"chain_name": "junotestnet", "chain_id": "uni-6", "latest_queried_block": 1047501, "latest_height": 1047522}
2023-04-18T07:04:55.354130Z	info	Chain is not yet in sync	{"chain_name": "cosmoshubtestnet", "chain_id": "theta-testnet-001", "latest_queried_block": 15549292, "latest_height": 15549312}
2023-04-18T07:05:03.708917Z	info	Chain is in sync       	{"chain_name": "cosmoshubtestnet", "chain_id": "theta-testnet-001"}
2023-04-18T07:05:07.887343Z	info	Chain is in sync       	{"chain_name": "junotestnet", "chain_id": "uni-6"}
2023-04-18T07:05:16.049802Z	info	Successful transaction 	{"provider_type": "cosmos", "chain_id": "uni-6", "gas_used": 170675, "fees": "20334ujunox", "fee_payer": "juno19y6lwhdzcwdar69tyfkyjedhldc5jpqg2phskr", "height": 1047526, "msg_types": ["/ibc.core.client.v1.MsgUpdateClient", "/ibc.core.connection.v1.MsgConnectionOpenInit"], "tx_hash": "09FFE0BAB0A85C8C5CB11676E296240BBDF1E961E317C1DAB3095670FC35EEA0"}
2023-04-18T07:05:21.838587Z	info	Successful transaction 	{"provider_type": "cosmos", "chain_id": "uni-6", "gas_used": 171133, "fees": "20325ujunox", "fee_payer": "juno19y6lwhdzcwdar69tyfkyjedhldc5jpqg2phskr", "height": 1047527, "msg_types": ["/ibc.core.client.v1.MsgUpdateClient", "/ibc.core.connection.v1.MsgConnectionOpenInit"], "tx_hash": "4D8CCBE1C14EFC5B6FF2C0CAD2642E8DCB6983AC020BF3580D4101E74FF0D7A5"}
2023-04-18T07:05:29.043092Z	info	Successful transaction 	{"provider_type": "cosmos", "chain_id": "theta-testnet-001", "gas_used": 316460, "fees": "918uatom", "fee_payer": "cosmos1rxa3g70qg5vmkn7dk9xqn8kcgat39sh6a7ncmz", "height": 15549319, "msg_types": ["/ibc.core.client.v1.MsgUpdateClient", "/ibc.core.connection.v1.MsgConnectionOpenTry"], "tx_hash": "96F17276734FDC455CAFB60F46011376D74836A679E7EC8489332E421DF7A048"}
2023-04-18T07:05:34.742360Z	info	Successful transaction 	{"provider_type": "cosmos", "chain_id": "theta-testnet-001", "gas_used": 313733, "fees": "910uatom", "fee_payer": "cosmos1rxa3g70qg5vmkn7dk9xqn8kcgat39sh6a7ncmz", "height": 15549320, "msg_types": ["/ibc.core.client.v1.MsgUpdateClient", "/ibc.core.connection.v1.MsgConnectionOpenTry"], "tx_hash": "4CEA160C6A3E8C2327DC76616B9CF00505D47D183BC1A4752403EE3496614F0D"}
2023-04-18T07:05:39.120830Z	info	Successful transaction 	{"provider_type": "cosmos", "chain_id": "uni-6", "gas_used": 279738, "fees": "34507ujunox", "fee_payer": "juno19y6lwhdzcwdar69tyfkyjedhldc5jpqg2phskr", "height": 1047530, "msg_types": ["/ibc.core.client.v1.MsgUpdateClient", "/ibc.core.connection.v1.MsgConnectionOpenAck"], "tx_hash": "06AA0753A98E2A40982819097ED4D3BDA90BEF4C582B3EAA72D85A71404FA770"}
2023-04-18T07:05:44.298965Z	info	Successful transaction 	{"provider_type": "cosmos", "chain_id": "uni-6", "gas_used": 278348, "fees": "34331ujunox", "fee_payer": "juno19y6lwhdzcwdar69tyfkyjedhldc5jpqg2phskr", "height": 1047531, "msg_types": ["/ibc.core.client.v1.MsgUpdateClient", "/ibc.core.connection.v1.MsgConnectionOpenAck"], "tx_hash": "7AA118AB072D237AF3A51E397F55538EE9954FBA21FF8155C5E11769A4432ECA"}
2023-04-18T07:05:50.877685Z	info	Successful transaction 	{"provider_type": "cosmos", "chain_id": "theta-testnet-001", "gas_used": 236608, "fees": "678uatom", "fee_payer": "cosmos1rxa3g70qg5vmkn7dk9xqn8kcgat39sh6a7ncmz", "height": 15549323, "msg_types": ["/ibc.core.client.v1.MsgUpdateClient", "/ibc.core.connection.v1.MsgConnectionOpenConfirm"], "tx_hash": "D09C4248F82CA73CC6C20F9BAFA267DC940563DC932FD0F42CB69EBC7E6EAAA8"}
2023-04-18T07:05:51.602974Z	info	Connection handshake termination candidate	{"path_name": "junotestnet-cosmoshubtestnet", "chain_id": "theta-testnet-001", "client_id": "07-tendermint-1971", "termination_client_id": "07-tendermint-1971", "observed_client_id": "07-tendermint-1971", "termination_counterparty_client_id": "07-tendermint-173", "observed_counterparty_client_id": "07-tendermint-173"}
2023-04-18T07:05:51.603022Z	info	Found termination condition for connection handshake	{"path_name": "junotestnet-cosmoshubtestnet", "chain_id": "theta-testnet-001", "client_id": "07-tendermint-1971"}
```

</details>

#### 3. Channel の確立

Channel の確立もハンドシェイクで行います。ここでは、用途に合ったPortが設定されているか、IBC Packetの処理順やバージョンが整合しているか、といった内容を確認します。

ハンドシェイクの流れはConnection確立時と同様です。

```sh :terminal
$ rly tx channel <path_name> --src-port transfer --dst-port transfer --order unordered --version ics20-1
```

一つの Connection のなかで、用途別に複数の Channel を確立できます。この Channel はトークン転送に利用するため、双方の Port ID は `transfer` を指定します。トークン転送の場合、IBC Packet の処理は到着順になるため `unordered` を指定します（送信順の場合は `ordered` を指定します）。

<details><summary>実際のコマンド</summary>

```sh :terminal
$ rly tx channel junotestnet-cosmoshubtestnet --src-port transfer --dst-port transfer --order unordered --version ics20-1
2023-04-18T07:11:02.915637Z	info	Starting event processor for channel handshake	{"src_chain_id": "uni-6", "src_port_id": "transfer", "dst_chain_id": "theta-testnet-001", "dst_port_id": "transfer"}
2023-04-18T07:11:04.454118Z	info	Chain is in sync	{"chain_name": "junotestnet", "chain_id": "uni-6"}
2023-04-18T07:11:05.014282Z	info	Chain is in sync	{"chain_name": "cosmoshubtestnet", "chain_id": "theta-testnet-001"}
2023-04-18T07:11:13.257791Z	info	Successful transaction{"provider_type": "cosmos", "chain_id": "uni-6", "gas_used": 214818, "fees": "26073ujunox", "fee_payer": "juno19y6lwhdzcwdar69tyfkyjedhldc5jpqg2phskr", "height": 1047589, "msg_types": ["/ibc.core.client.v1.MsgUpdateClient", "/ibc.core.channel.v1.MsgChannelOpenInit"], "tx_hash": "2B9600F32F238013B499B538F30DBD0B74CA52FB260F51475D39F8510D1E4F33"}
2023-04-18T07:11:27.838476Z	info	Successful transaction{"provider_type": "cosmos", "chain_id": "theta-testnet-001", "gas_used": 291046, "fees": "842uatom", "fee_payer": "cosmos1rxa3g70qg5vmkn7dk9xqn8kcgat39sh6a7ncmz", "height": 15549383, "msg_types": ["/ibc.core.client.v1.MsgUpdateClient", "/ibc.core.channel.v1.MsgChannelOpenTry"], "tx_hash": "1CD97081D58CD3429E08F7A57D72B86EC350257AE505705708F9BDA7D3758CD7"}
2023-04-18T07:11:41.499505Z	info	Successful transaction{"provider_type": "cosmos", "chain_id": "uni-6", "gas_used": 185629, "fees": "22278ujunox", "fee_payer": "juno19y6lwhdzcwdar69tyfkyjedhldc5jpqg2phskr", "height": 1047594, "msg_types": ["/ibc.core.client.v1.MsgUpdateClient", "/ibc.core.channel.v1.MsgChannelOpenAck"], "tx_hash": "F5258B420ECCD897BC18F5DA36FCF3FE8BB74FCAABAEA36D1AC2A5CF18445CB4"}
2023-04-18T07:11:55.142134Z	info	Successful transaction{"provider_type": "cosmos", "chain_id": "theta-testnet-001", "gas_used": 245333, "fees": "705uatom", "fee_payer": "cosmos1rxa3g70qg5vmkn7dk9xqn8kcgat39sh6a7ncmz", "height": 15549388, "msg_types": ["/ibc.core.client.v1.MsgUpdateClient", "/ibc.core.channel.v1.MsgChannelOpenConfirm"], "tx_hash": "B5713AA5C7BC80DE29A6544B32200B41A63C06EE418E60576166B285AFE05ACF"}
2023-04-18T07:11:55.545469Z	info	Channel handshake termination candidate	{"path_name": "junotestnet-cosmoshubtestnet", "chain_id": "theta-testnet-001", "client_id": "07-tendermint-1971", "termination_port_id": "transfer", "observed_port_id": "transfer", "termination_counterparty_port_id": "transfer", "observed_counterparty_port_id": "transfer"}
2023-04-18T07:11:55.545553Z	info	Found termination condition for channel handshake	{"path_name": "junotestnet-cosmoshubtestnet", "chain_id": "theta-testnet-001", "client_id": "07-tendermint-1971"}
```
</details>

#### Relayer の起動

秘密鍵の生成と Faucet，Path の設定が正しく完了すると、以下のコマンドですべてのステータスが正になります。

```sh :terminal
$ rly chains list
 1: theta-testnet-001    -> type(cosmos) key(✔) bal(✔) path(✔)
 2: uni-6                -> type(cosmos) key(✔) bal(✔) path(✔)
 3: constantine-2        -> type(cosmos) key(✔) bal(✔) path(✔)
```

ステータスが正常であることを確認できたら、Relayer を起動します。コマンドを実行すると、待機状態になります。

```sh :terminal
$ rly start <path_name>
```

<details><summary>実際のコマンド</summary>

```sh :terminal
$ rly start junotestnet-cosmoshubtestnet
```

</details>

### トークンの転送

トークンを転送するには、先ほど確立した Channel を識別するための Channel ID が必要になります。

Mintscan を用いて src_chain 上で処理した ChannelOpenAck の TX を表示すると、src_chain 側の Channel ID と dst_chain（counterparty）側の Channel ID が確認できます。

双方のブロックチェーンで異なる Channel ID が割り振られますが、転送時には src_chain 上の Channel ID を指定します。

```sh :terminal
$ rly tx transfer <src_chain_name> <dst_chain_name> <amount> <to_address> <channel_id> --path <path_name>
```

<details><summary>実際のコマンド</summary>

```sh :terminal
$ rly tx transfer junotestnet cosmoshubtestnet 10000ujunox cosmos1rxa3g70qg5vmkn7dk9xqn8kcgat39sh6a7ncmz channel-195 --path junotestnet-cosmoshubtestnet
2023-04-18T07:43:58.869509Z	info	Successful transaction{"provider_type": "cosmos", "chain_id": "uni-6", "packet_src_channel": "channel-195", "packet_dst_channel": "channel-2493", "gas_used": 109075, "fees": "12326ujunox", "fee_payer": "juno19y6lwhdzcwdar69tyfkyjedhldc5jpqg2phskr", "height": 1047935, "msg_types": ["/ibc.applications.transfer.v1.MsgTransfer"], "tx_hash": "C1906456FBEC5F183919C3B332FA5817F11ACA10779D8CC6458F88B4235BBBA1"}
```

</details>

トークンの転送処理を行うと、src_chain 上でトークンがロックされ、dst_chain 上で IBC トークン（voucher token）が発行されます。このとき発行される IBC トークンには、ネイティブトークンの Denom がそのまま用いられるのではなく、IBC 専用の Denom（IBC/xxxx）が付与されます。

IBC トークンの Denom（xxxx の部分）はハッシュ値が用いられており、以下のように決定されます。

```
Denom = IBC/{SHA256("<Port ID>/<Counterparty Channel ID>/<Origin Denom>")}
```

以上を踏まえ、３パターンのトークン転送について検証を行いました。

#### 1. 他のブロックチェーンへのネイティブトークン転送

Juno testnet 上のネイティブトークン（Junox）を Cosmos Hub testnet に転送しました。

その結果、Juno では指定した数量分のネイティブトークンが減少し、Cosmos Hub で IBC トークンとして受け取ったことを確認しました。また、Denom は以下のようになりました。

```
IBC/{SHA256("transfer/channel-2493/ujunox")}
= IBC/b30a84dd243c51acd2da0b38f8aae428d3216428cbc6093125bb20c69ca34cc3
```

#### 2. IBC トークンの返還

1 で受け取った IBC トークンを Cosmos Hub から Juno に返還しました。利用した Channel は 1 の転送時と同じものです。

その結果、Cosmos Hub で IBC トークンが失われ、Juno でネイティブトークンとして受け取ったことを確認しました。

次に、Juno から Cosmos Hub へ転送したネイティブトークンを用意し、転送時とは異なる Channel を経由して Juno へ返還しました。

その結果、Cosmos Hub で IBC トークンが失われましたが、転送時と Channel が一致しなかったため、Juno で IBC トークンとして受け取ったことを確認しました。

IBC ではチェーン間を複数の Channel で接続できます。しかし、転送時と返還時で異なる Channel を利用してしまうと、Juno 上でロックされたネイティブトークンをアンロックできないことがわかりました。

#### 3. 第三者のブロックチェーンへの転送

三者間でトークンを転送したときの動作を見るため、Archway のネイティブトークン（Const）を Juno へ転送し、Juno で受け取った IBC トークンを Cosmos Hub へ転送しました。

ネイティブトークン転送時と同様に、IBC トークンの Denom を指定してコマンドを実行した結果、IBC Transfer の TX がブロックチェーンに記録されたことを確認しました。

このとき、Juno で保管されていた IBC トークンは失われたものの、Cosmos Hub で受け取った IBC トークンは Mintscan や Relayer が取得するトークン一覧に表示されませんでした。

したがって、受け取った IBC トークンを第三者のブロックチェーンへ転送するという使い方は想定されていないことがわかりました。

### IBC の利用上の課題

IBC は仲介者を信頼せずに TX を他のブロックチェーンに転送できる有望な技術の一つですが、以下のような課題も挙げられます。

#### Denom の扱い

現状では IBC は代替性トークンの転送に用いられることが多いです。他のブロックチェーンに転送する際には Denom としてハッシュが付与されますが、このハッシュ導出には Channel ID が含まれています。

転送したときと異なる Channel でトークンを返送してしまうと、ロックされたトークンはアンロックされず、新たな IBC トークンが発行されてしまいます。そのため、経由する Channel を一つに定めるか、経由した Channel をアプリケーションなどで管理しなければなりません。

また、ハッシュは可読性が低いため、アプリケーション側でユーザが認識できるようサポートする必要があります。現状、Osmosis などのアプリケーションでは、元の Denom で表示するようになっています。

#### 実装コストの高さ

Cosmos SDK で開発されたブロックチェーンはモジュールを導入することで IBC に対応できます。その一方、他のブロックチェーンで IBC を利用するには、各自の仕様や独自の言語に対応した検証機能を実装する必要があります。

オンチェーンでの検証のコストが高いため、CPU の秘密計算領域である TEE（Trusted Execution Environment）を利用した [Light Client Proxy（LCP）](https://github.com/datachainlab/lcp) という方法も提案されています。

## まとめ

はじめに述べたように、非中央集権や改ざん耐性などの特徴をもつブロックチェーンをデータ流通の仕組みとして今後活用するには、エコシステム同士の接続が必要になると考えられます。

IBC はブロックチェーンの仕様に依存せずに利用できるプロトコルとして、相互運用性を実現する有望な技術の一つです。

現在は Cosmos エコシステム内の接続に主に用いられていますが、YUI（Hyperledger Labs）や LCP など Cosmos 外のエコシステムと接続する取り組みも進んでいます。

## 参考

検証に際し、以下のドキュメントを参考にしました。

- [Chapter Overview - The Interchain, Its Ecosystem, and ATOM | Developer Portal](https://tutorials.cosmos.network/academy/1-what-is-cosmos/)
- [Interchain Developer Academy](https://ida.interchain.io/)
- [GitHub - cosmos/relayer: An IBC relayer for ibc-go](https://github.com/cosmos/relayer)
- [Light Client | Tendermint Core](https://docs.tendermint.com/v0.34/tendermint-core/light-client.html)

相互運用性や IBC の詳細は下記レポートでも取り上げています。

[【先端技術レポート】ブロックチェーンの相互運用性とは | 日本総研](https://www.jri.co.jp/page.jsp?id=105692)