ブロックチェーンEthereum入門 2



目的

今回は、ブロックチェーンEthereum入門 1の続きとして、Ethereumのプライベートテストネットワークを構築し、ネットワーク監視のためのツールのインストールと実行方法を紹介する。

監視イメージを参照してほしい。

https://ethstats.net/

以降の手順では、ブロックチェーンEthereum入門 1で使用した同一のコンピューター1台へのインストールとしている。ツールを複数台のコンピューターに分けてインストールすることも可能だが、この場合、”localhost”の設定を当該のコンピューターに読み替えてほしい。
Windows環境(64bit版必須)を前提に、Windows 7 Professional SP1 64bitでの動作を確認している。(最後の複数ノード環境の構築ではUbuntu、OS Xも使用)

準備

ツールのインストールと実行には、gitとnode.jsが必要だ。インストールされていないコンピューターを使用しているなら、以下のサイトなどからダウンロードし、設定してほしい。

また、node.jsのパッケージgrunt-cliとpm2も必要となるので、例えば、以下のコマンドでインストールしておく。

npm install -g grunt-cli
npm install -g pm2

前回の続きとして、Ethereumブロックチェーンブラウザのインストールを行っている前提で進めていることをご了承いただきたい。未インストールの場合は、以下のサイトからEthereum-Walletのzipファイルをダウンロードし、任意の場所に展開する。

Ethereumノードは同梱されているgeth.exeを使用する。

展開後のディレクトリイメージ

Ethereum-Wallet-win64-0-5-1
│  Ethereum-Wallet.exe
├─locales
└─resources
    └─node
        └─geth
              geth.exe

Ethereumネットワーク監視の構成

今回構築しようとしているEthereumネットワーク監視の構成は以下の通りだ。

Ethereumネットワーク監視の構成

network idの値、およびJSON RPC、Network listen、WS Serverの各ポート番号を独自に決めておいてほしい。なお、以降の例では次の値を使用している。

項目 備考
network id 1457239471 gethの起動オプションに設定、初回起動時点のエポック秒を使用
JSON RPC 58545 gethの起動オプションに設定
Network listen 50303 gethの起動オプションに設定
WS Server 53000 eth-netstatsが参照する環境変数(PORT)に設定、WS_SECRET環境変数にシークレットを設定する必要もあり

JSON RPC

今回は、Ethereumノード(geth)のJSON RPCを有効にする。
https://github.com/ethereum/wiki/wiki/JSON-RPC
Ethereumノードは、JSON RPC により操作および状態参照することができる。Web3.jsライブラリはJSON RPCのラッパーだ。
https://github.com/ethereum/wiki/wiki/JavaScript-API
このように、JSON RPC によりEthereumノードの様々な操作ができてしまうので、JSON RPCを有効にするならセキュリティー的には要注意だ。

また、gethのコマンドラインオプション”console”で立ち上がるコンソールはJavaScriptのREPLで、Web3.jsのAPIが使用できる。
起動コマンドオプションの詳細は、

geth --help

か、または、
https://github.com/ethereum/go-ethereum/wiki/Command-Line-Options
を参照してほしい。

前掲の構成図には、Ethereum上のアプリケーション開発イメージを示した。 GUIフロントエンドをJavaScript +Web3.jsで、Solidityと呼ばれる言語でコントラクト(Ethereum上で実行する任意の計算)をそれぞれプログラミングするわけだ。

このようなEthereumのアプリケーションをコミュニティではdapp(decentralized app)と呼んでいる。
http://dapps.ethercasts.com/
コントラクトについては、次回紹介する予定だ。

それでは、ここからEthereumノード(geth)を起動し、ネットワーク監視環境の構築を行っていく。

ブロックチェーンのリセット

ブロックチェーンEthereum入門 1から続きであれば、改めて、プライベートなテストネットワークを初期状態から作成する。
これには、以下のディレクトリを削除してほしい。

C:\Users\<ユーザー名>\AppData
├─Ethash
└─Roaming
    ├─Ethereum
    └─Mist

以降は初期状態を前提に進める。まずはアカウントを再作成する。

アカウントの事前作成

コマンドプロンプトを開き、geth.exeのあるディレクトリに移動する。

Ethereum-Wallet-win64-0-5-1
└─resources
    └─node
        └─geth
              geth.exe

以下のコマンドでアカウントを作成できる。最低1つ作成する。いくつか作成しておくとよい。

geth account new

パスワードを2度入力後、作成されたアカウントのアドレスが表示される。

データディレクトリを見てみると、例えば以下のようになる。
ここでは4アカウントを作成している。keystoreの以外のファイルは、まだない。

C:\Users\<ユーザー名>\AppData\Roaming\Ethereum
└─keystore
        UTC--2016-03-06T08-27-00.952140000Z--652bf10ea5f23a734efc36d6cf0a7a67cc962451
        UTC--2016-03-06T08-27-05.188382300Z--cb2b90f336d7594a7642a53c25279761ad8583f3
        UTC--2016-03-06T08-27-08.767587000Z--42defddaf318b7e690339c34818087fc481aa5d2
        UTC--2016-03-06T08-27-12.342791500Z--4c67f43f862722a9c3089ba4d7fa20e00f5ba3ef

genesis.jsonの作成

genesis.jsonは、ブロックチェーンのノード間で最初のブロックの合意をとるためのファイルだ。最初のブロックは何らかの形で人為的に決定するより他ないからだ。
ブロックデータを持っていない、まっさらのノードの初回起動するときに使用する。genesis.jsonは必須でないが、今後、テストネットワークへのノード追加を考えている場合など、作っておくと都合が良い。新規ノード追加を容易にできる。

ここでは、公式のテストネットワーク(名前はModern、network id=2)で使ったとされているものをベースに一部変更してみる。

変更点は以下の通り。

difficulty:
マイニング(ブロック生成におけるハッシュ計算)の難易度、マイニングがすぐに開始されるようにしたいので難易度を下げる。
alloc:
マイニングの手間を省くため、初期状態で特定のアカウントにether割り当てを行っておく。設定単位はwei(1ether=10の18乗wei)。

以上を踏まえたgenesis.jsonの内容は次の通り。

{
    "nonce": "0x00006d6f7264656e",
    "difficulty": "0x200",
    "mixhash": "0x00000000000000000000000000000000000000647572616c65787365646c6578",
    "coinbase": "0x0000000000000000000000000000000000000000",
    "timestamp": "0x00",
    "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "extraData": "0x",
    "gasLimit": "0x2FEFD8",
    "alloc": {
        "0x652bf10ea5f23a734efc36d6cf0a7a67cc962451": { "balance": "100000000000000000000" },
        "0xcb2b90f336d7594a7642a53c25279761ad8583f3": { "balance": "10000000000000000000" }
    }
}

例では、coinbaseと他の1アカウントにetherを割り当てている(下表を参照)。
アカウントのアドレスと初期ether値は各自の設定を行ってほしい。アドレスの設定は”0x~”とすること。

対象アカウント アドレス 初期 ether
coinbase 0x652bf10ea5f23a734efc36d6cf0a7a67cc962451 100
Account1 0xcb2b90f336d7594a7642a53c25279761ad8583f3 10

gethの起動

それでは、各設定値を決定したら、以下の起動テンプレートでgethを起動だ。

geth --networkid <networkid> --genesis <genesis.jsonのパス> --rpc --rpcport <rpcport> --rpccorsdomain "*" --port <port> --nodiscover --mine --minerthreads 2 console 2>> node.log

gethのログファイルを作るには、エラー出力をリダイレクト(2>> ログファイル)する。

例では、次の起動コマンドラインとポート、およびファイル配置で進めている。

geth --networkid 1457239471 --genesis genesis.json --rpc --rpcport 58545 --rpccorsdomain "*" --port 50303 --nodiscover --mine --minerthreads 2 console 2>> node.log
Ethereum-Wallet-win64-0-5-1
│  Ethereum-Wallet.exe
├─locales
└─resources
    └─node
        └─geth
                geth.exe
                genesis.json

起動オプションの補足説明:

--mine:
起動時からマイニングを開始
--minerthreads:
マイニングのスレッド数、PCのCPUコアに応じて適度な値を設定
--rpccorsdomain:
JavaScriptのクロスドメイン制限を回避。テストのときは設定しておくと便利(未設定だと、フロントエンドのアプリケーションによっては問題発生することがある。*はドメイン制限なし)。
--nodiscover:
ピアノードのディスカバリーを抑止。ノード追加は手動になる。もし、ノード数を制限してピア数も事前に決められるなら--maxpeersを指定してもよいかもしれない。

Ethereum-Walletを起動し、状態を確認してみる。
まだマイニングが開始されていなくとも、genesis.jsonの設定通りアカウントに対してetherが割り当てられているはずだ。

マイニングが開始されると、MainAccountのetherが増えていく。

なお、ここまで確認できたら、いったんマイニングを停止しておいてもよい。
以下のように、gethのコンソールで"miner.stop()"と入力する("miner.stop(スレッド数)"としてもよい)。

eth-netstatsのインストール

eth-netstatsのインストールを行う。このプログラムは、Ethereumの各ノードから状態を収集し、それらの状態を可視化するサーバーだ。
今回の手順ではEthereumノード(geth)と同一のコンピューターにインストールしているが、実用的にはノードではないコンピューター1台にインストールするなどでよいだろう。

インストールを開始する。
コマンドプロンプトを開き、eth-netstatsダウンロードするディレクトリに移動する。
場所は任意。以降の例ではC:\Ethereumの下にダウンロードしているので、次の通り。

c:
cd \
mkdir Ethereum
cd Ethereum

以下のコマンドを実行する。

git clone https://github.com/cubedro/eth-netstats
cd eth-netstats
npm install

ソースファイルのビルドを行う。
以下を実行し、”Done, without errors.”が表示されたら完了だ。

grunt all

通信ポートとシークレットを決定し、それらを環境変数に設定してほしい。例えば以下のように設定し、”npm start”でプログラム起動する。

set PORT=53000
set WS_SECRET=secret

npm start

上記の通信ポートにブラウザでアクセスすれば、ネットワーク状態画面が表示される。(ただし、監視ノードがまだないので画面が出るだけ)
例の通りなら、http://localhost:53000となる。

eth-net-intelligence-apiのインストール

eth-net-intelligence-api は、名前の通りEthereumの各ノード状態をAPIとして公開するものだ。このAPIを使用して状態を可視化するのが、先ほどインストールしたeth-netstatsだ。
ノード状態はJSON-RPCで取得される(このため、上記でのgeth起動時にJSON-RPCを有効にした)ため、例えばノードを動作させている同一コンピューターにインストールするのがよいのではないだろうか。
今回の手順では、ノード(geth)と同一のコンピューターにインストールする。

インストールを開始する。
コマンドプロンプトを開き、eth-net-intelligence-apiをダウンロードするディレクトリに移動する。
場所は任意。以降の例ではC:\Ethereumの下にダウンロードしているので、ここまでの続きなら次の通り。

cd \Ethereum

以下のコマンドを実行する。

git clone https://github.com/cubedro/eth-net-intelligence-api
cd eth-net-intelligence-api
npm install

eth-net-intelligence-apiディレクトリにあるapp.jsonを通り書き換える。
もとのapp.jsonファイルを退避して、ハイライトしている項目を設定してほしい。
“RPC_HOST”、”RPC_PORT”、”LISTENING_PORT”はgeth起動時のコマンドラインで指定した各々の値だ。
eth-netstatsの監視画面での表示名は、"INSTANCE_NAME"に設定する。
"WS_SERVER"と"WS_SECRET"はeth-netstatsを参照するように設定する。"WS_SERVER"にはアドレスとポート(PORT環境変数の値)、"WS_SECRET"はWS_SECRET環境変数の値だ。

ここまで同じ手順を踏んでいるなら、設定は以下のようになる。

[
  {
    "name"              : "node-app",
    "script"            : "app.js",
    "log_date_format"   : "YYYY-MM-DD HH:mm Z",
    "merge_logs"        : false,
    "watch"             : false,
    "max_restarts"      : 10,
    "exec_interpreter"  : "node",
    "exec_mode"         : "cluster_mode",
    "env":
    {
      "NODE_ENV"        : "test",
      "RPC_HOST"        : "localhost",
      "RPC_PORT"        : "58545",
      "LISTENING_PORT"  : "58101",
      "INSTANCE_NAME"   : "node1",
      "CONTACT_DETAILS" : "",
      "WS_SERVER"       : "http://localhost:53000",
      "WS_SECRET"       : "secret",
      "VERBOSITY"       : 2
    }
  }
]

app.jsonの設定が終わったら、pm2 startで起動だ。

pm2 start app.json

なお、止めるときは pm2 killとする。

ネットワーク状態の表示

マイニングを止めているのなら再開する。gethコンソールで、例えば以下の通り入力する。

miner.start(2)

なお、gethのコンソールごと落としてしまったなら再起動する。今回の起動では--genesisオプション指定はもう不要だ。
(ブロックチェーンのデータを削除しない限り、今後もgeth再起動時のgenesisオプション不要)

geth --networkid 1457239471 --rpc --rpcport 58545 --rpccorsdomain "*" --port 50303 --nodiscover --mine --minerthreads 2 console 2>> node.log

正常に通信ができていると、eth-netstatsのコンソールにログが表示されていく。

ブラウザでeth-netstatsのページにアクセスしてみると、以下のような状態監視画面が現れる。
例の通りなら、http://localhost:53000になる。

Ethereumノードの追加

Ethereumノードとするコンピューターを複数台用意できれば、ここまでで構築したテストネットワークにノードを追加してみることができる。

https://github.com/ethereum/go-ethereum/wiki/Connecting-to-the-network

なお、以降の動作確認例での追加EthereumノードはUbuntuおよびOS X上に構築していることをご了承いただきたい。ただし、Windows環境でも手順的には同様だ。

新たなEthereumノードとなるコンピューターにはgethとeth-net-intelligence-apiをインストールする必要がある。eth-netstatsは1台あればよいので、追加インストールは不要だ。

Ethereumノードのインストール

新たなEthereumノードとなるコンピューターにgethをインストールする。
これまでと同様にEthereum-Walletを展開してもよいし、Ethereumノードとしてだけの用途であれば、以下を参考にgethを別途インストールしてもよい。

https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum#installation-instructions

eth-net-intelligence-apiのインストール

gethをインストールしたコンピューターに、前述と同じ手順でeth-net-intelligence-apiをインストールする。

eth-net-intelligence-apiディレクトリにあるapp.jsonも前掲の手順同様の設定が必要だ。
“RPC_HOST”、”RPC_PORT”、”LISTENING_PORT”は、全ノード同一値としておく方がよいだろう。
"INSTANCE_NAME"はeth-netstatsの監視画面での表示名なので、重複しないように設定する。
"WS_SERVER"と"WS_SECRET"はeth-netstatsのサーバーを参照するように設定する。"WS_SERVER"にはアドレスとポート(PORT環境変数の値)、"WS_SECRET"はWS_SECRET環境変数の値だ。

Ubuntu、OS X環境では、以下のようなapp.json設定で動作する。(ハイライト部が設定箇所)
Windows環境では前掲のapp.json設定をベースにしてほしい。

[
  {
    "name"              : "node-app",
    "script"            : "app.js",
    "log_date_format"   : "YYYY-MM-DD HH:mm Z",
    "merge_logs"        : false,
    "watch"             : false,
    "max_restarts"      : 10,
    "exec_interpreter"  : "node",
    "exec_mode"         : "fork_mode",
    "env":
    {
      "NODE_ENV"        : "test",
      "RPC_HOST"        : "localhost",
      "RPC_PORT"        : "58545",
      "LISTENING_PORT"  : "58101",
      "INSTANCE_NAME"   : "<監視画面での表示名>",
      "CONTACT_DETAILS" : "",
      "WS_SERVER"       : "http:// <eth-netstats サーバーのアドレス>:53000",
      "WS_SECRET"       : "secret",
      "VERBOSITY"       : 2
    }
  }
]

ピアノードの設定

Ethereumネットワークに参加するには、既存ノードのピアノードになればよい。
ピアノード間ではgenesis.jsonファイルが共通でなければならないので、既存ノードで使用したファイルを追加ノードにコピーする。

コピーが終わったら、追加ノードのgethを既存ノードと同一のコマンドラインで順次起動していく。ただしマイニングは行わない。起動テンプレートは次の通り。

geth --networkid <networkid> --genesis <genesis.jsonのパス> --rpc --rpcport <rpcport> --rpccorsdomain "*" --port <port> --nodiscover console 2>> node.log

例では次のコマンドラインで実行している。

geth --networkid 1457239471 --genesis genesis.json --rpc --rpcport 58545 --rpccorsdomain "*" --port 50303 --nodiscover console 2>> node.log

次に、追加ノードのenode値(ノードの識別子)を調べる。gethコンソールで以下を入力する。

admin.nodeInfo

以下のような情報が表示されるので、enodeの値をメモする。IPアドレス部が表示されない場合は、別途IPアドレスを調べて補完する。
例えば以下では、enodeは”enode://0ebd~6f24@[::]:50303”の部分で、[::]を実際のIPアドレスにする。

ここで、一旦既存ノードに戻る。

既存ノードのgethのconsoleで、admin.addPeerを実行する。引数には先ほど調べた追加ノードのenodeを文字列で渡す。

admin.addPeer(<enodeの文字列>)

ノードが追加されれば、以下のようにadmin.peersで追加ノードが確認できる。

Ethereum Walletの画面でも、ピアの数が増えているはずだ。

さらにノード追加したい場合は、ここまでの手順を繰り返せばよい。

なお、ピアノードが常に固定で決まっているなら、static-nodes.jsonファイルを作成してデータディレクトリ(WindowsではC:\Users\<ユーザー名>\ AppData\Roaming\Ethereumがデフォルト)に配置しておくことで、geth再起動のたびにaddPeerをやり直す手間を省略できる。
例えば3ノードあるとき、static-nodes.jsonファイルに3ノード分のenodeを記載して、各ノードのデータディレクトリに配置しておくなどすればよい。

[
    "enode://0ebd~省略~6f24@192.168.0.11:50303",
    "enode://a0e3~省略~b523@192.168.0.12:50303",
    "enode://2273~省略~e441@192.168.0.13:50303"
]

監視画面へのノード追加

追加ノードでeth-net-intelligence-apiを起動する。

pm2 start app.json

正常に通信ができていると、eth-netstatsのコンソールに追加ノードからの通信ログが表示されていく。
eth-netstatsの監視画面を確認すると、ノードが増えているはずだ。
以下の例では既存ノードに2ノードを追加し、全部で3ノードとしている。

なお、接続が切れたノードが表示残りしている場合、eth-netstatsを再起動すると消える。

参考

マイニングについて、監視画面の表示を見てUnclesやLAST BLOCKの表示が赤くならないように、マイニングノード(マイナー)数を調節した方がよいかもしれない。ブロックチェーンの状態がOKなら、全体的に緑や青の文字表示になる。
実際のEthereumネットワークでは、多くのノードが参加してマイニングを行っている。テストネットワークのようにノード数が少ない状態では、全ノードでマイニングしてしまうとブロックがあまり増えていかない場合がある。例えば2ノードしかないなら、マイニングは1ノードだけで行う方がよいかもしれない(もう一方のノードはブロックをもらうだけ)。

最後に

今回はEthereumのテストネットワークを作成し、その監視を行ってみた。ブロックチェーンが分散ネットワークであることのイメージをつかむ手助けとなっていれば幸いだ。次回はEthereumの大きな特徴でもあるコントラクトに触れる予定だ。



ブロックチェーンEthereum入門 2