Enterprise ethereum の quorum を試して見る

# はじめに

[Quorum](https://www.jpmorgan.com/global/Quorum) は J.P Morgan が開発を進めているエンタープライズ用に Ethereum を fork したものです。具体的には [go-ethereum](https://github.com/ethereum/go-ethereum) (geth) の fork で 2018 年 4 月時点では geth 1.7.2 をベースにした Quorum 2.0.2 が最新です。

Quorum の概要と実際に private network を触って見る所までを記事にまとめました。

# Qurorum とは

簡単に言うと Enterprise 版の Ethereum で、以下の機能を Ethereum に追加しています。

- トランザクションのプライバシー管理機能
- ネットワークに参加可能なノードの管理機能
- プラガブルで高速なコンセンサスメカニズム

[ドキュメントの repository](https://github.com/jpmorganchase/quorum-docs/blob/master/Quorum_Architecture_20171016.pdf) にあるスライドにわかりやすく説明してあります。

<img width="769" alt="quorum_1.png" src="https://qiita-image-store.s3.amazonaws.com/0/28899/9ef34603-d154-7bc3-710d-03e9876027c2.png">

## トランザクションのプライバシー管理

通常 Ethereum では全てのデータが公開されていますが、Quorum では特定のコントラクトやトランザクションを特定のノード間のみに公開しその他のノードには非公開にする事が可能です。

## ノードの管理

Quorum ではネットワークに参加するノードを制限する事が可能です。これにより、悪意のある第三者などが勝手にノードを立ててネットワークに参加する、などといった事が起こらないように出来ます。

## コンセンサスメカニズム

ご存知の通り Ethereum は Proof of work コンセンサスメカニズムを採用していますが Quorum ではネットワークに参加するノードが管理されているのでもっと高速なコンセンサスメカニズムを採用可能です。現時点では以下の 2 つが実装されているようです。

- Raft based コンセンサス
- イスタンブール BFT

# 実際に動かして試してみる

この [repository](https://github.com/jpmorganchase/quorum-examples) に quorum のテスト環境がまとまっている。内容としては、7 つの quorum node を同時に動かして、上述のプライバシー管理やノード管理を実際に触って見る事が出来るというものです。

## 事前準備

[VirtualBox](https://www.virtualbox.org/wiki/Downloads) と [Vagrant] (https://www.vagrantup.com/downloads.html) をインストールしておきます。因みに私は Vagrant のバージョンが古すぎた為、最初の base box のダウンロードでこけてハマりました。Vagrant 2.0.3 にバージョンアップしたら問題が解決しました。

## 環境構築

repository の root フォルダで下記コマンドを実行

```console
$ vagrant up
```

## Vagrant 環境に入る

Vagrant が準備できたら中に入り、デモがあるフォルダに移動します。

```console
$ vagrant ssh
$ cd quorum-examples/7nodes/
```

## node を起動する

```console
$ ./raft-init.sh
$ ./raft-start.sh
$ ps aux | grep geth
vagrant   9137  3.9 12.6 1356092 259632 pts/0  Sl   14:07   0:19 geth --datadir qdata/dd1 --raft --rpc --rpcaddr 0.0.0.0 --rpcapi admin,db,eth,debug,miner,net,shh,txpool,personal,web3,quorum --emitcheckpoints --permissioned --raftport 50401 --rpcport 22000 --port 21000 --unlock 0 --password passwords.txt
vagrant   9138  3.7  8.5 1082268 174140 pts/0  Sl   14:07   0:18 geth --datadir qdata/dd2 --raft --rpc --rpcaddr 0.0.0.0 --rpcapi admin,db,eth,debug,miner,net,shh,txpool,personal,web3,quorum --emitcheckpoints --permissioned --raftport 50402 --rpcport 22001 --port 21001
vagrant   9139  3.8  8.5 1016668 174704 pts/0  Sl   14:07   0:19 geth --datadir qdata/dd3 --raft --rpc --rpcaddr 0.0.0.0 --rpcapi admin,db,eth,debug,miner,net,shh,txpool,personal,web3,quorum --emitcheckpoints --permissioned --raftport 50403 --rpcport 22002 --port 21002
vagrant   9140  4.2  8.6 994516 177340 pts/0   Sl   14:07   0:21 geth --datadir qdata/dd4 --raft --rpc --rpcaddr 0.0.0.0 --rpcapi admin,db,eth,debug,miner,net,shh,txpool,personal,web3,quorum --emitcheckpoints --permissioned --raftport 50404 --rpcport 22003 --port 21003
vagrant   9141  3.8  8.6 1001336 176364 pts/0  Sl   14:07   0:19 geth --datadir qdata/dd5 --raft --rpc --rpcaddr 0.0.0.0 --rpcapi admin,db,eth,debug,miner,net,shh,txpool,personal,web3,quorum --emitcheckpoints --raftport 50405 --rpcport 22004 --port 21004
vagrant   9142  3.8  8.5 1009528 175524 pts/0  Sl   14:07   0:19 geth --datadir qdata/dd6 --raft --rpc --rpcaddr 0.0.0.0 --rpcapi admin,db,eth,debug,miner,net,shh,txpool,personal,web3,quorum --emitcheckpoints --raftport 50406 --rpcport 22005 --port 21005
vagrant   9143  3.9  8.4 1310672 173256 pts/0  Sl   14:07   0:19 geth --datadir qdata/dd7 --raft --rpc --rpcaddr 0.0.0.0 --rpcapi admin,db,eth,debug,miner,net,shh,txpool,personal,web3,quorum --emitcheckpoints --raftport 50407 --rpcport 22006 --port 21006
vagrant   9381  0.0  0.0  12944   900 pts/0    S+   14:16   0:00 grep --color=auto geth
```

* `raft-init.sh` は内部で `cp raft/nodekey<x> qdata/dd<x>/geth/nodekey` を呼んでいます。この nodekey を　使って生成されるのが `enode` と呼ばれる geth node の固有 ID です。この `enode` はノードの管理を行う際に重要です。

## トランザクションのプライバシー管理を試す

まずは `geth` が立ち上がっている状態で smartcontract を作ります。

```
$ ./runscript.sh script1.js
```

この smartcontract は非常にシンプルなもので `simplestorage.sol` が実装で、compile された ABI と Bytecode が `script1.js` に直接記載してあります。

`script1.js` ではこのコントラクトを node1 と node7 にしか公開しないようにするためにコントラクトの作成時に `privateFor` パラメーターを指定しています。

```
simpleContract.new(42, {from:web3.eth.accounts[0], data: bytecode, gas: 0x47b760, privateFor: ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]}, () => {});
```

`privateFor` には自分の ID は含めないので、ここではコントラクトの作成者である node1 と `ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc` で指定される node7 に対して公開され、それ以外のノードには公開されません。

コマンドを実行すると quorum 上に simplestorage コントラクトが作られるので確認します。
`less qdata/log/1.log` に tx が記載されているのでそれを使って `contract address` が確認できます。

```
$ geth attach ipc:qdata/dd1/geth.ipc
> eth.getTransactionReceipt("Tx hash")
{
  blockHash: "0x6a41f637680140a5eec70fdee8331221954a77c70bc426abf66f400ca428fa5f",
  blockNumber: 1,
  contractAddress: "0x1932c48b2bf8102ba33b4a6b545c32236e342f34",
  cumulativeGasUsed: 0,
  from: "0xed9d02e382b34818e88b88a309c7fe71e65f419d",
  gasUsed: 0,
  logs: [],
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  root: "0x51508436508985c1606f18235b61c606f1387ab1e7090ebc997f768f2a3fee0a",
  to: null,
  transactionHash: "0xd1ef3d4bd0051291e21470a7868cf712b674f94709ca4280d4b79a020fc21a3c",
  transactionIndex: 0
}
```

では、このコントラクトアドレスを使ってプライバシーを確認します。まずターミナルを 3 つ立ち上げて、それぞれ node1, node4, node7 の geth のインタラクティブモードに入ります。それぞれで下記コマンドを打ってテストの準備をします。

```
> var address = "0x1932c48b2bf8102ba33b4a6b545c32236e342f34";
> var abi = [{"constant":true,"inputs":[],"name":"storedData","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"x","type":"uint256"}],"name":"set","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"},{"inputs":[{"name":"initVal","type":"uint256"}],"type":"constructor"}];
> var private = eth.contract(abi).at(address)
```

まずは初期値の確認を行います。 `script1.js` によると、simplestoraget コントラクトの初期値は 42 です。各ノードでそれぞれ値を読むと、node4 だけが 0 になっている事がわかります。

- node1

```
> private.get()
42
```

- node4

```
> private.get()
0
```

- node7

```
> private.get()
42
```

また、値の更新のクエリを発行時にも権限を指定する事ができます。

```
> private.set(4,{from:eth.coinbase,privateFor:["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]});
```

再度各ノードで値を読んで見ると

- node1

```
> private.get()
4
```

- node4

```
> private.get()
0
```

- node7

```
> private.get()
4
```

となります。

最後に、トランザクションで node7 を権限んから外し、node4 をいれてみます。

```
> private.set(10,{from:eth.coinbase,privateFor:["oNspPPgszVUFw0qmGFfWwh1uxVUXgvBxleXORHj07g8"]});
```

各ノードで値を読んで見ると

- node1

```
> private.get()
10
```

- node4

```
> private.get()
0
```

- node7

```
> private.get()
0
```

となります。node7 は権限から外されているから読めませんが node4 も値が読めていません。これは node4 はそもそも contract 自体へのアクセス権限を持っていないからと考えられます。

# 終わりに

Enterprise 版 Ethereum である Qurorm を触ってみました。まだまだ何とか動かせたという感じでしたが、コンセプトは面白いなと思いました。また、トンラザクションは非常に早く Gas 代も掛からない為、旨く使えばかなり面白いサービスが作れるのでは無いかと思います。もう少し触ってみて実際のサービスでの使い方などを模索したいと思います。