Windows10だけで気軽にEthereumの開発を試してみる。

# 趣旨
- 気軽にEthereum/SmartContract(Geth/Solidity)を試してみたい。
- でも、お金はかけたくない。
- WindowsのPCなら持ってる、Mac持ってない。
- フロントとも繋いでみたい。（Gethだけ触れれば良いわけではない）

### 方針
1. windows上に環境を作る。
1. Windows Subsystem for Linux（WSL）を使う。
1. Windows Subsystem for Linux（WSL）+ Dockerを使う。
1. Hyper-V + Dockerを使う。（Win10Proの場合）

色々考えられますが、今回は気軽さ重視で１＋２にします。

### ゴールイメージ
+ ブラウザやIDEはWindows上で動かす。
+ GethはWSLのUbuntu上で動かす。
+ プライベートチェーンを作る。
+ GethのローカルコンソールでEthereumの動作を試す。
+ 簡単なhtml＋Javascriptを書いてGethの動作を試す。
+ 簡単なSmartContractを書いてデプロイする。
+ 簡単なhtml＋Javascriptを書いてSmartContractの動作を試す。

# やること
1. [Windows側の環境整備](#1-windows側の環境整備)
    1. [Chromeの準備](#11-chromeの準備)
    1. [Remixの準備（solidity用IDE）](#12-remixの準備solidity用ide)
1. [Ubuntu on WSL on Windows側の環境整備](#2-ubuntu-on-wsl-on-windows側の環境整備)
    1. [WSLの準備](#21-wslの準備)
    1. [Ubuntuの準備](#22-ubuntuの準備)
    1. [Gethの準備](#23-gethの準備)
    1. [プライベートチェーンの準備](#24-プライベートチェーンの準備)
1. [プライベートチェーンでEthereum基本操作のお試し](#3-プライベートチェーンでethereum基本操作のお試し)
    1. [Gethコンソールの起動](#31-gethコンソールの起動)
    1. [基本操作のお試し](#32-基本操作のお試し)
1. [RPC APIでのGeth利用](#41-rpc-apiでのgeth利用)
    1. [GethのRPC APIを有効にする](#41-gethのrpc-apiを有効にする)
    1. [動作確認](#42-動作確認)
1. [フロントとGethの連携](#5-フロントとgethの連携)
    1. [連携用のhtml＋Javascriptの準備](#51-連携用のhtmljavascriptの準備)
    1. [動作確認](#52-動作確認)
1. [RemixでSmartContractお試し](#6-remixでsmartcontractお試し)
    1. [お試し用Solidity（コントラクトコード）の準備](#61-お試し用solidityコントラクトコードの準備)
    1. [Remix内のテストVMへのデプロイ](#62-remix内のテストvmへのデプロイ)
    1. [動作確認](#63-動作確認)
1. [RemixからプライベートチェーンにSmartContractをデプロイ](#7-remixからプライベートチェーンにsmartcontractをデプロイ)
    1. [Remixとプライベートネットワークの接続](#71-remixとプライベートネットワークの接続)
    1. プライベートネットワークへのデプロイ
    1. 動作確認
1. フロントとSmartContractの連携
    1. 連携用のhtml＋Javascriptの準備
    1. 動作確認

# 手順
復習を兼ねて、のんびりまとめます。


## 1. Windows側の環境整備
###    1.1. Chromeの準備
**Windows上での作業です。**
1.こちらからダウンロードします。
　https://www.google.com/intl/ja_ALL/chrome/

問題ないと思うので手順は割愛します。

###    1.2. Remixの準備（solidity用IDE）
Web版もありますが、ローカルに完結したほうが気軽なのでダウンロードします。
  <details><summary>Web版について</summary>
  こちらから利用できます。
　https://remix.ethereum.org
　Web版からプライベートネットワークに接続する場合は、Geth側のファイアウォールやグローバルIPが関連してくるので、気軽さは損なわれると思います。
  プライベートネットワークではなく、テストネットワークを使う手もあります。</details>

**Windows上での作業です。**
1.こちらからダウンロードします。
　https://github.com/ethereum/browser-solidity
　画面右の[Clone or download]ボタン　>　Download ZIP

2.ダウンロードしたファイル[browser-solidity-gh-pages.zip]を解凍します。

3.解凍したフォルダの中にある[index.html]を開きます。

## 2. Ubuntu on WSL on Windows側の環境整備
###    2.1. WSLの準備
**Windows上での作業です。**
1.WSLの有効化
　Windowsの検索窓で「Windowsの機能または有効化」と入力し、選択します。
　「Windows Subsystem for Linux」にチェックを入れます。
　再起動が必要とのメッセージが出るので、OSを再起動します。


###    2.2. Ubuntuの準備
**Windows上での作業です。**
1.Microsoft StoreよりUbuntuのダウンロード
　Windowsの検索窓で「Microsoft Store」と入力し、選択します。
　Microsoft Store右上にある検索窓で「Ubuntu」と入力し、選択します。
　表示された「Ubuntu」を選択し、入手します。

**Ubuntu上での作業です。**
2.Ubuntuの起動
　Windowsの検索窓で「Ubuntu」と入力し、選択します。
　「Ubuntu」が別ウィンドウで起動します。

3.Ubuntuの初期設定
　Ubuntu用のユーザ設定をします。
　ユーザ名とパスワードを指定します。


###    2.3. Gethの準備
**Ubuntu上での作業です。**

    $ sudo add-apt-repository -y ppa:ethereum/ethereum
    $ sudo apt-get update
    $ sudo apt-get install ethereum
    $ geth --help

参考：https://github.com/ethereum/go-ethereum/wiki/Installation-Instructions-for-Ubuntu

###    2.4. プライベートチェーンの準備
**Ubuntu上での作業です。**

```
1.作業ディレクトの準備
    $ mkdir eth_private_net

2.Genesisブロックの定義（1つ目のブロック！）
    $ vi eth_private_net/myGenesis.json
    $ cat eth_private_net/myGenesis.json
    {
      "config": {
        "chainId": 15
      },
      "nonce": "0x0000000000000042",
      "timestamp": "0x0",
      "parentHash":     "0x0000000000000000000000000000000000000000000000000000000000000000",
      "extraData": "",
      "gasLimit": "0x8000000",
      "difficulty": "0x4000",
      "mixhash":     "0x0000000000000000000000000000000000000000000000000000000000000000",
      "coinbase": "0x3333333333333333333333333333333333333333",
      "alloc": {}
    }

3.Genesisブロックの初期化
    $ geth --datadir /home/ubuntu/eth_private_net init /home/ubuntu/eth_private_net/myGenesis.json
```

参考：https://github.com/ethereum/go-ethereum/blob/master/README.md#operating-a-private-network


## 3. プライベートチェーンでEthereum基本操作のお試し
###    3.1. Gethコンソールの起動
**Ubuntu上での作業です。**

    $ geth --networkid "15" --nodiscover --datadir "/home/ubuntu/eth_private_net" console 2>> /home/ubuntu/eth_private_net/geth_err.log

###    3.2. 基本操作のお試し
**Ubuntu上のGethコンソールでの作業です。**

色々やってみましょう(*'ω')ﾉ

```
- Genesisブロックの確認
    > eth.getBlock(0)

- 次のブロックの確認　※まだ存在しないことを確認
    > eth.getBlock(1)

- アカウント作成
    > personal.newAccount("passwd00")

- 作成済みアカウントの確認
    > eth.accounts

- コインベースの確認　※マイナーが獲得したコインの格納先、デフォルトでは最初につくったアカウント
    > eth.coinbase

- コイン保持量の確認　その１
    > eth.getBalance(eth.accounts[0])

- コイン保持量の確認　その２
    > web3.fromWei(eth.getBalance(eth.accounts[0]),"wei")
    > web3.fromWei(eth.getBalance(eth.accounts[0]),"kwei")
    > web3.fromWei(eth.getBalance(eth.accounts[0]),"mwei")
    > web3.fromWei(eth.getBalance(eth.accounts[0]),"gwei")
    > web3.fromWei(eth.getBalance(eth.accounts[0]),"microether")
    > web3.fromWei(eth.getBalance(eth.accounts[0]),"milliether")
    > web3.fromWei(eth.getBalance(eth.accounts[0]),"ether")
    > web3.fromWei(eth.getBalance(eth.accounts[0]),"kether")
    > web3.fromWei(eth.getBalance(eth.accounts[0]),"mether")
    > web3.fromWei(eth.getBalance(eth.accounts[0]),"gether")
    > web3.fromWei(eth.getBalance(eth.accounts[0]),"tether")

- マイニング開始
    > miner.start()

- マイニング状態確認　※true = マイニング中
    > eth.mining

- マイニング停止
    > miner.stop()

- 作成済みのブロック数の確認　※増えてることを確認　ブロック生成にマイニング15秒ほど
    > eth.blockNumber

- 次のブロックの確認
    > eth.getBlock(1)

- アカウント追加
    > personal.newAccount("passwd01")

- アカウントのロック解除　※送金前に送金元アカウントのロック解除が必要
    > personal.unlockAccount(eth.accounts[0])
    > Passphrase:passwd00

- コイン（ether）送金　※実行するとトランザクションIDが表示される
    > eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(100, "ether")})
    > "0x314c58b02d04ab4807fda5d82b16c0caa4e9e9c26f53791b70db930a551788da"

- トランザクションIDの確認　※BlockNumberがnullであることを確認、まだブロックに取り込まれていない
    > eth.getTransaction("0x314c58b02d04ab4807fda5d82b16c0caa4e9e9c26f53791b70db930a551788da")

- コイン保持量の確認　※送金トランザクションが成立していないので、まだ 0 etherの状態であることを確認
    > web3.fromWei(eth.getBalance(eth.accounts[1]),"ether")

- マイニング開始　※ブロックを作る、トランザクションを処理する
    > miner.start()

- マイニング停止
    > miner.stop()

- トランザクションIDの再確認　※BlockNumberを確認　どのBlockに取り込まれたかわかる
    > eth.getTransaction("0x314c58b02d04ab4807fda5d82b16c0caa4e9e9c26f53791b70db930a551788da")

- コイン保持量の確認　※送金トランザクションが成立たので、100 etherを保持していることを確認
    > web3.fromWei(eth.getBalance(eth.accounts[1]),"ether")

- アカウントのロック解除　※送金前に送金元アカウントのロック解除が必要
    > personal.unlockAccount(eth.accounts[1])
    > Passphrase:passwd01

- アカウント作成
    > personal.newAccount("passwd02")

- コイン（ether）送金
    > eth.sendTransaction({from: eth.accounts[1], to: eth.accounts[2], value: web3.toWei(50, "ether")})

- 手数料（Gas）の確認　※送金には手数料がかかる　手数料はマイナーの報酬になる
    > web3.fromWei(eth.getBalance(eth.accounts[1]),"ether")
    > web3.fromWei(eth.getBalance(eth.accounts[2]),"ether")

- Gethの終了
    > exit
```
参考：https://github.com/ethereum/go-ethereum/wiki/Management-APIs#list-of-management-apis

## 4. RPC APIでのGeth利用
###    4.1. GethのRPC APIを有効にする
**Ubuntu上での作業です。**

    $ geth --networkid "15" --nodiscover --rpc --rpcapi "eth,net,web3,admin,personal" --rpccorsdomain "*" --datadir "/home/ether/eth_private_net" console 2>> /home/ubuntu/eth_private_net/geth_err.log


 Gethが起動したら、そのままの状態にしておきます。

参考：https://github.com/ethereum/go-ethereum/blob/master/README.md#programatically-interfacing-geth-nodes

###    4.2. 動作確認
**Windows上での作業です。**
Ubuntuのアイコンを右クリック > [Ubuntu]を選択、別ウィンドウで開きます。

**Ubuntu（別ウィンドウ側）上での作業です。**

```
- APIを使ってcoinbaseを確認
    $ curl -X POST http://localhost:8545 -H 'Content-Type: application/json' --data '{"jsonrpc":"2.0","method":"eth_coinbase","params":[],"id":64}'

- APIを使って新規アカウント作成　※geth起動時に明示しないとpersonalは使えない
    $ curl -X POST http://localhost:8545 -H 'Content-Type: application/json' --data '{"jsonrpc":"2.0","method":"personal_newAccount","params":["passwd04"],"id":65}'

```
参考：
https://github.com/ethereum/go-ethereum/wiki/Management-APIs
https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_coinbase

## 5. フロントとGethの連携
###    5.1. 連携用のhtml＋Javascriptの準備
**Windows上での作業です。**
1.作業ディレクトの準備
　任意の場所に「test」フォルダを作ります。

2.sample.html作成
　「test」フォルダに「sample.html」を作成します。
　テキストエディタで「sample.html」を開き、内容が以下の通りになるよう編集します。

```
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>My test page for js-ether</title>
  <script language="javascript" type="text/javascript" src="https://cdn.jsdelivr.net/gh/ethereum/web3.js/dist/web3.min.js"></script>
  <script src="sample.js"></script>
</head>
<body>
  <h1>My test page</h1>
  <button type="button" onClick="getCoinbase();">get coinbase</button>
  <div id="coinbase"></div>
</body>

</html>
```

3.sample.js作成
　「test」フォルダに「sample.js」を作成します。
　テキストエディタで「sample.js」を開き、内容が以下の通りになるよう編集します。

```
var Web3 = require('web3');
var web3 = new Web3();
web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545'));

function getCoinbase() {
    var coinbase = web3.eth.coinbase;
    document.getElementById('coinbase').innerText = 'coinbase: ' + coinbase;
}
```

###    5.2. 動作確認
**Windows上での作業です。**
1.Chromeで「sample.html」を開きます。
　ボタンを押すとこんな感じになります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/285503/99a34f7c-a0a8-3e1c-9fe4-c9f8cf44333e.png)



## 6. RemixでSmartContractお試し
###    6.1. お試し用Solidity（コントラクトコード）の準備
**Remixでの作業です。　※起動の仕方は 1.2. Remixの準備の通りです**
1.Remixの「index.html」を開くと、ブラウザIDEとsampleコードが表示されます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/285503/a5eeaa8b-f867-c21f-f602-9964b3c1874b.png)

2.素敵なsample「Accounts.sol」を、そのまま利用させて頂きます。
　「test」フォルダに「sample2.sol」ファイルを作成し、以下の内容をコピーします。
　※文字コードをUTF-8にしておくと文字化けしません。

```
pragma solidity ^0.4.9;
 
//------------------------------------------------------------------------------
//アカウントを管理するコントラクト。以下の機能を実装する
//　・ユーザーアカウントの作成
//　・アカウントへの入金／残高確認
//　・ユーザー間の支払い
//------------------------------------------------------------------------------
contract Accounts {
    uint accountId;    //ユーザーアカウントID
    struct Account {
        address addr;  //ユーザーアドレス（今回はパスワードとして利用）
        uint balance;  //アカウント残高
    }
    mapping(uint => Account) accounts; //ユーザーアカウントの連想配列
 
    function Accounts(){ //コンストラクタ　今回は処理なし
    }
 
    //1.口座を新規作成する
    function createAccount(address _addr)returns(uint _accountId) {
        accountId += 1;
        accounts[accountId].addr = _addr;
        accounts[accountId].balance = 0;
        return accountId;
    }
 
    //2.口座に入金する
    function deposit(uint _fromAccId, address _accAddr, uint _cash)returns(bool _ret) {
        if(accounts[_fromAccId].addr != _accAddr)//アドレス値が正しくない場合は処理せず終了（アドレス値をパスワードとして利用）
            return false;
        accounts[_fromAccId].balance = accounts[_fromAccId].balance + _cash;
            return true;
    }
 
    //3.口座残高を取得（参照）する
    function getAccountInfo(uint _id)constant returns(address _addr, uint _balance) {
        return (
            accounts[_id].addr, //セキュリティ観点では本来この値を戻すのは問題：本稿ではアドレス型の値の形式を紹介するためにあえて戻り値にする
            accounts[_id].balance
            );
    }
 
    //ユーザー間で支払いをする
    function payment(uint _fromAccId, address _accAddr,  uint _toAccId, uint _money)returns (bool _ret) {
        if(accounts[_fromAccId].balance < _money)//残高不足の場合は処理せず終了
            return false;
        if(accounts[_fromAccId].addr != _accAddr)//アドレス値が正しくない場合は処理せず終了（アドレス値をパスワードとして利用）
            return false;
        accounts[_fromAccId].balance -= _money;
        accounts[_toAccId].balance += _money;
        return true;
    }
}
```

2.作成した「sample2.sol」をRemixで読み込みます。
　画面左上のフォルダアイコンから「sample2.sol」ファイルを指定してください。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/285503/07b71078-c70c-3cfb-d8c3-1bec4cff168d.png)


###    6.2. コンパイル + Remix内のテストVMへのデプロイ
**Remixでの作業です。**

1.「sample2.sol」を選択します。（ファイル名が太字になっていればOKです）
![image.png](https://qiita-image-store.s3.amazonaws.com/0/285503/2e605650-a317-f015-2e03-363b20be6c80.png)

2.「Compile」タブの「Start to compile」ボタンを押します。

3.以下の通り、「sample2.sol」で定義したContract名「Account」が表示されていることを確認します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/285503/a94b5f0e-9b63-e109-9ded-e6daeb612e0d.png)

4.「Run」タブの「Environment」の値が「JavaScript VM」になっていることを確認します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/285503/65586dc9-8850-3a25-f8d0-fc80f5a5638f.png)

5.「Run」タブのContract名の下にある「Create」ボタンを押します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/285503/a27c7f0e-93bf-c43d-c3e8-33ec483f91bb.png)

6.作成されたContractのアドレスと「sample2.sol」で定義したfunctionの情報が表示されます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/285503/553412ca-ebf0-d661-cff2-4877c11f5f3d.png)


###    6.3. 動作確認
**Remixでの作業です。**

1.ContractをデプロイしたAccount(geth側）とは別のAccount(geth側）を選択します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/285503/ab7df9dd-f96d-8180-4365-73a049f86305.png)

2.Account(geth側）表示の右にあるボタンを押し、コピーします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/285503/89490daa-e778-bbe0-6478-cd81051f65e1.png)

3.コピーしたAccount（geth側）の情報を貼り付け、Function「createAccount」実行します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/285503/39650c8d-21c8-8610-d71d-2d93dfd2631d.png)

4.Function「getAccountInfo」に、値1を入力して実行します。
　作成したAccount(Contract内）の情報が「sample2.sol」で定義した通りに表示されます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/285503/a01209e8-b5a1-ba56-d921-6c653f3b5979.png)



## 7. RemixからプライベートチェーンにSmartContractをデプロイ
###    7.1. Remixとプライベートネットワークの接続
**Remixでの作業です。　※「4.1. GethのRPC APIを有効にする」が完了している前提です**
1.「Run」タブの「Environment」を「Web3 Provider」に変更します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/285503/188599bf-de54-6032-3fef-0dca8a1e09f7.png)

2.接続先のGethを聞かれるので、`「http://localhost:8545」`を指定します。（デフォルトでOKです）
![image.png](https://qiita-image-store.s3.amazonaws.com/0/285503/d35eef0b-4099-137a-883a-074ec70a77e4.png)

3.表示されるAccount（geth側）の情報が「3.2. 基本操作のお試し」で作成したものに変わることを確認します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/285503/5f4d421b-2064-1403-9ecc-6090d8c6916d.png)



###    7.2. プライベートネットワークへのデプロイ
**Ubuntu上のGethコンソールでの作業です。**
1.下記のコマンドを実行します。

```
- アカウントのロック解除　※Contractのデプロイには、Account(Geth側）のロック解除が必要
    > personal.unlockAccount(eth.accounts[0])
    > Passphrase:passwd00

- マイニングの開始　※Contractをデプロイするトランザクションがブロックに取り込まれないと反映されない
    > miner.start()
```

**Remixでの作業です。**
2.「Run」タブのContract名の下にある「Create」ボタンを押します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/285503/a27c7f0e-93bf-c43d-c3e8-33ec483f91bb.png)


3.作成されたContractのアドレスと「sample2.sol」で定義したfunctionの情報が表示されます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/285503/553412ca-ebf0-d661-cff2-4877c11f5f3d.png)



###    7.3. 動作確認
**Remixでの作業です。**

1.Contractのアドレス確認
　「Run」タブの下の方に記載されています。こちらで確認・コピーが可能です。
　※この情報がContractとの連携時に必要になります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/285503/e2d9a516-40a8-e6c6-e221-c340157de27e.png)

2.ContractのABI確認
「Compile」タブのContract名の右にある「Details」ボタンを押します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/285503/0bc9936e-055a-bc13-fb29-3091a6ac0c81.png)

　こちらで確認・コピーが可能です。
　※この情報がContractとの連携時に必要になります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/285503/c82b43e2-fde3-a3bd-7331-10c89adaa7e7.png)

3.Function実行
　お好みで！

## 8. フロントとSmartContractの連携
###    8.1. 連携用のhtml＋Javascriptの準備
**Windows上での作業です。**


###    8.2. 動作確認
**Windows上での作業です。**
1.Chromeから確認


### 参考にさせていただいたサイト
#### WSL関連
【Windows 10 Installation Guide】
　https://docs.microsoft.com/en-us/windows/wsl/install-win10

#### Ethereum関連
【Ethereum入門】
　https://book.ethereum-jp.net/first_use/connect_to_private_net.html

【Geth】
　https://github.com/ethereum/go-ethereum

【Remix】
　https://remix.readthedocs.io/en/latest/