この記事はEthereum Advent Calendar 2017の15日目の記事です。
Qiitaで記事を書くのは初めてなので、拙い部分が多いと思われますが誰かの役に立てれば幸いです。
今回はSolidityの代わりにLLLでコントラクタをコンパイルするところまでやってみます。
参考:https://media.consensys.net/the-structure-of-an-lll-contract-5adfd322be2
LLLでスマートコントラクタを書く理由
Ethereumのコントラクトは、EVM(Ethereum Virtual Machine)という仮想環境上で実行されます。SolidityやLLLで書かれたコードはバイトコードにコンパイルされてからEVMにデプロイして、初めて実行できるようになるわけですが、Ethereumにはトランザクションにgasを支払う必要があります。デプロイもトランザクションの一種なので当然gasを支払う必要が出てきます。
このgasというのは言ってしまえば手数料となりますが、当然トランザクションデータ長、デプロイする場合はバイトコード長が短い方が安く済みます。
Solidityは書きやすい反面、レイヤーが高く抽象化されています。そのためバイトコードは意図してるよりも長くなりがちです。
一方でLLLは手間がかかる一方で、アセンブラコードが容易に想像できる構造をしているので、出力されるバイトコードの長さもある程度想像できるものになります。
LLLはそういった点で優れており、またEVMやコントラクトの理解につながると思います。
環境設定
環境
Mac OS X High sierra 10.13.1
LLLコンパイラのビルドとインストール
LLLのコンパイラ(lllc)のインストールを行なっていきます
まず作業用のディレクトリにgit cloneしましょう
$ git clone --recursive https://github.com/ethereum/solidity.git
solidityディレクトリに移動します。
$ cd solidity
ビルドようのディレクトリを作成します。
$ mkdir build & cd build
solidityフォルダを指定してcmakeを実行します。
$ cmake ..
インストール
$ make install
$lllc --version LLLC, the Lovely Little Language Compiler Version: 0.4.20-develop.2017.12.4+commit.4cad0b22.Darwin.appleclang
と表示されればインストール完了です。
次からは実際にLLLでコントラクトを書いていきます。
LLLで何もしないコントラクタを書いてみる
とりあえず、何もしない、支払いを受け付けないコードを見ていきましょう。
solidityではpayable
は関数の有無で自動で判別されているので、当然バイトコード化した時にもコストを払っていることになっていますが、LLLでは判別から書いていくことでコスト削減につながります。
とりあえず、コードを見ていきましょう。
(seq
(when (callvalue) (panic))
(codecopy 0x00 (bytecodesize) 32))
(sstore 0x00 (mload 0x00)))
seq
は中括弧{}
に相当するもので、これでスコープを指定します。
(when (callvalue) (panic))
の行を見ていきます。
(when PRED BODY)
はPREDの値が0以外の時にBODYを実行することになっています。
callvalue
はcall時の引数なので何か引数があったらpanic
で実行を終了します。
続いてメモリ上にコントラクタを読み込んでいきましょう。
codecopy
ではコントラクタの場所と長さを指定することでメモリ上にコピーされます。
sstore
はメモリからストレージ上にコピーするためのものでコントラクタが永続的に機能するためのものです。mload
でメモリからコピーしてからsstore
最後でEVMのメモリ上にコピーされました。
コンパイル
lllc your_file_name.lll --hex
3415600657fe5b60206014600039600051600055
これでメモリ上に支払い不可の何もしないコントラクタがコンパイルされてバイトコードが出力されました。
ABIは何もしていないコードなので空のままです。
おわりに
ここから先に実際にコントラクタ部分を書いていく場合、情報が少ないのでLLLのリファレンスとgithubのコードを追いかけながら書いていくことがメインとなるでしょう。
またgithub上にlll-stdlib
を公開してくれている方がいるので、リファレンスと併用しながら書いていくといいと思います。
LLLのLispライクな見た目とは異なってアセンブラ単位でコードを書いていくので学習コストが思ったより高かったのですが、変更点のあまりないような細々したコントラクタをいくつか作らないといけない時にはsolidityよりもLLLの方が適しているとも感じました。
触ってみるとEVMの挙動が少しづつ理解できるので、実用レベルに到達しないまでも実際に使ってみるのも悪くないと感じました。