ScillaでHello World

# はじめに
この記事ではZilliqaというブロックチェーンのために設計されたScillaという言語を取り上げます。下記が分かっていれば読める記事かと思います。どうでしょうか。

  * ブロックチェーンではコインを送り合うことができること。
  * コインの送り合いにはそのブロックチェーン上にアカウントが必要なこと。
  * アカウントにはざっくりいうと、単純にコインを送り合いたいユーザを表すアカウントと、コントラクトと呼ばれるブロックチェーン上で実行されるプログラムを表すアカウントの２つがあること。

## この記事について
  * コントラクトと呼ばれるブロックチェーン上で実行されるプログラムを扱う
  * ScillaでHello Worldしてみて何となくScillaやブロックチェーンについて雰囲気がわかるのが目的。
  * Zilliqaやブロックチェーン自体の説明はしない。
  * 対象は何となくブロックチェーンがわかるプログラマ。

## Scilla
  * **Scilla**はブロックチェーンの1つである**Zilliqa**のために設計された言語です。
    * 他のブロックチェーンでは、例えばEthereumではSolidityという言語が使われます。
  * 従来のブロックチェーンで起きた事件のいくつかは、プログラムのミスであることに着目し、言語レベルで安全性を担保する機能を実装する目的で設計されました。
    * ScillaにはCoqで行われるような形式的検証の機能があります。従来は主に数学の証明のために使われてきたと思います。デプロイ後にソースを改変できないブロックチェーンでは最初にプログラムの検証が大事だということで形式的検証が言語レベルでサポートされているようです。
  * 公式のブログが参考になります。
    * [Scillaデザインストーリー](https://blog.zilliqa.com/scillaデザインストーリー-8a96f2b0094f)

## 前提
  * 私はブロックチェーンエンジニアではありません。
  * Zilliqa、Scillaがどれくらい普及するかわかりません。
  * Scillaの詳細な言語仕様は説明しません。

# Hello World

ありがたいことに、テスト環境のWeb IDEを用意してくれています。パブリックなブロックチェーンなので普及のためだと思います。

さっそく[Web IDE](https://savant-ide.zilliqa.com/)を開いて見ましょう。

![1.JPG](https://qiita-image-store.s3.amazonaws.com/0/55081/a4128b2a-db56-e2ce-59d5-563b9c0690c6.jpeg)

既にサンプルファイルが多数用意されています。
左ペインの`HelloWorld.scilla`を選択すると下記のソースコードが表示されます。

```HelloWorld.scilla
(* HelloWorld contract *)

import ListUtils

(***************************************************)
(*               Associated library                *)
(***************************************************)
library HelloWorld

let one_msg = 
  fun (msg : Message) => 
  let nil_msg = Nil {Message} in
  Cons {Message} msg nil_msg

let not_owner_code = Int32 1
let set_hello_code = Int32 2

(***************************************************)
(*             The contract definition             *)
(***************************************************)

contract HelloWorld
(owner: ByStr20)

field welcome_msg : String = ""

transition setHello (msg : String)
  is_owner = builtin eq owner _sender;
  match is_owner with
  | False =>
    msg = {_tag : "Main"; _recipient : _sender; _amount : Uint128 0; code : not_owner_code};
    msgs = one_msg msg;
    send msgs
  | True =>
    welcome_msg := msg;
    msg = {_tag : "Main"; _recipient : _sender; _amount : Uint128 0; code : set_hello_code};
    msgs = one_msg msg;
    send msgs
  end
end


transition getHello ()
    r <- welcome_msg;
    msg = {_tag : "Main"; _recipient : _sender; _amount : Uint128 0; msg : r};
    msgs = one_msg msg;
    send msgs
end

```

必要なところを説明すると`transition setHello (msg : String)`や`transition getHello ()`は、String型の引数`msg`を取る`setHello`メソッドと、引数を取らない`getHello`メソッドです。Scillaは`transition`という言葉を使っていますので今後トランジションと呼びましょう。`field welcome_msg : String = ""`はString型で初期値が`""`の変数で、フィールドと呼びます。これらのトランジションを使って、`welcome_msg`フィールドの値を読み書きします。とりあえずサンプルファイルをテスト環境にデプロイしてみましょう。

## サンプルファイルのデプロイ

右ペインのDEPLOYタブを選びます。`Select account`をクリックするとデプロイに使うアカウントを自由に選ぶことができます。適当なアカウントを選択してください。`Choose a scilla source file`に`HelloWorld.scilla`を指定します。テスト環境では複数のアカウントが既に用意されていて、表示されているアカウントは、この記事を読まれている方によって別々だと思います。以後の画像では私の環境での文字列を表示しています。

![2.JPG](https://qiita-image-store.s3.amazonaws.com/0/55081/6dd27b45-8944-765d-96ed-99001735f503.jpeg)

`Initialisation Parameters`に`Select account`でリストされたアカウントの中から適当なものを選んでコピペしてください。先ほどと同じアカウントでも構いません。DEPLOYボタンでデプロイします。

![3.JPG](https://qiita-image-store.s3.amazonaws.com/0/55081/cd19c346-c281-1543-bfaa-e0a0d2dca101.jpeg)

以下のようにデプロイの手数料（Gas）に53ZIL（Zilliqaで扱うコイン）がかかりました。

![4.JPG](https://qiita-image-store.s3.amazonaws.com/0/55081/31fe3500-8b5a-5aaa-3d38-d7a599eb3813.jpeg)

ちなみにテスト環境の全てのアカウントは初期状態で100000000ZILを持っていますが、デプロイに使ったアカウントを見てみると53ZIL減っています。

![5.JPG](https://qiita-image-store.s3.amazonaws.com/0/55081/a4d8d9b7-14fc-5bf2-0ced-da60638bd000.jpeg)

`HelloWorld.scilla`の以下の部分を見てください。

```HelloWorld.scilla
(***************************************************)
(*             The contract definition             *)
(***************************************************)

contract HelloWorld
(owner: ByStr20)
```

これはコントラクト（ブロックチェーン上で実行されるプログラム）の宣言です。デプロイされるとHelloWorldコントラクトがブロックチェーン上に作成されて、イミュータブルな`ByStr20`型の変数`owner`が初期化されます。初期値はデプロイ時に`Initialisation Parameters`のところで指定したアカウントです。後に説明しますが、この時に指定したアカウントでしか、`welcome_msg`フィールドの値を書き換えることができません。

デプロイしたコントラクトを見てみましょう。`STATE`タブの`Contract State`を見てください。

![init.JPG](https://qiita-image-store.s3.amazonaws.com/0/55081/bce05eff-c89b-2daa-82ac-d74877bfc039.jpeg)

initを見ると、ownerが`Initialisation Parameters`のところで指定したアカウントで初期化されているのがわかるかと思います。便宜上、以後このアカウントを**ownerアカウント**と呼びます。

## setHelloトランジション

それでは次に、右ペインの`CALL`タブを開いて、ownerアカウントでwelcome_msgフィールドの値を書き換えて見ましょう。

![8.JPG](https://qiita-image-store.s3.amazonaws.com/0/55081/15b8e075-37d6-ad73-5123-b1273dac3c65.jpeg)

上から順にコントラクトを呼び出すアカウント（今回指定するのはownerアカウントです）、デプロイしたHellowWorldコントラクトを指定します。トランジションに`setHello`を指定します。下の方の`Transition Parameters`に`Hello World!`と指定して`CALL TRANSITION`ボタンを押して、setHelloトランジションを呼び出してみましょう。

![hello.JPG](https://qiita-image-store.s3.amazonaws.com/0/55081/0581a523-1386-797b-edba-0a6a6bcecb61.jpeg)

成功すると以下のようになります。今回は手数料として243ZILがownerアカウントから使われたようです。

![9.JPG](https://qiita-image-store.s3.amazonaws.com/0/55081/b09b4111-a79c-283b-7cee-feb50c776803.jpeg)

さっそく、HelloWorldコントラクトのwelcom_msgフィールドが書き換わったか見てみましょう。右ペインの`STATE`タブから`Contract State`の`state`を見ると、welcome_msgフィールドの値が`Hello World!`に書き換わっているのがわかるかと思います。`state`の`0`に`_balance`という、作成時に初期化され、全てのコントラクトが持つフィールドがありますが、今回は説明を省きます。

![11.JPG](https://qiita-image-store.s3.amazonaws.com/0/55081/8b84184c-a75a-048f-ad79-8742387c2ed9.jpeg)

改めて`transition setHello (msg : String)`を見てみます。

```HelloWorld.scilla
transition setHello (msg : String)
  is_owner = builtin eq owner _sender;
  match is_owner with
  | False =>
    msg = {_tag : "Main"; _recipient : _sender; _amount : Uint128 0; code : not_owner_code};
    msgs = one_msg msg;
    send msgs
  | True =>
    welcome_msg := msg;
    msg = {_tag : "Main"; _recipient : _sender; _amount : Uint128 0; code : set_hello_code};
    msgs = one_msg msg;
    send msgs
  end
end
```

`is_owner = builtin eq owner _sender;`で変数`is_owner`にコントラクト作成時に初期化したイミュータブルな変数`owner`とHelloWorldコントラクトを呼び出したアカウント`_sender`を比較した結果を格納(正確には式を束縛ですが)しています。

`  | False =>`の部分は関数型言語で使われるパターンマッチで、`False`の場合の処理が書かれています。

今回はownerアカウントで呼び出したので、`owner`と`_sender`は一致しています。なので`  | True =>`の方にマッチして、`welcome_msg := msg;`でwelcome_msgが書き換わり、`msg = {_tag : "Main"; _recipient : _sender; _amount : Uint128 0; code : set_hello_code};`により、変数`msg`にMessage型の値の` {_tag : "Main"; _recipient : _sender; _amount : Uint128 0; code : set_hello_code};`が格納され、`msgs = one_msg msg;`により、変数`msgs`に`one_msg`関数を引数`msg`で呼び出した結果が格納されます。`one_msg`は以下のように記述されています。

```HelloWorld.scilla
let one_msg = 
  fun (msg : Message) => 
  let nil_msg = Nil {Message} in
  Cons {Message} msg nil_msg
```
これによりMessage型のリストが返されます。そして、最後に`send msgs`でコントラクトにMessage型のリストを送っています。

STATEタブで、welcome_msgフィールドに`Hello World!`が格納されたのが確認できると思います。本記事ではやりませんが、ownerアカウント以外で試すとwelcome_msgは書き換わりません。

![12.JPG](https://qiita-image-store.s3.amazonaws.com/0/55081/121bfb70-4410-1ba6-fae4-f120268b4bba.jpeg)

## getHelloトランジション

最後にgetHelloトランジションを呼び出してみましょう。CALLタブを開いて、上から順に任意のアカウントと、HelloWorldコンストラクタ、getHelloトランジションを指定します。

![13.JPG](https://qiita-image-store.s3.amazonaws.com/0/55081/0be6c0c8-5631-f94e-aad7-a1ef0b63ca13.jpeg)

`CALL TRANSION`ボタンまで押したら`STATE`タブを開いてみてください。今回はwelcome_msgフィールドを書き換えていないので、`state`は変わりません。

![14.JPG](https://qiita-image-store.s3.amazonaws.com/0/55081/46247dbc-9baf-3bcb-0926-cedcb9e99123.jpeg)

getHelloトランジションのソースコードは以下のようになっています。

```HelloWorld.scilla
transition getHello ()
    r <- welcome_msg;
    msg = {_tag : "Main"; _recipient : _sender; _amount : Uint128 0; msg : r};
    msgs = one_msg msg;
    send msgs
end
```

ミュータブルな変数welcome_msgから変数`r`に値を読み出して、変数`msg`にMessage型の値、`{_tag : "Main"; _recipient : _sender; _amount : Uint128 0; msg : r};`を入れて`msgs = one_msg msg;`でMessage型のリストを作り、`send msgs`で送っています。送られた`msgs`は`messageLog`に表示されるので見てみましょう。

STATEタブのHelloWorldコントラクトの`messageLog`の`1`が今送った`msgs`です。ちなみに`0`はさきほど、setHelloトランジションで送ったものです。

![15.JPG](https://qiita-image-store.s3.amazonaws.com/0/55081/f31a0aa6-b43d-910e-855e-760f536a2f03.jpeg)

ちなみに、getHelloトランジションはwelcome_msgフィールドの値を読み出してmessageLogに値を書き込むというものでした。コンストラクトの呼び出しは取引が発生します。取引には手数料が必要です。また取引はブロックチェーンに書き込まれます。STATEタブを開いてコントラクトを表示するだけなら取引が発生していませんので、チェーンには何も書き込まれません。

# おわりに

以上で簡単ではありますが、「ScillaでHello World」でした。現状Zilliqaはテストネットで運用されていますが、予定では2019年1月にメインネットに移行するそうです。ZilliqaはBitcoinやEthereumのスケーリングの問題を解決しています。例えば、メインネットへの参加ノード数によってはクレジットカード並の速度で決済ができるようです。詳細は[公式サイト](https://zilliqa.com)のドキュメントを御覧ください。それでは皆さん良いブロックチェーンライフを。

# おまけ

## コインとトークン

私はブロックチェーン初心者ですが、ネット上のいくつかの文献を見ると、仮想通貨という言葉がコインとトークンのどちらの意味でも使われていて混乱しました。コントラクトはプログラムなので、あるアカウントAが10000という値を持っているという表現をScillaで書けます。また、アカウントBに100送ったら、Aから100減らすみたいな処理を書いたとします。そのように処理を書いていくと最終的にZilliqa上で値の送り合いができますよね。この値をトークンと呼んでいるようです。トークンに対して、ここではZILに当たるものをコインもしくは、ネイティブトークンと呼ぶようです。恐らく仮想通貨はコインとトークンを包含した広い意味で使われているので、ITエンジニアがITエンジニア向けに書く記事においてはコインとトークンを使い分けてほしい気がします。

## なぜトークンなのか

詳細を説明すると長くなるので、簡単に説明します。メインネットをローンチ後は、そのネットワークに参加するコンピュータ（ノード）が少数のうちは、チェーンが不安定だったり、悪さができたりします。なので、既に安定しているブロックチェーン上でトークンという形で値の送り合いをできる仕組みを作っているようです。

## スマートコントラクト

この記事ではScillaで書かれたプログラムをコントラクトと表記しました。その意味でスマートコントラクトという言葉を使うのに違和感を覚えたので、スマートを省略しました。スマートコントラクトが概念を連想させるからなのか、もしくは紙の契約に対してということを強調する雰囲気だからでしょうか...。既に文脈がブロックチェーンの話で、具体的な実装を指すならコントラクトと言った方がなんかしっくりくるので、コントラクトと表記しました。ただスマートフォンのことをフォンと呼ばれても「？」となるので、省略しない方がいいでしょうか。フォンという言葉はすぐに電話一般を連想できるますが、コントラクトだとすぐに契約のイメージが湧きにくい日本人特有のものでしょうか。教えてください。