初めてのDApps（Truffle編）

[前回](https://qiita.com/tomo1026/items/f71469dbd8786344e6fa)はMeteorを利用してDAppsを開発してみました。
今回はTruffle(トリュフ)というフレームワークで同じように試してみます。
デプロイ部分やテストなども説明しているので長文です。

#Truffleとは
Consensysが提供しているDApps開発用フレームワーク。
デプロイやテスト実行なども含めてフレームワーク化されており、ドキュメント（英語）も提供している。

参考URL:
http://truffleframework.com/
http://truffleframework.com/tutorials/

合わせてGanacheやDrizzleも提供されておりDAppsを作る上での環境が現状最も充実している。

#準備

##NodeJSのインストール
https://nodejs.org/en/ から最新版をダウンロードしてインストーラでインストールします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/113188/a1261566-ca21-b85f-98b5-b71795377624.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/113188/a2c3015e-72a1-a4cd-79a1-524983378db5.png)

##truffleのインストール

truffleはnpmコマンドでインストールします。

```bash:truffleのインストール
$ npm install -g truffle
/usr/local/bin/truffle -> /usr/local/lib/node_modules/truffle/build/cli.bundled.js
+ truffle@4.0.6
added 91 packages in 6.651s
```

```bash:truffleのバージョンの確認
$ truffle version
Truffle v4.0.6 (core: 4.0.6)
Solidity v0.4.19 (solc-js)
```

##Ganacheのインストール
ついでにGanacheというツールもダウンロードします。

http://truffleframework.com/ganache/ からインストーラーをダウンロードします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/113188/df92d438-24e6-19be-6f6e-282803582c08.png)

#プロジェクトの作成

プロジェクトを作成するには適当な場所にフォルダを作成し、その中にテンプレートのコードをダウンロードします。
今回はコンセンシスが公開しているPet Shopというテンプレートでプロジェクトを作成してみます。
Pet Shopの詳しい手順は　http://truffleframework.com/tutorials/pet-shop を参照ください。

##フォルダの作成

```bash:フォルダの作成

$ mkdir pet-shop-tutorial
$ cd pet-shop-tutorial/
```

##テンプレートのダウンロード

```bash:pet-shopテンプレートのダウンロード

$ truffle unbox pet-shop
Downloading...
Unpacking...
Setting up...
Unbox successful. Sweet!

Commands:

  Compile:        truffle compile
  Migrate:        truffle migrate
  Test contracts: truffle test
  Run dev server: npm run dev

```

テンプレートではなく空のプロジェクトを作りたい場合は以下のようにinitオプションを使用します。

```bash:空のプロジェクトを作る場合

$ truffle init

```

##プロジェクトの構造
こちらはDAppsに特化しているだけあって構造はわかりやすいです。

- contractsにsolidityのコードを追加します。
- migrationsはデプロイ用のコードです。
- srcの下は通常のWebアプリのソースコードです。
- testの下にテストコードを書いていきます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/113188/5af190c5-5a95-f4b6-f655-4e5f2cf26f9c.png)


#DAppsの作成

ここから先はPetshopのチュートリアルに従います。

##Adoption.sol の作成

![image.png](https://qiita-image-store.s3.amazonaws.com/0/113188/b7d32d1f-9340-e7e4-e241-c09fcc112004.png)

以下のコードを記載します。

```javascript:Adoption.sol
pragma solidity ^0.4.17;
contract Adoption {
  address[16] public adopters;
  // Adopting a pet
  function adopt(uint petId) public returns (uint) {
    require(petId >= 0 && petId <= 15);
    adopters[petId] = msg.sender;
    return petId;
  }
  // Retrieving the adopters
  function getAdopters() public view returns (address[16]) {
    return adopters; 
  }
}
```

##コンパイル
以下のコマンドでsolidityのコードをコンパイルします。
現在はWarningが出ますが特に問題ないのでそのまま進みます。

```bash:コンパイル
$ truffle compile
Compiling ./contracts/Adoption.sol...
Compiling ./contracts/Migrations.sol...

Compilation warnings encountered:

/Users/tomonariokubo/truffleProjects/pet-shop-tutorial/contracts/Migrations.sol:11:3: Warning: No visibility specified. Defaulting to "public".
  function Migrations() {
  ^
Spanning multiple lines.
,/Users/tomonariokubo/truffleProjects/pet-shop-tutorial/contracts/Migrations.sol:15:3: Warning: No visibility specified. Defaulting to "public".
  function setCompleted(uint completed) restricted {
  ^
Spanning multiple lines.
,/Users/tomonariokubo/truffleProjects/pet-shop-tutorial/contracts/Migrations.sol:19:3: Warning: No visibility specified. Defaulting to "public".
  function upgrade(address new_address) restricted {
  ^
Spanning multiple lines.

Writing artifacts to ./build/contracts
```

##移行スクリプトを作成
truffleではデプロイ用のスクリプトを作成する仕組みになっています。
これを一度作るとコマンドライン一行で毎回デプロイできるので便利です。

以下のように2_deploy_contracs.jsを作ります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/113188/3344f9e1-0226-2fff-0f4e-96c3de5f0c14.png)

```javascript:2_deploy_contracs.js
var Adoption = artifacts.require("Adoption");
  module.exports = function(deployer) {
  deployer.deploy(Adoption);
};
```

#デプロイ

##ブロックチェーンネットワークの開始

プライベートネットを開始するにはGanacheアイコンをクリックするだけです。
これでプライベートネットがローカル環境に開始され、マイニングも自動的に開始されます。
さらにアカウントがランダムに１０個出来上がります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/113188/a14ae2e6-2eea-1fc6-62ca-b97b92340091.png)

プライベートネットにSolidityのコードをデプロイします。

```bash:デプロイの実行
$ truffle migrate
Using network 'development'.

Running migration: 1_initial_migration.js
  Deploying Migrations...
  ... 0xa62e50bcc466353b229a9d9c4f1d61ff0c27eb3f7423174532eb9e875c318485
  Migrations: 0x8cdaf0cd259887258bc13a92c0a6da92698644c0
Saving successful migration to network...
  ... 0xd7bc86d31bee32fa3988f1c1eabce403a1b5d570340a3a9cdba53a472ee8c956
Saving artifacts...
Running migration: 2_deploy_contracts.js
  Deploying Adoption...
  ... 0x4f39b4b30e8d5283a79691f34367345f5d20ed5d1aeef99c6b44d1364ca72c22
  Adoption: 0x345ca3e014aaf5dca488057592ee47305d9b3e10
Saving successful migration to network...
  ... 0xf36163615f41ef7ed8f4a8f192149a0bf633fe1a2398ce001bf44c43dc7bdda0
Saving artifacts...
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/113188/417e06c1-3040-200a-8405-e1acedf339c3.png)

#テストスクリプトの作成

以下のようにテストスクリプトを作成し、テストを自動化することができます。

```
pragma solidity ^0.4.17;
import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";
import "../contracts/Adoption.sol";
contract TestAdoption {
  Adoption adoption = Adoption(DeployedAddresses.Adoption());
  // Testing the adopt() function
  function testUserCanAdoptPet() public {
    uint returnedId = adoption.adopt(8);
    uint expected = 8;
    Assert.equal(returnedId, expected, "Adoption of pet ID 8 should be recorded.");
  }
  // Testing retrieval of a single pet's owner
  function testGetAdopterAddressByPetId() public {
    // Expected owner is this contract
    address expected = this;
    address adopter = adoption.adopters(8);
    Assert.equal(adopter, expected, "Owner of pet ID 8 should be recorded.");
  }
  // Testing retrieval of all pet owners
  function testGetAdopterAddressByPetIdInArray() public {
    // Expected owner is this contract
    address expected = this;
    // Store adopters in memory rather than contract's storage
    address[16] memory adopters = adoption.getAdopters();
    Assert.equal(adopters[8], expected, "Owner of pet ID 8 should be recorded.");
  }
}
```


```bash:テストの実行

$ truffle test
Using network 'development'.

Compiling ./contracts/Adoption.sol...
Compiling ./test/TestAdoption.sol...
Compiling truffle/Assert.sol...
Compiling truffle/DeployedAddresses.sol...


  TestAdoption
    ✓ testUserCanAdoptPet (120ms)
    ✓ testGetAdopterAddressByPetId (202ms)
    ✓ testGetAdopterAddressByPetIdInArray (205ms)


  3 passing (1s)
```

#ブラウザで実行
##Metamaskの準備
Metamaskを新規で導入する場合は http://truffleframework.com/tutorials/pet-shop の手順に従ってもいいが、すでに使っている場合は以下の手順。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/113188/2e76bb16-68c2-db67-cb53-e7e0124e338a.png)


![image.png](https://qiita-image-store.s3.amazonaws.com/0/113188/cd647d1b-8387-43ef-ce17-92b3c80d8894.png)

##Ganacheでプライベートキーを確認

![image.png](https://qiita-image-store.s3.amazonaws.com/0/113188/8d274e53-fba4-ac5f-bbf9-7d054b04916b.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/113188/6a6b2ae9-514e-878b-682c-3fb5363fa93d.png)


![image.png](https://qiita-image-store.s3.amazonaws.com/0/113188/bab2ab2f-ce55-8d02-2da9-a1847ad30563.png)


Account4という名前で出来ました。(Account4は私の環境の場合です。また名前は自由に変更できます。）


![image.png](https://qiita-image-store.s3.amazonaws.com/0/113188/9f0fe2dd-4012-099b-37d2-f4ae5077589e.png)



```bash:ブラウザで実行
$ npm run dev
```
以下のように画面が表示されれば成功です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/113188/351860cd-8af2-5935-aa24-29bca1c0e031.png)


Adoptボタンを押すと以下のようにMetamaskのポップアップが出てきますのでSubmitをクリックします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/113188/edcdad9a-6e72-e686-c6ba-d2a0921d9f24.png)


ブラウザをリロードしてSuccessに変わっていれば成功です。


#最後に
実はこの記事を書いている最中にLoom Networkという会社が運営している以下のサイトを見つけました。
最初に見つけた際は目から鱗でした。
内容としてはSolidityの基本を学びながら最終的にはDAppsでのゲーム開発の流れが日本語で理解できます。

https://cryptozombies.io