Ethereum コントラクトの動作を確認するまでの手順


## やりたいこと

* 手元環境（macOS Sierra）にて、できるだけ簡単にコントラクト開発環境を整えたい。
* brewで簡単インストールしたgethは1.6.xで1.5.xから仕様が変わっているので動作および開発手順を確認したい。

## Gethのインストールと環境構築

### インストール

brewを使うと簡単にインストール可能です。が、最新版（2017年8月7日時点で1.6.7）がインストールされるためgeth内でsolcが利用出来ないなど、過去のgethの動作と仕様が違うため注意が必要です。

```bash
brew tap ethereum/ethereum
brew install ethereum
```

>過去資産利用重視の人は1.5.xをソースでインストールした方がいいかもしれません。

### 初期化（Genesisブロック）

これはローカルでテストネットを利用するときにだけ必要な操作です。

#### 作業フォルダと初期ファイルの作成

作業ディレクトリを作成して、そこにGenesisブロックの情報を記述したjsonファイルを作成します。

```bash
cd
mkdir eth_private
vi ./eth_private/myGenesis.json
```

ネットワークIDは被った場合の対応としてnonceも変更しておきます。
また、configにてhomesteadBlockを0に設定しておきます。そうしないとコントラクトが[うまく動作しない場合](http://qiita.com/him0net/items/6bcc00ea2445e13a79da)があるようです。私はしばらくハマりました。

```bash
{
	"nonce": "0x0000000000000099",
	"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
	"difficulty": "0x400",
	"alloc": {},
	"coinbase": "0x3333333333333333333333333333333333333333",
	"timestamp": "0x0",
	"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
	"extraData": "0x",
	"gasLimit": "0x8000000",
	"config": {
		"homesteadBlock": 0
	}
}
```

#### 初期化

ファイルを作成したら初期化を実行します。

```bash
geth --datadir /Users/hoge/eth_private/ init /Users/hoge/eth_private/myGenesis.json
```

>hogeのところは自分のアカウント名に置き換えます。

### 起動

動作（マイニング）を開始するには必ずetherbase address(coinbase)が必要となります。いろいろな方法で指定できますが、最初に作られたaccountが設定デフォルトで設定されるのでaccountを作っておきます。

#### コンソールの起動

```bash
geth --networkid "10" --nodiscover --datadir "/Users/hoge/eth_private" console 2>> /Users/hoge/eth_private/geth_err.log
```

>networkidは既に予約されている0,1,2,3以外なら何でもOKです。

#### Accountの追加

```bash
> personal.newAccount("hoge1")
"0xcdf63ba3db701a5a5704cd5d9671b2e3076037c0"
>
> personal.newAccount("hoge2")
"0x120f06b2fa782301b8eea4ec27c146e37f075e84"
```

>hoge1, hoge2はユーザー名ではなくパスフレーズとなります。

#### Coinbaseの確認

```bash
> eth.coinbase
"0xcdf63ba3db701a5a5704cd5d9671b2e3076037c0"
```

#### マイニングしてみる

```bash
> miner.start()
null
```

#### マイニングの状態を見ている

```bash
> miner.getHashrate()
0
```

>この値が0以上ならマイニングが進んでいます。最初のカウントアップには10分くらいかかります。

#### マイニングを停止する

```bash
> miner.stop()
true
```

#### 残高を確認してみる

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

#### 送金をしてみる

まずはアカウント（送信元）をunlockします。

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

そして送金。

```bash
eth.sendTransaction({from: "0xcdf63ba3db701a5a5704cd5d9671b2e3076037c0", to: "0x120f06b2fa782301b8eea4ec27c146e37f075e84", value: web3.toWei(3, "ether")})
```

>送金を完了するにはマイニングをスタートさせておく必要があります。

#### コンソールを抜ける

```bash
> exit
```

ここまででコンソールを利用した操作はだいたいわかりました。
次に、コントラクトの開発や外部からの操作に必要なRPCに対応した状態でgethを起動する方法を見てみます。

### マイニングやRPCをONの状態で起動（+コンソール）

```bash
geth --mine --minerthreads 2 --identity "sampleNode" --rpc --rpcport 8575 --rpcapi "web3,eth,net,personal" --rpccorsdomain "*" --rpcaddr "0.0.0.0" --datadir "/Users/hoge/eth_private" --nodiscover --networkid 10 console 2>> /Users/hoge/eth_private/geth.log
```

>実際にコントラクトの開発を行う際は上記に--unlock 0,1 など、利用するアカウントを指定してunlockします（主導でも可）。

#### RPCでの接続確認

```bash
curl -X POST http://127.0.0.1:8575/  --data '{"jsonrpc":"2.0","method":"web3_clientVersion","params":[],"id":1}' -H "Content-Type: application/json"

{"jsonrpc":"2.0","id":1,"result":"Geth/sampleNode/v1.6.7-stable-ab5646c5/darwin-amd64/go1.8.3"}
```

無事にRPC経由で接続できるようです。接続を確認したら一旦exitしておきます。

>1.7.xではapplication/jsonじゃないとダメ！と怒られます。-H "Content-Type: application/json" をつけてあげましょう。

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

gethと連携してスマートコントラクトを開発する方法はいくつかありますが、ここでは一番オーソドックスなbrowser-solidity(Remix)を利用する方法を検証してみます。

なお、方法については[こちら](http://inon29.hateblo.jp/entry/2017/07/12/155443)の記事が大変参考になりました。


### Remixインストール

>nodeのバージョンを選ぶようです。8.xはNGで、7.xにしました。また、あらかじめwgetのインストールが必要。
さらにはnpm install -D babel-preset-envを実行。

```bash
git clone https://github.com/ethereum/browser-solidity
cd browser-solidity
npm install
```



### 起動

```bash
npm start
```

起動したら http://localhost:8080 にアクセスします。

### ローカルファイルの同期

Remixで編集しているファイルはWeb Storageに保存されるようです（多分）。
ファイル管理という視点では微妙なのでローカルフォルダとRemixを同期してローカルでファイルを管理できるようにします。

#### Remixdのインストール

どからでも利用できるように-gでインストールします。

```bash
npm install -g remixd
```

#### 紐付け

インストールが完了したら、同期したいPathを指定して起動させます。

```bash
remixd -S /path/to/sync
```

remixdを起動したらRemix側（ブラウザ側）でリンクボタンをクリックします。

<img src="http://www.bluecode.jp/qiita/eth01/001.png" width="600" style="border: 1px solid #aaa">

ダイアログが表示されるのでConnectを選択します。

<img src="http://www.bluecode.jp/qiita/eth01/002.png" width="600" style="border: 1px solid #aaa">

リンクボタンが緑に変わり左ペインにlocalhost（指定さたPath）が表示されます。

<img src="http://www.bluecode.jp/qiita/eth01/003.png" width="400" style="border: 1px solid #aaa">

### RPC + unlockしてgethを起動

では、デプロイ先となるgeth（プライベートネット）を起動します。
基本的には先述のRPC対応での起動と同じですが、--unlock 0,1 というオプションが追加されています。

これは、geth.accounts[0]とgeth.accounts[1]で取得できるアカウントアンロックする指定です。

>送金したりコントラクトを発行するためには、それを行うユーザーの「アンロック」が必要になります。

```bash
geth --mine --minerthreads 2 --identity "sampleNode" --rpc --rpcport 8575 --rpcapi "web3,eth,net,personal" --rpccorsdomain "*" --rpcaddr "0.0.0.0" --datadir "/Users/hoge/eth_private" --nodiscover --networkid 10 --unlock 0,1 console 2>> /Users/hoge/eth_private/geth.log
```

起動時にパスフレーズを聞いてくるので入力します。

>上記の通り操作していれば、それぞれhoge1とhoge2となっています。


### Remixからgethへの接続

Remixを起動した時点では、RemixはJavascript VMを実行環境として利用するようになっています。これを起動中のテストネットに変更してやります（もちろん、VMのままデバッグをしても問題ありません）。

左ペインでEnvironmentメニューからWeb3 Providerを選択します。

<img src="http://www.bluecode.jp/qiita/eth01/004.png" width="400" style="border: 1px solid #aaa">

接続するか？と聞いてくるのでOKを選択します。

<img src="http://www.bluecode.jp/qiita/eth01/005.png" width="400" style="border: 1px solid #aaa">

続いて表示されるダイアログで接続先のEndpoint（URL）を指定します。

>なお、私の環境ではサーバ名がlocalhostではうまく接続できず、127.0.0.1と記入する必要がありました。

<img src="http://www.bluecode.jp/qiita/eth01/006.png" width="400" style="border: 1px solid #aaa">

Accountにgethで作成したアカウントや残高が表示されれば接続できています。

<img src="http://www.bluecode.jp/qiita/eth01/007.png" width="400" style="border: 1px solid #aaa">

### HelloWorldコントラクトの実装

HelloWorldがコントラクトか？という議論はさておき、もっとも簡単なプログラムをデプロイしてみます。
下記コードをRemixのエディタ上にペーストします（私はhello.solというファイル名にしました）。

>同期フォルダにファイルを追加するのはMac側のFinderでファイルを追加するしかないようです。

```solidity
pragma solidity ^0.4.13;

contract HelloWorld{
    
    //メソッド
    function Hello() constant returns (string){
        return "Hello World";
    }
    
}
```

### デプロイ

記述が終わったら右ペインにある[Create]をクリックします。

>unlockを忘れるとcallback contain no result Error: authentication needed: password or unlockというエラーが出ます。

<img src="http://www.bluecode.jp/qiita/eth01/010.png" width="600" style="border: 1px solid #aaa">

処理が開始されると、Waiting for transaction to be mined...というメッセージが表示されます。

<img src="http://www.bluecode.jp/qiita/eth01/011.png" width="400" style="border: 1px solid #aaa">

マイニングが完了すると展開先のアドレスやその他の情報が表示されます。

<img src="http://www.bluecode.jp/qiita/eth01/012.png" width="400" style="border: 1px solid #aaa">

### 動作確認

メソッドを実行するには[Hello]という青いボタンを押します。このコントラクトは静的なものなので何の変化もありませんが、動的なメソッドであれば内容が変更されていれば値が変化します。

## geth（他の環境）からコントラクトを利用する

### アクセスに必要な情報を取得

外部からコントラクトを利用するには

* コントラクトのアドレス
* ABI（I/Fの定義情報。まあWSDLみたいな意味合いのもの）

の2つが必要です。これは、左ペインの情報から取得できます。

>Contract detailをクリックすれば詳細情報が表示されます。

アドレスは文字通りaddressの所で、ABIはInterfaceってところの情報です。

<img src="http://www.bluecode.jp/qiita/eth01/013.png" width="400" style="border: 1px solid #aaa">

### gethから利用してみる

gethのコンソールで以下のような操作をします。

* addressを登録
* abiを登録
* abiとaddressからcontract（へのアクセス）を生成
* contractの内容確認
* 内容確認（うまく生成できてないと0xとなっている）
* .call()にて実行

という流れになっています。

>なお、冒頭のGenesisブロックの生成で、"homesteadBlock": 0の記述が無いとうまく動きません(getCodeで0xが返る）でした。

```bash
>
> var address = "0xe5578dde70d8ddf6ee7372fcdb604d1f7daeb513"
undefined
>
> var abi = [{"constant":true,"inputs":[],"name":"Hello","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"}]
undefined
>
> var contract = eth.contract(abi).at(address)
undefined
>
> contract
{
  abi: [{
      constant: true,
      inputs: [],
      name: "Hello",
      outputs: [{...}],
      payable: false,
      type: "function"
  }],
  address: "0xe5578dde70d8ddf6ee7372fcdb604d1f7daeb513",
  transactionHash: null,
  Hello: function(),
  allEvents: function()
}
>
> eth.getCode(address)
"0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063bcdfe0d51461003e575b600080fd5b341561004957600080fd5b6100516100cd565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100925780820151818401525b602081019050610076565b50505050905090810190601f1680156100bf5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6100d5610111565b6040805190810160405280600b81526020017f48656c6c6f20576f726c6400000000000000000000000000000000000000000081525090505b90565b6020604051908101604052806000815250905600a165627a7a723058200088f64d820dc93d3166441a68bf7c298c0ee25a88eda9cc16e31eb509a998cb0029"
>
>
> contract.Hello.call()
"Hello World"
>
```

## その他

jsのコンソールアプリやWeb経由での利用は[こちら](http://qiita.com/zaburo/private/35757fcc688942d7b5f4)をご覧ください。