CordaのにおけるFlowの役割が理解できる。
はじめに
Cordaの開発では、典型的なコード構造として、CorDappを、contractsとworkflowsの2つのモジュールに分けることができます。contractsは、statesとcontractsを含むモジュールで、workflowsはCorda Flowを含みます。workflows用に単一のモジュールを持つことで、配布ロジックがシンプルになります。すなわち、全てのFlowが単一のjarファイルにパッケージされます。一方で、あるノードにCorDappをインストールすると、必要かどうかに関わらず、すべてのFlowが利用可能になることを意味します。この事象は、ノードがさまざまな役割を果たし、さまざまな機能を必要とするネットワークでより起こりやすくなります。
例えば、自動車登録用のCorDappをイメージしてください。ネットワークの参加者には、Department of Motor Vehicleといった政府機関を表すノード(以下、DMVノード)と、車の所有者を表す複数のノード(以下、所有者ノード)があるとします。DMVノードは所有者ノードに対し、登録証発行トランザクションを開始し、所有者ノードはトランザクションの情報を検証し、問題がなければそれを受け入れることになります。一般的なセットアップでは、 Initiator FlowsとResponder Flowsの両方が同じjarファイルにバンドルされています。つまり、登録証発行用のInitiator Flowsは、所有者ノードが実行することを想定していなくても、所有者ノードにインストールされてしまいます。
コードでアクセスを制限
この問題について、一つの解決策は、Flowロジックの中で、現在のノードが特定のトランザクションを開始する資格があるかどうかをチェックすることです。自動車登録のCorDappを例にとると、登録証発行Flowを開始するノードがDMVノードであるかどうかをチェックし、そうでない場合は例外を投げます。しかし、この方法は、より複雑なユースケースでは拡張性が低く、Flowのコードのメンテナンスが無駄に困難になる可能性があります。
Flowを分解してアクセスを制限
より理想的なアプローチは、workflowsをより小さなモジュールに分割し、ノードが必要とするFlowのみをインストールすることです。例えば、登録証発行のInitiator Flowsのように、DMVノードでのみ開始できるFlowを1つのjarファイルに束ねることができます。一方、登録証発行のResponder Flowsのように、所有者ノードのみが実行可能なFlowは、別のjarファイルに束ねます。
再び自動車登録用のCorDappを例にとります。このCorDappには、自動車登録と、自動車の所有者から別の所有者への譲渡という2種類のトランザクションがあるとします。モジュール構造は以下のようになります。
ご覧の通り、Initiator Flowsはdmv-workflowsモジュールにあります。DMVノードのみがこれらのトランザクションを開始できることを意味しています。一方、Responder Flowsは、owner-workflowsに分類されています。
Cordaでは、@InitiatedBy
アノテーションを用いて、Responder Flowsの対応するInitiatorを指定する必要があります。例えば、RegisterFlowHandler
では、RegisterFlow
に応答することを指定する必要があります。
しかし、所有者ノードには dmv-workflows モジュールがインストールされていないため、Responder Flowsを実行するとエラーが発生します。この問題を解決する一つの方法として、RegisterFlow
の抽象的な親クラス(AbstractRegisterFlow
とします)を定義し、この親クラスを所有者ノードにもインストールされる共有モジュールで公開します。この共有モジュールは、上の構造ツリーでは common-workflows モジュールです。
そして、AbstractRegisterFlow
を @InitiatedBy
に渡すことで、RegisterFlow
が AbstractRegisterFlow
のサブクラスであることから、オーナーノードが RegisterFlow
に応答できるようにします。
RegisterFlow
の定義は次のようになります。
BootStrapperを使用してネットワークを展開する場合(本番環境では推奨されません)、特定のノードにインストールするモジュールを指定することができます。例えば、build.gradle 内にある DMV ノードのノード設定では、dmv-workflows モジュールをインストールするように指定します。
一方で所有者ノードの設定は次のようにします。
結論
この記事では、異なるノードに独立してFlowをインストールできるようにInitiator FlowsとResponder Flowsを分離する方法について説明してきました。この方法は、ノードで実行可能なFlowを定義するための、拡張性のある方法としてだけでなく、CorDappにおけるworkflowsのモジュール化を促進し、配布のための高い柔軟性を提供します。注意すべきは、分離はInitiator FlowsとResponder Flowsの間で常に起こるわけではないということです。モジュールをどのように定義するかは、アプリケーションの要件によって異なります。
この記事で使用したサンプルの詳細に興味がある方は、こちらのGithubからソースコードをご覧いただけます。
<ご質問・ご要望の例>
- Corda Portalの記事について質問したい
- ブロックチェーンを活用した新規事業を相談したい
- 企業でのブロックチェーン活用方法を教えて欲しい 等々