ブロックチェーンにアクセスできるウェブサイトを作ってみる

#はじめに
![image.png](https://qiita-image-store.s3.amazonaws.com/0/158180/9a663f6b-9604-98c5-25a3-182a76a412ed.png)
　[前回の記事](https://qiita.com/Yu-Nie/items/b11b3a784661a03bbb6a)ではイーサリアムで動くフリマアプリのスマートコントラクトを作成しました．Remix（スマートコントラクトの総合開発環境）からフリマアプリを実行することは可能ですが，一般ユーザーには敷居が高いかもしれません．そこで今回は名簿を作成するコントラクトをテストネットワークに公開し，ウェブサイトからアクセスするところまでをご紹介したいと思います．
　この記事で作成するウェブサイトは以下で公開しています．
https://yutaizumi.github.io/AddressSmartContract/address.html
![image.png](https://qiita-image-store.s3.amazonaws.com/0/158180/c0ba9eb7-0b4f-9b70-6238-b7e205f90662.png)

#使用するツールとライブラリ
###MetaMask
　MetaMaskはイーサリアム用のウォレットアプリで，GoogleChromeやFierFoxのアドオンとして提供されています．これを使うとイーサリアムの送金やコントラクトの実行が簡単にできます．インストール方法についてはたくさん記事が出ていますので，割愛します．例えば以下を参考にして下さい．
　[MetaMask(メタマスク)の使い方まとめ！入出金・トークン追加も超簡単](https://crypto-times.jp/metamask/)

###Remix
　現在コントラクトの開発にはsolidityという言語が最も使われています．Remixはsolidityの総合開発環境でブラウザ上で動くので，インストール作業はありません．以下にアクセスして下さい．
　https://remix.ethereum.org

###Web3js
　Web3jsはjavaScriptからブロックチェーン上の情報にアクセスするためのライブラリです．今回はCDNから読込みます．HTMLファイルに以下を記述することで利用できます．

```html
<script src="https://cdn.jsdelivr.net/gh/ethereum/web3.js@1.0.0-beta.36/dist/web3.min.js" integrity="sha256-nWBTbvxhJgjslRyuAKJHK+XcZPlCnmIAAMixz6EefVk=" crossorigin="anonymous"></script>
```

#テスト用のコントラクト
　以下は名簿を作成するためのコントラクトです．ユーザーのウォレットアドレス，名前，Emailアドレスを記録します．このコントラクトをテストネットワークに公開し，ウェブサイトからアクセス出来るようにします。

```java
pragma solidity ^0.4.23;

contract registerAccount{
    
    uint public numAccount; // アカウント番号
    
    // コンストラクタ
    constructor() public {
        numAccount = 0;
    }
    
    // アカウント情報を記録する構造体
    struct account {
        address addr; // ウォレットアドレス
        string name;  // 名前
        string email; // Emailアドレス
    }
    mapping(uint => account) public accounts;
    
    // アカウント情報を登録する関数
    function register(string _name, string _email) public {
        accounts[numAccount].addr = msg.sender;
        accounts[numAccount].name = _name;
        accounts[numAccount].email = _email;
        numAccount++;
    }
}
```

　ここで，RemixのJavaScript VMでコントラクトを実行してみます．JavaScript VMはコントラクトを疑似的に実行する環境で，マイニングやブロックチェーンへの書き込みは行われません．処理が高速でデバックに便利です。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/158180/5835d7ae-cc6b-2f62-cb3d-ea2238de0e92.png)
　Remixを起動してテキストエリアにコントラクトをコピペして下さい．コンパイラのバージョンは0.4.23+commit.124ca40dを指定します．
![image.png](https://qiita-image-store.s3.amazonaws.com/0/158180/3d4c7ba8-568f-ac79-e8fe-d3df694f09ae.png)
　次に右上のRunタブを選択し，実行環境がJavaScript VMになっていることを確認してます．"Deploy"をクリックすると，右下にコントラクトが表示されます．
![image.png](https://qiita-image-store.s3.amazonaws.com/0/158180/6400369c-655b-d4f8-58c9-cb38bdf8b263.png)
　コントラクトを選択すると，関数と変数の一覧が表示されます．registerに適当な名前とEmailを入力し"transact"をクリックしてみて下さい．その後accountsの"call"をクリックすると，情報が保存されていることが分かります．

#コントラクトをテストネットにデプロイする
　JavaScript VMでコントラクトの動作が確認できたら，イーサリアムのテストネットにコントラクトを公開します．イーサリアムにはライブネットとテストネットがあり，テストネットはコントラクトの動作確認を行うための環境です．よって，テストネット上で取引される仮想通貨は日本円やドルと交換することはできません．
　まずは，MetaMaskを起動し，Ropstenテストネットワークに接続して下さい．
![image.png](https://qiita-image-store.s3.amazonaws.com/0/158180/f05b1b6c-da9b-a06d-4460-90cb8b911fcd.png)
　コントラクトの公開や実行にはRopstenテストネットワークのEtherが必要です．以下の方法でEtherを取得します．
![image.png](https://qiita-image-store.s3.amazonaws.com/0/158180/cc709db8-3cef-a39c-b018-8cb0506c7202.png)
　"振込"をクリックし，次に"ETHERを取得する"をクリックします．
![image.png](https://qiita-image-store.s3.amazonaws.com/0/158180/9d1693b9-2953-946b-aedd-5d60ec60dcfa.png)
　"request 1 ether from faucet"をクリックして下さい．しばらく待つとウォレットに1etherが入金されます．
　MetaMaskを起動し，Ropstenテストネットワークに接続した状態でRemixを開いてください．RunタブのEmvironmentはinjected Web3を選択します．Ropstenテストネットワークに接続されていれば，右側にRopstenと表示されるはずです．
![image.png](https://qiita-image-store.s3.amazonaws.com/0/158180/259a3efa-e19a-ed78-478e-30b6525a999e.png)
　次に"Deploy"をクリックします．ここで，MetaMaskが起動し，以下の様な画面が表示されるはずです．"確認"をクリックすれば，コントラクトがテストネットワークに公開されます．
![image.png](https://qiita-image-store.s3.amazonaws.com/0/158180/903427a5-644c-f89d-1f57-bb12d819d388.png)
　Remixからコントラクトを実行する方法はJavaScript VMの場合と同じですが，実行にはetherを消費します．試しにregisterを実行してみて下さい．MetaMaskが起動するはずです．なお，変数の取得にはetherはいらないので，MetaMaskは起動しません．

#コントラクトにアクセスするウェブサイトを作成する
###入力フォームを作る
　まずは入力フォームを表示するhtmlファイルを作ります．ブラウザで表示するとこんな感じです．
![image.png](https://qiita-image-store.s3.amazonaws.com/0/158180/d9096af6-ca48-258a-2f72-88f7802b87f9.png)

```html:registerAccount.html
<!DOCTYPE html>
<html>
<title>registerAccount</title>
<head>
<meta charset="UTF-8">
<script src="https://cdn.jsdelivr.net/gh/ethereum/web3.js@1.0.0-beta.36/dist/web3.min.js" integrity="sha256-nWBTbvxhJgjslRyuAKJHK+XcZPlCnmIAAMixz6EefVk=" crossorigin="anonymous"></script></script>
<script language="javascript" type="text/javascript" src="registerAccountAbi.js"></script>
<script language="javascript" type="text/javascript" src="registerAccount.js"></script>
</head>
<body>
    ユーザー名：<br>
    <input name="UserName" id="UserName" type="text" value="" /><br>
    Eメールアドレス：<br>
    <input name="UserEmail" id="UserEmail" type="email" value="" /><br>
    <p><button onclick="registerInfo()">登録</button></p><br>
    アカウント番号：<br>
    <input name="NumAccount" id="NumAccount" type="number" value="" /><br>
    <p><button onclick="showInfo()">アカウント情報表示</button></p><br>
    <ul id="AccountInfo"></ul>
</body>
</html>
```
###スクリプトを書く
　スクリプトの解説は需要があれば追記しようと思います．ご不明な点があればコメントまたはご連絡下さい．m(__)m

```javascript:registerAccount.js
// メタマスクがインストールされているかのチェック
if (typeof web3 !== 'undefined') {
    web3js = new Web3(web3.currentProvider);
} else {
    alert("MetaMaskをインストールして下さい．");
}

// メタマスクのアドレスを取得する
web3js.eth.getAccounts(function(err, accounts) {
    coinbase = accounts[0];
    console.log("coinbase is " + coinbase);
    if (typeof coinbase === 'undefined') {
        alert("MetaMaskを起動してください．")
    }
});

// コントラクトのアドレス
// あなたがデプロイしたコントラクトのアドレスに書き換えて下さい．
const address = "0x89b88f608febd2e58c2be995e77e437c43ba1c7a";

// コントラクトのインスタンスを生成
contract = new web3js.eth.Contract(abi, address);

// アカウント登録する関数
function registerInfo() {
    // テキストボックスに入力されている情報を取得する
    var UserName = document.getElementById("UserName").value;
    var UserEmail = document.getElementById("UserEmail").value;

    // コントラクトの呼び出し
    return contract.methods.register(UserName, UserEmail)
    .send({ from: coinbase })
    .on("receipt", function(receipt){
        console.log("success");
    })
    .on("error", function(error){
            console.log("error"); 
    });
}

// アカウント情報を表示する関数
function showInfo() {
    var NumAccount = document.getElementById("NumAccount").value;
    // 表示されている情報を空にする
    sl = document.getElementById('AccountInfo');
    while(sl.lastChild) {
        sl.removeChild(sl.lastChild);
    }

    // 変数を取得する
    contract.methods.accounts(NumAccount).call().then(function(account){
        for (var i = 0; i < Object.keys(account).length/2; i++) {
            var li = document.createElement('li');
            li.textContent = Object.keys(account)[i+Object.keys(account).length/2] + " : " + account[i];
            document.getElementById('AccountInfo').appendChild(li);
        }
    });
}
```

　デプロイしたコントラクトはアドレスという固有の値を持っています．```const address```にはあなたがデプロイしたコントラクトのアドレスを指定してください．コントラクトのアドレスはRemixから取得できます．私の場合は```0x89b88f608febd2e58c2be995e77e437c43ba1c7a```でした．
![image.png](https://qiita-image-store.s3.amazonaws.com/0/158180/272c305c-fe21-c7d5-d20d-c148b66a609d.png)

###ABIを取得する
　ABIにはコントラクトの変数や関数，パラメーターなどがどのようにやり取りするのかが記録されており，コントラクトの実行や変数の取得に必要な情報です．ABIはRemixから取得できます．CompileタブのABIをクリックするとABIがクリップボードにコピーされます．registerAccount.jsという名前で保存してください．
　![image.png](https://qiita-image-store.s3.amazonaws.com/0/158180/1fe353f0-a187-bfb8-bc87-f72c151da961.png)

```json:registerAccountAbi.js
var abi = [
	{
		"constant": false,
		"inputs": [
			{
				"name": "_name",
				"type": "string"
			},
			{
				"name": "_email",
				"type": "string"
			}
		],
		"name": "register",
		"outputs": [],
		"payable": false,
		"stateMutability": "nonpayable",
		"type": "function"
	},
	{
		"constant": true,
		"inputs": [],
		"name": "numAccount",
		"outputs": [
			{
				"name": "",
				"type": "uint256"
			}
		],
		"payable": false,
		"stateMutability": "view",
		"type": "function"
	},
	{
		"constant": true,
		"inputs": [
			{
				"name": "",
				"type": "uint256"
			}
		],
		"name": "accounts",
		"outputs": [
			{
				"name": "addr",
				"type": "address"
			},
			{
				"name": "name",
				"type": "string"
			},
			{
				"name": "email",
				"type": "string"
			}
		],
		"payable": false,
		"stateMutability": "view",
		"type": "function"
	},
	{
		"inputs": [],
		"payable": false,
		"stateMutability": "nonpayable",
		"type": "constructor"
	}
]
```
###ウェブサイトの動作確認
　以上で作成した３つのファイルをワーキングフォルダに保存します．動作確認するにあたり１つ注意点があります．MetaMaskを起動した状態でWeb3ライブラリを使用しているウェブサイトを開くと，MetaMaskが接続しているネットワークが自動的に検出されます．ところが，registerAccount.htmlをダブルクリックで開いてしまうと，ftp接続されてしまいネットワークが検出されず，ブロックチェーンの情報を取得することができません．
　そこでMONGOOSE WEB SERVERを使ってregisterAccount.htmlにhttp接続します．以下から
MONGOOSE FREE EDITIONをダウンロードして下さい．
　https://cesanta.com/binary.html
使い方は簡単で，ダウンロードしたexeファイルをワーキングフォルダに保存し起動します．ワーキングフォルダ内のファイル一覧がブラウザに表示されますので，registerAccount.htmlを選択してください．
![image.png](https://qiita-image-store.s3.amazonaws.com/0/158180/c46c2d02-e48e-c7fc-5dc4-23875258ff2d.png)
　これでregisterAccount.htmlからアカウントの登録とアカウント情報の表示ができるはずです．
![image.png](https://qiita-image-store.s3.amazonaws.com/0/158180/d77c842d-23f4-a24c-bb19-d5a57e48e99c.png)

#終わりに
　使い易いユーザーインターフェースを作ったり，スマホアプリからアクセスできるようにしたいのですが，フロントエンド初心者なのでこれから勉強してスキルを身に着けていきたいと思っています．