はじめに
本記事は、過去にコンセンサス・ベイスが主宰していたオンラインサロンの記事です。記事は2017年~2018年にかけて執筆されたため、一部は、既に古くなっている可能性があります。あらかじめご了承ください。
今回の内容
本稿では、シャーディングを実装したパブリックチェーンであるZilliqaを用いた、セキュアでスケーラブルなスマートコントラクトの実現について、全3回で解説します。
第3回では、Scilla言語の解説と、Scilla言語を用いたサンプルコントラクトの実行例を示します。
第1章 Scilla言語の初歩
Zilliqaブロックチェーンのコントラクト言語であるScillaは、OCamlにより実装されており、文法もOCamlに似た関数型言語です。まずは、Scilla言語の初歩的な構文について紹介します。
コメント
Scillaのコメントは、 (* と *) で囲まれた部分です。
コード1. Scillaのコメント構文
(* 一行コメント *)
(*
* 複数行コメント
* 複数行コメント
*)
イミュータブルな変数
Scillaの変数には、イミュータブル(不変)な変数とミュータブル(可変)な変数があります。
イミュータブルな変数は、コントラクトの初期パラメタとして定義し、一度設定されるとあとから変更することはできません。
コード2. コントラクトとイミュータブルな変数の定義構文
contract MyContract
(* Immutable fields declaration *)
(vname_1 : vtype_1,
vname_2 : vtype_2)
イミュータブルな変数は、変数名と型をコロンでつなぎます。複数の変数を定義する場合は、カンマで連結します。
ミュータブルな変数
Scillaのミュータブルな変数は、fieldとも呼ばれ、コントラクトの動的な状態を表現する変数です。ミュータブルな変数の定義は、fieldキーワードを用いて、変数名 : 型 = 式という形でおこないます。
コード3. ミュータブルな変数(field)の定義構文
field vname_1 : vtype_1 = expr_1
field vname_2 : vtype_2 = expr_2
...
Transitions
コントラクトの状態を変化させる機能を、ScillaではTransitionと呼びます。Transitionの定義は、transitionキーワードとendキーワードを用いて、コード4に示す構文でおこないます。
コード4. Transitionの定義構文
transition foo (vname_1 : vtype_1, vname_2 : vtype_2, ...)
...
end
Transitionの定義の中では、引数で定義した変数のほか、トランザクションの発行者アドレスを表す _sender と、送金されたZILトークンの量 _amount が利用できます。
Let束縛
Scillaでは、letキーワードを用いて、ある式に別の名前をつけることができます。例えば、oneという名前にInt32型の1という値を束縛させる場合、「let x = f」という構文を用いて、コード5のように記述します。この束縛は、コントラクト全体で参照されます。
コード5. Letキーワードによるグローバルな束縛
let one = Int32 1
コントラクト全体ではなく、特定の関数内でのローカルな束縛をおこないたい場合は、「let x = f in expr」という構文を用います。これは、expr内でのみx = fの束縛が有効化されるという意味です。
コード6に示す例は、「builtin add one two」という表現内において、twoという名前にInt32の2という値を束縛し、「let two ~ one two」という表現内において、oneという名前にInt32の1という値を束縛し、最終的な評価値をsumという名前に束縛する、という意味です。
コード6. Letキーワードによるローカルな束縛
let sum =
let one = Int32 1 in
let two = Int32 2 in
builtin add one two
第2章 HelloWorldコントラクトの実行
それでは、Scillaの公式サンプルコードとして提供されているHelloWorldコントラクトを例にして、コントラクトを実行してみましょう。
ScillaのWeb IDE(https://savant-ide.zilliqa.com/)を用いると、シミュレートされたZilliqaブロックチェーンに独自のコントラクトをデプロイし、トランザクションの発行や状態の確認をすることができます。
まず、左のサイドバーから「HelloWorld.scilla」を開き、コードの内容を確認します。デプロイをおこなうには、右のサイドバーの「DEPLOY」タブを選択し、アカウントとソースコードを選択します。アカウントは、デフォルトで残高を持ったアカウントが複数用意されています。
HelloWorldコントラクトは、初期パラメタとしてownerのアドレスを指定する必要があります。上記で選択したアカウントのアドレスをコピーし、初期パラメタとして指定し、DEPLOYを実行します。
デプロイが完了したら、右のサイドバーの「CALL」タブを選択し、Transitionを実行してみましょう。
さきほどデプロイしたアカウントとコントラクトのアドレスを選択すると、実行可能なTransitionとして「setHello」「getHello」が選べます。今回は、setHelloを選択し、「Transition Parameters」に任意のメッセージを指定し、「CALL TRANSITION」を実行します。
Transitionが実行されると、クライアントにコントラクトの実行結果のメッセージが送信されますが、現時点ではこのWeb IDEから実行結果のメッセージを確認することはできません。
代わりに、右のサイドバーの「STATE」タブから、コントラクトの状態を確認できます。
第3章 CrowdFundingコントラクトの実行
続いて、Web IDEを用いてCrowdFundingコントラクトの実行を試してみましょう。CrowdFundingのコントラクトは、初期パラメタとしてowner, max_block, goalが指定できます。max_blockは、クラウドファンディングが終了する期限のBlock Heightを指定します。
現在のBlock Heightは、中央パネルの上部に表示されています。デフォルトでは10000msごとに新しいブロックが生成されますが、Settingからブロック生成間隔を調整できます。
例えば、max_block = 現在のBlock Height + 30、goal = 3000でCrowdFundingを開始してみましょう。
コントラクトのデプロイが成功したら、「CALL」タブを選択してください。CALLタブに移動後、アカウントとコントラクト(Crowdfunding)を選択すると、Transitionとして「Donate」、「GetFunds」、「ClaimBack」が選択できます。
まず、デプロイしたアカウントとは別のアカウントを選択し、Donateを実行してみましょう。クラウドファンディングの目標値が3000なので、それ以下の値でDonateを実行します。
Donateが成功すると、中央パネルの上部の「Events」に「DonationAccepted」イベントが通知されます。
複数のアカウントを切り替えてDonateを繰り返し、30ブロック以内に目標値のクラウドファンディングを達成すると、コントラクトのオーナーはGetFundsにより募集したファンドを受け取ることができます。
一方、30ブロック以内に目標値のファンドが集まらなかった場合には、それぞれの参加者はClaimBackにより預けていたファンドを取り戻すことができます。ClaimBackはGetFundsを利用したい場合はコントラクトのオーナーアカウント、ClaimBackを利用したい場合はDonateしたアカウントを利用してください。
それぞれの条件のときに、正しくコントラクトが動作するかを実際に試してみましょう。
まとめ
ScillaのWeb IDEでは、HelloWorldやCrowdFunding以外にも多くのサンプルコントラクトを提供しています。それぞれのコントラクトの実行を試してみたり、独自のコントラクトを実装し、実行を試してみたりして、Scilla言語への理解を深めてみてください。
以上。
参考文献
- Scilla Documentation
https://scilla.readthedocs.io/en/latest/ - Create a smart contract on Zilliqa in 12 simple steps with the new Scilla IDE
https://blog.zilliqa.com/budil-savant-ide-566cf6d50c07 - Scilla IDE
https://savant-ide.zilliqa.com/ - Zilliqa Gitter
https://gitter.im/Zilliqa/