Truffleを使ってEthereumでペットショップアプリを作る〜前半：コントラクトの実装＆テスト〜

#はじめに
Truffleのチュートリアルをひたすらやっていくだけです。
[ETHEREUM PET SHOP](http://truffleframework.com/tutorials/pet-shop#ethereum-pet-shop)


**事前に用意しておくもの**
Node.js(6以上)

#Truffleのインストールとプロジェクトの作成
Truffle＝トリュフ　です。
絵柄的にきのこのトリュフじゃなくて、チョコだと思います。

npmを使ってインストールします。

```bash
$ npm install-g truffle
```

今回は`work`フォルダの下に`pet-shop`フォルダを作ってプロジェクトとします。
通常は`truffle init`でプロジェクトを作成するのですが、Truffle Boxという、テンプレみたいなのがあるらしく、その中にチュートリアルのペットショップ用のものがあるようなので今回はこれにします。
[Truffle Boxes](http://truffleframework.com/boxes/)

```bash
$ cd work
$ mkdir pet-shop
$ cd pet-shop
$ truffle unbox pet-shop
```
`pet-shop`フォルダの中にいろんなものができました。


#Ganacheのインストール
開発環境用のチェーンを作ったりGUIで見えるようにするやつだそうです。
ガナッシュがなんなのかわかりませんが、きっとお菓子なのでしょう。
gethだけでやってるときはターミナル画面にひたすらマトリックスみたいなのが流れて、アカウントなどはひたすら`eth.accounts`とかを打ってましたがそれが見えるようになるなんて楽ですね。

こちらからダウンロードします。
[Ganache](http://truffleframework.com/ganache/)

インストールしたら起動しておきます。
ポートはデフォルトで`7545`が開放されているかと思うのでこれはこのままで。


#コントラクトの記述
コントラクトは`contracts`フォルダの中に入れていきます。
`adoption.sol`を作成して、記述していきます。

```bash
$ touch contracts/Adoption.sol
```
```:Adoption.sol
pragma solidity ^0.4.2;

contract Adoption{

    // 変数宣言
    address[16] public adopters;
}
```

`pragma~`は`Migration.sol`にあわせて`^0.4.2`にしてみました。
Solidity?スマートコントラクト?Ethereum?の「お作法」に則り、コントラクトに関わるものは大文字で記述します。
ちなみに`adopt`は「採用する」というイメージが強いですが、ペットを飼うという意味もあるみたいです。

今回は「16匹が売り場に並んでおり、それぞれに飼い主がつく」という想定らしく、アドレス型で16個のarrayが宣言されています。
`adopters[0]`から`adopters[15]`まで作成されました。
`public`なのでどこからでも呼び出せます。

このコントラクトの中に関数を書いていきます。

```:Adoption.sol
    // 整数型のpetIdを入れると結果が整数型で返ってくる関数
    function adopt(uint petId) public returns (uint){
        // ペットは16匹しかいないので、範囲外のリクエストが来たら終わりとする
        require(petId>=0 && petId<=15);

        adopters[petId] = msg.sender; //トランザクション実行者のアドレスを入れ込む

        return petId; // petIdを返す
    }
```

`msg.sender`はトランザクション実行者のアドレスを呼び出すメソッドですね。

ペットが買われていくとそれに応じて販売状況を更新しないといけないので現在の状況を取得するための関数を作ります。

```:Adoption.sol
    // adoptersの状況を取得する関数
    function getAdopters() public view returns (address[16]){
 
        return adopters;
    }
```

`view`によって読み取り専用にしています。以前は`constant`を使用していたようで、時々`constant`を使用したものを見ることがありますが、現在は`view`でいいそうで。

#コンパイル

ここまでは人間が読めるコードで書いて来ましたが、Ethereumに載せるにはバイトコードにしないといけないのでコンパイルします。

アプリケーションが入ったフォルダでTruffleのコンパイルを実行します。

```bash
$ truffle compile
```

完了すると最後に`Writing artifacts to ./build/contracts`と出てきますが、その通り、`build`というディレクトリにJSON形式でのコントラクトが生成されました。
以下のような感じでコンパイルされました。

```json:Adoption.json
"bytecode": "0x6060604052341561000f57600080fd5b6102dd8061001e6000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633de4eb171461005c57806343ae80d3146100ad5780638588b2c514610110575b600080fd5b341561006757600080fd5b61006f610147565b6040518082601060200280838360005b8381101561009a57808201518184015260208101905061007f565b5050505090500191505060405180910390f35b34156100b857600080fd5b6100ce60048080359060200190919050506101c8565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561011b57600080fd5b61013160048080359060200190919050506101fd565b6040518082815260200191505060405180910390f35b61014f610272565b60006010806020026040519081016040528092919082601080156101be576020028201915b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610174575b5050505050905090565b6000816010811015156101d757fe5b016000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008082101580156102105750600f8211155b151561021b57600080fd5b3360008360108110151561022b57fe5b0160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550819050919050565b610200604051908101604052806010905b600073ffffffffffffffffffffffffffffffffffffffff1681526020019060019003908161028357905050905600a165627a7a7230582006abed684f9643fae8cd0377c8f2066f8c3226711091ba957fb093580ac96dd00029",
  "deployedBytecode": "0x606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633de4eb171461005c57806343ae80d3146100ad5780638588b2c514610110575b600080fd5b341561006757600080fd5b61006f610147565b6040518082601060200280838360005b8381101561009a57808201518184015260208101905061007f565b5050505090500191505060405180910390f35b34156100b857600080fd5b6100ce60048080359060200190919050506101c8565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561011b57600080fd5b61013160048080359060200190919050506101fd565b6040518082815260200191505060405180910390f35b61014f610272565b60006010806020026040519081016040528092919082601080156101be576020028201915b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610174575b5050505050905090565b6000816010811015156101d757fe5b016000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008082101580156102105750600f8211155b151561021b57600080fd5b3360008360108110151561022b57fe5b0160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550819050919050565b610200604051908101604052806010905b600073ffffffffffffffffffffffffffffffffffffffff1681526020019060019003908161028357905050905600a165627a7a7230582006abed684f9643fae8cd0377c8f2066f8c3226711091ba957fb093580ac96dd00029",
  "sourceMap": "25:635:0:-;;;;;;;;;;;;;;;;;",
  "deployedSourceMap": "25:635:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;567:90;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;567:90:0;;;;;;;;;;;;;;;;48:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;164:351;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;567:90;611:11;;:::i;:::-;642:8;635:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;567:90;:::o;48:27::-;;;;;;;;;;;;;;;;;;;;;;;;;:::o;164:351::-;207:4;348:1;341:5;:8;;:21;;;;;360:2;353:5;:9;;341:21;333:30;;;;;;;;391:10;373:8;382:5;373:15;;;;;;;;;;;:28;;;;;;;;;;;;;;;;;;485:5;478:12;;164:351;;;:::o;25:635::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o",
  "source": "pragma solidity ^0.4.2;\n\ncontract Adoption{\n    address[16] public adopters;\n\n    // 整数型のpetIdを入れると結果が整数型で返ってくる関数\n    function adopt(uint petId) public returns (uint){\n\n        // ペットは16匹しかいないので、範囲外のリクエストが来たら終わりとする\n        require(petId>=0 && petId<=15);\n        adopters[petId] = msg.sender; //トランザクション実行者のアドレスを入れ込む\n\n        return petId; // petIdを返す\n    }\n\n    // adoptersの状況を取得する関数\n    function getAdopters() public view returns (address[16]){\n \n        return adopters;\n    }\n\n}",
```
メインチェーンにデプロイするとバイトコードは誰でも見ようとすれば見れる状態になってしまいます。
したがって、コード上に直接秘密鍵を書いてしまうと読み取られてしまうらしいので要注意



#マイグレーション
`migrations`の中に`2_deploy_contracts.js`を作成してマイグレーションに必要なコードを記述します。
シンプルなのでささっとvimで作成＆記述。

```bash
$ vi migrations/2_deploy_contracts.js
```

```javascript:2_deploy_contracts.js
var Adoption = artifacts.require("Adoption");

module.exports = function(deployer){
	deployer.deploy(Adoption);
};
```
意味はさっぱりわかりません。

そしてmigrateします。

```bash
$ truffle migrate
```
マイグレートされ、コントラクトがチェーン（今回はプライベートネット）の中にデプロイされました。
Ganacheを確認すると、index0のアドレスのetherが減り、`BLOCKS`のメニューを見るとなにやらブロックができ、GASが使用されていることがわかります。
<img width="1197" alt="Ganache.png" src="https://qiita-image-store.s3.amazonaws.com/0/246332/cb91d85d-2872-8a3a-fb13-811b30d870db.png">


#スマートコントラクトのテスト
ちゃんと出来てるかチェックします。
性質上、デプロイするともう未来永劫そのままで修正不可能なのでテストは必須だからなのか、Truffleにはご丁寧に、テスト用のあれこれが用意されています。
`test`フォルダができていると思うのでここにあれこれテスト用のものを作っていきます。

```bash
$ touch test/TestAdoption.sol
```

```:TestAdoption.sol
pragma solidity ^0.4.2;

import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol"; //デプロイしたアドレスを取得
import "../contracts/Adoption.sol"; //テスト対象のコントラクト

contract TestAdoption {
    Adoption adoption = Adoption(DeployedAddresses.Adoption());
}
```

`Assert.sol`ですが、Truffleに用意されてる変数の型などをチェックしてくれる関数が詰まったやつだそうです。
フルコードは[こちら](https://github.com/trufflesuite/truffle-core/blob/master/lib/testing/Assert.sol)

8番のものを試しに買ってみて、想定する数値が返されるかのテストをコンストラクトの中に追記。
全文はこんな感じ。

```:TestAdoption.sol
pragma solidity ^0.4.2;

import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";
import "../contracts/Adoption.sol";

contract TestAdoption {
    Adoption adoption = Adoption(DeployedAddresses.Adoption());

    // petIdの投入テスト
    function testUserCanAdoptPet() public {
        uint returnedId = adoption.adopt(8); //adopt関数は入れた数が返ってくるはず

        uint expected = 8; // 8を入れたら8が返ってくるはず

        // 結果が想定と正しくなかったらエラーメッセージを出す
        Assert.equal(returnedId, expected, "Adoption of pet ID 8 should be recorded.");
    }

    // 8番にきちんと飼い主のアドレスが記録されているかのテスト
    function testGetAdopterAddressByPetId() public {
        address expected = this;

        address adopter = adoption.adopters(8);

        Assert.equal(adopter, expected, "Owner of pet ID 8 should be recorded.");
    }

    // 配列の8番目にきちんと入っているかのテスト
    function testGetAdopterAddressByPetIdInArray() public {
        address expected = this;

        address[16] memory adopters = adoption.getAdopters();

        Assert.equal(adopters[8], expected, "Owner of pet ID 8 should be recorded.");
    }
}
```

テストを実行

```bash
$ truffle test
```

なんだかんだあって、こんな感じのが出てればテスト合格です。

```bash
  TestAdoption
    ✓ testUserCanAdoptPet (77ms)
    ✓ testGetAdopterAddressByPetId (64ms)
    ✓ testGetAdopterAddressByPetIdInArray (76ms)

  3 passing (999ms)
```

コントラクト部分はこれでOKなので続いてWeb UIの部分を作っていきます。
[後半へ続く](https://qiita.com/gaisho81/items/65d759d813acf7c39581)