Win10のBash on Windows でEthreumを開発してみる（準備編）

## こんな人に向けた記事
難しい説明は抜きにして手順やTIPSだけ簡潔にまとめた記事を見ながらポチポチ試しながら理解したい人向け。

## 前提
この記事を読む前に[Win10のBash on Windows をインストール](https://qiita.com/yukio_tokuyoshi/items/042546812c663ceeccf3 "Win10のBash on Windows をインストール")を先にどうぞ。

## Ethreumと関連ツールのインストール、各種設定
### インストール
```bash
$ sudo add-apt-repository -y ppa:ethereum/ethereum
$ sudo apt update
$ sudo apt install ethereum
$ sudo apt install solc
```
### Dir準備
```bash
$ sudo mkdir /private_eth
$ sudo chmod 777 /private_eth/
```

### 初期化用ファイル準備
C:\work\genesis.json
をWindowsのディレクトリにUTF8で用意してください。とりあえず開発用なので内容は適当でOK。（viエディタ等で用意するよりWindowsのディレクトリに用意する方が楽だろうという意味合いでこっちに作成する例にしました。手順確認のため、何度もrmでディレクトリごと消して確認していた、という理由もあります。）

```json
{
"config": {
        "chainId": 123456789,
        "homesteadBlock": 0,
        "eip155Block": 0,
        "eip158Block": 0
          },
"alloc"      : {},
"coinbase"   : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x20000",
"extraData"  : "",
"gasLimit"   : "0x2fefd8",
"nonce"      : "0x0000000000000042",
"mixhash"    : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp"  : "0x00"
}
```

### genesisブロックの初期化
```bash
$ geth --datadir /private_eth init /mnt/c/work/genesis.json
```

### geth の起動
```bash
$ geth --nodiscover --datadir /private_eth
```

## gethを操作する（アカウント作成～採掘）
先ほど起動したgethを動かしたまま、別ウインドウを開いてコンソールを起動してください。

### gethコンソールを別で立ち上げる
```bash
$ geth attach /private_eth/geth.ipc
```

### アカウントがないことを確認する
ここからはgethコンソールの操作を>で説明します。

```
> eth.account
[]
```

### 新規アカウントを作成する
```
> personal.newAccount("アカウントのpassword")
```

### アカウントが作成されたことを確認する
```
> eth.account
```

### アカウントをアンロックする
採掘するためにアンロックする必要があります。パスワード聞かれますので上記で設定した"1つ目のアカウントのpassword"を入力してください。

```
> personal.unlockAccount(eth.accounts[0])
```

### 開発で使う分の採掘をする
開発用途なので必要な時だけ採掘してください。

```
> miner.start()
```

別ウインドウ側を見ましょう。実際にマイニングが開始されます。

```
INFO [04-27|13:26:24] Commit new mining work                   number=20 txs=0 uncles=0 elapsed=2.001s
INFO [04-27|13:26:24] Successfully sealed new block            number=20 hash=0fe44d…b26983
INFO [04-27|13:26:24] 🔗 block reached canonical chain          number=15 hash=c6a2b0…c88282
INFO [04-27|13:26:24] 🔨 mined potential block                  number=20 hash=0fe44d…b26983
INFO [04-27|13:26:24] Commit new mining work                   number=21 txs=0 uncles=0 elapsed=151µs
INFO [04-27|13:26:24] Successfully sealed new block            number=21 hash=b95c29…6fd59d
INFO [04-27|13:26:24] 🔗 block reached canonical chain          number=16 hash=8fcab0…0ceeb9
INFO [04-27|13:26:24] 🔨 mined potential block                  number=21 hash=b95c29…6fd59d
INFO [04-27|13:26:24] Mining too far in the future             wait=2s
```

### 採掘できているか残高を確認する

```
> eth.getBalance(eth.accounts[0])
```

### 必要ないときは採掘を止めます
後述のContractを扱うときはマイニングしている必要あるので、適宜Start、Stopしてください。

```
> miner.stop()
```

## Contractを動かす
ここからが本題。

### solファイルを用意する
C:\work\HelloWorld.sol　をUTF8で作成する

```
pragma solidity ^0.4.13;

contract HelloWorld {
    string _message;

    function setMessage(string message) {
        _message = message;
    }

    function getMessage() returns (string) {
        return _message;
    }
}
```

### solをコンパイルする
テキストに出す必要は無いのですが、ファイルに残った方が便利そうなので。

```bash
$ solc --bin --abi /mnt/c/work/HelloWorld.sol >> /mnt/c/work/HelloWorld.sol.txt
```

以下の内容のテキストが出力されます

```
======= /mnt/c/work/HelloWorld.sol:HelloWorld =======
Binary: 
608060405234801561001057600080fd5b506102d7806100206000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063368b877214610051578063ce6d41de146100ba575b600080fd5b34801561005d57600080fd5b506100b8600480360381019080803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929050505061014a565b005b3480156100c657600080fd5b506100cf610164565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561010f5780820151818401526020810190506100f4565b50505050905090810190601f16801561013c5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b8060009080519060200190610160929190610206565b5050565b606060008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156101fc5780601f106101d1576101008083540402835291602001916101fc565b820191906000526020600020905b8154815290600101906020018083116101df57829003601f168201915b5050505050905090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061024757805160ff1916838001178555610275565b82800160010185558215610275579182015b82811115610274578251825591602001919060010190610259565b5b5090506102829190610286565b5090565b6102a891905b808211156102a457600081600090555060010161028c565b5090565b905600a165627a7a723058207d10a97dd1ad400deeda71921fe9e414d354b320436b6951314567971dfc9ffc0029
Contract JSON ABI 
[{"constant":false,"inputs":[{"name":"message","type":"string"}],"name":"setMessage","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"getMessage","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]
```

### Contractをデプロイする
gethコンソールで以下コマンドを実行します。

```
> bin = "0x608060405234801561001057600080fd5b506102d7806100206000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063368b877214610051578063ce6d41de146100ba575b600080fd5b34801561005d57600080fd5b506100b8600480360381019080803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929050505061014a565b005b3480156100c657600080fd5b506100cf610164565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561010f5780820151818401526020810190506100f4565b50505050905090810190601f16801561013c5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b8060009080519060200190610160929190610206565b5050565b606060008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156101fc5780601f106101d1576101008083540402835291602001916101fc565b820191906000526020600020905b8154815290600101906020018083116101df57829003601f168201915b5050505050905090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061024757805160ff1916838001178555610275565b82800160010185558215610275579182015b82811115610274578251825591602001919060010190610259565b5b5090506102829190610286565b5090565b6102a891905b808211156102a457600081600090555060010161028c565b5090565b905600a165627a7a723058207d10a97dd1ad400deeda71921fe9e414d354b320436b6951314567971dfc9ffc0029"

> abi = [{"constant":false,"inputs":[{"name":"message","type":"string"}],"name":"setMessage","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"getMessage","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]

> contract = eth.contract(abi)

> HelloWorld = contract.new({ from: eth.accounts[0], data: bin, gas: 1000000 })
```

アンロックしていないとこのようなメッセージが出ます。採掘を止めてからしばらくするとロックされていると思いますので再度アンロックしてから実施してください。

```
> HelloWorld = contract.new({ from: eth.accounts[0], data: bin, gas: 1000000 })
Error: authentication needed: password or unlock
    at web3.js:3143:20
    at web3.js:6347:15
    at web3.js:5081:36
    at web3.js:3021:24
    at <anonymous>:1:14
```

またこのとき、マイニングしていないとブロックチェーンにとりこまれません。

```
> HelloWorld = contract.new({ from: eth.accounts[0], data: bin, gas: 1000000 })
{
  abi: [{
      constant: false,
      inputs: [{...}],
      name: "setMessage",
      outputs: [],
      payable: false,
      stateMutability: "nonpayable",
      type: "function"
  }, {
      constant: false,
      inputs: [],
      name: "getMessage",
      outputs: [{...}],
      payable: false,
      stateMutability: "nonpayable",
      type: "function"
  }],
  address: undefined,
  transactionHash: "0x2471e25618efc5c18a80537abaa939e620737301152422cfad32cda8d019d80b"
}
> HelloWorld.getMessage.call()
TypeError: Cannot access member 'call' of undefined
    at <anonymous>:1:1
```

デプロイされたかどうかはコントラクト名をタイプすればわかります。

#### 取り込み前

```
> HelloWorld
{
  abi: [{
      constant: false,
      inputs: [{...}],
      name: "setMessage",
      outputs: [],
      payable: false,
      stateMutability: "nonpayable",
      type: "function"
  }, {
      constant: false,
      inputs: [],
      name: "getMessage",
      outputs: [{...}],
      payable: false,
      stateMutability: "nonpayable",
      type: "function"
  }],
  address: undefined,
  transactionHash: "0xfb92336e24422be457bf4f0ac6bb7d2dfa1337554cb782e359898d9ec2630c78"
}
>
```

address: undefined の場合、取り込まれていません。
マイニングを再度再開して様子をみてから確認しましょう。

#### 取り込み後

```
> HelloWorld
{
  abi: [{
      constant: false,
      inputs: [{...}],
      name: "setMessage",
      outputs: [],
      payable: false,
      stateMutability: "nonpayable",
      type: "function"
  }, {
      constant: false,
      inputs: [],
      name: "getMessage",
      outputs: [{...}],
      payable: false,
      stateMutability: "nonpayable",
      type: "function"
  }],
  address: "0x2158e824b2f706f4047802d1e80740f059e1506c",
  transactionHash: "0xfb92336e24422be457bf4f0ac6bb7d2dfa1337554cb782e359898d9ec2630c78",
  allEvents: function(),
  getMessage: function(),
  setMessage: function()
}
```

それではコントラクトを動かしてみましょう。

```
> HelloWorld.setMessage.sendTransaction("test123", { from: eth.accounts[0] })
Error: authentication needed: password or unlock
    at web3.js:3143:20
    at web3.js:6347:15
    at web3.js:5081:36
    at web3.js:4137:16
    at <anonymous>:1:1
```

またもアンロックしろということで、おまじないのようにアンロックを書きたくなってきたので引数にパスワードつきで。

```
> personal.unlockAccount(eth.accounts[0], "password")
true
> HelloWorld.setMessage.sendTransaction("test123", { from: eth.accounts[0] })
"0x9a4743fa6636924c77069c1b56fe9fcea813550f05c6a609747d422da4644f70"
> HelloWorld.getMessage.call()
""
>
```

あえてこの状態はマイニング止めて行いました。マイニングを開始し、再度Getしてみます。

```
> miner.start()
> HelloWorld.getMessage.call()
"test123"
>
> miner.stop()
> personal.unlockAccount(eth.accounts[0], "password")
true
> HelloWorld.setMessage.sendTransaction("test456", { from: eth.accounts[0] })
"0x5c3218ed780130525a623a2893169e30b9f2936b2afe264ba542829ef9ce309d"
>
> HelloWorld.getMessage.call()
"test123"
>
```

はい、このようにマイニング中のみコントラクトの中に"test123"が書き込まれていました。再開すると、また内容が変わります。

```
> HelloWorld.getMessage.call()
"test123"
> miner.start()
null
> HelloWorld.getMessage.call()
"test456"
```

sendTransactionはマイニング必要、Getする（コントラクトの中の変数が書き換わらない処理）だけであればマイニング不要とわかりました。
例えばログ専用のコントラクトを作りたい場合、年ごとにプライベートノードわけておくと低負荷で参照系を運用できるなぁ、とか考えてしまいます。
長くなりましたがネットの記事を色々見て試しはしたものの随所に落とし穴があることがわかり、引っかかった部分のTIPSも含めて記載しています。
次回は実際にログ蓄積するI/FをもったContractを作成してみようと思います。