18
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ParityでプライベートなEthereumブロックチェーンを構築する

Posted at

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種類あり、今回のようなリスト指定の他に、バリデータコントロール用のコントラクトをデプロイし、これを利用することでオンラインでバリデータを追加したり削除したりできるようになります。
バリデータコントロール用のコントラクトを実装する手法については、コントラクトそのものの開発手法の理解が必要になりますので、別の機会にご紹介したいと思います。

以上、何かのお役に立てば幸いです。

18
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?