【Ethereum】Truffleの導入からサンプルトークンの送受信確認まで

# はじめに
今まではdappの開発を、gethを使ったプライベートネットワークで行っていたが、マシンがしょぼいためかブロック生成に時間がかかり、開発が全然進まなかった。
調べるとTruffleという素晴らしいフレームワークがあるとのことで、早速使ってみることにする。

# 環境
macOS High Sierra

# Truffleのインストール
以下のコマンドでTruffleをインストール

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

# プロジェクトの作成
Truffleを使うにはプロジェクトがないと話にならない。
ゼロから作っても良いが、まずはサンプルプロジェクトから始める。
Truffleフレームワークには、[Truffle Boxes](https://truffleframework.com/boxes)というものがあり、このサンプルアプリケーションを使ってTruffleの使い方および、dapp開発の流れを学べる。
今回は、トークンを作り、アカウント同士で交換するまでを体験できる[MetaCoin box](https://truffleframework.com/boxes/metacoin)を使ってみる。
まず、プロジェクト用のディレクトリを用意。


```
$ mkdir MetaCoin
$ cd MetaCoin/
```

そして、MetaCoin boxを取り込む

```
$ truffle unbox metacoin
Downloading...
Unpacking...
Setting up...
Unbox successful. Sweet!

Commands:

  Compile contracts: truffle compile
  Migrate contracts: truffle migrate
  Test contracts:    truffle test
```
成功すると以下のフォルダ構成が作成される。

```
$ tree 
.
├── LICENSE
├── contracts
│   ├── ConvertLib.sol
│   ├── MetaCoin.sol
│   └── Migrations.sol
├── migrations
│   ├── 1_initial_migration.js
│   └── 2_deploy_contracts.js
├── test
│   ├── TestMetacoin.sol
│   └── metacoin.js
├── truffle-config.js
└── truffle.js

3 directories, 10 files
```
`contrats/`はSolidityファイル
`migrations/`はデプロイ用のスクリプト
`test/`はテスト用のスクリプト
が格納されている。

初めてだし、どんなコントラクトなのか覗いてみる。

```solidity:contrats/MetaCoin.sol
pragma solidity ^0.4.18;

import "./ConvertLib.sol";

contract MetaCoin {
	mapping (address => uint) balances;

	event Transfer(address indexed _from, address indexed _to, uint256 _value);

	constructor() public {
		balances[tx.origin] = 10000;
	}

	function sendCoin(address receiver, uint amount) public returns(bool sufficient) {
		if (balances[msg.sender] < amount) return false;
		balances[msg.sender] -= amount;
		balances[receiver] += amount;
		emit Transfer(msg.sender, receiver, amount);
		return true;
	}

	function getBalanceInEth(address addr) public view returns(uint){
		return ConvertLib.convert(getBalance(addr),2);
	}

	function getBalance(address addr) public view returns(uint) {
		return balances[addr];
	}
}
```
MetaCoinトークンのコントラクト。
MetaCoinの送信を行う`sendCoin`、
MetaCoinとEthの変換を行う`getBalanceInEth`、
MetaCoin残高を返す`getBalance`、
だけの比較的シンプルなコントラクト。
EthとMetaCoinの変換を行う処理は、`ConvertLib.sol`でライブラリとして提供されている。

```solidity:contracts/ConvertLib.sol
pragma solidity ^0.4.4;

library ConvertLib{
	function convert(uint amount,uint conversionRate) public pure returns (uint convertedAmount)
	{
		return amount * conversionRate;
	}
}
```

`Migrations.sol`はMetaCoinコントラクトには関係なく、デプロイの履歴をブロックチェーンに保存してくれるコントラクトのようだ。
詳細は後日調べることにする。


# コントラクトのコンパイル
コントラクトのコンパイルもTruffleでできる。

```
$ truffle compile
Compiling ./contracts/ConvertLib.sol...
Compiling ./contracts/MetaCoin.sol...
Compiling ./contracts/Migrations.sol...
Writing artifacts to ./build/contracts
```
`contracts`以下の`.sol`ファイルが自動でコンパイルされ、buildフォルダ以下に`artifacts`と呼ばれるコントラクト情報を格納したファイルが生成される。

```
$ tree
.
├── LICENSE
├── build
│   └── contracts
│       ├── ConvertLib.json
│       ├── MetaCoin.json
│       └── Migrations.json
├── contracts
:
（略）
```

# テスト
コントラクトのテストもTruffleで実施できる。

```
$ truffle test ./test/TestMetacoin.sol 
Using network 'test'.

Compiling ./contracts/ConvertLib.sol...
Compiling ./contracts/MetaCoin.sol...
Compiling ./test/TestMetacoin.sol...
Compiling truffle/Assert.sol...
Compiling truffle/DeployedAddresses.sol...


  TestMetacoin
    ✓ testInitialBalanceUsingDeployedContract (73ms)
    ✓ testInitialBalanceWithNewMetaCoin (72ms)


  2 passing (692ms)
```
あらかじめ`.sol`をコンパイルしておかなくても、必要なファイルはコンパイルされてからテストが実施されるようだ。
javascriptを用いたテストは以下の通り。

```
$ truffle test ./test/metacoin.js
Using network 'test'.



  Contract: MetaCoin
    ✓ should put 10000 MetaCoin in the first account (50ms)
    ✓ should call a function that depends on a linked library (56ms)
    ✓ should send coin correctly (127ms)


  3 passing (257ms)
```
違いは、`.sol`の方はコントラクトの関数テスト。`.js`の方はネットワーク上でトークンの送受信ができているかのテストだろうか。
テスト用ソースの書き方と、`.sol`と`.js`のテストの違いについては後日調べる。


# デプロイ
Truffleには、ローカルマシンで起動するテストネットワークが備わっている。
本物のEthereumネットワークとは相互作用しないので、安心してテストができる。

デプロイのコマンドを実行。

```
$ truffle develop
Truffle Develop started at http://127.0.0.1:9545/

Accounts:
(0) 0x627306090abab3a6e1400e9345bc60c78a8bef57
(1) 0xf17f52151ebef6c7334fad080c5704d77216b732
(2) 0xc5fdf4076b8f3a5357c5e395ab970b5b54098fef
(3) 0x821aea9a577a9b44299b9c15c88cf3087f3b5544
(4) 0x0d1d4e623d10f9fba5db95830f7d3839406c6af2
(5) 0x2932b7a2355d6fecc4b5c0b6bd44cc31df247a2e
(6) 0x2191ef87e392377ec08e7c08eb105ef5448eced5
(7) 0x0f4f2ac550a1b4e2280d04c21cea7ebd822934b5
(8) 0x6330a553fc93768f612722bb8c2ec78ac90b3bbc
(9) 0x5aeda56215b167893e80b4fe645ba6d5bab767de

Private Keys:
(0) c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3
(1) ae6ae8e5ccbfb04590405997ee2d52d2b330726137b875053c36d94e974d162f
(2) 0dbbe8e4ae425a6d2687f1a7e3ba17bc98c673636790f1b8ad91193c05875ef1
(3) c88b703fb08cbea894b6aeff5a544fb92e78a18e19814cd85da83b71f772aa6c
(4) 388c684f0ba1ef5017716adb5d21a053ea8e90277d0868337519f97bede61418
(5) 659cbb0e2411a44db63778987b1e22153c086a95eb6b18bdf89de078917abc63
(6) 82d052c865f5763aad42add438569276c00d3d88a2d062d36b2bae914d58b8c8
(7) aa3680d5d48a8283413f7a108367c7299ca73f553735860a87b08f39395618b7
(8) 0f62d96d6675f32685bbdb8ac13cda7c23436f63efbb9d07700d8669ff12b7c4
(9) 8d5366123cb560bb606379f90a0bfd4769eecc0557f1b362dcae9012b548b1e5

Mnemonic: candy maple cake sugar pudding cream honey rich smooth crumble sweet treat

⚠️  Important ⚠️  : This mnemonic was created for you by Truffle. It is not secure.
Ensure you do not use it on production blockchains, or else you risk losing funds.

truffle(develop)> 
```

10個のアカウントとそのprivate keyが自動で発行される、Truffleのdevelopプロンプトで操作できるようになる。
ここでは、いままでコマンドに付けてきた`truffle`コマンドが不要になる。例えば、
`$ truffle compile`
と打っていたものが、
`truffle(develop)> compile`
で実行できる。

migrateしてみる。

```
truffle(develop)> migrate
Using network 'develop'.

Running migration: 1_initial_migration.js
  Deploying Migrations...
  ... 0xb674c966783b1c021c542dc9114fc928df0b0925b0d65a9fbc10dd79b61158b4
  Migrations: 0x8cdaf0cd259887258bc13a92c0a6da92698644c0
Saving successful migration to network...
  ... 0xd7bc86d31bee32fa3988f1c1eabce403a1b5d570340a3a9cdba53a472ee8c956
Saving artifacts...
Running migration: 2_deploy_contracts.js
  Deploying ConvertLib...
  ... 0xedec131c49eb231aaa58c9e7bd1cda0a63452ea053bc986fb211edba4e646920
  ConvertLib: 0x345ca3e014aaf5dca488057592ee47305d9b3e10
  Linking ConvertLib to MetaCoin
  Deploying MetaCoin...
  ... 0x33f1f0adcdd957fd78b78bcf1e5be5caae6a929b19c77267476a0d6f6db550be
  MetaCoin: 0xf25186b5081ff5ce73482ad761db0eb0d25abfbf
Saving successful migration to network...
  ... 0x059cf1bbc372b9348ce487de910358801bbbd1c89182853439bec0afaee6c7db
Saving artifacts...
```
migration用のスクリプトが実行され、コントラクトのアドレスが取得できた。
`MetaCoin: 0xf25186b5081ff5ce73482ad761db0eb0d25abfbf`

# トークンの送信
デプロイできたので、コントラクトのメソッドを呼び出してみる。

## `getBalance`の呼び出し：

```
truffle(develop)> MetaCoin.deployed().then(function(instance){return instance.getBalance(web3.eth.accounts[0]);}).then(function(value){return value.toNumber()});
10000

truffle(develop)> MetaCoin.deployed().then(function(instance){return instance.getBalance(web3.eth.accounts[1]);}).then(function(value){return value.toNumber()});
0
```
`account[0]`が`10000 MetaCoin`。他のアカウントが`0 MetaCoin`持っていることが確認できた。

## `getBalanceInEth`の呼び出し：
```
truffle(develop)> MetaCoin.deployed().then(function(instance){return instance.getBalanceInEth(web3.eth.accounts[0]);}).then(function(value){return value.toNumber()});
20000
```
今回は、`1 MetaCoin = 2 Eth`としたので、`20000 Eth`持っていることが確認できた。

## `sendCoin`の呼び出し：
`account[0]`から`account[1]`へ、`500 MetaCoin`送ってみる。

```
truffle(develop)> MetaCoin.deployed().then(function(instance){return instance.sendCoin(web3.eth.accounts[1], 500);});
{ tx:
   '0xa6c465de6c68c8fa29b1a7020006715d2749381421376d72ae1a1d2f6803a695',
  receipt:
   { transactionHash:
      '0xa6c465de6c68c8fa29b1a7020006715d2749381421376d72ae1a1d2f6803a695',
     transactionIndex: 0,
     blockHash:
      '0xc4eafb83f144ee3d93249895e38db546084842e1645ce4ab3126dc478029e074',
     blockNumber: 6,
     gasUsed: 51057,
     cumulativeGasUsed: 51057,
     contractAddress: null,
     logs: [ [Object] ],
     status: '0x01',
     logsBloom:
      '0x00000000000000000000000000000000010000000000000000000010000000000000000000000020000000000000000000000000000000000000000000000000000000000000000010000008000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000010000000000000000000010000000000000000000000000000000000000000010000000002000000000000000000000000000000000000002000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' },
  logs:
   [ { logIndex: 0,
       transactionIndex: 0,
       transactionHash:
        '0xa6c465de6c68c8fa29b1a7020006715d2749381421376d72ae1a1d2f6803a695',
       blockHash:
        '0xc4eafb83f144ee3d93249895e38db546084842e1645ce4ab3126dc478029e074',
       blockNumber: 6,
       address: '0xf25186b5081ff5ce73482ad761db0eb0d25abfbf',
       type: 'mined',
       event: 'Transfer',
       args: [Object] } ] }
```
トランザクション情報が出力され、ブロックにも記録されていることが確認できる。

```
truffle(develop)> MetaCoin.deployed().then(function(instance){return instance.getBalance(web3.eth.accounts[0]);}).then(function(value){return value.toNumber()});
9500
truffle(develop)> MetaCoin.deployed().then(function(instance){return instance.getBalance(web3.eth.accounts[1]);}).then(function(value){return value.toNumber()});
500
```
アカウントの残高を確認すると、確かに`account[0]`から`500 MetaCoin`減り、`account[1]`に`500 MetaCoin`増えていることが確認できた。

# さいごに
gethでメソッドの実行確認をしていたのが残念だったくらい快適に開発ができる。
いくつか発展的なチュートリアルをこなしてから、自分のdapp開発にも使ってみよう。

# 宿題
- [ ] `migration.sol`が何をしているか
- [x] テストコード`.sol`と`.js`の違い → [【Ethereum】Truffleによるコントラクトのテスト](https://qiita.com/Kumamera/items/10ee87d1f76b53e0bd82)
- [x] テストコードの書き方 → [【Ethereum】Truffleによるコントラクトのテスト](https://qiita.com/Kumamera/items/10ee87d1f76b53e0bd82)
- [x] `tx.origin`とは → [【Solidity】tx.originとmsg.senderの違い](https://qiita.com/Kumamera/items/a81de80a56340076e254)


# 参考文献
[Truffle Suite](https://truffleframework.com/docs/truffle/quickstart)