【Corda4.5】SendAllを使って、効率よく他ノードへメッセージを送ろう


はじめに

最近、またCordaに浸かってます。
どーも、のぶこふです。

今回は、Corda4.5の新機能の目玉?でもある「SendAll」を紹介しようと思います。

SendAllとは?

Corda4.5で新規導入されたAPIです。
SendAllMapも併せて新規導入されていますが、今回は省略させていただきます。

これまでは、Send APIを使用して、各カウンターパーティに対して、一度だけメッセージを送っていました。
SendAllを使用することで、同様の処理を、効率よく実施することが可能になります。

Send/ReceiveやSendAll/ReceiveAllなど、メッセージの送受信の概略はコチラ

APIの詳細はドキュメントを参照ください
https://api.corda.net/api/corda-os/4.5/html/api/kotlin/corda/net.corda.core.flows/-flow-logic/send-all.html

ソースコード

[PR]今回も、サンプルのソースコードを用意してあります。
サクッと試してみたい方は、使ってみてください。

SendAllを使用するFlowと、Sendを使用するFlowの両者を用意してあるので、比較が行いやすいかと思います。

▼Github
※最新版ではTxを発行出来るようにしていますが、下記シナリオではTxは発行していません
https://github.com/nobkovskii/corda_sendall_sample

解説

基本的には、ソースコードをご覧いただければ分かるかと思いますが、簡単に解説を行います。
※解説に不要な箇所は削除してあります

  • Sessionを張ります。(①)
    • 今回はサンプルのため、宛先を固定しています。
  • SessionのSetとpayload(メッセージ)を引数に指定します。(②)
  • 受信側(Responder)は、payload(メッセージ)と同じ型を受信します。(③)
class Initiator(private val data: String) : FlowLogic<Unit>() {
    @Suspendable
    override fun call() {
        // String -> Party
        val b = toParty("O=PartyB,L=New York,C=US")
        val c = toParty("O=PartyC,L=New York,C=US")

        // sessionを張る
        // サンプルのため、宛先は固定
        //  --------------------------------- ①
        val sessionB = initiateFlow(b)
        val sessionC = initiateFlow(c)

        // sendAll(payload: Any, sessions: Set<FlowSession>, maySkipCheckpoint: Boolean = false): Unit
        //  --------------------------------- ②
        sendAll(data, setOf(sessionB, sessionC)) 
    }

    private fun toParty(name: String): Party {
        println(name)
        val x500Name = CordaX500Name.parse(name)
        return serviceHub.networkMapCache.getPeerByLegalName(x500Name) as Party
    }
}


@InitiatedBy(Initiator::class)
class Responder(val counterPartySession: FlowSession) : FlowLogic<Unit>() {
    @Suspendable
    override fun call() {
        // receiveAll(receiveType: Class<R>, sessions: List<FlowSession>, maySkipCheckpoint: Boolean = false): List<UntrustworthyData<R>>
        //  --------------------------------- ③
        val list = receiveAll(String::class.java, listOf(counterPartySession))
        list[0].unwrap { data -> println(data) }
    }
}

実行結果

続いて、実行結果です。
【注意】:今回のシナリオは、単にメッセージを送っているだけなので、本結果=TPSではありません。

▼実行環境

概要 説明
Corda OSS 4.5
PC Windows10 64bit(core i7,8GB)
Node A~E+Notaryの計6台。

▼シナリオ

PartyAから、他全ノードに対してメッセージを送る。
SendAllとSendをそれぞれ10回実行する。

▼実行結果

平均でも、瞬間風速でもSendAllのほうが優秀な結果が出ました。
※単位はms

↓のGifは、実際に動かしてみたアニメーションです。
裏で色々と起動していたため、処理時間が上記よりもかかっていますが、SendAllのほうが一瞬で各ノードへ送信しているように見えるのではないでしょうか。

配置
PartyA PartyD
PartyB PartyE
PartyC Notary

おわりに

今回はCorda4.5で新規導入された「FlowLogic.SendAll」を紹介しました。
Corda OSSではマルチスレッドでの動作が行えないので、こういったパフォーマンス向上系のAPIは嬉しいですね。

CordaのTPSにおいて、ボトルネックとなっているのは署名を集める(確認する)処理なので、今後に期待です。
※OSSのCollectSignatureFlowではsendを使用していた認識で、sendAllの使用箇所はほぼ無い

Githubにあげてあるソースコードには、sendとTx発行の両方が実行出来るようになっていますので、参考にしてみてください。

今回はここまでです。
ありがとうございました。