Ethereum
mist
geth
METAMASK
Thruffle

Ethereum入門(1) - スマートコントラクトの開発環境を構築する

More than 1 year has passed since last update.

当初、Vagrantでと考えていたのですが、MISTを使う際に、ホストOSとゲストOSをつなぐ方法が面倒だったので、Ethereumの構築を色々と試してみましたが、最終的にMAC環境に落ち着きました。ここでは、スマートコントラクトの開発を行うためのソフトウェアをインストールしていきます。

  • MACへの開発環境構築
  • Homebrewのインストール
  • Nodejsのインストール
  • Geth (Go Ehtereum) のインストール
  • TestRPCのインストール
  • Thruffle のインストール
  • プライベートネットの初期化と起動
  • Gethコンソールによる操作
  • MISTのインストール
  • Metamaskのインストール

MACへの開発環境構築

まず、XCODEのインストールを行います。こちらは、単にAPPSTOREからインストールするだけです。
https://itunes.apple.com/jp/app/xcode/id497799835?mt=12
iOSやmaxOSの開発環境であるXCODEが必要な理由としては、homebrewを実行するに当たってのさまざまな開発ツールがバンドルされているからです。

続いて、xcodeをコマンドラインで扱うために、xcodeのコマンドラインツールをインストールします。

$ xcode-select --install

Homebrewのインストール

https://brew.sh/
macのパケージマネジャーであるHomebrewもインストールします。

$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Nodejsのインストール

Nodejsは、サーバーサイドで動作するjavascriptです。DApps(Decentralized Apps:分散型アプリケーション)を開発するために必要となります。

$ brew install node

Geth (Go Ehtereum) のインストール

brew tapコマンドは、非公式のリポジトリをHomebrewに追加することができます。brewコマンドを使いinstall,uninstall,updateが簡単に行えるようになります。

$ brew tap ethereum/ethereum
$ brew install ethereum

TestRPCのインストール

スマートコントラクトをテストするためのアプリケーションです。メインネットワークに配置する前に、TESTRPC上のテストチェーンで開発を行う必要があり、この時に使われるのが、TestRPCです。テストする際は、実際のチェーンではなく、このシミュレーター上で行います。

$ npm install -g ethereumjs-testrpc

Thruffle のインストール

http://truffleframework.com/
開発中のスマートコントラクトをテスト、配置するのを簡単にしてくれるフレームワークです。
- 迅速な開発のための自動契約テスト。
- スクリプト可能な、拡張可能な展開と移行のフレームワーク。
- 任意の数のパブリックネットワークとプライベートネットワークに展開するためのネットワーク管理
- ERC190規格を使用したEthPM&NPMによるパッケージ管理。
- 直接契約通信用の対話式コンソール。
- 緊密な統合をサポートする設定可能なビルドパイプライン。
- Truffle環境内でスクリプトを実行する外部スクリプトランナー。

プライベートネットワークの初期化

まずは、プライベートのチェーンを格納するためのディレクトリを作成します。

$ mkdir -p ~/applications/blockchain/privatenet

次にネットワークIDを決める
1は、メインネット、2は、Roberston テストネットワーク。
3は、mordent USテストネットワークとしてつかわれているので、それ以外を使用します。
今回は、2000を使用します。

genesis.json
{
    "coinbase": "0x0000000000000000000000000000000000000001",
    "difficulty": "0x400",
    "extraData": "",
    "gasLimit": "0xffffffff",
    "nonce": "0x0000000000000042",
    "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "timestamp": "0x00",
    "alloc": {},
    "config": {
        "chainid": 2000,
        "homesteadblock": 0,
        "eip155block": 0,
        "eip158Block": 0
    }
}

下記のコマンドで、genesisブロックを初期化します。cd で ~/applications/blockchain/privatenet のプライベートディレクトリ直下に移動してください。

$ cd ~/applications/blockchain/privatenet
$ geth --datadir ~/applications/blockchain/privatenet init ./genesis.json
Takeos-MacBook-Pro:privatenet takeo$ geth --datadir ~/applications/blockchain/privatenet init ./genesis.json
WARN [11-10|12:57:21] No etherbase set and no accounts found as default 
INFO [11-10|12:57:21] Allocated cache and file handles         database=/Users/takeo/applications/blockchain/privatenet/geth/chaindata cache=16 handles=16
INFO [11-10|12:57:21] Writing custom genesis block 
INFO [11-10|12:57:21] Successfully wrote genesis state         database=chaindata                                                      hash=17fa94…cca181
INFO [11-10|12:57:21] Allocated cache and file handles         database=/Users/takeo/applications/blockchain/privatenet/geth/lightchaindata cache=16 handles=16
INFO [11-10|12:57:21] Writing custom genesis block 
INFO [11-10|12:57:21] Successfully wrote genesis state         database=lightchaindata                                                      hash=17fa94…cca181

ここで、treeを打ち込んでみます。ディレクトリ直下にファイルが生成されているのが確認出来ます。

$ tree .
.
├── genesis.json
├── geth
│   ├── chaindata
│   │   ├── 000001.log
│   │   ├── CURRENT
│   │   ├── LOCK
│   │   ├── LOG
│   │   └── MANIFEST-000000
│   └── lightchaindata
│       ├── 000001.log
│       ├── CURRENT
│       ├── LOCK
│       ├── LOG
│       └── MANIFEST-000000
└── keystore

Gethフォルダには、全てのチェーンデータを保存します。keystoreフォルダには、全てのアカウント情報が含まれることになります。

アカウントの作成

これから、Geth上で、3つのアカウントを作成します。
1. マイニングをおこなっていくに当たって報酬を受け取るアカウント
2-3: DAppを作成する際に、使用するアカウントで、通貨ETHをやり取りするためのテスト用のアカウトです。

アカウントの作成(マイニング用)

アカウントを作成するには、account newコマンドを使います。これにより、ハッシュ化された公開鍵が作成されます。尚、パスワードは、テスト用では簡単なものでよいですが、本番で使う場合は、セキュリティ度の高いものを使用してください。

$ geth --datadir ~/applications/blockchain/privatenet account new
WARN [11-10|13:04:07] No etherbase set and no accounts found as default 
Your new account is locked with a password. Please give a password. Do not forget this password.
Passphrase:
Repeat passphrase: 
Address: {9454d424f7205e51a96305d8de04c38b3799b804}

これをあと2回繰り返します。

$ geth --datadir ~/applications/blockchain/privatenet account new
Your new account is locked with a password. Please give a password. Do not forget this password.
Passphrase:
Repeat passphrase: 
Address: {12b32e5d0c197e9ac95adab9b1eb358ca052bdd5}
$ geth --datadir ~/applications/blockchain/privatenet account new
Your new account is locked with a password. Please give a password. Do not forget this password.
Passphrase:
Repeat passphrase: 
Address: {2a398426217a32f79adbea9ac1edca6d360c40b5}

ここで、再度作成されたファイルを見てみると、Keystoreフォルダに、アカウント3つ分、UTCで始まるファイルが作成されていることがわかります。Json形式で作成されたこのファイルには、秘密鍵や公開鍵などの重要な情報が記載されています。もし誤って削除してしまうと、二度と通貨を取り戻すことができなくなります。

$ tree .
.
├── genesis.json
├── geth
│   ├── chaindata
│   │   ├── 000001.log
│   │   ├── CURRENT
│   │   ├── LOCK
│   │   ├── LOG
│   │   └── MANIFEST-000000
│   └── lightchaindata
│       ├── 000001.log
│       ├── CURRENT
│       ├── LOCK
│       ├── LOG
│       └── MANIFEST-000000
└── keystore
    ├── UTC--2017-11-10T04-04-44.233433749Z--9454d424f7205e51a96305d8de04c38b3799b804
    ├── UTC--2017-11-10T04-07-14.732579465Z--12b32e5d0c197e9ac95adab9b1eb358ca052bdd5
    └── UTC--2017-11-10T04-07-45.427245197Z--2a398426217a32f79adbea9ac1edca6d360c40b5

account list コマンドでリスト化することが出来ます。その他、updateimportなどがあるので、helpで確認してみてください。

$ geth --datadir ~/applications/blockchain/privatenet account list
Account #0: {9454d424f7205e51a96305d8de04c38b3799b804} keystore:///Users/takeo/applications/blockchain/privatenet/keystore/UTC--2017-11-10T04-04-44.233433749Z--9454d424f7205e51a96305d8de04c38b3799b804
Account #1: {12b32e5d0c197e9ac95adab9b1eb358ca052bdd5} keystore:///Users/takeo/applications/blockchain/privatenet/keystore/UTC--2017-11-10T04-07-14.732579465Z--12b32e5d0c197e9ac95adab9b1eb358ca052bdd5
Account #2: {2a398426217a32f79adbea9ac1edca6d360c40b5} keystore:///Users/takeo/applications/blockchain/privatenet/keystore/UTC--2017-11-10T04-07-45.427245197Z--2a398426217a32f79adbea9ac1edca6d360c40b5

プライベートネットワークインスタンス起動

メインネットへのノードの起動は、gethコマンド一発で可能です。また、プライベートノードのディレクトリ直下でコマンドを打ち込めば、これまた、オプションなしの、geth コマンドで起動するのですが、色々と便利なオプションもあるので、これらを使用していきます。ちなみにコマンドが長すぎるので、シェルスクリプトファイル化(startinstancenode.sh)しました。

startinstancenode.sh
geth --networkid 2000 --mine --datadir "~/applications/blockchain/privatenet" --nodiscover --rpc --rpcport "8545" --port "30303" --rpccorsdomain "*" --nat "*" --rpcapi eth,web3,personal,net --unlock 0 --password password --ipcpath "~/Library/Ethereum/geth.ipc"
Option.
networkid: genesisブロックを作成した時のIDを使います。
mine: プログラムを起動した際に、ノードが採掘作業をするかどうかを設定します。
datadir: チェーンデータが保存される場所をを指定します。指定しなければ、デフォルトの場所を示します。
nodiscover: 指定しない場合、プログラムはノードを探そうとします。この指定をすることで、ノードを探すことを停止しています。
rpc, rpcport: rpcとrpcのポート番号を指定しています。
port: 各ノードによって使用されるポートで、新しい取引とブロックを配信する際に使用されます。P2Pの為につかわれるポートとも言えます。
rpccorsdomain: IPアドレスの形式で書かれ、エンドポイントに接続するIPアドレスです。ここでは全てのノードからのIPを許可しています。
nat: ネットワークパラメータ
rpcapi: RPCエンドポイントからのAPI通信を許可するリストです。
unlock: 指定されたアカウントをアンロックします。ここでは最初のアカウントをアンロックしています。
password: アンロックするためにパスワードが必要となりますが、そのパスワードを記述したファイルを指定しています。(ここでは、パスワードをpasswordと設定しています。)
ipcpath: (*この指定は、MACOSのみに有効です。)ここには、geth.ipcへのファイルパスを指定します。

それぞれのパラーメータの意味は、以下のとおりになります。ここで注目しておきたいのは、ipcpathです。

Gethは、プログラムを起動すると、デフォルトでは、geth.ipcファイルがプライベートネットワークのフォルダ直下に作成されますが、このgeth.ipcソケットファイルの場所を指定するのが、ipcpathです。ちなみい、プログラムを終了するとこのソケットファイルは消えてなくなります。このファイルを通じてRPC経由データをやり取りすることになります。

後々、インストールすることになるMISTは、ノードのアプリケーションを起動し、 ~/Library/Ethereum/geth.ipc を作成しますが、そのソケットファイルが既にある場合は、そのファイルを通じて、ノードに接続を行う仕様となっています。

そのため、このipcpathは、MISTを開発ツールとして使う前提とした設定としています。

gethのjavascriptについては、

https://github.com/ethereum/go-ethereum/wiki/javascript-console

に詳しく記載されています。

権限を変更した上で、下記のファイルを実行します。

$ chmod a+x startinstancenode.sh
$ ./startinstancenode.sh

これにより、マイニングが開始され、PCが唸りをあげて採掘作業を開始します。

Gethコンソール

さて、プライベートネットでマイニングが開始されましたが、プライベートネットを操作するための手段が必要です。それを実現するためのものが、Gethコンソールになります。geth attachコマンドを叩くことで、コンソール画面となります。

$ geth attach
Welcome to the Geth JavaScript console!
instance: Geth/v1.7.2-stable-1db4ecdc/darwin-amd64/go1.9.2
coinbase: 0x9454d424f7205e51a96305d8de04c38b3799b804
at block: 119 (Fri, 10 Nov 2017 14:10:06 JST)
 datadir: /Users/test/applications/blockchain/privatenet
 modules: admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0

attachオプションでは、接続先のノードを指定していませんが、デフォルトでは、http://localhost:8545geth.ipcを通じて、ノードに接続します。以下のような形で、接続先を指定することも可能です。

$ geth attach ipc:/some/custom/path
$ geth attach http://localhost:8545
$ geth attach ws://191.168.1.1:8546

これでGethコンソールにアタッチできました。

Gethコンソール上の操作

Gethコンソール上の操作に移る前に、プライベートネットワークインスタンス起動時に見た、オプションを見てください。
--rpcapi eth,web3,personal,net
これは、コンソール上で、指定したapiオブジェクトを読み込むようにしています。

例えば、

> eth.accounts
["0x9454d424f7205e51a96305d8de04c38b3799b804", "0x12b32e5d0c197e9ac95adab9b1eb358ca052bdd5", "0x2a398426217a32f79adbea9ac1edca6d360c40b5"]

と打ち込むと、作成した3つのアカウントのアドレスがリスト化されます。
次に以下のように打ち込んでみてください。

> eth.getBalance(eth.coinbase)
1.78e+21

獲得したETHの残高が表示されます。web3のapiを利用してもう少しわかりやすい形式に変換します。

> web3.fromWei(eth.getBalance(eth.coinbase), "ether")
2460

数分走らせただけで、2460イーサを獲得しました!今の価値に換算すると1億くらいでしょうか!
残念ながら、プライベートのネットワークID 2000番で流通している通貨です。しかし、これを考えると、通貨を世の中に広めたイーサリアムの開発者は、とんでもない資産家になっていますね。

PCが唸りをあげて発掘作業に取り組んでいるのですが、少しうるさいので、マイニングを停止します。停止するには以下のコマンドを打ち込みます。miner.start()で再開出来ます。

> miner.stop()
true

アカウントのアンロック

アカウントを作成し、インスタンスを起動した時点では、アカウントがロックされている状態なので、ロックを解除します。

> personal.unlockAccount(eth.accounts[1], "password2", 300)
> personal.unlockAccount(eth.accounts[2])
Passphrase: 
Unlock account 0x2a398426217a32f79adbea9ac1edca6d360c40b5

各アカウントの残高を確認する

> web3.fromWei(eth.getBalance(eth.coinbase), "ether")
> web3.fromWei(eth.getBalance(eth.accounts[0]), "ether")
> web3.fromWei(eth.getBalance(eth.accounts[1]), "ether")
> web3.fromWei(eth.getBalance(eth.accounts[2]), "ether")

genesisブロックを生成した際、conibaseは、マイニングから収集されたすべての報酬が転送される160ビットのアドレスでした。

> web3.fromWei(eth.getBalance(eth.coinbase), "ether")

このコマンドでは、eth.coinbaseを指定しました。このcoinbaseは、マイニングで獲得した報酬がすべて転送される特別なコマンドとなります。gethコマンドでインスタンスを起動した際に、デフォルトで0番目のアカウントに紐付けられることにも注意してください。web3.fromWei(eth.getBalance(eth.coinbase), "ether")web3.fromWei(eth.getBalance(eth.accounts[0]), "ether") は同じ残高を示しています。 Gethコマンドでインスタンスを起動した際には、unlockオプションで、0とパスワードを指定しました。

送金する

coinbase(account[0])から、100ETHを2回、accounts[1]へ送金し、300ETHを1回、accounts[2]へ送金するコマンドです。

> eth.sendTransaction({from: eth.coinbase, to:eth.accounts[1], value: web3.toWei(100, "ether")})
> eth.sendTransaction({from: eth.coinbase, to:eth.accounts[1], value: web3.toWei(100, "ether")})
> eth.sendTransaction({from: eth.coinbase, to:eth.accounts[2], value: web3.toWei(300, "ether")})

マイニングを停止している場合は、当然ですが、値が反映されません。

> miner.start()
で、マイニングを開始して残高をチェックします。
> web3.fromWei(eth.getBalance(eth.accounts[1]), "ether")
200
> web3.fromWei(eth.getBalance(eth.accounts[2]), "ether")
300

プライベートネットの起動からマイニングを行いつつ、Gethコンソールでアカウントの操作を行いました。一旦、Gethコンソールから抜け、MISTの環境を整えます。

MISTのインストール

MISTは非中央集権的なWEBアプリケーションと言われています。2つの主要なコンポーネントがあり、一つはウェブブラザで、もう一つは、イーサリアムの全てのノードと接続します。まだ開発途中で、ブラウザとしてのセキュリティは甘いので注意が必要です。

https://github.com/ethereum/mist/releases/
ここでは、Mist-macosx-0-9-2.dmg
をダウンロードします。

MISTを立ち上げる前に、プライベートネットを立ち上げましょう。

$ cd /Users/test/applications/blockchain/privatenet
先程、作成したプライベートネットのディレクトリに移動します。

プライベートネットのインスタンスを立ち上げます。
$ ./startinstancenode.sh
マイニングが開始されたのを確認し、MISTを立ち上げてください。

MISTが立ち上がるのが、確認出来るはずです。

ここで、先にプライベートネットを立ち上げる必要性について説明します。プライベートネットを立ち上げた際に、geth.ipc ソケットファイルが再生され、各ノードは、このソケットを通じてノードが識別されます。今回、startinstancenode.shのなかで、ipcpath として、"~/Library/Ethereum/geth.ipc" を指定しました。

MISTアプリケーションもGethアプリケーションを搭載しており、MIST自身でもマイニングを行う機能があります。もししていしなければ、~/Library/Ethereum/"のディレクトリにgeth.ipcを作成し、マイニングを開始します。ただし、もし先にgeth.ipcファイルが有った場合は、そのそのソケットファイルを通じて、通信を行う仕様となっています。

もし、プライベートネットのgeth.ipcファイルを別の場所に配置したい場合、以下のコマンドラインをmacosから起動することで、geth.ipcのパスを指定することが出来ます。

$ open -a /applications/mist.app/contents/macos/mist --args --rpc /path/to/somewhere/else/geth.ipc

MISTでアカウントを作成してみる

MISTがプライベートネットで立ち上がっているのを確認し、アカウントを作成してます。
その後、geth attachでgethコンソールを立上げ、eth.accountsでリストを確認すると増えているのが確認できます。

$ geth attach
instance: Geth/v1.7.2-stable-1db4ecdc/darwin-amd64/go1.9.2
coinbase: 0x9454d424f7205e51a96305d8de04c38b3799b804
at block: 1010 (Fri, 10 Nov 2017 16:06:59 JST)
 datadir: /Users/takeo/applications/blockchain/privatenet
 modules: admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0
> eth.accounts
["0x9454d424f7205e51a96305d8de04c38b3799b804", "0x12b32e5d0c197e9ac95adab9b1eb358ca052bdd5", "0x2a398426217a32f79adbea9ac1edca6d360c40b5", "0x081f5a77ebf15708fdd32a6e10dfa8155ec340ec", "0x3f67695fc1e23ddd03605671233775612059a92d"]

ethereum mistのコミュニティ(備忘録)

https://gitter.im/ethereum/mist

METAMASKのインストール

https://metamask.io/
METAMASKはChromeのエクステンションで、ウェブウォレットです。MISTではプライベートネットとMISTは、自動的に同期していました。

MISTとgethは、geth.ipcを通じて、同じKeysoreディレクトリをシェアしているからです。METAMASKでは、プライベートノードを立ち上げていても、自動的には同期しません。これは、単にMETAMASKUとMISTのKEYSTOREディレクトリの場所が異なるからです。
METAマスクでは、メインネットだけでなく、プラベートネットも指定できるため、開発には都合がよく作られているため採用しているエンジニアがおおいものと思われます。

さて、これで、スマートコントラクトDAppを開発するための環境が整いました。次回から、実際にスマートコントラクトを作成していきたいと思います。