Ethereumで仮想通貨を発行する

この記事ではMac OS Sierra 10.12.4を使っています

Ethereumは、シンプルなコードで書かれた「コントラクト」を実行することで、様々なネットワークを生み出すことのできるブロックチェーンです。

コントラクトとしては「通貨を発行する」、「税金を払う」、「クラウドセールを実施する」など様々な種類のものを発行することができ、その手軽さと汎用性の高さからAugur,DAO,OmiseGOなどEthereum上でトークンを発行されたプロジェクトは多々あります。

何回かに分けてEthereumで仮想通貨を発行する、というところまでチュートリアルでやってみます。今回はgethの環境構築までを実施します。

# gethのインストール

ethereumのクライアントとして今回はgethをインストールします。goで書かれたEthereumのクライアントでメジャーなものになります。

Mac OSではhomebrewで簡単にインストールできます。


```shell-session
brew tap ethereum/ethereum
brew install ethereum
```

 あるいは、ethereumのGitHubrリポジトリよりgit cloneしてビルドする形になります。
（探せばいくらでもあるのでここは省略）

# genesisファイルの作成

json形式でブロックチェーンの元となる、genesisブロックを作成します。
genesisブロック例


```sh

{
  "nonce"      : "0x0000000000000099",
  "alloc"      : {},
  "coinbase"   : "0x0000000000000000000000000000000000000000",
  "difficulty" : "0x20000",
  "extraData"  : "",
  "gasLimit"   : "0x2fefd8",
  "mixhash"    : "0x0000000000000000000000000000000000000000000000000000000000000000",
  "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
  "timestamp"  : "0x00"
}

```

# gethを初期化する

genesisblockができたので、genesisを元にgethによって初期化、フォルダを作成します。

```sh
geth --datadir $HOME/eth/testnet init $HOME/eth/testnet/genesis.json
```
 

実行後にtreeコマンドを打つと以下のように結果が出ます。自動的にフォルダが作成されて便利ですね。

```sh
tree

├── genesis.json
├── geth
│   └── chaindata
│       ├── 000002.log
│       ├── CURRENT
│       ├── LOCK
│       ├── LOG
│       └── MANIFEST-000003
└── keystore

```
 

##RPCオプションを設定してgethを起動する

rpcオプションを追加してgethを起動します。
rpcオプションを設定することで、gethのコンソールからだけでなく、HTTP経由でリクエストの受け口を設定することができます。(rpcはremote procedure callの略)

これを設定しないと、後から仮想通貨コントラクトを実行するためのbrowser-solidityからローカルネットワークへの接続ができなくなってしまいます。

```sh
geth --networkid 2222 --nodiscover --maxpeers 0 --datadir $HOME/eth/testnet/ --rpc -rpccorsdomain "*" --rpcaddr "0.0.0.0"  console 
```

オプションの説明

* --rpc HTTP-RPC を有効にする
* --rpccorsdomain  RPC接続する接続元のIPアドレス、ポート番号を設定します。「*」を設定すると全ての接続元からアクセスを許可します。
* --rpcaddr  RPC接続の受け口のIPアドレスを設定します。デフォルトはlocalhostで、「0.0.0.0」を設定すると、全てのアクセスを受け付けます。（よしなに割り振ってくれます）
* --networkid ネットワーク識別子。0~3までは予約済だが、それ以外の数値を設定します
* --nodiscover 他のノードから検出できないようにするオプション
* --maxpeers 自分のノードに接続できるノード数。テストなので0を設定します
* console gethを実行してコンソールを起動する

他のオプションの詳細はEthereumのgithubに載っています。

Ethereumのgithub
https://github.com/ethereum/go-ethereum/wiki/Command-Line-Options
 
ローカルネットワークなので、「*」など雑に指定しておりますが、本当はIPアドレスなどをきちんと設定した方が良いです。

##アドレスを作成する

consoleが起動したら新しいアドレスを作成します。
personal.newAccountの引数はパスワードです。
"first","second"というパスで２つアドレスを作成します。

```sh
personal.newAccount("first")
0x4351987e308450b8e6d2c46031add1f4e4a4f330

personal.newAccount("second")
0xa7dc9556fdd013545ba496dd981422eaa53a0a62
```

eth.accountsでアドレスができている事を確認します。

```sh
eth.accounts
["0x4351987e308450b8e6d2c46031add1f4e4a4f330", "0xa7dc9556fdd013545ba496dd981422eaa53a0a62"]
```

確認後、後ほど実施するマイニングのために、
マイニング報酬受け取り用アドレスを設定します。

```sh
miner.setEtherbase(eth.accounts[0]) #マイニング報酬受け取り用アドレスを設定
eth.coinbase #マイニング報酬受け取り用アドレスの確認
"0x4351987e308450b8e6d2c46031add1f4e4a4f330"
```

## ローカルのテストネットワークでマイニングを実施する

最初に作ったアドレスの残高と、このネットワークのブロックが0であることを確認します。

```sh
> eth.getBalance(eth.accounts[0])  #アドレス残高0
0

> eth.blockNumber #ブロック高0
0
```

マイニングを開始します。
引数1はマイニングのためのスレッドの数です。成功するとtrueが帰ってきて、ログが流れます。

```sh
> miner.start(1)
true

> I0908 01:27:02.630945 eth/backend.go:475] Automatic pregeneration of ethash DAG ON (ethash dir: /Users/nao/.ethash)
I0908 01:27:02.630946 miner/miner.go:136] Starting mining operation (CPU=1 TOT=2)
I0908 01:27:02.631403 eth/backend.go:482] checking DAG (ethash dir: /Users/nao/.ethash)
I0908 01:27:02.642987 miner/worker.go:516] commit new work on block 1 with 0 txs & 0 uncles. Took 11.628222ms
I0908 01:27:02.644081 vendor/github.com/ethereum/ethash/ethash.go:259] Generating DAG for epoch 0 (size 1073739904) (0000000000000000000000000000000000000000000000000000000000000000)
I0908 01:27:03.696831 vendor/github.com/ethereum/ethash/ethash.go:291] Generating DAG: 0%

....
0909 10:01:52.497921 miner/worker.go:516] commit new work on block 942 with 0 txs & 0 uncles. Took 229.749µs
I0909 10:01:53.426768 miner/unconfirmed.go:105] 🔗  mined block #937 [3911fcec…] reached canonical chain
I0909 10:01:53.426836 miner/unconfirmed.go:83] 🔨  mined potential block #942 [aac320ba…], waiting for 5 blocks to confirm
```

報酬を確認します。

```sh
eth.getBalance(eth.accounts[0]) #weiで表示
4.955e+21
web3.fromWei(eth.getBalance(eth.accounts[0]),"ether") #etherで表示
4955
```

先ほどは0でしたが、4955ether溜まっていましたね。
マイニング報酬のetherが溜まったようです。
マイニングはこのまま続けておきます。

## browser-solidityからローカルのネットワークに接続する

Ethereumでは、ブラウザ上で開発できるIDEであるbrowser-solidityが存在します。
自動的なコンパイル、GUIでコントラクト発行テストも実施できる、と便利なIDEになっております。

[githubのリポジトリ](https://github.com/ethereum/browser-solidity)からbrowser-solidityを落としてきてinstallします。

開発時の安定版として提供されているのはgh-pagesブランチであるため、git clone後にブランチを切り替えます。

```sh
git clone https://github.com/ethereum/browser-solidity.git #masterを落としてくる
cd browser-solidity #落としてきたフォルダに移動
git checkout -b gh-pages origin/gh-pages # branchを切り替え
```

起動後、index.htmlをひらけばbrowser-solidityが開かれます。

<img width="1157" alt="1.png" src="https://qiita-image-store.s3.amazonaws.com/0/85120/633b5e17-6937-0197-d36d-1e605530383a.png">


右側のEnvironmentでWeb3 Providerを選択します。
どこに接続するか聞かれるので、localhostを選択しましょう。
ポート番号はgethのデフォルト、8545を指定します。

<img width="1155" alt="2.png" src="https://qiita-image-store.s3.amazonaws.com/0/85120/a1209286-c679-a50e-51fa-32f1c95384d8.png">


右側の「account」にローカルのアカウントが出てくれば成功です。
ずっとマイニングしっぱなしだったのでetherがかなり溜まっていますね。

<img width="1385" alt="3.png" src="https://qiita-image-store.s3.amazonaws.com/0/85120/92e33105-9109-deb9-da9a-258c414b22f2.png">


## browser-solidityで仮想通貨コントラクトを発行する

さて、ついにやっと仮想通貨を発行します。

まずはローカルネットワークのアドレスを使うためにgethからアカウントのアンロックを行います。
personal.unlockAccountの第1引数はアカウント、第2引数はパスフレーズ、第3引数はアンロックする秒数です。
第3引数のデフォルトは300(5分)で、0を設定すると無限になります。
アカウントのアンロックもセキュリティ上あまりよろしくはないので、開発時限定として気をつけてください。

```sh
personal.unlockAccount(eth.accounts[0],"first")
true
```

browser-solidityに[Ethereum公式チュートリアル](https://www.ethereum.org/token)から仮想通貨コントラクトコードから持ってきて貼り付けます。
EthereumはSolidityというJavaScriptライクな言語でスマートコントラクトを書いて動かします。

```
pragma solidity ^0.4.16;

contract MyToken {
    /* This creates an array with all balances */
    mapping (address => uint256) public balanceOf;

    /* Initializes contract with initial supply tokens to the creator of the contract */
    function MyToken(
        uint256 initialSupply
        ) {
        balanceOf[msg.sender] = initialSupply;              // Give the creator all initial tokens
    }

    /* Send coins */
    function transfer(address _to, uint256 _value) {
        require(balanceOf[msg.sender] >= _value);           // Check if the sender has enough
        require(balanceOf[_to] + _value >= balanceOf[_to]); // Check for overflows
        balanceOf[msg.sender] -= _value;                    // Subtract from the sender
        balanceOf[_to] += _value;                           // Add the same to the recipient
    }
}
```

function MyTokenがこのコントラクトのコンストラクタで、initialSupplyを設定して初期のトークンコントラクトを発行します。

二つ目にあるfunction transferが送り先アドレスと金額を設定する送金のための関数です。

今回は100000単位分のトークンを設定してContractを発行します。

browser-solidityの右下にある「Create」にinitialSupplyの引数100000を設定してクリックします。


10~20秒ほどして、マイニングが完了すると、使用したgasの代金、変数や関数のボックスが右下に現れます。

うまくいかない場合は、コンソール側でマイニングが走っているか確認してみてください。

<img width="1133" alt="4.png" src="https://qiita-image-store.s3.amazonaws.com/0/85120/6c5fcd8c-0f72-eba5-772f-84fc15c1e790.png">

balanceOfに実行したアドレスを設定してクリックし、実行してみます。
アドレスは"（ダブルクォート）で囲んで設定します。

<img width="1147" alt="5.png" src="https://qiita-image-store.s3.amazonaws.com/0/85120/8927f4fd-d475-8532-3e8d-414a3384633a.png">


MyToken100000単位ができていることが確認できますね。
あっけない感じですが、最低限のコイン発行は完了しました。

## 発行した仮想通貨を送金する

右下のtransfer関数に、「送り先アドレス」、「送金金額」を設定して実行します。
送り先アドレスには二つ目に作ったアドレス、送金金額には20000単位を設定します。
しばらくしてマイニングが完了すると送金結果が出てきます。

<img width="617" alt="6.png" src="https://qiita-image-store.s3.amazonaws.com/0/85120/ea7825cf-ba0c-0562-eaf2-b9183653190d.png">

balanceOfを先ほど同様に確認すると、1つ目のアドレスから20000単位へり、2つ目のアドレスに20000単位増えていることが確認できます。

1つ目のアドレス(20000単位減って80000単位）
<img width="640" alt="7.png" src="https://qiita-image-store.s3.amazonaws.com/0/85120/3620fada-c5a9-cc78-635e-ac81c0abfcec.png">

2つ目のアドレス(20000単位増加）
<img width="618" alt="8.png" src="https://qiita-image-store.s3.amazonaws.com/0/85120/9aa3423b-4b02-2af7-0f76-3dceddfee185.png">

送金もできることが確認できましたね。

## 感想

Ethereumで、最低限の機能に限ればこれだけでも通貨は発行できます。
Dappsと組み合わせて作成を行い、流通のプラットフォームとなるプロジェクトをいかに設計し、通貨としての機能をいかに使わせるシステムにするかが肝となると考えています。

そんなわけで近々、Dappの開発に関して（勉強して）記事を書きたいと思います。


## 参考サイト

[Ethereum公式 トークン発行](https://www.ethereum.org/token)

[browser-solidityのgithubリポジトリ](https://github.com/ethereum/browser-solidity:title)

[gethのコマンドオプション](https://github.com/ethereum/go-ethereum/wiki/Command-Line-Options:title)