DockerでTruffleとganache-cli開発環境を作ってみる

# はじめに
スマートコントラクトの開発をしようと思ったときに、
自分のPCにnodejsやtruffleなど色々なものを入れるのが嫌だったので、Dockerだけで動作する環境を作ってみました。

# 環境
OS: Windows 10

# やってみる
### 1.dockerのネットワーク作成
ganache用DockerのIPアドレスを固定化したいため、ネットワークを作成します。

```terminal
$ docker network create  --subnet=172.18.0.0/16 test_net
dfe148a3b2816882f8ac5ac7cb94a79bb4e1ef378288e43eac60515df1ddc398

$ docker network list
NETWORK ID          NAME                DRIVER              SCOPE
f379ac7c11b6        bridge              bridge              local
a7e6f4a88723        host                host                local
7fcae840c4f5        none                null                local
dfe148a3b281        test_net            bridge              local
```

### 2.ganache用のDockerを作成
[ganacheのgithubの手順](https://github.com/trufflesuite/ganache-cli)を参考に、ganacheのdockerを作成します。
今回はIPを固定にしたいので、netとipのオプションも追加します。

```terminal
$ docker run -d -p 8545:8545  --net=test_net --ip=172.18.0.5 --name gana trufflesuite/ganache-cli:latest
```

作成したコンテナのログを確認します。

```terminal
$ docker logs -f gana
Ganache CLI v6.4.1 (ganache-core: 2.5.3)
(node:1) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.

Available Accounts
==================
(0) 0x6df229104c1b6f04bbd68afd07d535d2ccadac28 (~100 ETH)
(1) 0xda69c4d9178254ab895f95ff6f21e10fab953d30 (~100 ETH)
(2) 0x9cb9366a753da47053a409e19b1b9a345fdef219 (~100 ETH)
(3) 0x4545e5c2fb9c3a2b06c43fb93e542cc6115509af (~100 ETH)
(4) 0x700b58da0966c8aa1ab71527c3bb830b3274a91b (~100 ETH)
(5) 0xc497f0fb52a11e66c2097e5488fb655f8a19ffb3 (~100 ETH)
(6) 0x16378b97cedc0f52fb71760c5bd0941bb85ea89e (~100 ETH)
(7) 0xdb24e07e637dea6cb83d37d95260434cc103333c (~100 ETH)
(8) 0x2b45f0abcc2db45c3abeef0b8a7ac79bbbfde420 (~100 ETH)
(9) 0x8b4ab25f4c53f89ca2258589d5e77cc3e8a5466d (~100 ETH)

Private Keys
==================
(0) 0x8e87218fe82c3f47073a9363dfa52916e91e435093f2443d00306ffff7895649
(1) 0xc03b19b30f56c9e46f9555057a1dbd1bd8f2286f9c527c2c658cc9b479c53e8f
(2) 0xb47ecd0895de2ef31180011b3b5d19af37486134f7b35452aeaaa6a3a7d3ff89
(3) 0x48605a21579e877e4fc10c0aa85f6c1f15870743d8d00b83c0254f20b81e8d2e
(4) 0x7f7e4248385dbb3f95f30e2a08bef3828dd55020799ea172ad096233e28ad722
(5) 0x1a582fa60c9a6faf372352ff0eef21ed93f299fd3f4d43f6e7cd0d8afd42f684
(6) 0xd0ac93cca580632ed32dd765f38259a37ae68023c9249bff88b7f9483e034fe4
(7) 0x6d52d1bcc8ef9efb94f4ca89153ec42976f826416402447a8faa161c91c0cec7
(8) 0x24515fdfcd2f459a2a1141ddf3bd11b493263b012512cdd44449762bd39a8798
(9) 0x5a6dac6fdd4bec7053b1ad983e2e3aaab85e472f1bd43a2b69e363ae260f17bf

HD Wallet
==================
Mnemonic:      salmon lunar jelly gas upgrade next involve final trigger describe auction refuse
Base HD Path:  m/44'/60'/0'/0/{account_index}

Gas Price
==================
20000000000

Gas Limit
==================
6721975

Listening on 0.0.0.0:8545
```
ちゃんと動いてそうです。
これでganacheの準備は完了です。

### 3.truffle環境の作成
ubuntuにnodejs、truffle、vimを入れていきます。
まずは、ubuntuのdockerを作成。

```terminal
docker run -it --name tr_gna --net=test_net ubuntu:18.04
```

次にnodejsを入れていきます。
今回はバージョンを変更しやすいnvmでインストールしていきます。

```terminal
$ apt-get update
$ apt-get install -y curl

$ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash
$ . ~/.bashrc
$ nvm install 10
$ nvm use 10
```

nodejsを入れたので、truffleをインストールしてきます。

```terminal
$ npm install -g truffle
```

ubunutにtruffleが入りました。
truffleで作成したファイル設定を一部変更する必要があるので、追加でvimも入れます。

```terminal
$ apt-get install -y vim
```

ここまでで、truffle用のdocker作成は完了です。
ganacheのdockerとの連携を確認したいので、サンプルのプログラムを作成します。

```terminal
$ cd
$ mkdir MetaCoin
$ cd MetaCoin
$ truffle unbox metacoin
$ ll
total 28
drwxr-xr-x 5 root root 4096 Apr  3 03:55 ./
drwx------ 1 root root 4096 Apr  3 03:55 ../
-rw-r--r-- 1 root root 1075 Apr  3 03:55 LICENSE
drwxr-xr-x 2 root root 4096 Apr  3 03:55 contracts/
drwxr-xr-x 2 root root 4096 Apr  3 03:55 migrations/
drwxr-xr-x 2 root root 4096 Apr  3 03:55 test/
-rw-r--r-- 1 root root  503 Apr  3 03:55 truffle-config.js
```
MetaCoin配下のtruffle-config.jsをganacheのdockerを参照するように変更します。

```terminal:truffle-config.js(修正前)
module.exports = {
  // Uncommenting the defaults below 
  // provides for an easier quick-start with Ganache.
  // You can also follow this format for other networks;
  // see <http://truffleframework.com/docs/advanced/configuration>
  // for more details on how to specify configuration options!
  /*
  networks: {
    development: {
      host: "127.0.0.1",
      port: 7545,
      network_id: "*"
    },
    test: {
      host: "127.0.0.1",
      port: 7545,
      network_id: "*"
    }
  }
  */
};
```
host部分にはganacheコンテナに割り振った固定IPを設定。
port部分にはganacheのログより出力されているポート番号"8545"を設定

```javascript:truffle-config.js(修正後)
module.exports = {
  // Uncommenting the defaults below 
  // provides for an easier quick-start with Ganache.
  // You can also follow this format for other networks;
  // see <http://truffleframework.com/docs/advanced/configuration>
  // for more details on how to specify configuration options!
  networks: {
    development: {
      host: "172.18.0.5",
      port: 8545,
      network_id: "*"
    },
    test: {
      host: "172.18.0.5",
      port: 8545,
      network_id: "*"
    }
  }
};
```

以上で設定完了です。
実際に動かしてみます。

### 4.動かしてみる
テストコマンドを実行してみます。

```terminal
$ truffle test ./test/TestMetacoin.sol

Compiling your contracts...
===========================
> Compiling ./contracts/ConvertLib.sol
> Compiling ./contracts/MetaCoin.sol
> Compiling ./contracts/Migrations.sol
> Compiling ./test/TestMetacoin.sol
> Artifacts written to /tmp/test-11933-4213-1ellnuw.vqf8
> Compiled successfully using:
   - solc: 0.5.0+commit.1d4f565a.Emscripten.clang



  TestMetacoin
    ✓ testInitialBalanceUsingDeployedContract (71ms)
    ✓ testInitialBalanceWithNewMetaCoin (53ms)


  2 passing (5s)

```

上手く動きました。
次にマイグレード。

```terminal
$ truffle migrate

Compiling your contracts...
===========================
> Compiling ./contracts/ConvertLib.sol
> Compiling ./contracts/MetaCoin.sol
> Compiling ./contracts/Migrations.sol
> Artifacts written to /root/MetaCoin/build/contracts
> Compiled successfully using:
   - solc: 0.5.0+commit.1d4f565a.Emscripten.clang


Starting migrations...
======================
> Network name:    'development'
> Network id:      1554263922708
> Block gas limit: 0x6691b7


1_initial_migration.js
======================

   Deploying 'Migrations'
   ----------------------
   > transaction hash:    0x93b3c0b20a73046215d3e7ad63ee2e8a8ecfdf32b731615d614b1cb40aa01eea
   > Blocks: 0            Seconds: 0
   > contract address:    0x62caC8AC9558d91432feF6dcf578524116F61Ed6
   > account:             0x6dF229104C1b6F04BBD68Afd07D535D2ccaDac28
   > balance:             99.6615823
   > gas used:            284908
   > gas price:           20 gwei
   > value sent:          0 ETH
   > total cost:          0.00569816 ETH


   > Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:          0.00569816 ETH


2_deploy_contracts.js
=====================

   Deploying 'ConvertLib'
   ----------------------
   > transaction hash:    0xa244d12e476b292969371bf60a8440f1942f18301b93dfd2ee83009d40adb073
   > Blocks: 0            Seconds: 0
   > contract address:    0x97F9Af1C95b97c26ea6b4f767aCc5b1e1bfa46E5
   > account:             0x6dF229104C1b6F04BBD68Afd07D535D2ccaDac28
   > balance:             99.6585058
   > gas used:            111791
   > gas price:           20 gwei
   > value sent:          0 ETH
   > total cost:          0.00223582 ETH


   Linking
   -------
   * Contract: MetaCoin <--> Library: ConvertLib (at address: 0x97F9Af1C95b97c26ea6b4f767aCc5b1e1bfa46E5)

   Deploying 'MetaCoin'
   --------------------
   > transaction hash:    0x4d05c81739bdc99d575782b8acdd02d7469db7377d1349ba67a35a7fadfc1733
   > Blocks: 0            Seconds: 0
   > contract address:    0x4C36EC7895F0Cb518f07CE24A2905667e770A29D
   > account:             0x6dF229104C1b6F04BBD68Afd07D535D2ccaDac28
   > balance:             99.65133436
   > gas used:            358572
   > gas price:           20 gwei
   > value sent:          0 ETH
   > total cost:          0.00717144 ETH


   > Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:          0.00940726 ETH


Summary
=======
> Total deployments:   3
> Final cost:          0.01510542 ETH
```

上手く動いていそうです。
環境構築完了です！

あとは、truffle側のDockerに共有ディレクトリを設定したり、ソースをアップロードするなどすれば、
nodejsなどを入れなくても、Docker上でスマートコントラクトの開発ができます！

### 番外編① metamaskでganacheを参照してみる

ganache起動時に表示されたニーモニックを設定。
![WS000000.JPG](https://qiita-image-store.s3.amazonaws.com/0/359665/2c27fef5-1d91-b248-88d9-6c9948b02f80.jpeg)

ganacheで作成されたアカウントを参照できました！

![WS000001.JPG](https://qiita-image-store.s3.amazonaws.com/0/359665/42c083b0-997b-d0c0-f495-f8069a6c0451.jpeg)

### 番外編② Remixでganacheを参照してみる

EnvironmentでWeb3Providerを選択。
![WS000002.JPG](https://qiita-image-store.s3.amazonaws.com/0/359665/f99368c6-5fe1-e951-5484-5be2d069b6b7.jpeg)

ganacheを参照するように設定。
![WS000003.JPG](https://qiita-image-store.s3.amazonaws.com/0/359665/7d4860f5-35ae-89a3-8020-a197ec2bf691.jpeg)

Accountを参照すると沢山アカウントが入っています。
![WS000004.JPG](https://qiita-image-store.s3.amazonaws.com/0/359665/96592ad5-a1f3-4d2b-ba60-0f50ffb6ff1e.jpeg)

Hollowが返ってくるようにデプロイして、スマートコントラクトを実行。
![WS000005.JPG](https://qiita-image-store.s3.amazonaws.com/0/359665/19edfec7-5327-3a49-3b9e-6fd9c0857846.jpeg)
ちゃんとHollowが返ってきました！

# まとめ
今回はDockerでganacheとtruffleの環境を作成してみました。
ganacheはオプションでデータの永続化など色々設定できるみたいなので、そのうちやってみたいと思います。