Quorum (geth) のソースコードを修正して試す環境を構築する

# はじめに

[以前の記事](https://qiita.com/doskin/items/61fc50996c1a4ef1cb48) で [quorum の公式 example](https://github.com/jpmorganchase/quorum-examples) を使ってプライベート Tx を試してみました。

本記事では、quorum のソースコード (quorum 2.0.2 は geth 1.7.2 の fork) を修正しながらネットワークを構築し、トランザクションを試してみます。

本記事の内容は [こちらの repository](https://github.com/tsuzukit/quorum-docker-Nnodes-1) に纏めたので興味がある方は実際に動かしてみてください。この repository は ConcenSys が作った quorum 学習用の repository をちょっと改造して気軽に geth 側のソースコードも弄れるようにしたものです。実際にこの環境で quorum を触っていた際にバグを見つけましたが、修正をして動作確認を行い、[プルリク](https://github.com/jpmorganchase/quorum/pull/350)を投げるといった事にも利用出来ました。

# 全体構成

全体構成としては、Docker-compose で quorum の network を構築しつつ、truffle を使えるコンテナを立ててそこからテストコマンドなどを実行できるようにします。

quorum の node が建っているコンテナに `docker exec` して `geth attach` を行う事ももちろん可能ですが、実際のユースケースでは Web3 + JSONRpc といったアクセスが想定されるため truffle のコンテナを建てて気軽に試せるようにします。 

<img width="817" alt="quorum-dev.png" src="https://qiita-image-store.s3.amazonaws.com/0/28899/4fabcaab-edcc-c900-c946-3cd567dee5cc.png">

# 使い方

ここから、実際に環境の準備の仕方を解説します。

## セットアップ

[Docker for mac](https://www.docker.com/docker-mac) をインストールしておいてください。
Docker がインストールされたら repository を clone して submodule を初期化します。

```bash
$ git clone git@github.com:tsuzukit/quorum-docker-Nnodes-1.git
$ git submodule update --init
```

Submodule になっている folder が quorum のソースコードです。Default では本家の dev ブランチを持って来ますが、適宜ご自分の fork した repository に向けるなどしてください。

## ビルド

以下のコマンドでコンテナイメージをビルドできます。

```bash
$ sh script/build-all.sh
```

`quorum` イメージと `truffle` イメージがビルドされます。
`quorum` イメージビルド時に submodule のソースコードから quorum をビルドします。

```Dockerfile 
COPY ./ /work/env

RUN  cd env/quorum && \
     make all && \
     cp build/bin/geth /usr/local/bin && \
     cp build/bin/bootnode /usr/local/bin && \
     cd ../.. && \
     rm -rf env
```
[Dockerfile](https://github.com/tsuzukit/quorum-docker-Nnodes-1/blob/master/docker/quorum/Dockerfile#L35-L40) から抜粋
 
## 起動

起動の前に何台の quorum node で network を構築したいかを決めます。
`Nnodes/setup.sh` をエディタで開いて、`ips` 変数に必要な台数分の ip を記載してください。下記例では 3 台の quorum node で network を構築します。

```
ips=("172.13.0.2" "172.13.0.3" "172.13.0.4")
```

下記コマンドで `docker-compose.yml` ファイルなど必要なファイルを作成します。プライベート Tx に必要な `constellation` の public key もこの時に作成されます。

```bash
$ ./setup.sh
```

セットアップが終わったらいよいよ起動します。

```bash
$ docker-compose up -d
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                     NAMES
ca860bc74dd9        quorum              "/qdata/start-node.sh"   42 minutes ago      Up 42 minutes       0.0.0.0:27003->9000/tcp   nnodes_node_3_1
8bd3c56a5811        quorum              "/qdata/start-node.sh"   42 minutes ago      Up 42 minutes       0.0.0.0:27001->9000/tcp   nnodes_node_1_1
72b64cff36e0        quorum              "/qdata/start-node.sh"   42 minutes ago      Up 42 minutes       0.0.0.0:27002->9000/tcp   nnodes_node_2_1
7f5a4dd6bef7        truffle             "/bin/sh -c 'tail -f…"   42 minutes ago      Up 42 minutes                                 nnodes_truffle_1
```

これで無事にネットワークが起動されました。

## トランザクションを投げてみる

`nnodes_truffle_1` にいくつかサンプルスクリプトを作ってあるので、それで動作確認が出来ます。また、自分でコントラクトを作って　deploy してテストするという事も可能です。コンテナの中は `truffle` コマンドが使えるようになっていますので、solidity のコンパイルなども可能です。

下記コマンドでコンテナに入り　`scripts` フォルダに移動します。

```
$ docker exec -it nnodes_truffle_1 ash
$ cd scripts
```

scripts フォルダの中の `.js` ファイルは中で web3 を JSONRpc　経由で quorum に繋いで Tx を投げています。

```
const Web3 = require('web3');
// 172.13.0.2:8545 が docker-compose の network 内に建っている geth の node ip と port
const provider = new Web3.providers.HttpProvider("http://172.13.0.2:8545"); 
const web3 = new Web3(provider);
```

`scripts` フォルダの中に色々な種類の Tx を発行出来るようにサンプルを用意したので、必要に応じて実行してみてください。

```
# ls -al
deploy_erc20.js // 独自 ERC20 を deploy する
private.js // private transaction を投げる
public.js // public transaction を投げる
send.js // ether を送る
sign.js // Tx にサインして rlp encode されたデータを得る （quorum node に Tx は投げない)
```

# Quorum のソースコードを修正

Quorum のソースコードの修正の仕方は非常に簡単です。
`quorum` フォルダに入って、必要な修正を行います。

例えば [Tx の Singer を作る Quorum 独自メソッド](https://github.com/jpmorganchase/quorum/blob/master/core/types/transaction_signing.go#L43) の直前に Log を仕込んでみます。

```golang

import (
    ...
    "github.com/ethereum/go-ethereum/log"
)

func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer { 
    log.Warn("Just a test log")
...
}
```

この状態で、 image をビルドし直して再起動すれば修正が反映された形で再度ネットワークが構築されます。

```
$ sh script/stop.sh
$ sh script/rebuild-quorum.sh
$ cd NNodes
$ ./setup.sh
$ docker-compose up -d
```

network が起動したら、Tx を投げてみると実際に Log が表示されるのがわかります。

下記コマンドでログを出しながら、truffle コンテナから Tx を投げ込むとログが見えます。

```
$ tail -f qdata_1/logs/geth.log
...
WARN [04-27|08:47:41] Just a test log 
``` 

# 終わりに

おそらく同様のやり方は go-ethereum 本体でも使えると思います。開発には Visual Studio Code を使っている方が多いと思いますが、ちょっとした動作確認は unit test 等で行って、ネットワーク上での挙動や結合テスト的なものなどを、ローカルマシン上に作った簡易な環境でテスト出来るので、それなりに捗りそうだなと思います。私はまだ go-ethereum を触り始めたばかりなのでこの環境で動かしながら理解を深めたいと思います。