チュートリアル用のスマートコントラクト（MetaCoin）をローカル環境にデプロイしてみる。

## はじめに
最近、仮想通貨やブロックチェーンの注目度が高まり、概念や用語（What）に関する記事はだいぶ増えてきたと思いますが、開発（How）に関する記事はまだまだ少ないので、自身の理解を深めるためにも、やったことを少しずつ発信していきたいと思います。

#### 今回やること

truffleのチュートリアルで提供されているスマートコントラクト（Metacoin.sol）をローカル環境にデプロイします。
※スマートコントラクトは既存のものを使うため、solidityの作成については触れておりません

## システム構成
ブロックチェーンの全体感を掴むために、システム概要についてサーバモデルとの比較で図示してみました。ブロックチェーンの構成要素をサーバモデルに当てはめると、以下のような位置付けになります。（私の理解なので正確でない部分があるかもしれません）

* クラウド・オンプレ環境　→　ブロックチェーンネットワーク
* サーバアプリ　→　スマートコントラクト
* データベース　→　分散台帳　

図１：サーバモデル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576521/fc95270d-bcb7-399c-61d8-f691533af732.png)

図２：ブロックチェーンモデル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576521/6b14664a-1c9e-efb6-a2dc-5a2ee6ae823e.png)

#### ブロックチェーンネットワーク
スマートコントラクトや分散台帳などブロックチェーンの構成要素を配置するための仮想的なネットワーク。イーサリアム本体やテスト用のropsten、kovan、rinkebyなどがありますが、今回はGanacheを使ってローカル環境にブロックチェーンを構築します。

#### スマートコントラクト
データモデルの定義、およびデータへの読み書きを行うAPI（ABIと呼びます）を定義するファイルであり、solidityを使って作成します。なおスマートコントラクトとやりとりするフロントエンドについてはJavaScriptで記述します（ここはサーバモデルと同じ）。

#### 分散台帳
データベースへのトランザクションログを集めた台帳。ブロックチェーン上の全てのノードが同じ台帳を保持するため、可用性が高く、データの改竄が困難。

## スマートコントラクトの開発

#### 開発環境の準備
スマートコントラクトの開発環境として[Truffle](https://trufflesuite.com/docs/truffle/)を使います。

Truffleインストール

```
npm install -g truffle
```
プロジェクトの作成。今回はMetaCoin.solがプリセットされた環境を使います。

```
mkdir MetaCoin
cd MetaCoin
truffle unbox metacoin
```
上記コマンドを投入すると、以下のディレクトリが作成されます。

```
.
├── 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
```
#### スマートコントラクトの記述
今回は既にあるコントラクト（MetaCoin.sol)を使うため、新たにスマートコントラクトは作成しませんが、新規作成する場合には/contracts下に作成します。

ちなみに「MetaCoin.sol」は独自に定義した仮想通貨（MetaCoin）を取り扱うスマートコントラクトで以下の内容となっています。

```js
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.25 <0.7.0;

import "./ConvertLib.sol";

// This is just a simple example of a coin-like contract.
// It is not standards compatible and cannot be expected to talk to other
// coin/token contracts. If you want to create a standards-compliant
// token, see: https://github.com/ConsenSys/Tokens. Cheers!

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];
	}
}
```

contract MetaCoinの中にconstructorと3つのfunctionがあります。いずれもpublic指定になっており、外部から呼び出し可能となっています。このうちsendCoinとgetBalanceをフロントエンド（後述）で使います。

##### function
* sendCoin:送金
* getBalanceInEth:残高照会（ETH単位）
* getBalance:残高照会


#### ローカルブロックチェーンの構築
ローカルブロックチェーンの構築には[Ganache](https://trufflesuite.com/ganache/)を使います。以下URLからインストーラをダウンロードしてインストールを行います。
https://trufflesuite.com/ganache/

インストールしたアプリを起動すると、ワークスペースを選択する画面が表示されます。ここで***NEW WORKSPACE***ボタンを押すと以下の設定画面が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576521/229c2b7a-6d5b-ea3d-73b8-bcfe97360ac1.png)
***WORKSPACE NAME***には適当なワークスペース名をつけます。
***TRUFFLE PROJECTS***のところには、GanacheとTruffleプロジェクトとの紐付けるために、プロジェクトのディレクトリ直下にあるtruffle-config.jsを読みこむ必要がありますが、その前に以下の記述（Ganacheが動作しているport番号をdevelopment/test環境として設定）を追加します。

```js
module.exports = {
  networks: {
   development: {
     host: "127.0.0.1",
     port: 7545,
     network_id: "*"
   },
   test: {
     host: "127.0.0.1",
     port: 7545,
     network_id: "*"
   }
  },
};
```
truffle-config.jsの編集が終わったら、***ADD PROJECT***ボタンから読み込みます。

**SAVE WORKSPACE**ボタンを押してワークスペースの構築が完了すると、テスト用のユーザアカウント（残高：100ETH）が10個作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576521/1567231e-af35-6a9d-752f-787306b0f801.png)

### デプロイ
Ganacheの構築が完了したら、MetaCoin.solをデプロイしていきます。

#### solidityファイルのコンパイル
まずは以下コマンドでsolidityファイルのコンパイルを行います。

```
truffle compile
```
コンパイルを行うと、build/contracts/配下にMetaCoin.jsonというファイルが生成されます。これはartifactと呼ばれ、スマートコントラクトのABI内容が記述されたファイルになります。後ほどフロントエンド構築の時に使います。

#### マイグレーションファイルの作成
コンパイルが完了したらGanacheへのマイグレーションを行います。マイグレーションを行う際にはマイグレーションファイルを作成する必要があります。作成したマイグレーションファイルは/migrations下に格納します。チュートリアルでは既に以下の２ファイルが作成されるため、新たに作成する必要はありません。

* 1_initial_migration.js
* 2_deploy_contracts.js

※ 1_initial_migration.jsはマイグレーション履歴を追跡するファイルでどのプロジェクトにもデフォルトで作成されます。

#### マイグレーションの実行
以下コマンドでマイグレーションを行います。

```
truffle migrate
```
マイグレーションが完了するとスマートコントラクトにアドレスが付与されます。Ganacheアプリの**CONTRUCTS**から確認できます。スマートコントラクトのアドレスはフロントエンドで使います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576521/2eea9be9-ad09-ab6a-bccd-cd725731bc1f.png)
またマイグレーションはブロックチェーンへの書き込みが伴うためガス代（ETH）がかかります。Ganacheアプリの**ACCOUNTS**を見ると、1個目のユーザアカウントのETH残高が減っていることが確認できると思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576521/fcf33115-a264-6367-48e2-2ce51bcb3576.png)


## フロントエンド
フロントエンドはJavaScriptを使って構築します。今回はReactを使いました。
以下より、truffleプロジェクトとは別の場所にgit cloneしてください。

https://github.com/sordes1219/metacoin-frontend.git

/pages/index.jsがスマートコントラクトとやりとりするファイルになります。何点か補足します。

17行目：
スマートコントラクトのアドレスを格納する変数。ここは各自の環境で異なるため、**Ganacheにデプロイしたスマートコントラクト（MetaCoin）のアドレス**に書き換えてください。

20行目：
スマートコントラクトとのやりとりは[web3](https://web3js.readthedocs.io/en/v1.7.0/index.html)というライブラリを使います。ここではweb3インスタンスをGanacheのRPC SERVERアドレスで初期化しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576521/90dd924e-9c87-5a6d-53ce-77019deb0e6f.png)

23行目：
web3インスタンスを元にスマートコントラクト接続用のインスタンスを作成しています。引数としてスマートコントラクトのアドレスとMetaCoinABIを渡しています。MetaCoinABIは/abi/metacoin_abi.jsで定義していますが、内容としては前述のMetaCoin.json内の"abi"で与えられる配列が記載されています。


42,55行目：
スマートコントラクト接続用のインスタンスを使って、sendCoin ABI/getBalance ABIを呼び出す関数です。

17行目のスマートコントラクト（MetaCoin）のアドレスを書き換えたら、npmインストール＆起動します。

```
cd metacoin-frontend
npm i
npm run dev
```

ここまでうまくいっていれば、[http://localhost:3000/](http://localhost:3000/)からフロントエンドアプリにアクセスできるはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576521/d4e22126-9f6a-d112-6122-0adedc92b77d.png)


#### フロントエンドアプリの仕様
* **MetaCoinアドレス**と**送金先アドレス**では、Ganacheで作成されたテスト用のユーザアカウント（10個）が選択できるようになっています。
* 残高には選択中のアドレスのMetaCoin残高（※ETH残高ではありません）が表示されます。初期状態では1個目のアカウントが10000Metaを保有しており、他は0Metaになっています。
* 送金先アドレスと送金額を指定して送金ボタンを押すと、Ganacheブロックチェーンに送金内容が書き込まれ、残高表示に反映されます。例えば1個目から2個目に100Meta送金した場合、1個目が9900Meta、2個目が100Metaになっているはずです。
* 送金（ブロックチェーンへの書き込み）にはガス代（ETH）がかかります。Ganacheアプリの**ACCOUNTS**を見ると送金元アカウントのETH残高が減少していると思います。なおMetaCoinの残高照会はブロックチェーンへの書き込みを行わないためガス代がかかりません。

以上です。