Scalar DL Emulator を使って、コントラクト、ファンクションの実行を試してみる

# 実行環境
* Ubuntu16.04LTS
* Oracle Java 8
* Gradle 4.10.2

# Scalar DLとは
Scalar社が開発した、ブロックチェーンにヒントを得た分散型台帳プラットフォームソフトウェア。
詳しく知りたい場合はこちら
[Scalar DLT | Scalar, Inc.](https://scalar-labs.com/product/)
[Scalar DL Docs](https://scalardl.readthedocs.io/en/latest/)

# emulatorとは
Scalar DL Emulator とは、Scalar社が提供するScalar DLのコントラクト、ファンクションの実行をエミュレーションするソフトウェア。
詳細はこちら
[Scalar DL emulator - GitHub](https://github.com/scalar-labs/scalardl-tools/tree/master/emulator)

　Scalar DLのコントラクトを実行するためには、docker環境やSandbox環境で実行環境を用意してコントラクトを登録する必要があるが、コントラクトを登録・実行する場合、Scalar DLの制約としてコントラクトID・FunctionIDを一意にしなければならなかったり、登録したコントラクトの変更や削除ができなかったりする。そのためコントラクトやFunctionのちょっとした修正のたびに一意なIDの設定・登録の作業等が必要になり、開発・テストの効率が下がるという面があった。
　しかし、emulatorを用いることでローカルのメモリ内で疑似的にScalar DLを実行できるので、Functionが操作する事前のスキーマ定義やコントラクトの再登録時の制約を（あまり）気にしなくてよくなり、emulatorを終了させると内容がクリアされるために気軽に何度もコントラクトの実行をテストすることができるようになる。

　ただし、emulatorには実際のScalar DLにある改ざん検知機能がないなどいくつかの機能制限があり、また外部アプリケーションからの接続テストが出来ないという点には注意が必要である。
※Sandbox環境を利用すれば外部アプリケーションからコントラクトを実行可能だが、Functionは未対応。

`Function`についての説明はこちら
[Dockerを利用してScalar DLを使ってみた](https://qiita.com/y18sakamoto/items/4e2166ede6e3797d6ebc)

# 環境構築
githubからemulatorをダウンロード

`$ git clone https://github.com/scalar-labs/scalardl-tools.git`
`$ cd scalardl-tools-master/emulator`

ツールのビルド
`$ ./gradlew installDist`

成功すると`/build/install/emulator/bin`に実行可能ファイルが作成される

emulatorの起動
`$ ./build/install/emulator/bin/emulator`

emulatorコンソールが表示されれば成功
`exit`またはCtrl+dで終了する

ファイルを指定しながらemulatorを起動することで、複数のコマンドを一度に実行することもできる
`$ ./build/install/emulator/bin/emulator -f cmds.txt`

ヘルプの表示
`$ ./build/install/emulator/bin/emulator -h` またはemulatorコンソール上で`help`

# サンプルコントラクト・Functionの実行
### コントラクトの準備
サンプルとして最初からディレクトリに置かれている`StateUpdater.java`を使用する
`src/main/java/com/scalar/client/tool/emulator/contract/StateUpdater.java`

### Functionの準備
Functionを置くディレクトリを作成する

`$ mkdir src/main/java/com/scalar/client/tool/emulator/function`
`$ vi src/main/java/com/scalar/client/tool/emulator/function/SchemaUpdater.java`

``` SchemaUpdater.java
package com.scalar.client.tool.emulator.function;

import com.scalar.database.api.Get;
import com.scalar.database.api.Put;
import com.scalar.database.api.Result;
import com.scalar.database.io.IntValue;
import com.scalar.database.io.Key;
import com.scalar.database.io.TextValue;
import com.scalar.ledger.database.MutableDatabase;
import com.scalar.ledger.udf.Function;
import java.util.Optional;
import javax.json.JsonObject;

public class SchemaUpdater extends Function {
  @Override
  public void invoke(
    MutableDatabase database,
    JsonObject contractArgument,
    Optional<JsonObject> functionArgument) {

    String userId = functionArgument.get().getString("user_id");
    int state = contractArgument.getInt("state");
    String assetId = contractArgument.getString("asset_id");

    Get get =
      new Get(
        new Key(new TextValue("user_id",userId)),
        new Key(new IntValue("state",state)))
        .forNamespace("test")
        .forTable("test_schema");
    database.get(get);

    Put put =
      new Put(
        new Key(new TextValue("user_id",userId)),
        new Key(new IntValue("state",state)))
        .withValue(new TextValue("value",assetId))
        .forNamespace("test")
        .forTable("test_schema");
    database.put(put);
  }
}
```

### コントラクト・Functionの登録
コントラクトとFunctionはそれぞれ、実行前に一意なIDで登録しておく必要がある。登録にはID、クラス名、クラスファイルのパスが必要。

コントラクトの登録
`scalar> register state-updater com.scalar.client.tool.emulator.contract.StateUpdater ./build/classes/java/main/com/scalar/client/tool/emulator/contract/StateUpdater.class`

Functionの登録
`scalar> register-function schema-updater com.scalar.client.tool.emulator.function.SchemaUpdater ./build/classes/java/main/com/scalar/client/tool/emulator/function/SchemaUpdater.class`

### コントラクトの実行
`"_functions_"`に配列形式で実行するFunctionのIDを指定する。複数のFunctionを一度に実行することもできる。

`scalar>  execute state-updater {"asset_id": "XXX", "state": 1, "_functions_": ["schema-updater"]} -fa {"user_id":"test_user"}`
※-fa(-function-argument)で指定するJSON文字列にはスペースを入れないこと。エラーが発生する。

### コントラクトの実行結果の確認
emulatorにはget,put,scanの3つのコントラクトがデフォルトで登録されており、特別に定義をせずに使えるようになっている。
`scalar> get XXX`

`"state": 1`と表示される

### Functionの実行結果の確認
`database`コマンドで登録された値を確認する
`scalar> database -p={"user_id":"test_user"} -c={"state":1} -t=test_schema -n=test get`

`{"value":"XXX"}`と表示される