Corda 5のNotaryのアーキテクチャの詳細・Notaryリソースを細かくスケーリングしてTCOを削減できること
はじめに
Notaryに関する以前の記事(翻訳未済)では、Notaryとは何か、そしてなぜNotaryがCordaのUTXO台帳を保護する上で重要な役割を果たすのかについて説明しました。
この記事では、Corda 5のNotaryのアーキテクチャの詳細を掘り下げ、新しいNotaryを簡単に導入できるソリューションを提供すると同時に、Notaryリソースをより細かくスケーリングできるようになった結果しTCOを削減できることを説明します。
キーコンセプト
まずはじめに、Notaryの動作を理解する上で基本となる、Corda 5のNotaryに関する基礎概念を紹介します。
ノータリゼーションとユニークネス検証
大まかに言うと、CordaのNotaryは2つの要素で構成されています。
一つ目は、Flowで、Notaryの確認を要求するクライアントの(仮想)ノードがNotaryの(仮想)ノードとのセッションを確立し、Notaryはプロトコルが規定する独自の検証を実行します。
2つ目の部分は一意性チェックで、二重消費を防ぐことでUTXOモデルの台帳の整合性を保証する固定されたロジックです。2つ目のロジックは、Flowプロトコルの一部として呼び出されます。
この二つの要素は、以前のバージョンのCordaのNotaryプロトコルでも用いられています。一つ目の部分に含まれる検証方法は、Non-Validating(非検証)プロトコルとValidating(要検証)プロトコルの二つがあります。
この二つは、Flowで定義される検証内容が異なっています。Non-Validating(非検証)プロトコルは取引の構造が正しいことを確認するための最低限のチェックだけを実行する一方、Validating(要検証)プロトコルは当該取引のバックチェーン全体に対してContractの内容検証を実行します。
二つのプロトコルに共通するのは、二重消費を防ぐために一意性チェックロジックを呼び出すことです。
この機能的な分離はCorda 5でも維持されています。さらに、Corda5ではこの二つの機能の責任分担が明確に分離され、基本的なアーキテクチャによりよく反映iしました。この点については後ほど詳しく説明します。
Notaryのプロトコル
Corda 4は前節で示した、2つのNotaryプロトコルをサポートします。(ValidatingとNon-Vlidating)
プロトコルの選択はネットワークオペレーターによってNotaryサービスごとに行われ、Notaryの設定値として(True/Falseいずれかを)指定することで実現します。これらのプロトコルはCorda 4のランタイムにハード的に組み込まれており、別のプロトコルを定義することはできません。
Corda 5は、異なるアプローチをとります。Notaryプロトコルを(Notaryに渡す)「プラグインCorDapps」として定義します。
「プラグインCordapp」は”クライアント”コンポーネントと”サーバー“コンポーネントの二つから構成されます。”クライアント”コンポーネントは、(通常のNodeにインストールされる)「アプリケーションCorDapps」にバンドルされ、Notaryに検証依頼を送信するためのInitiatingFlow(訳註:通信相手への送信を定義したFlow)が含まれています。一方、”サーバ“コンポーネントも用意されます。こちらはNotary専用CorDappの一部としてインストールされ、Notaryの仮想ノードに常駐します。”サーバ”コンポーネントはNotaryリクエストを処理するResponderFlow(訳註:InitiatingFlowに対応する通信プロトコルを定義したFlow)を含みます。
Corda 4とは異なるこのアーキテクチャは、CorDapp開発者とNotary運用者は、サポートしたいNotaryのプロトコル(複数可)を決定する必要があることを意味します。
しかし、ビジネスネットワークオペレーターが、ネットワーク上のどの仮想ノードとどのNotaryに参加を許可するかを決定するので、最終的な決定権をビジネスネットワークオペレーターが管理していることに変わりはありません。このトピックについては、次回のブログ記事でより詳しく説明します。
以前述べたように、MGM(メンバーシップグループマネージャー)はNotaryサービスを特定のNotaryプロトコルにリンクさせるための情報を保持しています。この情報はネットワークオペレータによって署名され、その後、ネットワークメンバーに配布されます。これにより、Notaryの検証時に(仮想)ノードが適切なプロトコルを選択することができます。
Notary サービスとNotary仮想ノード
Notaryサービスとは何か、そしてNotaryサービスを実現するNotary仮想ノードとは何なのかを説明します。
Corda 5 のNotaryモデルは Corda 4 で利用可能な高可用性Notaryと似ていますが、いくつかの違いがあります。
まず、Corda 5 では、Notaryは常にNotaryサービスの x500nameによって参照されます。つまり、CorDappsがNotary検証を依頼する際、Notaryサービスのx500nameを指定して検証を依頼します。つまり、すべてのNotaryはCorda 4の高可用性Notaryと同じように扱われます。
MGM(メンバーシップグループマネージャー)は、ネットワーク内に損じする各Notaryサービスのx500nameと、その各サービスがサポートするNotaryプロトコル、Notaryサービスの代表として機能するNotary仮想ノードをブロードキャストすることで、ネットワーク上で利用可能なNotaryサービスを定義します。
Notary仮想ノードは、通常の「アプリケーション」仮想ノードと同様、ネットワークに登録され、Flowを実行し、独自のデータベース、秘密鍵と公開鍵、x500name、およびIDを保持します。
通常ノードとの唯一の違いは、Notary仮想ノードは、アプリケーション仮想ノードとは異なる一群のFlowを含む、Notary専用のCordaパッケージインストーラ(CPI)を実行し、これらの仮想ノードがNotary検証要求に応答できるようにする点です。Notaryアプリケーションのパッケージングについては、別のブログ記事でより詳しく説明します。
注:このブログでは、わかりやすくするために、Notaryではない仮想ノードを「アプリケーション」仮想ノードと呼ぶことにします。
アリス、ボブ、チャーリーという3つのアプリケーション仮想ノードがあるネットワークを想像してください。また、ネットワーク上に1つのNotaryサービスがあり、そのサービスを実現している2つのNotary仮想ノードがあります。このようなネットワークは、次のように表示されます。
公証役場から代理人へのメッセージの解決方法については、後ほどご紹介します。
屋上屋を架している?
Corda 5の高可用性に関するブログ記事を読まれた方は、Corda 5では単一の仮想ノードだけで高可用性を実現している、なぜ複数の仮想ノードでNotaryサービスを表現できるように、Notaryサービスのx500nameという抽象化レイヤーを使い続けるのかと質問されるかもしれません。
通常、Notaryサービスを表す仮想ノードは1つであると予想され、実際Corda 5.0リリースではこれが唯一の選択肢になります。しかし、この抽象化を維持することで、1つのNotaryサービスを異なる地域にまたがるCordaクラスタによって提供することができ、さらに高い耐障害性を提供することができます。
Notaryの一生
Corda 5 のNotaryに関する基本概念を説明したところで、Notaryのライフサイクルを見てみましょう。これは大きく分けて以下の段階に分かれます。
・Notaryサービスを表す仮想ノードの作成
・ネットワーク登録
・Notary検証リクエスト
それぞれを順番に見ていきましょう。
仮想ノードの作成
前述のとおり、Notary仮想ノードはアプリケーション仮想ノードとほとんど同じように動作します。Notary仮想ノードを作成するメカニズムは、アプリケーション仮想ノードと同じですが、2つの小さな違いがあります。
- アプリケーションCorDapp CPIではなく、Notary用のCPIに関連付けられます。
- ネットワーク上の未使用と使用済みのStateに関連するデータを保存する「ユニークネス」データベースを保有します。他の仮想ノードデータベースとは異なり、このデータベースはNotaryサービスを表す全てのNotary仮想ノード間で共有され、ネットワーク上の状態の一貫したビューを持っていることを保証します。
先ほどのアリス、ボブ、チャーリー、そしてNotaryサービスによるネットワークの例に戻ると、このネットワークは次のように表示されます。
上記の各データベースは、必ずしも異なる物理データベースである必要はなく、同じ物理データベース内の異なるスキーマであってもかまいません。この時点では、公証人の仮想ノード作成についてのみ説明し、公証人サービスについては説明していないことに注意してください。Notaryサービスは、”ネットワーク定義”の一部として登場します。
ネットワーク定義
Notary仮想ノードの登録は、アプリケーション仮想ノードの登録と同じプロセスに従います。ただし、登録要求プロセスの中でいくつかの追加情報を必要とします。
"corda.roles.0" : "notary"
この仮想ノードがネットワーク上でNotaryの役割を担うことをフラグ付けします。
"corda.notary.service.name" : <x500 name>
この仮想ノードが表現するNotaryサービスをユーザーが特定するためのx500 nameです。
"corda.notary.service.plugin" : <protocol name>
サービスがサポートするNotaryプロトコルの名前です。これは事実上、Corda 4のValidatingNotaryであるかどうかを示すフラグを置き換えるもので、今後新しいNotaryプロトコルを柔軟に記述できるようになります。この点については、今後のブログ記事で詳しく説明します。
じっしtNotaryサービスを表す最初のNotary仮想ノードのメンバーシップリクエストが承認された時点で、Notaryサービスは誕生します。この時点で、Notaryサービスはネットワークのメンバーシップ情報に現れ、アプリケーションCorDappがNotary検証で使用できるようになります。
Notary検証リクエスト
Notaryサービスがネットワークに見えるようになると、アプリケーションはCorda 4で行ったのとほぼ同じ方法でNotary検証リクエストを実行します。
finalityロジックを呼び出す際に、CorDappはNotary検証に使いたいNotaryサービスを指定します。この時点で、CordaのFlowは2つの決定をしなければなりません。
- どのNotaryプロトコルを使うか。
- どの仮想ノードにNotary検証リクエストを送るか。なぜなら、(P2P)メッセージングレイヤーは仮想ノードだけを理解し、Notaryサービスを理解しないためです。
これらの決定は両方とも Corda によって自動的に処理され、CorDapp 開発者による介入は必要ありません。Notaryプロトコルの選択は簡単です。アプリケーションCPI(Corda Package Installer)は、アプリケーションがサポートするプロトコルのためのNotaryクライアントCPK(Corda Package )を含んでいます。
Notary検証リクエストが要求されると、クライアントノードはNotaryサービスのMGMメタデータを検索し、指定されたプロトコルに一致するNotaryクライアントCPKを検索し、呼び出します。
仮想ノードの選択も同様に簡単です。MGMメタデータには、NotaryサービスのためのNotary仮想ノードのリストも含まれています。これらはラウンドロビン方式で選択され、Notary検証を要求するノードが、選択されたNotary仮想ノードにフローを送信し、そのNotary仮想ノードが対応するResponderFlowを開始します。
Notary検証リクエストの処理
Notary仮想ノード上で実行されるResponderFlowは、特別なことを最初からすることはありません。通常のResponderFlowと同様に、好きなロジックを実行することができます。Non-ValidatingのNotaryプロトコルの場合、ロジックは最小限で、単に受信したトランザクションの整合性のチェックを実行するだけです。
このロジックが実行されると、Flowは次に一意性チェック機能を呼び出します。この機能 は、TransactionのInput Stateがすでに使われていないことを確認し、含まれるすべてのInput Stateに対する一意性 チェックに合格した場合にのみInput Stateの消費処理を行います。
Corda 4では、一意性チェックはFlow処理とは別のスレッドである程度のTransactionの塊に対してバッチ的に実行され、DBへのラウンドトリップ数を減らすことでパフォーマンスを向上させていました。
このバッチ処理のアプローチはCorda 5でも変わりませんが、実装は多少異なっています。一意性チェックは別のスレッドを走らせるのではなく、データベースワーカーの一部として生きる専用の一意性プロセッサーによって処理されます。Notaryフローは、Cordaメッセージバスにメッセージを置くサービスを呼び出すことで一意性チェックを要求し、そのメッセージは一意性プロセッサに拾われます。
一意性プロセッサはメッセージバスから要求のバッチを引き出します。Corda 4とは異なり、これらのリクエストは複数のNotaryサービスに対する複数のNotary仮想ノードからのものである可能性があります。これに対処するために、uniquenessプロセッサは、各リクエストのバッチを、リクエストを行ったNotary仮想ノードに基づいてサブバッチに分割し、各Notary仮想ノードに対して正しいuniquenessデータベースを使用し、異なるサービス間の適切なデータ分離があることを保証します。
応答はメッセージバスに戻され、Flowに拾われます。そして、Flowは成功したNotaryリクエストに対してNotaryの鍵で署名します。
このアプローチには、いくつかの利点があります。一意性プロセッサは、Notary仮想ノードの一意性データベースへの排他的なアクセスを持ちますが、他のデータベースへのキーやアクセスは持ちません。次に、フローとuniquenessのリソースを独立して拡張することができます。リソースを大量に消費する重いNotaryプロトコルを実行する場合、適度な数のデータベースワーカーを実行しながら、Flowワーカーの数を拡張することができます。その逆の場合は、データベースワーカーの数を増やすこともできます。一意性プロセッサを独自のワーカーに分離した方が性能的に有利な場合は、そのような設定も可能です。上の図では、複数のFlowプロセッサからのリクエストを1つのユニークネスプロセッサで処理する例を見ています。
まとめ
この投稿では、Corda 5 の新しいNotaryアーキテクチャを説明し、Corda4から変更を加えたその理由も合わせて示しました。このシリーズの次のブログ記事では、NotaryプラグインのCorDappアーキテクチャについてより詳細に説明し、これがCorDapp開発者やビジネスネットワークオペレーターにとって何を意味するのかを議論します。
<ご質問・ご要望の例>
- Corda Portalの記事について質問したい
- ブロックチェーンを活用した新規事業を相談したい
- 企業でのブロックチェーン活用方法を教えて欲しい 等々
SBI R3 Japan エンジニアリング部長
書籍出してます:https://amzn.asia/d/c0V31Vd
趣味:サッカー、ガンプラ、ドライブ、キャンプ