Solidityの開発環境を構築する

木内智史之介(シャッチョー)
ミンカさんけっこんしてくださいおねがいします(ズザー SEGAさん、DIVAの筐体ください(ズザー

Solidityとは?

イーサリアムのスマートコントラクト上で動作するアプリケーションを開発するために開発された言語です。
文法は、「JavaScriptに似ている」と言われているそうですが、僕個人の感想としては、今の所そんな印象はないですね(笑)

Crypto Zombies

Dappsの開発にあたって、Solidityの習熟は必須です。
Solidityの習熟に関しては、正直、僕のテキトーなブログを読むよりか、Crypto Zombies をプレーする方が数万倍理解が深まるので、今すぐ Crypto Zombies をプレイしてみてください!(笑)

Solidityの開発環境の構築

Crypto Zombiew を一通りプレーした開発者であれば、もう何かDappsを開発したくてソワソワしているに違いありません。 早速、Solidityの開発環境を構築するとしましょう。

エディタ

僕個人は、どの言語も大抵vimで書いてしまうので、Solidityに関しても同様にvimで書く事にします。

ひとまず、シンタックスハイライトが機能するように、 vim-solidty をインストールします。

.config/nvim/dein.toml
[[plugins]]
repo = 'tomlion/vim-solidity'

(dein を使っている事前提になっています)
他のエディタではどうすればいいかって?知らんがな。好きなエディタで好きなように書けばいいんや…!

コンパイル環境

homebrewなどで、solc(Solidityのコンパイラ)などをインストールしてもいいんですが、ローカルのマシンに開発のためのいろいろを入れるのって、バージョン管理を含めると本当に面倒ですよね。
常に最新を使えばいいのであればいいのですが、開発言語はプロジェクト毎にバージョンがマチマチだったりで…。

なので、今回は、dockerで開発環境を整えたいと思います。

docker-compose.yml
services:
solc:
image: ethereum/solc:stable
working_dir: /app
volumes:
- .:/app:cached
hello-world.sol
pragma solidity ^0.4.24;
contract HelloWorld {
function helloWorld() private pure returns (string) {
return "Hello World!!";
}
}
$ docker-compose run solc --bin hello-world.sol
======= hello-world.sol:HelloWorld =======
Binary:
6080604052348015600f57600080fd5b50603580601d6000396000f3006080604052600080fd00a165627a7a72305820308bea8df021330d1252290980a666061c2482aad2dc1fddcf08cb2b163a4a890029

これで、単純なコンパイルは行えるようになりました

テスト環境

実装したアプリケーションのテストを行うにあたって、実際にスマートコントラクト上にデプロイしないといけないとなると、ちょっと大変ですよね?
なにより、スマートコントラクト上に展開されたロジックは、以降改変不可能になります。

なので、実際にスマートコントラクト上にデプロイする前に、ローカルでテストを行えるように、「Populus」というスマートコントラクト開発フレームワークを活用してみましょう。

PopulusはまだDocker関係が整備されてないので、自前で書きます。

docker/sol/Dockerfile
FROM ethereum/solc:stable
ENV LC_ALL C.UTF-8
ENV LANG C.UTF-8
RUN apk --update add python3 python3-dev gcc make pkgconfig autoconf automake libtool \
openssl-dev libffi-dev musl-dev \
&& pip3 install --upgrade pip \
&& pip3 install populus eth-testrpc eth-abi==0.5.0 eth-utils==0.7.4 web3==3.16.5
# populusを指定してもいいが、テストの実行は `py.test` コマンドを使用するので...
ENTRYPOINT [""]
docker-compose.yml
services:
sol:
# 上記のDockerfileをDockerHubに上げてあるので、下記のように書けます
image: 8823scholar/sol
working_dir: /app
volumes:
- .:/app:cached
$ docker-compose run sol populus
Usage: populus [OPTIONS] COMMAND [ARGS]...
Populus
Options:
-p, --project PATH Specify a populus project directory
-l, --logging TEXT Specify the logging level. Allowed values are
DEBUG/INFO or their numeric equivalents 10/20
-h, --help Show this message and exit.
Commands:
chain Manage and run ethereum blockchains.
compile Compile project contracts, storing their...
config Manage and run ethereum blockchains.
deploy Deploys the specified contracts to a chain.
init Generate project layout with an example...
upgrade Upgrade a project config, and if required...

うん、インストールできた!

$ docker-compose run sol populus init
Wrote default populus configuration to `./../usr/lib/python3.6/site-packages/populus/assets/defaults.v8.config.json`.
Created Directory: ./contracts
Created Example Contract: ./contracts/Greeter.sol
Created Directory: ./tests
Created Example Tests: ./tests/test_greeter.py
# このままテストを実行するとこけるので、populusのプロジェクト設定ファイルをコピーしてくる
# 他の環境では必要ないかも
$ docker-compose run sol cp ./../usr/lib/python3.6/site-packages/populus/assets/defaults.v8.config.json project.json

初期化も問題なさそう。

$ docker-compose run sol populus compile
> Found 1 contract source files
- contracts/Greeter.sol
> Compiled 1 contracts
- contracts/Greeter.sol:Greeter
> Wrote compiled assets to: build/contracts.json

生成されたサンプルのコンパイルも問題なさそうですね!

$ docker-compose run sol py.test
================================== test session starts ===================================
platform linux -- Python 3.6.3, pytest-3.7.1, py-1.5.4, pluggy-0.7.1
rootdir: /app, inifile:
plugins: populus-2.2.0
collected 2 items
tests/test_greeter.py .. [100%]

テストの実行も問題なし!
warningが出るやもですが、ライブラリのバージョン依存関係が今うまく連携とれていないようなので、それぞれ最新でいけるようになったら解消されると思います。

さあ、デプロイをしてみましょう…!

$ docker-compose run sol populus deploy --chain tester --no-wait-for-sync
> Found 1 contract source files
- contracts/Greeter.sol
> Compiled 1 contracts
- contracts/Greeter.sol:Greeter
Please select the desired contract:
0: Greeter
: 0 # 0を入力する
Beginning contract deployment. Deploying 1 total contracts (1 Specified, 0 because of library dependencies).
Greeter
Deploying Greeter
Deploy Transaction Sent: 0xeb025f49255e5841779231b79f29fa47ae826c1965fd15765fdc9cca7160120a
Waiting for confirmation...
Transaction Mined
=================
Tx Hash : 0xeb025f49255e5841779231b79f29fa47ae826c1965fd15765fdc9cca7160120a
Address : 0xc305c901078781C232A2a521C2aF7980f8385ee9
Gas Provided : 464124
Gas Used : 364124
Verified contract bytecode @ 0xc305c901078781C232A2a521C2aF7980f8385ee9
Deployment Successful.

成功…!

上記は、ローカルのテストネット上にデプロイしているのですが、もちろんメインネットに向けてデプロイする事も可能です。

これで、Dappsを開発するための環境が整いましたね…!

振り返り

今回、Dockerで開発環境を構築したのですが、テストの実行を py.test ではなく populus test のように実行できるといいなと思いました。
その方が、docker-compose に渡す引数の数を減らせるんですよね。

あと、pip でインストールするライブラリのバージョン指定がつらいw もしかしたら、何も考えずに全て最新入れればいいようにできるのかもですが、僕の試したタイミングではダメでした。
また今度試してみようと思います。