Parityとは
Ethereum Clientで一番メジャーなのは geth ですが、その他にもいくつかのクライアントソフトウェアが存在します。
parity は Ethereum と Parity Technologies 社の共同設立者である Gavin Wood によって発明された Ethereum クライアントです。コンセンサスアルゴリズムとして PoW と PoA に対応しています。
PoA の特徴
PoA はコンソーシアムや特定の事業体に閉じた利用など、性善説が成り立つ範囲でブロックチェーンを利用する場合に有効で、あらかじめバリデータと呼ばれるマイニングノードを決めておくことにより PoW のような膨大な計算パワーを必要としないエコなブロックチェーンネットワークを構築することができるコンセンサスアルゴリズムです。
geth クライアントでも PoA モードを動かすことはできますが、geth の PoA と Parity の PoA は仕様が異なります。geth は開発用途で1台のノードで PoA を動作させるためのもので、Parity の PoA は AuthorityRound というエンジンを利用し、複数のバリデータが一定時間ごとにマイニングする権利を順に保有していくというアルゴリズムを採用しています。実運用においては AuthorityRound を利用することになります。
やること
- parity で PoA コンセンサスアルゴリズムでのプライベートブロックチェーンネットワークを構築します。
- AWS上にEC2インスタンス(OS:ubuntu16.04)を2台構築し、これらをバリデータノードとして接続します。parity ネットワークでは常時最低2台のバリデータノードが稼働している必要があります。障害など実運用を考慮すると、最低でも3台以上のノードで構築することが推奨されますが、ここでは基本的な手順をご紹介するため最低限の構成である2台のバリデータを接続します。なお、3台目以降も同様の手順で構築することができます。
構築手順
※ 2台の EC2 インスタンスをそれぞれ node#1、node#2 とします。
※下記手順を node#1、node#2 の両方に対して同様に行います。
1台のみに行ってAMI化してもう1台のインスタンスを複製すると効率的だと思います。
1. 基本ライブラリのインストール
$ sudo su -
# apt-get update
# apt-get install openssl libssl-dev libudev-dev
# curl https://sh.rustup.rs -sSf | sh
2. parityのインストール
最新の安定バージョンをインストールします。
正しくインストールされると /usr/bin/ 配下に parity の実行ファイルが配置されます。
# bash <(curl https://get.parity.io -kL) -r stable
コンソール出力例)
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 170 0 170 0 0 193 0 --:--:-- --:--:-- --:--:-- 193
100 4278 100 4278 0 0 3459 0 0:00:01 0:00:01 --:--:-- 3459
Release selected is: stable
Upgrading parity from 0.0.0 to 1.10.4
Preparing to unpack .../parity_1.10.4_ubuntu_amd64.deb ...
Setting up parity (1.10.4) ...
3. インストール確認
parity コマンド でバージョン情報を取得できればインストール成功です。
# parity --version
コンソール出力例)
Parity
version Parity/v1.10.4-stable-39b9f1e-20180514/x86_64-linux-gnu/rustc1.25.0
Copyright 2015, 2016, 2017, 2018 Parity Technologies (UK) Ltd
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
By Wood/Paronyan/Kotewicz/Drwi?ga/Volf
Habermeier/Czaban/Greeff/Gotchac/Redmann
4. 一時的な parity の起動
parity の動作に必要なデフォルトディレクトリを作成するため、一時的にparityを起動します。
# parity --no-warp --geth
オプションの説明
--no-warp : ネットワーク上のスナップショットと同期しない
--geth : geth 互換モードで起動する
5. 一時起動した parity の停止
Ctrl + C
を入力して parity を停止します。これにより、
/root/.local/share/io.parity.ethereum
ディレクトリが作成され、この配下に台帳データやキーペア、設定ファイルなどが配置されます。
6. ブロックチェーンの動作設定ファイル作成
# vi /root/.local/share/io.parity.ethereum/chain-spec.json
下記内容のファイルを作成し、保存してエディタを終了します。
{
"name": "MyChain",
"engine": {
"authorityRound": {
"params": {
"stepDuration": "5",
"validators" : {
"list": [
]
}
}
}
},
"params": {
"gasLimitBoundDivisor": "0x400",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "11111"
},
"genesis": {
"seal": {
"authorityRound": {
"step": "0x0",
"signature": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
}
},
"difficulty": "0x20000",
"gasLimit": "0x5B8D80"
},
"accounts": {
"0x0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
"0x0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
"0x0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
"0x0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }
}
}
主なパラメータの説明
"name": ブロックチェーンに付与す名前です。ここでは「MyChain」という名前を設定します。
"engine": コンセンサスアルゴリズムに関連する設定を記述します。
"authorityRound": PoAを利用する場合の設定
"stepDuration": ブロック生成間隔(秒)の指定
"validators": バリデータアカウントの設定。アドレスをリストで記載する方法と、バリデータを制御(登録・削除等)するコントラクトを指定する方法があります。今回はリスト指定とします。
"params": ブロックに関する情報を設定します。
"networkID" : ネットワークID(ブロックチェーンネットワークを識別するためのID)
"genesis": ジェネシスブロック(ブロックチェーンの一番最初のブロック)に関する情報を設定します。
"accounts": このブロックチェーンが生成される時点で登録するアカウントの情報を設定します。上記4行はスマートコントラクトを実行するためには必須の設定です。
7. parity プロセスの動作設定ファイル作成
# vi /root/.local/share/io.parity.ethereum/config.toml
下記内容のファイルを作成し、保存してエディタを終了します。
[parity]
chain = "chain-spec.json"
base_path = "/root/.local/share/io.parity.ethereum"
[network]
port = 30303
reserved_peers = "/root/.local/share/io.parity.ethereum/enodes"
[rpc]
port = 8545
apis = ['web3','eth','net','personal','parity','parity_set','traces','rpc','parity_accounts']
主なパラメータの説明
[parity]
chain = [ブロックチェーン設定ファイルのパス]
[network]
port = [parityノード同士がP2P通信する際に使用するポート番号]
reserved_peers = [常に接続したいノード情報を記載したファイルのパス]
[rpc]
port = [クライアントからのRPC接続に応答するポート番号]
※下記手順は各インスタンス個別に行います。プロンプトは下記のとおりに読み替えてください。
[node#1] # node#1上のrootユーザで実行するコマンド
[node#2] # node#2上のrootユーザで実行するコマンド
8. アカウント作成
node#1 にバリデータアカウントとユーザアカウント、node#2 にバリデータアカウントをそれぞれ作成します。
- node#1 での手順
parity の起動
[node#1] # parity --no-warp --geth
バリデータアカウントの作成
[node#1] # curl --data '{"jsonrpc":"2.0","method":"parity_newAccountFromPhrase","params":["node1", "samplepass"],"id":0}' -H "Content-Type: application/json" -X POST localhost:8545
{"jsonrpc":"2.0","result":"0x00aa39d30f0d20ff03a22ccfc30b7efbfca597c2","id":0}
ユーザアカウントの作成
# curl --data '{"jsonrpc":"2.0","method":"parity_newAccountFromPhrase","params":["user", "samplepass"],"id":0}' -H "Content-Type: application/json" -X POST localhost:8545
{"jsonrpc":"2.0","result":"0x004ec07d2329997267ec62b4166639513386f32e","id":0}
- node#2 での手順
[node#1] # parity --np-warp --geth
バリデータアカウントの作成
[node#1] # curl --data '{"jsonrpc":"2.0","method":"parity_newAccountFromPhrase","params":["node2", "samplepass"],"id":0}' -H "Content-Type: application/json" -X POST localhost:8545
{"jsonrpc":"2.0","result":"0x002e28950558fbede1a9675cb113f0bd20912019","id":0}
上記により、下記のとおりアカウントが作成されました。
ノード | 内訳 | フレーズ | パスワード | アドレス |
---|---|---|---|---|
node#1 | バリデータ | node1 | samplepass | 0x00aa39d30f0d20ff03a22ccfc30b7efbfca597c2 |
node#1 | ユーザ | user | smaplepass | 0x004ec07d2329997267ec62b4166639513386f32e |
node#2 | バリデータ | node2 | smaplepass | 0x002e28950558fbede1a9675cb113f0bd20912019 |
9. 各ノードの enode ID 確認
parity では、接続相手を識別するために enode ID という情報を使います。
[node#1] # curl --data '{"jsonrpc":"2.0","method":"parity_enode","params":[],"id":0}' -H "Content-Type: application/json" -X POST localhost:8545
{"jsonrpc":"2.0","result":"enode://90ba5c69cf13a5aaade33beee53d1064d2fd2d206878589d9e8dfef1a2a1730e8e95da518cf9f3f324dce803cc77ff010a7b05eafc885a2667d09777fc4386f8@[IPアドレス]]:30303","id":0}
[node#2] # curl --data '{"jsonrpc":"2.0","method":"parity_enode","params":[],"id":0}' -H "Content-Type: application/json" -X POST localhost:8545
{"jsonrpc":"2.0","result":"enode://95afc7bf4cc63a2efbeaa7e5afe490ed93d21d00bb0be5ed60ce868054a0441235fc9d2617a0d66edb62fc9677bb576c2cfd04a0a65890e4dabc04df5e882214@[IPアドレス]]:30303","id":0}
10. 設定反映のために parity を停止
[node#1] # pkill -KILL -x parity
[node#2] # pkill -KILL -x parity
11. 設定ファイル更新1
node#1、node#2 それぞれの chain-spec.json に各バリデータのアカウントアドレス、ユーザのアドレスを追記する。
[node#1] # vi /root/.local/share/io.parity.ethereum/chain-spec.json
[node#2] # vi /root/.local/share/io.parity.ethereum/chain-spec.json
バリデータ、ユーザのアドレスを追加し、保存してエディタを終了します。
{
"name": "MyChain",
"engine": {
"authorityRound": {
"params": {
"stepDuration": "5",
"validators" : {
"list": [
"0x00aa39d30f0d20ff03a22ccfc30b7efbfca597c2",
"0x002e28950558fbede1a9675cb113f0bd20912019"
]
}
}
}
},
"params": {
"gasLimitBoundDivisor": "0x400",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "11111"
},
"genesis": {
"seal": {
"authorityRound": {
"step": "0x0",
"signature": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
}
},
"difficulty": "0x20000",
"gasLimit": "0x5B8D80"
},
"accounts": {
"0x0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
"0x0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
"0x0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
"0x0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
"0x004ec07d2329997267ec62b4166639513386f32e": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }
}
}
12. 設定ファイル更新2
node#1、node#2 それぞれの config.toml にパスワードファイルの場所、各バリデータのアカウントアドレスを追記する。
- node#1
[node#1] # vi /root/.local/share/io.parity.ethereum/config.toml
バリデータのアドレスを追加し、保存してエディタを終了します。
[parity]
chain = "chain-spec.json"
base_path = "/root/.local/share/io.parity.ethereum"
[network]
port = 30303
reserved_peers = "/root/.local/share/io.parity.ethereum/enodes"
[rpc]
port = 8545
apis = ["web3", "eth", "net", "personal", "parity", "parity_set", "traces", "rpc", "parity_accounts"]
[account]
password = ["node.pwds"]
[mining]
engine_signer = "0x00aa39d30f0d20ff03a22ccfc30b7efbfca597c2"
- node#2
[node#2] # vi /root/.local/share/io.parity.ethereum/config.toml
バリデータのアドレスを追加し、保存してエディタを終了します。
[parity]
chain = "chain-spec.json"
base_path = "/root/.local/share/io.parity.ethereum"
[network]
port = 30303
reserved_peers = "/root/.local/share/io.parity.ethereum/enodes"
[rpc]
port = 8545
apis = ["web3", "eth", "net", "personal", "parity", "parity_set", "traces", "rpc", "parity_accounts"]
[account]
password = ["node.pwds"]
[mining]
engine_signer = "0x002e28950558fbede1a9675cb113f0bd20912019"
13. パスワードファイル作成
このパスワードはバリデータアカウント作成時に指定したものを記述します。parity 起動時にバリデータアカウントを認証するために使用します。
[node#1] # vi /root/.local/share/io.parity.ethereum/node.pwds
[node#2] # vi /root/.local/share/io.parity.ethereum/node.pwds
バリデータに設定したパスワードを記述して、保存してエディタを終了します。
samplepass
14. バリデータのピア接続リスト作成
このファイルを指定して parity を起動することで、2つのバリデータがP2P接続します。
- node#1
[node#1] # vi /root/.local/share/io.parity.ethereum/enodes
接続先となる node#2 の enode ID を記述して、保存してエディタを終了します。
enode://90ba5c69cf13a5aaade33beee53d1064d2fd2d206878589d9e8dfef1a2a1730e8e95da518cf9f3f324dce803cc77ff010a7b05eafc885a2667d09777fc4386f8@[IPアドレス]:30303
- node#2
[node#2] # vi /root/.local/share/io.parity.ethereum/enodes
接続先となる node#1 の enode ID を記述して、保存してエディタを終了します。
enode://90ba5c69cf13a5aaade33beee53d1064d2fd2d206878589d9e8dfef1a2a1730e8e95da518cf9f3f324dce803cc77ff010a7b05eafc885a2667d09777fc4386f8@[IPアドレス]:30303
15. parity 起動
[node#1] # parity --np-warp --geth
[node#2] # parity --np-warp --geth
16. ピア接続状況確認
標準出力されるログに「1/25 peers」と出力されれば接続成功です。
接続が失敗している場合は「0/25 peers」と出力されます。
peer接続成功時のログ例)
2018-07-09 01:19:20 UTC 1/25 peers 22 KiB chain 8 KiB db 0 bytes queue 17 KiB sync RPC: 0 conn, 0 req/s, 278 μs
まとめ
今回は Parity でプライベートなEthereum基盤を構築する方法をご紹介しました。
Parityが利用するPoAコンセンサスアルゴリズムは、PoWと違い非常に小さいリソースで動作し、プライベート型のブロックチェーンでは大変実用的であるといえます。
今回はバリデータのアカウントアドレスを設定ファイルにハードコードする手法で行いましたが、平文でアカウントアドレスやパスワードが分かってしまうというセキュリティ上の懸念があります。また、バリデータノードを追加したり削除したりする場合に、反映のためにノードを再起動しなければならないという制約があります。
バリデータの指定方法には2種類あり、今回のようなリスト指定の他に、バリデータコントロール用のコントラクトをデプロイし、これを利用することでオンラインでバリデータを追加したり削除したりできるようになります。
バリデータコントロール用のコントラクトを実装する手法については、コントラクトそのものの開発手法の理解が必要になりますので、別の機会にご紹介したいと思います。
以上、何かのお役に立てば幸いです。