Reference stateの可能性 ~課題解決編~

## 前書き
今回Reference state(以下Ref.state)に関する可能性を追求する調査を行いました。この調査により複数のユースケースで生じていた問題を解決することができます。本記事はCorda tech meetup 冬の陣(2023年2月22日開催)における発表の中で割愛した実際のテストコードを用いた結果の提示や詳しい説明の補足部分などを行う目的で作成されました。また、[**ユースケース紹介編**](https://qiita.com/ShotaIMO/items/b94dfb226d6196bd4308)と本記事の<font color="RED">**課題解決編**</font>の２つに分かれています。
Corda tech meetup 冬の陣のイベントレポートは[**こちら**](https://medium.com/corda-japan/corda-tech-meetup%E5%86%AC%E3%81%AE%E9%99%A3-%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%83%AC%E3%83%9D%E3%83%BC%E3%83%88-2023%E5%B9%B42%E6%9C%88%E9%96%8B%E5%82%AC-93ef6b20ffc7)になります。

## 自己紹介
SBI R3 Japan株式会社にインターンでお邪魔している大学３年の井本翔太と申します。大学進学以来ブロックチェーンに興味を持ち始め、その仕組みや活用方法を学ぶ過程でCordaと出会いました。現在は、Cordaの機能調査やデモアプリケーション修正といったエンジニア業務やプレゼン資料作成といったビジネスサイドの仕事までありがたいことに様々な業務を経験させていただいております。

## 3章：Reference stateを用いた解決策
さて、**ユースケース紹介編**で述べた課題である<font color="RED">**"消費状況を確認したいstateを問い合わせの際に消費することなく検証したい"**</font>を**Reference state(略称：Ref.state)** を用いて解決する手法を提案したいと思います。
Ref.stateについて詳しく知りたい方は[**Cordaのドキュメント**](https://docs.r3.com/en/tools/cdl/ledger-evolution-view/reference-states.html)または[**R3の記事**](https://training.corda.net/corda-advanced-concepts/reference-states/)をご覧ください。後者の記事の方が詳しく書かれています。簡単にまとめますと、Ref.stateはtxの参照情報を表し、通常のInputStateまたはOutputStateをaddReferenceState関数を利用することでRef.stateとして扱うことができます。また最大の特徴として<font color="RED">**Ref.stateは通常のstateと異なりNotaryで消費されません。**</font>

このNotaryでは消費されない特性を生かして、**消費状況を確認したいstateをRef.stateとしてtxに含めNotaryに問い合わせる手法**を提案したいと思います。この手法により従来手法で問題となっていた未消費でも消費済みになってしまう問題を解決することができます。消費済みだった場合はエラーとしてハッシュ値が通知されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2678414/504a30a7-5ce9-6f05-a27c-e409c33c6106.png)


## 4章：調査について
本章では、2章で提案した方法の実現性を調査するための調査を行いました。調査項目としては以下の2つになります。
- **調査1: Ref.stateのみのtxは作成可能か？**
- **調査2: Notaryが検知した複数のRef.stateはログにて全て検知できるか？**
※調査のために作成したコードは[**こちら**](https://github.com/ShotaIMO/possibilityOfReference.git)になります。

:::note
調査では、Corda trainingのIOU issue(発行)の処理にRef.stateを追加する処理を書き加えました。AddressStateという住所を表すstateをRef.stateとして扱い、PublishFlowでAddressStateの発行、MoveFlowでAddressStateの更新を行います。前述のStateやFlowについて詳しく知りたい方は[**こちらの記事**](https://qiita.com/ShotaIMO/items/c9a7fbac0ee2c33196cf)をご覧ください。
:::
### 調査1: Ref.stateのみのtxは作成可能か？
#### 背景
2章で消費状況を確認したいstateをRef.stateとしてtxに含めNotaryに問い合わせる手法を提案しました。そこで、txにはRef.state以外のコンポーネント(InputStateやOutputState)は必要なのかという疑問が浮かびました。
#### 方法
Ref.stateのみのtxを作成し、Notaryに問い合わせ、挙動を確認しました。
**1. PublishFlowを実行し、AddressStateを発行します。**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2678414/57d85e41-1196-f950-0b20-94f20fd8460b.png)

**2. コンポーネントはRef.stateのみなので、通常のstateであるIOU stateに関する処理やコマンドはコメントアウト後、IOUIssueFlowを実行し、AddressStateをRef.stateとして含めます。**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2678414/34ff8390-44d8-3045-c01b-bb6a3010357b.png)
上図からIOUIssueFlowが停止していることが分かると思います。

**3. IOUIssueFlowを実行したエンティティのログを見ます。**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2678414/10fbf0f0-ac80-7e0e-7443-32aa5849fc39.png)
今回はParticipant Aで実行したためParticipant Aのログを開くと、**"A transaction must contain at least one input or output state"** というエラーが出力されています。簡潔に説明しますと、<font color="RED">**txには少なくとも1つのInputStateまたはOutputStateが必要**</font>になります。このエラーは以下の[**WireTransaction.kt**](https://github.com/corda/corda/blob/release/os/4.6/core/src/main/kotlin/net/corda/core/transactions/WireTransaction.kt#L73)というファイルに示されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2678414/e72ccd9a-071b-8c0f-0023-e586fe7af84f.png)
#### 結果
Ref.stateのみのtxは作成できず、少なくとも１つのInputStateまたはOutputStateが必要になります。なおこのエラーはNotaryに渡す前である自己検証の段階で検知されました。
#### 実装検討
Ref.stateのみのtxは作成不可能であるため、以下のようにOutputState(今回はIOU state)に紐づけることにしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2678414/aacfcd92-2f9a-d8a8-af4e-9b4e95f06d40.png)
#### テスト
**1. 先ほど同様、PublishFlowにてAddressStateを発行します。赤線のtxhashを覚えておいてください。**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2678414/7fd6e556-cd8e-c9a4-1614-c9c351b44204.png)
**2. 続いて、IOUIssueFlow(コマンド等を含むIOU stateに関する処理をコメントアウト)を実行し、AddressStateをRef.stateとして含めます。赤線のSignedTransactionIdは次のステップで使用します。**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2678414/6c266361-3afc-4de6-1541-f37edd355d34.png)
**3. 先ほどのSignedTransactionIdを元にRef.stateとしてAddressStateが含まれているか確認します。**
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f323637383431342f39303932623862392d653163612d306530612d316338352d6635363032393335333139312e706e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2678414/338dfd3d-208f-4d76-5c12-d508b10c0ac5.png)

上図のreferenceという項目に、**428~**というtxhashが含まれています。これは**ステップ1で作成したAddressStateのtxhashと一致することが分かります。** したがって、先ほどのモデル図を元に作成したtxでNotaryに問い合わせることが可能になりました。

### 調査2: Notaryが検知した複数のRef.stateはログにて全て検知できるか？
:::note
Notaryが検知したRef.stateというのは消費済みのstateをRef.stateとした場合です。AddressStateをPublish(発行)後、Move(更新)を行うと、PublishしたAddressStateは消費済みになります。今回はこのPublishした消費済みのAddressStateをRef.stateとしてtxに複数含めたいと思います。
:::
#### 背景
調査1ではRef.stateの数が1つでしたが、実際には消費状況を確認したい複数のstateをRef.stateとして問い合わせた方が効率がいいのは明らかです。したがって、複数のRef.stateを含めてもエラーとなるRef.stateが全て検知できるか調査しました。
#### 方法
消費済みのstateをRef.stateとしてtxに10個含め、Notaryに問い合わせ、挙動を確認しました。
**1. PublishFlowを実行し、Ref.stateとするAddressStateを10個発行します。**

:::note
PublishFlowとMoveFlowは1つのStateに対する動作になります。Ref.stateとしたいStateを10個生成・更新したい場合は、PublishFlowとMoveFlowをそれぞれ10回実行します。
:::
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2678414/b3755f7c-77f2-86c2-56b9-5789c9060ea3.png)

上図の赤線がハッシュ値になります。この時、linearIdの399b62ca-8c0b-484a-8a84-562f6dfb005dを記録してください。また、AC5~から始まるハッシュ値を覚えておいてください。

**2. 先ほど記録したlinearIdをパラメータに指定してMoveFlowを実行し、AddressStateを更新します。**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2678414/85aebd98-c02d-1392-4c6c-cbad2f2cdea9.png)

**3. AddressStateを10個発行し、更新した後、IOUIssueFlowを実行し、AddressStateをRef.stateとして含めます。**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2678414/aa1525f6-0918-ba13-3773-f13d5be031ac.png)
上図からFlowが途中で停止していることが分かると思います。

**4. IOUIssueFlowを実行したエンティティのログを見る**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2678414/dca4c86d-8075-00a4-3021-90024b0ba8e8.png)
今回はParticipant Aで実行したためParticipant Aのログを開くと、何やらエラーが出ていることが分かります。また、**一番上のハッシュ値(AC5~)を見ていただくと最初にPublishしたAddressStateのハッシュ値と一致します。** 文量の都合上添付しませんでしたが、その他ハッシュ値もPublishしたAddressStateと一致します。エラーの文言としては、**"One or more input states or referenced states have already been used as input states in other transactions."**　と出力されています。このエラーは以下の[**NotaryError.kt**](https://github.com/corda/corda/blob/cd8cd60a0fd943198a87d266bd15b807eeaa20ba/core/src/main/kotlin/net/corda/core/flows/NotaryError.kt#L37)というファイルに示されています。簡潔に説明しますと<font color="RED">**消費済みのStateが含まれている**</font>と指摘されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2678414/ccd3b3ff-ef6e-79e5-e3a1-c22d39f3ff25.png)
<font color="RED">**上図から表示制限が５個に指定されているため、Notaryが検知したRef.stateは5つまでしか表示されません。**</font><font color="RED">赤枠</font>で囲った部分が検知されたRef.stateになりますが確かに10個含めたにも関わらず5個までしか出力されていません。

#### 結果
10個の消費済みのstateをRef.stateとして含め、Notaryに問い合わせたところ5個までしか確認できませんでした。

### 解決方法
実装はしていませんが、表示制限をかいくぐって全てのRef.stateを表示させる方法を考えました。先ほども述べた通り表示制限は5個なので、下図に示すよう、txに含めるRef.stateの数を最大５個とし、小分けにしてNotaryに問い合わせを行います。こうする事で理論上はNotaryに検知された全てのRef.stateを確認することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2678414/f49a6a8a-ba86-90d0-51e3-7e67b9c99d09.png)

## 5章：まとめ
今回は3つのユースケースに共通していた<font color="RED">**"特定のstateの消費状況をNotaryに問い合わせたい要望"**</font>をRef.stateを用いた手法により解決しました。提案手法の実現性を考えるために行った2つの調査の結果を以下に示します。
- **調査1: Ref.stateのみのtxは作成可能か？**
    - <font color="RED">**作成不可能。最低１個以上のInputStateまたはOutputStateを含める必要あり**</font>
- **調査2: Notaryが検知した複数のRef.stateはログにて全て検知できるか？**
    - <font color="RED">**最大５個まで表示可能。全てのRef.stateを確認するため、問い合わせの処理を小分けにして繰り返す手法が現状効果的**</font>


以上の調査結果から、Ref.stateで消費状況を変化させることなくNotaryへの問い合わせが可能になりました。また、この手法を実現することで、**関連するtxを渡される条件であれば第三者が、そのtxとチェーンで繋がるtxの存在を検知可能になります。** ゆえに、<font color="RED">**プライバシーを確保しつつ、透明性が向上した**</font>と考えることができます。

## 調査で作成したコード
調査で作成したコードは私の[**githubアカウント**](https://github.com/ShotaIMO/possibilityOfReference.git)にアップロードされています。興味のある方はぜひご覧ください。またSBI R3 Japanの提供するCorda trainingのコードにRef.stateの機能を追加したので、[**そちらのgithub**](https://github.com/sbir3japan/corda-dev-traning-sbir3japan.git)も見ていただくとより理解が深まると思います。


## 終わりに
**課題解決編**は以上になります。皆様が**Ref.stateがもたらす新たな可能性**を感じていただけたら幸いです。Cordaにご興味のある方は[**SBI R3 Japan株式会社**](https://sbir3japan.co.jp/)へ直接ご連絡いただければ幸いです。ご一読ありがとうございました。