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

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

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

## SendAllとは？
[Corda4.5で新規導入されたAPI](https://support.sbir3japan.co.jp/hc/ja/articles/360050810813-Corda-4-5%E3%83%AA%E3%83%AA%E3%83%BC%E3%82%B9%E3%83%8E%E3%83%BC%E3%83%88#%E6%96%B0%E3%81%97%E3%81%84flowapi)です。
SendAllMapも併せて新規導入されていますが、今回は省略させていただきます。

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

Send/ReceiveやSendAll/ReceiveAllなど、メッセージの送受信の概略は[コチラ](https://docs.corda.net/docs/corda-os/4.5/api-flows.html#communication-between-parties)。

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（メッセージ）と同じ型を受信します。（③）



```kotlin
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
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306608/d91d29cc-3d31-403c-fc34-5d6f662efc16.png)

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

||配置|
|---|---|
|PartyA|PartyD|
|PartyB|PartyE|
|PartyC|Notary|

![SendAll_Send_demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306608/2c931bab-b612-16c9-86b8-81772341dfb8.gif)


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

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

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

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