Quorumのネットワーク作成

#はじめに

__「Quorumでネットワークを作成してみたい」__
という人向けです。

前の記事はこちら
https://qiita.com/ryu3/items/d49f8faa5198c09a4ba9

Quorum でネットワークを作成してみます。
http://docs.goquorum.com/en/latest/Getting%20Started/Creating-A-Network-From-Scratch/

# Quorum with Raft consensus
## 1.ダウンロード

gitからダウンロードし、makeします。
また、PATHの設定もします。

```
$ git clone https://github.com/jpmorganchase/quorum.git
$ cd quorum
$ make all
$ export PATH=$(pwd)/build/bin:$PATH
```

## 2.ワークディレクトリとノードディレクトリの作成

下記のように作成します。

```
$ mkdir fromscratch
$ cd fromscratch
$ mkdir new-node-1
```

## 3.アカウント作成

ノードに1つアカウントを作成してみます。
ノードに複数のアカウントを作成することもできます。

```
$ geth --datadir new-node-1 account new
INFO [02-28|13:15:09.094] Maximum peer count                       ETH=25 LES=0 total=25
Your new account is locked with a password. Please give a password. Do not forget this password.
Passphrase: 
Repeat passphrase: 
Address: {86961e4ee758b8f1f5f8a5a308139c48592f3db9}

```

サービスによって下記のように使い分けられます。
- 1つのノードに複数のアカウントを作成する
- 追加のノードを作成する

## 4.`genesis.json`ファイルの作成

先ほど作ったアカウントのアドレス(`0x86961e4ee758b8f1f5f8a5a308139c48592f3db9`)を使って、`genesis.json`を作成します。初期の資金を追加しています。また、別のアドレス(`0xc5c7b431e1629fb992eb18a79559f667228cd055`)も追加しています。

```
{
  "alloc": {
    "0x86961e4ee758b8f1f5f8a5a308139c48592f3db9": {
      "balance": "1000000000000000000000000000"
    },
   "0xc5c7b431e1629fb992eb18a79559f667228cd055": {
      "balance": "2000000000000000000000000000"
    }
},
 "coinbase": "0x0000000000000000000000000000000000000000",
 "config": {
   "homesteadBlock": 0,
   "byzantiumBlock": 0,
   "chainId": 10,
   "eip150Block": 0,
   "eip155Block": 0,
   "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
   "eip158Block": 0,
   "isQuorum": true
  },
 "difficulty": "0x0",
 "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000",
 "gasLimit": "0xE0000000",
 "mixhash": "0x00000000000000000000000000000000000000647572616c65787365646c6578",
 "nonce": "0x0",
 "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
 "timestamp": "0x00"
}
```

## 5.ノードキーの作成
ノードキーを作成し`new-node-1`へ移動します。

```
$ bootnode --genkey=nodekey
$ ls
new-node-1	nodekey
$ mv nodekey new-node-1/
```

## 6.新しいノードのenode IDを表示します

```
$ bootnode --nodekey=new-node-1/nodekey --writeaddress > new-node-1/enode
$ cat new-node-1/enode  
20591db5036fedd953fe7e2da47df8e4661bc1bc3c33aa21a2ffe7817442033e009c3599f05e0977ba8abcb8b89c66f7b602cd21906d19e423156f9a038834db
```

## 7.`static-encode.json`の作成
ファイルには、enodeのIDとdevp2pおよびraftに使用するポートを含むノードの1行が含まれている必要があります。このファイルがノードのデータディレクトリにあることを確認してください。

```
$ vim static-nodes.json
[
  "enode://20591db5036fedd953fe7e2da47df8e4661bc1bc3c33aa21a2ffe7817442033e009c3599f05e0977ba8abcb8b89c66f7b602cd21906d19e423156f9a038834db@127.0.0.1:21000?discport=0&raftport=50000"
]
$ cp static-nodes.json new-node-1
```

## 8.ノードを初期化します。

```
$ geth --datadir new-node-1 init genesis.json
INFO [02-28|13:37:47.770] Maximum peer count                       ETH=25 LES=0 total=25
INFO [02-28|13:37:47.778] Allocated cache and file handles         database=/Users/nakata/project/quorum/fromscratch/new-node-1/geth/chaindata cache=16 handles=16
INFO [02-28|13:37:47.897] Writing custom genesis block 
INFO [02-28|13:37:47.898] Persisted trie from memory database      nodes=3 size=417.00B time=112.218µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [02-28|13:37:47.898] Successfully wrote genesis state         database=chaindata                                                          hash=a49ccf…8bfc53
INFO [02-28|13:37:47.898] Allocated cache and file handles         database=/Users/nakata/project/quorum/fromscratch/new-node-1/geth/lightchaindata cache=16 handles=16
INFO [02-28|13:37:47.973] Writing custom genesis block 
INFO [02-28|13:37:47.980] Persisted trie from memory database      nodes=3 size=417.00B time=6.917462ms gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [02-28|13:37:47.980] Successfully wrote genesis state         database=lightchaindata                                                          hash=a49ccf…8bfc53
```

## 9.ノードを開始します。
以下のように最初にスクリプトを作成し、実行してください。(プライバシーサポートなしでQuorumを起動しています。)

```startnode1.sh
#!/bin/bash
PRIVATE_CONFIG=ignore nohup geth --datadir new-node-1 --nodiscover --verbosity 5 --networkid 31337 --raft --raftport 50000 --rpc --rpcaddr 0.0.0.0 --rpcport 22000 --rpcapi admin,db,eth,debug,miner,net,shh,txpool,personal,web3,quorum,raft --emitcheckpoints --port 21000 >> node.log 2>&1 &
```

```
$ chmod +x startnode1.sh
$ ./startnode1.sh
```

これでノードが操作可能になり、以下のコマンドで接続できます。

```
$ geth attach new-node-1/geth.ipc
Welcome to the Geth JavaScript console!

instance: Geth/v1.8.18-stable-4b125de4(quorum-v2.4.0)/darwin-amd64/go1.13.1
coinbase: 0x3c3115f8c785bb6583c17f45fced7bd45f803068
at block: 0 (Thu, 01 Jan 1970 09:00:00 JST)
 datadir: /Users/nakata/project/quorum/fromscratch/new-node-1
 modules: admin:1.0 debug:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 personal:1.0 raft:1.0 rpc:1.0 txpool:1.0 web3:1.0

> raft
{
  cluster: [{
      hostname: "127.0.0.1",
      nodeActive: true,
      nodeId: "20591db5036fedd953fe7e2da47df8e4661bc1bc3c33aa21a2ffe7817442033e009c3599f05e0977ba8abcb8b89c66f7b602cd21906d19e423156f9a038834db",
      p2pPort: 21000,
      raftId: 1,
      raftPort: 50000,
      role: "minter"
  }],
  leader: "20591db5036fedd953fe7e2da47df8e4661bc1bc3c33aa21a2ffe7817442033e009c3599f05e0977ba8abcb8b89c66f7b602cd21906d19e423156f9a038834db",
  role: "minter",
  addLearner: function(),
  addPeer: function(),
  getCluster: function(callback),
  getLeader: function(callback),
  getRole: function(callback),
  promoteToPeer: function(),
  removePeer: function()
}
```

# Nodeを追加してみる

## 1.Node2を作成する

```
$ mkdir new-node-2
$ bootnode --genkey=nodekey2
$ cp nodekey2 new-node-2/nodekey
$ bootnode --nodekey=new-node-2/nodekey --writeaddress
30f87ff91dc8a3736160db818f441d60b4f21f297e5aa8a18b266c0c3a2d29950d1fa2123e059810ccf55411bef318b03e0ef3794df49668262aed25bd4daafb
```

Node2へファイルをコピーする

```
$ cp static-nodes.json new-node-2    
```
## 2.`static-node.json`の更新

Node2の内容を追加します。

```
$ vim new-node-2/static-nodes.json
[
  "enode://20591db5036fedd953fe7e2da47df8e4661bc1bc3c33aa21a2ffe7817442033e009c3599f05e0977ba8abcb8b89c66f7b602cd21906d19e423156f9a038834db@127.0.0.1:21000?discport=0&raftport=50000"
  "enode://30f87ff91dc8a3736160db818f441d60b4f21f297e5aa8a18b266c0c3a2d29950d1fa2123e059810ccf55411bef318b03e0ef3794df49668262aed25bd4daafb@127.0.0.1:21001?discport=0&raftport=50001"
]
```

## 3.Node2を初期化します。

```
$ geth --datadir new-node-2 init genesis.json
INFO [02-28|15:18:01.070] Maximum peer count                       ETH=25 LES=0 total=25
INFO [02-28|15:18:01.077] Allocated cache and file handles         database=/Users/nakata/project/quorum/fromscratch/new-node-2/geth/chaindata cache=16 handles=16
INFO [02-28|15:18:01.196] Writing custom genesis block 
INFO [02-28|15:18:01.197] Persisted trie from memory database      nodes=3 size=417.00B time=108.489µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [02-28|15:18:01.197] Successfully wrote genesis state         database=chaindata                                                          hash=6a66c3…c74d9d
INFO [02-28|15:18:01.197] Allocated cache and file handles         database=/Users/nakata/project/quorum/fromscratch/new-node-2/geth/lightchaindata cache=16 handles=16
INFO [02-28|15:18:01.266] Writing custom genesis block 
INFO [02-28|15:18:01.266] Persisted trie from memory database      nodes=3 size=417.00B time=123.111µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [02-28|15:18:01.267] Successfully wrote genesis state         database=lightchaindata                                                          hash=6a66c3…c74d9d
```

## 4.Node2を追加する
既に動いているNode１に接続し、`addPeer()`コマンドを実施する。

```
$ geth attach new-node-1/geth.ipc
Welcome to the Geth JavaScript console!

instance: Geth/v1.8.18-stable-4b125de4(quorum-v2.4.0)/darwin-amd64/go1.13.1
coinbase: 0x86961e4ee758b8f1f5f8a5a308139c48592f3db9
at block: 0 (Thu, 01 Jan 1970 09:00:00 JST)
 datadir: /Users/nakata/project/quorum/fromscratch/new-node-1
 modules: admin:1.0 debug:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 personal:1.0 raft:1.0 rpc:1.0 txpool:1.0 web3:1.0

> raft.addPeer('enode://30f87ff91dc8a3736160db818f441d60b4f21f297e5aa8a18b266c0c3a2d29950d1fa2123e059810ccf55411bef318b03e0ef3794df49668262aed25bd4daafb@127.0.0.1:21001?discport=0&raftport=50001')
2
> raft
{
  cluster: [{
      hostname: "127.0.0.1",
      nodeActive: false,
      nodeId: "30f87ff91dc8a3736160db818f441d60b4f21f297e5aa8a18b266c0c3a2d29950d1fa2123e059810ccf55411bef318b03e0ef3794df49668262aed25bd4daafb",
      p2pPort: 21001,
      raftId: 2,
      raftPort: 50001,
      role: "verifier"
  }, {
      hostname: "127.0.0.1",
      nodeActive: true,
      nodeId: "20591db5036fedd953fe7e2da47df8e4661bc1bc3c33aa21a2ffe7817442033e009c3599f05e0977ba8abcb8b89c66f7b602cd21906d19e423156f9a038834db",
      p2pPort: 21000,
      raftId: 1,
      raftPort: 50000,
      role: "minter"
  }],
  leader: "20591db5036fedd953fe7e2da47df8e4661bc1bc3c33aa21a2ffe7817442033e009c3599f05e0977ba8abcb8b89c66f7b602cd21906d19e423156f9a038834db",
  role: "minter",
  addLearner: function(),
  addPeer: function(),
  getCluster: function(callback),
  getLeader: function(callback),
  getRole: function(callback),
  promoteToPeer: function(),
  removePeer: function()
}
```

## 5.Node2を開始する

シェルを作成する。

```startnode2.sh
#!/bin/bash
PRIVATE_CONFIG=ignore nohup geth --datadir new-node-2 --nodiscover --verbosity 5 --networkid 31337 --raft --raftport 50001 --raftjoinexisting 2 --rpc --rpcaddr 0.0.0.0 --rpcport 22001 --rpcapi admin,db,eth,debug,miner,net,shh,txpool,personal,web3,quorum,raft --emitcheckpoints --port 21001 2>>node2.log &
```

Node2を実施します。

```
$ ./startnode2.sh 
nakataryuuzounoiMac:fromscratch nakata$ ps
  PID TTY           TIME CMD
 6793 ttys001    0:01.19 -bash
27012 ttys001    0:09.04 geth --datadir new-node-1 --nodiscover --verbosity 5 --networkid 31337 --raft --raftport 50000 --rpc --rpcaddr 0.0.0.0 --rpcport 22000 --rpcapi admin,db,eth,debug,miner,net,shh,txpool,personal,web3,quorum,raft --emitcheckpoints --port 21000
29112 ttys001    0:00.21 geth --datadir new-node-2 --nodiscover --verbosity 5 --networkid 31337 --raft --raftport 50001 --raftjoinexisting 2 --rpc --rpcaddr 0.0.0.0 --rpcport 22001 --rpcapi admin,db,eth,debug,miner,net,shh,txpool,personal,web3,quorum,raft --emitcheckpoints 
n
```

## 6. Node1へ`static-nodes.json`をシェア

```
$ cp new-node-2/static-nodes.json new-node-1
```

# Nodeの削除

## 1.動作しているチェーンから、`RAFT_ID`を取得します。

```
nakataryuuzounoiMac:fromscratch nakata$ geth attach new-node-1/geth.ipc
Welcome to the Geth JavaScript console!

instance: Geth/v1.8.18-stable-4b125de4(quorum-v2.4.0)/darwin-amd64/go1.13.1
coinbase: 0x86961e4ee758b8f1f5f8a5a308139c48592f3db9
at block: 0 (Thu, 01 Jan 1970 09:00:00 JST)
 datadir: /Users/nakata/project/quorum/fromscratch/new-node-1
 modules: admin:1.0 debug:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 personal:1.0 raft:1.0 rpc:1.0 txpool:1.0 web3:1.0

> raft.cluster
[{
    hostname: "127.0.0.1",
    nodeActive: true,
    nodeId: "30f87ff91dc8a3736160db818f441d60b4f21f297e5aa8a18b266c0c3a2d29950d1fa2123e059810ccf55411bef318b03e0ef3794df49668262aed25bd4daafb",
    p2pPort: 21001,
    raftId: 2,
    raftPort: 50001,
    role: "verifier"
}, {
    hostname: "127.0.0.1",
    nodeActive: true,
    nodeId: "20591db5036fedd953fe7e2da47df8e4661bc1bc3c33aa21a2ffe7817442033e009c3599f05e0977ba8abcb8b89c66f7b602cd21906d19e423156f9a038834db",
    p2pPort: 21000,
    raftId: 1,
    raftPort: 50000,
    role: "minter"
}]
```

2番を削除してみましょう。

## 2.`raft.removePeer()`を実行する

```
> raft.removePeer(2)
null
> raft.cluster
[{
    hostname: "127.0.0.1",
    nodeActive: true,
    nodeId: "20591db5036fedd953fe7e2da47df8e4661bc1bc3c33aa21a2ffe7817442033e009c3599f05e0977ba8abcb8b89c66f7b602cd21906d19e423156f9a038834db",
    p2pPort: 21000,
    raftId: 1,
    raftPort: 50000,
    role: "minter"
}]
```

## 3.`geth`を終了します。

```
$ ps | grep geth
27012 ttys001    0:13.61 geth --datadir new-node-1 --nodiscover --verbosity 5 --networkid 31337 --raft --raftport 50000 --rpc --rpcaddr 0.0.0.0 --rpcport 22000 --rpcapi admin,db,eth,debug,miner,net,shh,txpool,personal,web3,quorum,raft --emitcheckpoints --port 21000
29112 ttys001    0:04.63 geth --datadir new-node-2 --nodiscover --verbosity 5 --networkid 31337 --raft --raftport 50001 --raftjoinexisting 2 --rpc --rpcaddr 0.0.0.0 --rpcport 22001 --rpcapi admin,db,eth,debug,miner,net,shh,txpool,personal,web3,quorum,raft --emitcheckpoints --port 21001
$ kill 29112
$ ps | grep geth
  PID TTY           TIME CMD
27012 ttys001    0:13.93 geth --datadir new-node-1 --nodiscover --verbosity 5 --networkid 31337 --raft --raftport 50000 --rpc --rpcaddr 0.0.0.0 --rpcport 22000 --rpcapi admin,db,eth,debug,miner,net,shh,txpool,personal,web3,quorum,raft --emitcheckpoints --port 21000
```

# 終わりに
Nodeの追加/削除できるようになりました。
コントラクトの生成など試したことがまだありますね。