Hyperledger FireFly 簡易調査

## はじめに
昨今、NFT界隈をはじめ、ブロックチェーンのアプリケーション(以降、Web3アプリ)をいくつも見かけるようになってきました。そういったWeb3アプリは、たいていの場合、ブロックチェーン単体でシステムが組みあがるわけではなく、たとえば下図のように様々なシステム要素が必要になってきます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3655885/5fd6d7ba-bb18-ec86-05eb-739f35b68370.png" width=80%/>

そうなると、図の真ん中にあるコーディネートシステムのようなシステム要素間の連携を担うシステムが必要になってきます。このようなシステムの処理は、今までは自前で開発するしかなかったかと思います。しかし、こういった処理は定型的ではあるものの、それなりの品質も求められる(システムのコアインフラ部分であったりする)ため、自前でコードを書いて、メンテナンスしていくのもなかなか難しいところです。こういった課題感から既成のOSSやミドルウェアが何かないか探したところ、候補の一つとしてOSSの[Hyperledger FireFly](https://github.com/hyperledger/firefly)(以後、FireFly)に至った次第です。FireFlyの開発元は[Kaleido](https://www.kaleido.io/)で、Kaleidoの[マネージドサービス](https://www.kaleido.io/hyperledger-firefly)としても展開があります。

## FireFlyの位置づけについて
FireFlyやKaleidoの展開するマネージドサービスをWeb3アプリのインフラという位置づけとして代替品・競合を調べていくと、マネージドサービスでは当然存在はしていて、例えば下表のようなところではないかと思います。

| 会社名 | Webサイト |
|:-:|:-:|
| Alchemy | https://www.alchemy.com/ |
| Infra  | https://www.infura.io/ |

Web3アプリの開発で、仮にインフラ部分をこういったマネージドサービス企業にフルアウトソース可能なら、もちろんそれはそれで問題ないのですが、ブロックチェーンの["Don't trust. Verify."](https://ethereum.org/en/run-a-node/)といった精神を慮ると、とくにエンタープライズ領域のWeb3アプリ(例えば、信頼を自社の売りにしたい)において、自前でのブロックチェーンノードとノードを取り巻くシステム構成要素の組み立て方法を一度考えておいても損はないかもしれません。

## 実行構築
今回調査にあたり構築したFireFly実行環境を以下に示します。OSはWindows 10のWSL2上のUbuntu、DockerはUbuntuに直接インストールしました。

* Ubuntu 22.04.3 LTS (GNU/Linux 5.15.133.1-microsoft-standard-WSL2 x86_64)
* Docker Engine 24.0.7
* Docker Compose v2.21.0
* FireFly v1.2.2

### FireFlyの実行環境について補足
FireFlyの環境構築については、[Getting Started](https://hyperledger.github.io/firefly/gettingstarted/)の手順を踏むことで、インストールからFireFlyの起動までとくに問題なく進めることができるはずです。まず、[FireFly CLI](https://github.com/hyperledger/firefly-cli)をインストールし、以降はFireFly CLIを使って進めるのですが、このCLIにより作られる環境は、基本的にはWeb3アプリ開発中の検証用ローカル環境といった趣(これは、FireFly CLIのGitHubページに記載されているとおり)で、docker composeを使ったコンテナ環境です(以降、この環境をFireFlyローカル環境とします)。また、FireFly CLIでは、EthereumとHyperledger Fabricの2つのブロックチェーンのいずれかのFireFlyローカル環境を作成できるようになっています。今回の簡易調査では、Ethereumのみを対象としています。

## 実施内容
FireFlyの一通りの機能を見るには、公式ドキュメントに用意されている[Tutrials](https://hyperledger.github.io/firefly/tutorials/)をこなしていくとよさそうです。以後、Tutrialsだけでは分かり難かった箇所を中心に補足していきます。

### FireFlyローカル環境の起動
最初に、FireFlyローカル環境を作成します。最も簡素な環境とするため、メンバー数は1で、スタック名はdev2としました。作成コマンドは以下です。

```Shell
> ff init etherum dev2 1
```

ここで、FireFly CLIが作成してくれたdocker-composeファイルの場所がコンソールにエコーバックされるので、覚えておきます。(下記の画面例では`/home/ubuntu/.firefly/stacks/dev2/docker-compose.yml`)

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3655885/59fbffa9-7862-c7b6-b287-6bd8dd03f9ee.png" width=100%/>


その後、FireFlyローカル環境を立ち上げます。

```Shell
> ff start dev2
```

### FireFlyのアーキテクチャについて
FireFly公式ドキュメントの[Connector Frameworkのページ](https://hyperledger.github.io/firefly/overview/key_components/connectors.html)によると"Pluggable Microservices Architecture"との記載があります。より具体的にどうなっているかということが気になりますので、前述したFireFly CLIで作成されるdocker-composeファイルの中身に加えて、FireFlyローカル環境でどのようなコンテナが上がっているのかを確認します(下記の画面例で、見難いが赤枠のあたり)。これらを、FireFly公式ドキュメントにある[Pluggable Microservices Architectureの図](https://hyperledger.github.io/firefly/images/firefly_architecture_overview.jpg)と照らし合わせてみます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3655885/b4ed94d1-0000-61cc-0f04-6457d28d00b7.png" width=100% />


もう自明ではありますが、`dev2_firefly_core_0`コンテナがFireFly Core(Pluggable Microservices Architectureの図ではFireFlyCoreの箱と、FireFlyCoreにくっついている箱)で、`dev2_geth_0`と`dev2_ipfs_0`のコンテナは、それぞれEthereum[(Go Ethereum)](https://github.com/ethereum/go-ethereum)のノードとIPFS[(Go IPFS/Kubo)](https://github.com/ipfs/kubo)、その他は下表の通りの対応だと分かります。

|Plugin名|コンテナイメージ(コネクタ名)|コンテナ名|
|:-:|:-:|:-:|
|Digital Asset Plugin|firefly-tokens-erc20-erc721|dev2_tokens_0_0|
|Blockchain Plugin|firefly-evmconnect|dev2_evmconnect_0|
|Data Exchange Plugin|firefly-dataexchange-https|dev2_dataexchange_0|
|Shared Data Plugin|なし|なし|

Shared Data Pluginのコネクタコンテナがないのは、[Pluggable Microservices Architectureの図](https://hyperledger.github.io/firefly/images/firefly_architecture_overview.jpg)から読み取るにFireFly CoreのShared Data Pluginが直接IPFSとのやりとりをサポートしており、中間層のコネクタが不要ということかと思われます。また、FireFly Core自身のローカルDBは、FireFlyローカル環境のデフォルトでは組み込みDBの[sqlite3](https://hyperledger.github.io/firefly/reference/config.html#databasesqlite3)の構成となり、その他に[PostgreSQL](https://hyperledger.github.io/firefly/reference/config.html#databasepostgres)をサポートしています。従って、FireFlyローカル環境を脱していくには、少なくともFireFly Coreコンテナと自身のローカルDBのPostgreSQL化、および、これらのコネクタコンテナをしっかりと実行してあげればよさそうです。

### FireFly Coreと各コネクタについての概要調査
[FireFly CoreのGitHubページ](https://github.com/hyperledger/firefly)を見てみると、前述の各コネクタのソースリポジトリへのリンクがあります(下表)。今回は簡易調査なので、FireFly Coreと各コネクタについて、それぞれのGitHubリポジトリを軽く見ていきます。

|コネクタ名|GitHubリポジトリ|
|:-:|:-:|
|firefly-tokens-erc20-erc721|https://github.com/hyperledger/firefly-tokens-erc20-erc721|
|firefly-evmconnect|https://github.com/hyperledger/firefly-evmconnect|
|firefly-dataexchange-https|https://github.com/hyperledger/firefly-dataexchange-https|

#### FireFly Core

一般的に、ブロックチェーンのユースケースの一つとして考えられるのは、なんらか発生していくイベント履歴を時系列かつ証拠性のある形で記録しておく場所とすることです。このユースケースに対応するFireFlyの機能には、例えば[メッセージブロードキャスト機能](https://hyperledger.github.io/firefly/overview/multiparty/broadcast.html#blockchain-backed-broadcast)(Tutorialsの[Broadcast dataサンプル](https://hyperledger.github.io/firefly/tutorials/broadcast_data.html))でメッセージを送ると実行されるBatchPinというトランザクションがあります。例えば、FireFly Explorerの画面上では、Blockchain Events欄に一覧表示されます(下記の画面例参照)。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3655885/09be3c80-14e9-f3da-686b-cf62fd58a852.png" width=75%/>

##### BatchPinについて
まず、BatchPinが何者かですが、FireFly Core v1.2.2では、GitHubリポジトリ内の[FireFlyスマートコントラクト](https://github.com/hyperledger/firefly/blob/v1.2.2/smart_contracts/ethereum/solidity_firefly/contracts/Firefly.sol)が対応していると思われます。このFireFlyスマートコントラクトをFireFly Coreの初回起動前にブロックチェーンネットワークにデプロイし、その際に取得できるスマートコントラクトアドレスをFireFly Core Configurationの[`namespaces.predefined[].multiparty.contract[].location`](https://hyperledger.github.io/firefly/reference/config.html#namespacespredefinedmultipartycontract)に設定しておくようです。

##### スマートコントラクトのイベントサブスクライブ
次に、FireFly Explorerの画面上でBlockchain Events欄に一覧表示されるところですが、FireFly Coreはfirefly-evmconnectを経由してSolidity(つまりは[EVM](https://ethereum.org/en/developers/docs/evm/))の[スマートコントラクトイベント(または、ログともいう)](https://docs.soliditylang.org/en/stable/contracts.html#events)をサブスクライブして、履歴として持っており、画面はそれらをFireFly APIで取得して表示しているのでしょう。この機能は、トークンのtransferイベント([Metamaskを使った例を参照](https://hyperledger.github.io/firefly/tutorials/tokens/erc20.html#use-metamask))や、[カスタムのスマートコントラクト](https://hyperledger.github.io/firefly/tutorials/custom_contracts/ethereum.html#create-a-blockchain-event-listener)([TutorialsのListen for eventsの例を参照](https://hyperledger.github.io/firefly/tutorials/events.html))でももちろん動きます。スマートコントラクトのクライアントアプリとして、イベントサブスクライブを独自できっちり作り込むのは結構な労力を要するイメージがあるため(エンタープライズのサーバーサイドアプリなどで)、利用できるものがあるなら利用したいものです。

##### スマートコントラクトのラッパーAPI自動生成
上記の[カスタムスマートコントラクトの例](https://hyperledger.github.io/firefly/tutorials/custom_contracts/ethereum.html)の中に、任意の[スマートコントラクトのAPIラッパー](https://hyperledger.github.io/firefly/tutorials/custom_contracts/ethereum.html#create-an-http-api-for-the-contract)を生成してくれるFireFly便利機能の紹介があります。FireFlyはスマートコントラクトの[ABI JSON](https://docs.soliditylang.org/en/stable/abi-spec.html#json)さえ教えてもらえれば、それに対応するOpen APIの仕様([コマンドResponse](https://hyperledger.github.io/firefly/tutorials/custom_contracts/ethereum.html#response-3)のURLからswagger.jsonファイルがダウンロードできる)を起こして、下図のようなSwagger UI画面のURLを公開してくれます。これは本当に素敵な機能だと思います。毎度毎度のスマートコントラクトのラッパーAPI開発から解放されるかもしれません。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3655885/b8f35d94-621d-6a64-df9c-1bfde5136af5.png" width=60% />

以上が今回の簡易調査でのFireFly Coreのトピックで、以降はコネクタ(firefly-tokens-erc20-erc721、firefly-evmconnect、firefly-dataexchange-https)についてです。

#### firefly-tokens-erc20-erc721
firefly-tokens-erc20-erc721コネクタは、FireFly Coreとfirefly-evmconnectの間に入るコネクタで、[fftokens](https://hyperledger.github.io/firefly/reference/microservices/fftokens.html)という仕様に則ったHTTP/websocketのサーバーです。また、FireFlyでのトークンに対する考え方は、まず[TokenPool](https://hyperledger.github.io/firefly/reference/types/tokenpool.html)という用語にてトークンのスマートコントラクトのことを指し、次に[Token](https://hyperledger.github.io/firefly/reference/types/tokentransfer.html)という用語にてトークンスマートコントラクトのmint操作やtransfer操作の対象となるデータのことを指すとなっています。

#### firefly-evmconnect
firefly-evmconnectコネクタは、[firefly-ethconnect](https://github.com/hyperledger/firefly-ethconnect)という前身となるコネクタがあり、この前身のコネクタの開発・運用で得た知見を元にした改良版的位置づけとの記載があります。また、[FireFly Transaction Manager](https://github.com/hyperledger/firefly-transaction-manager)(FFTMと略される)というブロックチェーンプロダクト中立のコア機能ライブラリを利用して、EVMベースブロックチェーン固有の処理を付け加えるコネクタとなっているようです。ブロックチェーンへの橋渡し役として、FireFlyが実システム上でどこまで利用できるかは、これら3つのモジュールがシステム要件を満たすことができるのかといった観点で追加調査していく必要がありそうです。

#### firefly-dataexchange-https
firefly-dataexchange-httpsコネクタは、相互TLS認証(mutual-TLS, mTLS)によるデータ交換機能を扱うコネクタで、例えば、Tutorialsの[Privately send data](https://github.com/hyperledger/firefly-dataexchange-https)で示されるようなブロックチェーンの外側(オフチェーン)でのデータ交換の際に活躍するコネクタと考えられます。一般に、こういったデータ交換はブロックチェーンが得意とする領域(ブロックチェーンの場合はデータ共有によって実質的に情報交換を実現)なので、いったいなぜブロックチェーンのためのFireFlyというプロダクトでこのような機能が必要なのかという疑問も出そうですが、実世界のデータというのは、例えば全員に共有したいデータ、特定の相手とだけ共有したいデータ、自分だけの秘密にしたいデータといった様々に分類できますし、これらのデータをシステム上では同時に取り扱わなければならない場合が多いのではないかと思われます。

上記のようなすべてのデータ交換パターンに対し、ブロックチェーンプロダクト単体(オンチェーン単独チャネル)で何とかするのではなく、適材適所の方式を用いたマルチチャネルデータ交換(オンチェーンとオフチェーンのマルチチャネル)で対処するという考え方もできます。どちらにするかの選択はユースケース次第ですが、マルチチャネルでシステムを組むことにより、チャネル単位ではシンプルなシステム構成となることで、人間にとって理解しやすいシステムが出来上がる可能性も多いにありそうで、そういう点でFireFlyのデータ交換機能はなかなか便利で活躍が期待できそうな気もします。

以上で今回のFireFly簡易調査は終了です。

## おわりに
今回はFireFlyの簡易調査ということで、公式ドキュメントとGitHubリポジトリを表面的になぞったところまでです。FireFlyはFireFly CLIを使って動作させるところまでは簡単にできるものの、あくまで検証用のローカル環境でしかなく、Web3アプリを実現するシステム要素として本当に使えるのかは、さらなる追加調査に加えて動作検証も必要と考えています。