CordaにおけるReference Stateの活用方法(デモンストレーション編)

## まえがき
今回、Reference State(以下Ref.State)に関する細かな動作確認を行うため調査を行いました。
調査にあたりましてサンプルプログラムを作成しました。**[コード解説編](https://qiita.com/ShotaIMO/items/c9a7fbac0ee2c33196cf)**と**デモンストレーション編**の２部編成でお届けしたいと思います。**本記事はRef.Stateについて詳しく知りたいCordaに精通していらっしゃるエンジニアの方やセールスの方を対象としております。** Cordaについて詳しく知りたい方は **[R3公式ドキュメント](https://docs.r3.com/)** や **[株式会社digglueさんの記事](https://baasinfo.net/?p=2205#outline__2_2)** をご覧ください。また、Cordaの概念であるUTXOモデルについて知りたい方は、**[こちらの解説記事](https://medium.com/corda-japan/corda%E3%83%87%E3%83%BC%E3%82%BF%E3%83%A2%E3%83%87%E3%83%AB%E3%81%AE%E7%89%B9%E5%BE%B4-701d49f02cd)** をご覧ください。

## 自己紹介
SBI R3 Japan株式会社にインターンでお邪魔している井本翔太と申します。現在、都内の大学に通いながらエンジニアとして働かせていただいています。昨年からブロックチェーンに興味を持ち始め、その仕組みや活用方法を学ぶ過程でCordaと出会いました。私にとってCordaは社会にブロックチェーンという存在を浸透させる上で大きな役割を果たすと考えております。　　　

## 調査内容(再掲)
改めて調査内容の確認です。
**調査１：Ref.Stateをトランザクションに含め、コントラクトで検証可能か**
**調査２：あるノードで発行したRef.Stateのバックチェーンを別のノードで確認できるか**
**調査３：消費済みのRef.Stateをトランザクションに含められるか**


## 調査結果について(再掲)
調査１,２については要望を満たすことができましたが、**調査３はエラーが出力されました。**　　
調査３で出力されたエラーについては後ほど説明したいと思います。
<font color="Red">**※調査１,２と調査３では実装が異なるため、サンプルプログラムは2つ作成しました。**</font>


## サンプルプログラムについて(再掲)
サンプルプログラムはSBI R3 Japan株式会社が提供しております **[Corda trainingのコード](https://github.com/sbir3japan/corda-dev-traning-sbir3japan)**に**AddressState(住所録)をRef.Stateとして**加えました。Corda trainingで扱うプログラムはIOU(借用証書)の発行(Issue)、譲渡(Transfer)、返済(Settle)に関するプログラムになります。今回は必要最低限の機能を実装するためにRef.Stateの**実装対象をIssueのみ**に絞りました。

## デモンストレーション手順
:::note
前提条件としてデモンストレーションの実行はCordaのNode Terminal Windowで行いました。
:::
### 要望1(Node Terminal Window: <font color="Red">ParticipantA</font>で実行)
**1. PublishFlow.javaを実行して、AddressStateを発行する。**
**2. MoveFlowを実行して、AddressStateを更新する。**
**3. IOUIssueFlowを実行して、IOUを発行。この時、SignedTransactionIDを記録**
**4. トランザクションの詳細を調べるため、`run internalFindVerifiedTransaction txnId: Transaction-ID or Hash`というコマンドを実行。引数に手順3で記録したSignedTransactionIDを指定する。**
**5. referencesという項目に記載されているtxhashがMoveFlow実行後に表示されるハッシュ値と一致するか確認**
### 要望2(Node Terminal Window: <font color="Red">ParticipantB</font>と<font color="Red">ParticipantC</font>で実行)
**1. IOUTransferFlow.javaでIOUのトランザクションをParticipantBからParticipantCに渡す。**
**2. ParticipantCのNode Terminal Windowsにて`run internalFindVerifiedTransaction txnId: ~`を実行し、付随されているAddressStateのハッシュ値を確認する。**
**3. 再び`run internalFindVerifiedTransaction txnId: ~`を実行し、手順2で確認したハッシュ値を引数に指定する。InputStateに関する項目でハッシュ値を確認する。**
**4. 再び`run internalFindVerifiedTransaction txnId: ~`を実行し、手順3で確認したハッシュ値を引数に指定する。InputStateに関する項目が空白になっていれば、別ノードでAddressStateのバックチェーンが確認できた事になります。**
### 要望3(Node Terminal Window: <font color="Red">ParticipantA</font>で実行)
**1.PulishFlowを実行し、AddressStateを発行**
**2.MoveFlowを実行し、AddressStateを更新**
**3.IOUIssueFlowを実行。この時、SignedTransactionIDを記録。**
**4.`run internalFindVerifiedTransaction txnId: ~`を実行。引数には手順3で記録したSignedTransactionIDを指定**
**5.referencesという項目に記載されているtxhashがPublishしたAddressStateと一致するか確認**

## 調査結果
### 調査1: Ref.Stateをトランザクションに含め、コントラクトで検証可能か 
- **PublishFlow**
PublishFlowの実行結果です。**issuerがParticipantA**、**addressがshinjuku(新宿)** というAddressStateを発行しました。以下に実行結果を示します。
![publish.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2678414/488ea39a-2c6e-d91c-d373-dfa3e9d9fa32.png)
<font color="Red">**ref=8C7EF4～が発行したAddressStateのハッシュ値**</font>になります。
- **MoveFlow**
MoveFlowの実行結果になります。**新しいaddressをroppongi(六本木)** としAddressStateを更新しました。以下に実行結果を示します。
![move.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2678414/03cf5424-9837-3b3d-5a8e-f21727de0b0b.png)
<font color="Red">**ref=8169C4～が更新したAddressStateのハッシュ値**</font>になります。
- **IOUIssueFlow**
IOUIssueFlowの実行結果になります。
![IOUIssue.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2678414/1f52af4a-47cd-a47d-15ba-698ebfae858a.png)
**※SignedTransactionID=081209B～は次の手順で使用するため必ず記録します。**
- **コマンド**
続いて、AddressStateがIOUIssueのトランザクションに含まれている事を確認します。確認には
`run internalFindVerifiedTransaction txnId: ~`というコマンドを使用します。**この時、LinearIdを調査2で使用するため記録します。** 以下に実行結果を示します。※添付図は一部カットしています。
![IOU_internalFindVerified.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2678414/7560fbc4-afcc-2c63-a364-1f0e845a3e64.png)
コマンドの引数は先ほど記録したIOUIssueのSignedTransactionID=081209B～です。**<font color="Red">「references:」という項目に注目するとMoveしたAddressStateのハッシュ値(8169C4~)と一致</font>** することが分かります。したがって、**<font color="Red">Ref.State(AddressState)はトランザクションに含めることができると判明しました。</font>**
### 調査2: あるノードで発行したRef.Stateのバックチェーンを別のノードで確認できるか
- **IOUTransferFlow**
IOUTransferFlowの実行結果になります。引数にはLinearIdが必要になるため、調査1でトランザクションの詳細を調べた時にLinearIdを記録する必要があります。ここでは、IOUIssueのトランザクションをParticipantBからParticipantCへ渡します。
![IOUTransfer_from_participantB.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2678414/f7a6834f-bd1e-d19b-0113-730491cda425.png)
SignedTransactionId=870F57～は必ず記録します。
- **コマンド**
続いて、ParticipantCでAddressStateのバックチェーンをトレースします。先ほど記録したSignedTransactionIdを引数に指定し、`run internalFindVerifiedTransaction txnId: ~`を実行します。以下に結果を示します。※添付図は一部カットしています。
![internalFind_1_participantC.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2678414/9c344e1d-6a26-c78c-c6e9-2ad42cf5c706.png)
「referencese:」という項目からAddressState(addressはroppongi)のハッシュ値を確認します。そして、`run　internalFindVerifiedTransaction txnId: `を実行します。以下に結果を示します。※添付図は一部カットしています。
![internalFind_2_partcipantC.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2678414/fafb4ab3-d3d0-cfc6-a89f-b9fac04241a6.png)
赤枠からaddressがroppongiのAddressStateはtxhash=8C7EF4～というAddressState(addressはshinjuku)をinputStateとして使用している事が分かります。再び同様に、`run internalFindVerifiedTransaction txnId: ~`を実行します。※添付図は一部カットしています。
![internalFind_end_participantC.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2678414/d655e1e2-2e8f-e4b2-6120-4d8643d930ce.png)
赤枠からinputの項目が空であることが分かります。**<font color="Red">したがって、PublishしたAddressStateまでトレースできたことを意味します。</font>**
### 調査3: 消費済みのRef.Stateをトランザクションに含められるか
基本的な手順は調査1と同様です。
- **PublishFlow**
最初にsuginami(杉並区)のAddressStateを発行しました。赤色の下線部がハッシュ値です。
![3_move_hash.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2678414/873c7f7b-6ea5-80ec-652d-61fad2165e05.png)

- **MoveFlow**
次にAddressStateをsuginamiからnakano(中野区)に更新しました。赤色の下線部がハッシュ値です。
![3_publish_hash.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2678414/1bd06ae4-1852-69c4-6391-4e409754f72b.png)


- **IOUIssueFlow**
**コード解説編** にて、このIOUIssueFlowは1つ前のAddressStateを含める処理が記述されています事を確認しました。実行結果を以下に示します。![3_iouIssue.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2678414/8801b61a-e71a-d0f0-bf22-c1cbf42667b3.png)
previousHashという項目と先ほどのPublishFlowの実行結果からvaultQueryを用いた処理で1つ前のAddressStateが発見できている事が分かります。**<font color="Red">しかし、赤色の下線部からNotaryの処理で止まっている事が確認できます。</font>**
- **ParticipantAのログ**
先ほどNotaryの処理で止まっていたためParticipantAのログを確認します。すると以下のエラーメッセージが出力されていました。
![調査3_error_message.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2678414/0a4aa7c2-7f17-467f-a564-af13d918ce05.png)
事項でエラーの発生原因について解説したいと思います。

### 調査3のエラーについて
先ほどエラーメッセージを直訳すると「一つもしくは複数のStateまたはReference Stateは他のトランザクションの中で既にインプットとして使われた」という意味です。このエラーの原因として、**<font color="Red">Moveする段階で最初にPublishしたAddressState(=1つ前のRef.State)がInputStateとして使われた事をNotaryが記録する事</font>** が考えられます。詳しい説明のためにCDLを再掲します。
![CDL.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2678414/521c93f2-0fd1-96b1-2942-7edf34f94104.png)
上記のCDLからMoveFlowを実行する際には、PublishしたAddressStateがInputStateとして使われていることが分かります。**調査3ならsuginamiのAddressStateを消費して、nakanoのAddressStateを作成しています。** ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2678414/8f3affab-b894-9dda-5a63-8b7456257dab.png)
suginamiのAddressStateが消費済みという事実はNotaryに記録されます。したがって、**<font color="Red">IOUIssueのトランザクションにsuginamiのAddressState(1つ前のAddressState)を含めようとするとNotaryはNGを出します。</font>**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2678414/63709f50-404d-a217-35cb-7c0d252f31cd.png)
調査3が実現不可能な理由についてご理解いただけましたでしょうか?

### サンプルプログラムのURL
調査1,2のサンプルプログラムです。
[**https://github.com/ShotaIMO/investigation-of-ReferenceState**](https://github.com/ShotaIMO/investigation-of-ReferenceState)
調査3のサンプルプログラムです。
[**https://github.com/ShotaIMO/investigation-of-Previous-ReferenceState**](https://github.com/ShotaIMO/investigation-of-Previous-ReferenceState)

サンプルプログラム作成にあたって、ご協力いただいたSBI R3 Japan株式会社のエンジニアチームの皆様
ありがとうございました。
### 終わりに
以上が調査結果の報告になります。皆様のRef.Stateに対する理解が深まれば幸いです。Cordaにご興味のある方はSBI R3 Japan株式会社へ直接ご連絡いただければ幸いです。Ref.StateRに関する新たな調査も始動しておりますので、また記事にしたいと思います。ご一読ありがとうございました。