Hyperledger FabricにおけるEndorsement-Ordering-Validationモデルについて考える

本記事では、Hyperledger Fabricのトランザクション処理の特徴であるEndorsement-Ordering-Validation(EOV)モデルについて、良いところや課題について考察します。

## 良いところ

**Endorsementの並列処理**

Fabricのトランザクション処理は、[他の記事](https://qiita.com/hakozaki/items/9c7d1e00c4cf486a8f1f)等で詳しく解説されているのでここでは詳細は述べませんが、話の都合上、簡単に触れます。ざっくり言うとクライアント、Peer、Ordererという3人の登場人物が、Endorsement、Ordering、Validationという3つのフェーズで行います。

まず、クライアントが複数のPeerに対してトランザクション要求(例えば、AさんからBさんに100ドル送金してといった要求)を投げます。Peerは、その要求に従ってトランザクションを仮実行します。仮実行は、台帳の現在の状態に基づいて、このトランザクションがコミットされたらAさんとBさんの残高がどうなるかを計算するようなイメージです。Endorsementフェーズでは、いつの時点の状態を読んだか(Readセット)と、仮実行の結果(Writeセット)に署名を付与してクライアントに応答します。ReadセットとWriteセットは、以降、合わせてRWセットと呼びます。

クライアントは、複数のPeerから受領したRWセットが一致していれば、当該トランザクションをOrdererに送信します。Orderingフェーズでは、Ordererが、クライアントから受領した複数のRWセットを順番に並べ、1つのブロックにまとめた上で署名し、各Peerへばらまきます。

Validationフェーズでは、ブロックを受け取ったPeerが、各トランザクションのRWセットを検証した上で、コミット処理を行います。具体的には、Peerの署名の検証とともに、書き込み対象のデータが仮実行を行った時点から変更されていないかを確認します。変更されてしまっている場合には、当該トランザクションはアボートされます。

Fabric v1.0でEOVモデルが導入されたことにより、Endorsementフェーズで、投機的に複数のトランザクションを並列実行できるようになりました。v0.6までは全Peerで合意形成を行い、直列にトランザクションを実行しなければならなかったので、Peerをいくら増やしたところで性能をスケールさせることができなかったことを考えると、大きな変化だったと言えます。

**Endorsementの柔軟性**

もう1つ、EOVモデルの良いところは、どの取引に誰と誰の署名が必要かということを自由に定義できるところです。これは、Endorsement Policyという機能で、上記では、単に各PeerがRWセットに署名する(エンドースする)と書きましたが、どのPeerのエンドースが必要かを定義することができます。

例えば、3つの組織が参加するブロックチェーンネットワークで、各組織が2つずつPeerを運用している場合に、必ずしも全Peerから署名を得る必要はなく、全組織のいずれか1つのPeerの署名でOKといったポリシーや、いずれか2組織の署名でOKといったポリシーを書くことができます。これにより、結果の正しさと効率の良さを、アプリケーションの要件に合わせて自由に設計することができます。このような機能は、著者の知る限り、他のコンソーシアム型ブロックチェーンや分散台帳には見られない特徴的なものではないかと思います。

また、EOVモデルそのものからは外れてしまうのですが、Fabricが良くできているのは、このEndorsementの考え方がブロックチェーンネットワークの運用全体に行き届いているところです。例えば、ブロックチェーンネットワークでサービスを開始するにあたっては、(ある意味当然ではありますが)全組織の署名があってはじめて構成できるようになっていますし、ブロックチェーンネットワークに新しく組織を追加する際にも事前に定めたルール(e.g., 全員、過半数)にしたがって署名が求められるようになっています。このあたりの作り込みがしっかりしているのは大手ベンダ主導でしっかり開発されているが故かなと思います。

## 課題

Fabricのコンセンサスモデルの良いところについて述べてきましたが、色々と課題もあると思います。少々細かい話になってしまいますが、3つほど課題かなと思う点を挙げたいと思います。

**Validationフェーズの並列化**

EOVモデルの導入により、Endorsementフェーズにおける仮実行は並列処理が可能になったのですが、Validationフェーズは依然として直列実行になっています。署名の検証や、RWセットの検証を各トランザクションについて逐次やっていくのは非効率のように思います。

と思いながら、Fabricのコミュニティではどう考えているのか調べてみると、やはり課題意識はあるようで、署名の検証だけは並列でやろうとか、色々と議論されているようです。以下のJIRA、論文が参考になります。

https://jira.hyperledger.org/browse/FAB-12221
https://jira.hyperledger.org/browse/FAB-12280
https://arxiv.org/pdf/1808.08406.pdf


**アボートの削減**

EOVモデルの宿命のようにも思いますが、並列で仮実行している以上、同一のリソース(Key-Valueデータ)に更新が集中すると必然的にアボートが多くなります。特に、Fabricの場合、仮実行からコミットに至るまでに複数回のネットワーク通信を要するため、RDBMSの並行性制御よりも古い値を読みうる時間が長いのではないかと思います。例えば、送金アプリケーションにおいてあるユーザに送金が集中するといったことは容易に起こりうる状況なので、アプリケーション側のリトライに期待するだけでなく、何らかの工夫を期待したいところです。

ちなみに、これに関連しては、アカデミアの方では関連する取り組みがなされていました。下記の論文は、データベース関連の学会の最高峰の1つであるSIGMODで最近発表されたものですが、Orderingフェーズにおいて、各トランザクション間のRWセットの更新の依存関係を見た上で、なるべくアボートが少なくなるようトランザクションを並び替える手法が提案されています。

Sharma, A., Schuhknecht, F. M., Agrawal, D., & Dittrich, J., "Blurring the Lines between Blockchains and Database Systems: the Case of Hyperledger Fabric", SIGMOD 2019 (pp. 105–122)
https://dl.acm.org/citation.cfm?id=3319883


**負荷分散**

Endorsement Policyで誰の署名を得る必要があるか柔軟に定義できると延べましたが、裏を返すとクライアントがブロックチェーンネットワークに対してEndorsement Policyを踏まえつつ適切にトランザクション要求を投げる必要があります。ある組織に複数のPeerがあり、そのうち1つの署名を得れば良いケースでは、負荷がPeer間で均等になることも期待されます。これをクライアント(アプリケーション)が都度実装するのは負担が大きいので、Fabric v1.4ではSDKに[Connection Profile](https://qiita.com/jnmt/items/b9d73e82d1c6a7901175)という機能が導入されました。

Connection Profileにより、Endorsement Policyを考慮したトランザクション要求送信が容易にはなりましたが、負荷分散については単にラウンドロビンで投げるだけなようなので、これがもう少しインテリジェントになるとより実用的になるのではと思っています。