最近話題の分散型台帳 Scalar DLT について調べてみた（スマートコントラクト実行編）

前回は[株式会社Scalar](https://scalar-labs.com/)の開発している分散型台帳ソフトウェア、Scalar DLTについて調べてみました。

前回の記事：[最近話題の分散型台帳 Scalar DLT について調べてみた（基礎編）](https://qiita.com/DENEN_YOSHIDA/items/591a28ba8196d3fbda9a)

今回は実際にスマートコントラクトを触っていこうと思います。

# Scalar DLTの始め方
前回紹介したとおり、Scalar DLTにはScalar DLとScalar DBというソフトウェアが存在します。
Scalar DB単体を使うことも可能ですが、せっかくならスマートコントラクトが使えるScalar DLを試してみましょう。
現在はSandboxが提供されているので、そちらを利用させていただきます。

## Sandbox

Sandbox に関しては既に記事にされている方がいらっしゃったので以下を参考にさせていただきます。

[分散型台帳ソフトウェアScalar DLのSandbox環境を試してみた](https://qiita.com/shu22203/items/45a8df4d5a99bfedc3e5)

なお、記事内では以下の記述が有りましたが、現在はGitHubアカウントでサインインすればすぐに必要なファイルがダウンロード出来ました。
> 上記のURLからsandboxを利用するためのアクセス権をリクエストします。
> リクエスト後しばらくすると登録完了メールが届き、利用に必要な鍵ペア、証明書、設定ファイルなどが配布されます（自分は数十分で届きました）。

# スマートコントラクト
それではサンプルのコントラクトを実行してみましょう。
今回はmacOS 10.14.4の環境で作業を行います。
基本的には先述のページに従えば出来ますが、１つずつコマンドを追って説明していきます。

## Javaのインストール
まずはscalardl-client-sdkを動かすにはJAVAが必要となります。
というわけでJAVAのインストールを行いましょう。

```sh
Homebrewのインストール
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

homebrew-cask-versionsの導入
$ brew tap homebrew/cask-versions

Java 8のインストール
$ brew cask install adoptopenjdk8
```

## Sandboxの利用申請
続いて、Sandbox の利用申請を以下ページから行っていきます。

[Scalar DL Sandbox](https://scalar-labs.com/sandbox/)

こちらのページにアクセスし、GitHubアカウントでログインをしてください。
すると以下のようなページが表示されますので「Download」ボタンを押して必要なファイルをダウンロードしてください。
![sandbox01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427707/ea35bad2-44d8-4e65-1594-f8977e28ef3f.jpeg)

## セットアップ
ダウンロードしたファイルを解凍すると以下のファイルが展開されます。
※`{username}` はGitHubのユーザ名が入ります。

```sh
$ unzip ~/Downloads/scalar-sandbox-client-{username}.zip
$ ls ~/Downloads/scalar-sandbox-client-{username}
client.properties {username}-key.pem {username}.pem
```

簡単にファイルの説明は以下の通りです。

- client.properties
  - 設定ファイル
- {username}-key.pem
  - ユーザ専用の秘密鍵
- {username}.pem
  - ユーザの証明書

続いて、リポジトリのクローンを行っていきます。

```sh
$ git clone https://github.com/scalar-labs/scalardl-client-sdk.git
$ cd scalardl-client-sdk
```

リポジトリをクローンしたら先ほどダウンロードしたファイル群をコピーしていきましょう。

```sh
$ cp -r ~/Downloads/scalar-sandbox-client-{username}/* ./
```

## 証明書の登録

続いて Scalar DL Network に参加するために先ほどコピーしてきた証明書の登録を行います。

```sh
$ client/bin/register-cert -properties client.properties
```

## コントラクトの登録

いよいよコントラクトの登録を行っていきます。
コントラクトのソースはクローンしてきたリポジトリ内には存在するのですが、登録するためには以下のコマンドでコンパイルする必要があります。

```sh
$ ./gradlew assemble
```

それではコントラクトの登録を行ってみましょう。
今回利用するのは状態を更新する StateUpdater と、状態を確認する StateReader の２つになります。

```sh
$ client/bin/register-contract -properties client.properties -contract-id {username}-StateUpdater -contract-binary-name com.org1.contract.StateUpdater -contract-class-file build/classes/java/main/com/org1/contract/StateUpdater.class

$ client/bin/register-contract -properties client.properties -contract-id {username}-StateReader -contract-binary-name com.org1.contract.Reader -contract-class-file build/classes/java/main/com/org1/contract/StateReader.class
```

実行内容は単純ですが、オプションの説明は以下の通りです。

- -properties
  - 設定ファイルを指定する。今回はダウンロードしたclient.properties
- -contract-id
  - コントラクトを識別するID。ネットワーク内で一意で有る必要がある。
- -contract-binary-name
  - コントラクトの名称。Javaのソース上で定義されているものを指定。
- -contract-class-file
  - コントラクトのファイル。ビルドされたclassファイルを指定。

## コントラクトの実行
ここまできたらあとは実行するだけです。
StateUpdaterを利用して、特定のアセットに値を設定してみましょう。

```sh
$ client/bin/execute-contract -properties client.properties -contract-id {username}-StateUpdater -contract-argument '{"asset_id": "{username}-myasset", "state": 3}'

status: 200
```

こちらも非常にシンプルです。
`status: 200`が返ってくれば実行成功です。
先ほどと違うオプションは１つだけですね。

- -contract-argument
  - コントラクトに渡す引数をJSON形式で記述。

Updater を叩いたので次は Reader で値を確認しましょう。

```sh
client/bin/execute-contract -properties client.properties -contract-id {username}-StateReader -contract-argument '{"asset_id": "{username}-myasset"}'
status: 200
{"age":0,"input":{},"output":{"state":3},"contract_id":"{username}-StateUpdater","argument":{"asset_id":"{username}-myasset","state":3,"nonce":"b3a59ed7-e69a-49ea-83c4-7237296bf119"},"signature":"MEUCIBqkUbPI3l5TGx+MqjNFsUmv8UWJ0DYyjzeYgOauoB83AiEAuMwofkeQEJnTn/6W8sjilfawYcryPt3wZIgPfEprjTo=","hash":"fkXewkXuiof/PO87DKb6vfxdAMAisJ9WzXOvIyzXQoY=","prev_hash":""}
```

見づらいので出力を整形してみます。

```json
{
  "age": 0,
  "input": {},
  "output": {
    "state": 3
  },
  "contract_id": "{username}-StateUpdater",
  "argument": {
    "asset_id": "{username}-myasset",
    "state": 3,
    "nonce": "b3a59ed7-e69a-49ea-83c4-7237296bf119"
  },
  "signature": "MEUCIBqkUbPI3l5TGx+MqjNFsUmv8UWJ0DYyjzeYgOauoB83AiEAuMwofkeQEJnTn/6W8sjilfawYcryPt3wZIgPfEprjTo=",
  "hash": "fkXewkXuiof/PO87DKb6vfxdAMAisJ9WzXOvIyzXQoY=",
  "prev_hash": ""
}
```

output に注目してみると先ほど設定した値`3`が登録されているのがわかるでしょうか？
そしてこのアセットは初めての登録なのでinputやprev_hashが空になっています。

最後に同じアセットに対して違う値を設定してみましょう。

```sh
$ client/bin/execute-contract -properties client.properties -contract-id {username}-StateUpdater -contract-argument '{"asset_id": "{username}-myasset", "state": 100}'

status: 200
```

先ほど同様にStateReaderで値を確認してみます。

```sh
client/bin/execute-contract -properties client.properties -contract-id {username}-StateReader -contract-argument '{"asset_id": "{username}-myasset"}'
```

```json
{
  "age": 1,
  "input": {
    "{username}-myasset": {
      "age": 0,
      "data": {
        "state": 3
      }
    }
  },
  "output": {
    "state": 100
  },
  "contract_id": "{username}-StateUpdater",
  "argument": {
    "asset_id": "{username}-myasset",
    "state": 100,
    "nonce": "31f3c3d5-d7ab-4fd5-acae-fe0d0b95038c"},
  "signature": "MEUCIQC+pcBXSsAwmzsfX0xjXLEoANU47ONCA1e1xrQYsa+5pgIgToOUMKvv37nvZzAAFDR/EDKXe7fZzmfDWubM8TEMuTM=",
  "hash": "McnMW2rvOvLjeC4g6zc0yRd/ajX1Z3aIqeI9bQAc+ko=",
  "prev_hash": "fkXewkXuiof/PO87DKb6vfxdAMAisJ9WzXOvIyzXQoY="
}
```

outputのstateの値は更新されていますが、一度目のStateReaderの返り値との違いとしてはinputとprev_hashが目に付きます。
inputには１つ前のアセットの状態、prev_hashは１つ前のアセットのハッシュIDが入っています。
こういった形でハッシュチェーンが形成されていくんですね。

# まとめ
というわけで簡単では有りますがサンプルのコントラクトを実行してみました。
コントラクトがピュアなJavaで書けるのは使いやすいですね。
Ethereumでは（JavaScriptに似ているとはいえ）独自言語のSolidityだったり、Hyperledger FabricではGo言語が主流だったりする事を考えると、導入がしやすいのではないでしょうか？

現在はHyperledger FabricではGo言語以外にもNode.jsやJavaでも記述は可能だったりするので、次回以降でコードの書き方やデプロイの仕方なども比較していければと思います。