投稿日
Corda Webアプリケーション開発について
もくじ
はじめに
こんにちは。ブロックチェーン推進室の鈴木です。
私の所属するブロックチェーン推進室では、企業間取引に特化したエンタープライズブロックチェーンプラットフォーム:Cordaに関して機能調査を行っております。
Cordaは世界で350社を超える金融機関、規制当局、中央銀行、業界団体、システム・インテグレーターやソフトウェアベンダーにより構成されるR3エコシステムから、エンドユーザー目線で設計・開発されています。
また、4半期に1度のバージョンアップにより機能追加がされていますが、その機能がお客様に活用できるものなのか、ドキュメントだけではわからないことも多く、ブロックチェーン推進室独自で調査を進めています。
このブログでは、そういったCordaの機能調査をした結果を機能の使い方含めて紹介していきます。
Cordaの導入方法についてはこちらのドキュメントをご参照ください。
今後以下の内容で紹介しようと思います。
(以降、バージョンアップの都度、新機能を紹介予定)
第11回目は「Corda Webアプリケーション開発について」について紹介します。
はじめに
今回の記事では、CordaのWebアプリケーション開発について紹介します。
CorDappの開発に関する資料は多くありますが、フロント実装についてはあまり見受けられないように思います。
したがって本記事では、spring bootを使ったCordaのSampleのプロジェクトを元に独自でWebアプリケーションを開発いたしましたので、
そのWebアプリケーションの紹介とフロントとCorDappをRPCで接続する方法について紹介します。
Webアプリケーションの構成
▼構成図
CordaのWebアプリケーションの作成は以下の図の赤枠の範囲になります。
ClientSoftwareはHttpRequestができる画面であればどのような形でも問題ないので本記事ではWebAPIにフォーカスして解説します。
図1:全体像
▼sampleプロジェクト
Cordaのsampleにあるものを参考にして作成します。
https://github.com/corda/samples-kotlin/tree/master/Basic/cordapp-example
したがって今回はspring bootを使った構成で紹介します。
フロントに関するディレクトリはclient配下のものすべてになります。
以下はsampleのclient配下の構成図になります。
◎ディレクトリ階層
├─clients
│ ├─build.gradle
│ │
│ └─src
│ └─main
│ ├─kotlin
│ │ └─net
│ │ └─corda
│ │ └─samples
│ │ └─example
│ │ └─server
│ │ ├─Controller.kt
│ │ ├─NodeRPCConnection.kt
│ │ └─Server.kt
│ └─resources
│ └─static
│ ├─ app.js
│ └─ index.html //表示するHTMLの画面
RPCClientについて
RPCとは
RPCとはRemote Procedure Call(リモートプロシージャコール)の略で遠隔手続き呼び出しのことを指します。
ネットワーク上の別のサーバのプログラムを呼び出し実行させる手法です。
RPCClient
RPCClientはRPCを実行するクライアントであり、指定したサーバに接続し、様々なタスクを実行できます。
つまり、RPCClientを使ってCordaノードのFlowを実行したり、vaultを参照したりすることができます。
CordaではRPCClientは、JVM互換の言語で作成する必要がありますが、Cordaには標準で以下の2種類のRPCClientが用意されています。
そのため自分で作成する必要はありません。
◎CordaRPCClient
「CordaRPCOps」リモートインターフェースを介してノードと対話をする場合に使用します。
このリモートインターフェースを通して、vaultからstateを抽出したり、Flowを実行するなどのRPC操作ができます。
他のRPC操作については以下を参照してください。
https://docs.r3.com/en/platform/corda/4.8/open-source/api-rpc.html
◎MultiRPCClient
Corda4.6から新しく追加されたモジュールの一つで、従来の「CordaRPCOps」を含む、Cordaが提供する他のリモートインターフェースを使用してノードと対話する場合に使用します。
MultiRPCClientとリモートインターフェースは1対1の関係なので使用するリモートインターフェースの数だけ、MultiRPCClientを作成する必要があります。
2022年3月現在、MultiRPCClientが利用できるリモートインターフェースは以下の通りです。
- CordaRPCOps
vaultからstateの抽出やFlowの実行などの基本的なRPC操作ができます。 - AuditDataRPCOps
RPCアクティビティのログを監査します。 - FlowRPCOps
FlowHospitalのFlowを再試行したり、Flowを停止したりできます。 - NodeFlowStatusRpcOps
FlowHospitalによって現在監視されているFlowのステータスを表示します。 - NodeHealthCheckRpcOps
ノードの死活監視の他、メモリ使用量などに関するレポートを取得できます。 - NotaryQueryRpcOps
特定のStateがすでに使用されているかNotaryに確認します。
注意点として「CordaRPCOps」以外のリモートインターフェースはCorda Enterprise版の機能のためOSSでは使用できません。
本記事ではCordaRPCClientでの実装を紹介しています。
設定手順
今回、WebアプリケーションとCorDappを作成したので起動から画面表示まで紹介します。
ここではフロントアプリからCorDappに接続する際の設定方法を紹介します。
※独自で作成したアプリのため、gradleタスクやRPCのポートなど上記のsampleプロジェクトとは一部異なります。
▼build.gradleの設定
build.gradle(一部省略)
dependencies { // Corda dependencies. compile "$corda_release_group:corda-rpc:$corda_release_version" compile "net.corda:corda-jackson:$corda_release_version" // CorDapp dependencies. compile project(":contracts") compile project(":workflows") // Spring boot. compile("org.springframework.boot:spring-boot-starter-websocket:$spring_boot_version") { exclude group: "org.springframework.boot", module: "spring-boot-starter-logging" } compile "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}" compile "org.apache.logging.log4j:log4j-web:${log4j_version}" compile "org.slf4j:jul-to-slf4j:$slf4j_version" } springBoot { mainClassName = "net.corda.samples.example.webserver.ServerKt" } /* This task will start the springboot server that connects to your node (via RPC connection). All of the http requests * are in the Controller file. You can leave the Server.kt and NodeRPCConnection.kt file untouched for your use. */ task runTemplateServerA(type: JavaExec, dependsOn: assemble) { classpath = sourceSets.main.runtimeClasspath main = 'net.corda.samples.example.webserver.ServerKt' args '--server.port=10050', '--config.rpc.host=localhost', '--config.rpc.port=10006', '--config.rpc.username=user1', '--config.rpc.password=test' }
- dependencies
ここで以下の依存関係を記述します。- CordaのRPCのモジュール
- jacksonのモジュール
- 対象のCorDapp
- spring boot
- log4j
- task runTemplateServerA
ここではWebサーバの起動タスクを設定します。
Webアプリケーションを起動するためのメインクラスとRPCClientに渡すパラメータを記述します。
gradlew runTemplateServerAを実行することで一つのノードのWebサーバが起動します。
そのためノードごとにWebサーバを立てる必要があります。
図2:ノードとクライアントの関係図
▼node.confの設定
node.conf(一部省略)
rpcSettings { address="localhost:10006" adminAddress="localhost:10007" } security { authService { dataSource { type=INMEMORY users=[ { user=user1 password=test permissions=[ ALL //全てのRPC操作を許可 ] } ] } } }
- rpcSetting
ここではRPCのサーバとバインディングするホストとポートを設定します。 - security
RPC操作でのアクセスの設定を行います。
usersの中でユーザ名やパスワード、さらにその中のpermissionsにどのRPC操作を許可するかなどの設定をします。
▽RPC操作の許可設定- 全てのRPC操作を許可
(例:ALL) - 特定のFlowのみの実行許可
StartFlow.という構文で記述します。
(例:”StartFlow.net.corda.flows.ExampleFlow1″) - 特定のRPC操作のみの実行許可
InvokeRpc.という構文で記述します。
(例:”InvokeRpc.nodeInfo”)
- 全てのRPC操作を許可
実装方法
実装方法ではフロントアプリについて、主要な点を紹介します。
CorDppsの実装については割愛いたしますが概要のみ紹介します。
▼CorDapp
以下の画像は独自で作成したCorDappの全体像になります。
図3:作成したCorDappの全体像
Token SDKとアカウントライブラリを使ったアカウント間でトークンのやり取りを行うCorDappです。
◎登場人物
- BankA・・・ノード1
- Alice・・・BankAに属するアカウント1
- Bob・・・BankAに属するアカウント2
- BankB・・・ノード2
- Carol・・・BankBに属するアカウント1
- Dave・・・BankBに属するアカウント2
▼フロントアプリ
NodeRPCConnection.kt
RPCClientの初期化を行います。
起動時に受け取ったパラメータを使ってRPCClientを生成し、ノードと接続します。
起動時のパラメータは、上記のbuild.gradleに記載した「runTemplateServerA」の値を参照します。
このパラメータとnode.confの「rpcSettingsに記述のaddress」と「securityに記述のusersのユーザ名とパスワード」は一致させる必要があります。
private const val CORDA_USER_NAME = "config.rpc.username" private const val CORDA_USER_PASSWORD = "config.rpc.password" private const val CORDA_NODE_HOST = "config.rpc.host" private const val CORDA_RPC_PORT = "config.rpc.port" @Component open class NodeRPCConnection( @Value("${$CORDA_NODE_HOST}") private val host: String, @Value("${$CORDA_USER_NAME}") private val username: String, @Value("${$CORDA_USER_PASSWORD}") private val password: String, @Value("${$CORDA_RPC_PORT}") private val rpcPort: Int): AutoCloseable { lateinit var rpcConnection: CordaRPCConnection private set lateinit var proxy: CordaRPCOps private set @PostConstruct fun initialiseNodeRPCConnection() { val rpcAddress = NetworkHostAndPort(host, rpcPort) val rpcClient = CordaRPCClient(rpcAddress) val rpcConnection = rpcClient.start(username, password) proxy = rpcConnection.proxy } @PreDestroy override fun close() { rpcConnection.notifyServerAndClose() } }
Controller.kt
ここでは各Httpリクエストに対してどの処理を行うかをコーデイングします。
このControllerのフィールドに先ほど定義したNodeRPCConnectionクラスを指定し、spring bootによりDI(Dependency Injection)されます。
このNodeRPCConnectionのプロパティのリモートインターフェースを使ってRPC操作を行います。
下記コードにおけるproxy.startTrackedFlowはFlowを実行するRPC操作です。
** * Define your API endpoints here. */ @RestController @RequestMapping("/") // The paths for HTTP requests are relative to this base path. class UserController(rpc: NodeRPCConnection) { companion object { private val logger = LoggerFactory.getLogger(RestController::class.java) } private val proxy = rpc.proxy @PutMapping(value = [ "issueTokens" ], produces = [ TEXT_PLAIN_VALUE ]) fun issueToken(@RequestParam(value = "accountName") accountName: String, @RequestParam(value = "currency") currency: String, @RequestParam(value = "amount") amount: Long): ResponseEntity<String> { try { val accountName = accountName val currency = currency val amount = amount val result = proxy.startTrackedFlow(::IssueTokensFlow, accountName, currency, amount).returnValue.get() // Return the response. return ResponseEntity .status(HttpStatus.CREATED) .body(result) } catch (e: Exception) { return ResponseEntity .status(HttpStatus.BAD_REQUEST) .body(e.message) } } }
アプリの起動と実行手順
前述の独自で作成したCorDappとフロントアプリをローカル環境で実行します。 今回はトークンの発行を画面を使って紹介します。
起動手順
- nodeの起動
Webサーバの起動には先にノードを起動しておく必要があります。
sampleのプロジェクトと同様にrunnodes.batでノードを起動します。 - Webサーバの起動
BankA用のWebサーバを起動します。
build.gradleに記述したタスクを実行します。gradlew runTemplateServerA
次のように表示されていれば正しく起動できています。今回はローカル環境ですのでlocalhostと赤枠で囲ったポート番号へアクセスします。
図4:Webサーバ起動確認
実行手順
- Web画面表示
ブラウザからアクセスすると画面が表示されます。
画面が表示されない場合はノードのRPC設定に誤りがある可能性があるのでWebサーバの起動パラメータとnode.confのrpc設定が一致しているか確認してください。
図5:初期画面 - トークンの発行
発行ボタンを押下するとController.ktのissueTokenが呼び出されます。
図6:トークンの発行画面
このissueTokenのレスポンスとして以下の画面が返されます。
ここで発行した分のトークンが表示されます。
図7:トークンの発行後の画面
おわりに
今回はspring bootを使ったCordaのWebアプリケーションの紹介とフロントとCorDappをRPCで接続する方法について紹介しました。
spring bootを使った構築はCordaのドキュメントにも構築方法が記載されているので、これらを使ってWebアプリケーションを作成することがおすすめです。
本記事がCordaのWebアプリケーション開発の参考になれば幸いです。