分散型台帳 Scalar DLT のエミュレータを使って資産管理アプリケーションを触ってみた

今回は、[前回](https://qiita.com/DENEN_YOSHIDA/items/0cafa17922ac1904ad51/)解説した資産管理アプリケーションを用いて Scalar DLT のエミュレータを使ってみます。
実行環境は今までと同じくmacOS 10.14.4で作業を行います。

# エミュレータの入手と実行
まずはエミュレータを入手しましょう。
以下のコマンドで取得します。

```sh
$ git clone https://github.com/scalar-labs/scalardl-tools
```

クローンしてきたらビルドを行います。

```sh
$ cd scalardl-tools/emulator
$ ./gradlew installDist
```

ビルドしたら早速実行してみましょう。

```sh
$ ./build/install/emulator/bin/emulator
Scalar DL Emulator
Type 'help' for more information
scalar>
```

入力待ちになれば起動完了です。
サクッと起動しますね！

# 資産管理アプリケーションの入手

続いて資産管理アプリケーションを入手しましょう。
ソースの場所は前回ご紹介していますので、早速クローンしてきましょう。

```sh
$ git clone https://github.com/indetail-blockchain/getting-started-with-scalardl.git
```

なお、２つのプロジェクトを利用するのでディレクトリ構成は以下の形にしています。

> git/
　├ scalardl-tools/
　└ getting-started-with-scalardl/

# 資産管理アプリケーションのビルド
前回の記事でスマートコントラクトが６つ用意されていると紹介しました。
そのソースが実際に配置されているのは以下の場所になります。

```sh
$ ls -l getting-started-with-scalardl/src/main/java/com/scalar/am/contract
AddAssetContract.java
AddTypeContract.java
AssetHistoryContract.java
ListContract.java
ListTypeContract.java
StatusChangeContract.java
```

ではこちらをビルドしていきましょう。
ビルドはエミュレータの `src/main/java` 以下にソースを配置する事で可能です。
※スマートコントラクト以外のファイルを置いてしまうとビルドが失敗するので、余計なファイルはコピー後に削除しています。

```sh
$ cp -r getting-started-with-scalardl/src/main/java/com scalardl-tools/emulator/src/main/java/
$ rm -rf scalardl-tools/emulator/src/main/java/com/scalar/am/command
$ rm -f scalardl-tools/emulator/src/main/java/com/scalar/am/AssetManager.java
$ cd scalardl-tools/emulator/
$ ./gradlew build
```

無事ビルドされたら build ディレクトリを覗いてみましょう。

```sh
$ ls -l build/classes/java/main/com/scalar/am/contract
AddAssetContract.class
AddTypeContract.class
AssetHistoryContract.class
ListContract.class
ListTypeContract.class
StatusChangeContract.class
```

class ファイルが出来ていますね。

# スマートコントラクトの登録と実行
ではいよいよスマートコントラクトの実行を行っていきます。
まずはエミュレータを起動しましょう。

```sh
$ cd scalardl-tools/emulator
$ ./build/install/emulator/bin/emulator
Scalar DL Emulator
Type 'help' for more information
scalar>
```

まずはコントラクトを登録していきます。
全部で６つ登録します。

```sh
scalar> register add-type com.scalar.am.contract.AddTypeContract ../../getting-started-with-scalardl/build/com/scalar/am/contract/AddTypeContract.class {"holderId": "Admin"}
Contract 'add-type' successfully registered

scalar> register add-asset com.scalar.am.contract.AddAssetContract ../../getting-started-with-scalardl/build/com/scalar/am/contract/AddAssetContract.class {"holderId": "Admin"}
Contract 'add-asset' successfully registered

scalar> register list-type com.scalar.am.contract.ListTypeContract ../../getting-started-with-scalardl/build/com/scalar/am/contract/ListTypeContract.class {"holderId": "Admin"}
Contract 'list-type' successfully registered

scalar> register list-asset com.scalar.am.contract.ListContract ../../getting-started-with-scalardl/build/com/scalar/am/contract/ListContract.class {"holderId": "Admin"}
Contract 'list-asset' successfully registered

scalar> register status-change com.scalar.am.contract.StatusChangeContract ../../getting-started-with-scalardl/build/com/scalar/am/contract/StatusChangeContract.class {"holderId": "Admin"}
Contract 'status-change' successfully registered

scalar> register asset-history com.scalar.am.contract.AssetHistoryContract ../../getting-started-with-scalardl/build/com/scalar/am/contract/AssetHistoryContract.class {"holderId": "Admin"}
Contract 'asset-history' successfully registered
```

登録の際の `register` コマンドの仕様は以下の通りです。

```sh
register [実行時に使う名前] [Javaのクラス名] [クラスファイルのパス] [初期パラメータ]
```

スマートコントラクトの登録時に初期パラメータが渡せるのですが、この資産管理アプリケーションでは `holderId` を指定する必要があります。
この `holderId` は登録時のみ渡され、変更されない値になります。
これをスマートコントラクト内で利用・チェックすることで、**自分が登録した資産情報を他人が更新することを防ぐ**ことが可能になっています。
簡単なイメージとしては以下の感じです。
![auth.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427707/62a1fea9-9229-1055-8e34-a9165b154049.jpeg)
Scalar DLT ではアセット（資産）に対する参照・書き換えの権限コントロールは行っていないので、こういった形で予期せぬデータの更新を防ぐことが可能です。

それではいよいよ実行していきましょう。
なお、実行には `execute` を使います。

```sh
execute [スマートコントラクトの登録名] [パラメータ]
```

まずは資産の種類を登録します。

```sh
scalar> execute add-type {"name": "Tablet"}

{
   "result": "success",
   "message": "type Tablet put completed."
}
scalar> execute add-type {"name": "SmartPhone"}

{
   "result": "success",
   "message": "type SmartPhone put completed."
}
```

Tablet と SmartPhone という種類を追加しました。
次は本当に登録されているか確認しましょう。

```sh
scalar> execute list-type {}

{
   "result": "success",
   "message": "get list completed.",
   "types": [
       {
           "type": "SmartPhone",
           "age": 1
       },
       {
           "type": "Tablet",
           "age": 0
       }
   ]
}
```

ちゃんと保存されていますね。
ここの注意点としては、引数が無い場合は空の配列 `{}` を渡すというところです。
これを省略してしまうとエラーが出るのでご注意下さい。

続いて、資産を登録してみましょう。

```sh
scalar>

scalar> execute add-asset {"type": "Tablet", "asset": "iPad", "timestamp": 20190701120000, "id": "1001"}

{
   "result": "success",
   "message": "asset iPad put completed."
}
```

ID が 1001 で、Tablet に分類される iPad を登録しました。
timestamp にはUNIXタイムスタンプを登録するのですが、わかりやすく仮の値を指定しています。
これもデータが登録されているか確認してみます。

```sh
scalar> execute list-asset {"type": "Tablet"}

{
   "result": "success",
   "message": "get list completed.",
   "Tablet": [
       {
           "id": "1001",
           "name": "iPad",
           "timestamp": 20190701120000,
           "status": "in-stock"
       }
   ]
}
```

確かに iPad が登録されていますね。
status が in-stock になっているので、早速借りてみましょう。

```sh
scalar> execute status-change {"asset_id": "1001", "status": "on-loan", "timestamp": 20190701130000}

{
   "result": "success",
   "message": "Borrowed"
}

scalar> execute list-asset {"type": "Tablet"}

{
   "result": "success",
   "message": "get list completed.",
   "Tablet": [
       {
           "id": "1001",
           "name": "iPad",
           "timestamp": 20190701130000,
           "status": "on-loan",
           "holderId": "Admin"
       }
   ]
}
```

無事借りることが出来ました。
timestamp も更新され、status も on-loan に変更されていますね。
次は返却してみましょう。

```sh
scalar> execute status-change {"asset_id": "1001", "status": "in-stock", "timestamp": 20190701140000}

{
   "result": "success",
   "message": "Returned"
}

scalar> execute list-asset {"type": "Tablet"}

{
   "result": "success",
   "message": "get list completed.",
   "Tablet": [
       {
           "id": "1001",
           "name": "iPad",
           "timestamp": 20190701140000,
           "status": "in-stock"
       }
   ]
}
```

こちらも無事出来ました。
それでは最後に貸し出し履歴を確認しましょう。

```sh
scalar> execute asset-history {"id": "1001"}

{
   "result": "success",
   "message": "get history complete.",
   "history": [
       {
           "timestamp": 20190701140000,
           "status": "in-stock",
           "age": 2
       },
       {
           "timestamp": 20190701130000,
           "status": "on-loan",
           "age": 1,
           "holderId": "Admin"
       },
       {
           "timestamp": 20190701120000,
           "status": "in-stock",
           "age": 0
       }
   ]
}
```

登録、貸し出し、返却と履歴が残っていますね。

# まとめ
というわけでエミュレータを使って資産管理アプリケーションを動かしてみました。
エミュレータは起動も早くて動作も速いので作業が捗りますね。
今回はエミュレータを使ったので、exit してしまうとコントラクトとデータが消えてしまいます。
なので次は実際に Sandbox 環境への登録やその呼び出しといった辺りを追っていきたいと思います。