RaspberryPi4をETH2 Validatorにする(Nimbus Eth2使用)


#概要
RaspberryPi4 4GBで[Nimbus Eth2][NimbusURL](Validator)を実行するまでの手順メモです。


##やること

* ETH2メインネットでのNimbus実行環境を整える。
    * テストネットで実行する際も、手順は基本的に同一だが、テストネット用のETHをデポジットして、実行時の引数も置き換える必要がある。
* サービス登録して起動時に自動実行する。
* グローバルIPアドレスの変更に自動追従する。

基本的に、[Nimus公式のガイド][NimGuideURL]を参考にしています。
[Eth2 Staker Checklist](https://launchpad.ethereum.org/checklist)も参照。
また、基本的にメインネット前提に記載していますが、最初はテストネットで試した方が良いと思います。


#環境

* Raspberry Pi4 4GB
* SSD(書いた人は[Transcend SSD 480GB 2.5インチ](https://www.amazon.co.jp/gp/product/B01DRWWLUO/ref=ppx_yo_dt_b_asin_title_o09_s00?ie=UTF8&psc=1)を使用)
    * 性能の低い製品だとNimbusの動作に追いつかないので注意。
* ブロードバンド環境
    * グローバルIPを占有できる接続環境が必須。
    * 速度は1Mbps/s程度で良い(実行中は13GB/day程度、通信量を消費)
        * Wimaxルータは、大半(全部？)の使い放題プランでも10GB/3dayの通信量制限がある。制限を超えると混雑時(夕方から深夜帯)に1Mbps/s程度に速度制限されるが、Nimbusの動作は問題無い模様。
* 作業用PC(書いた人はWindows：Linuxの方が良いと思います)

#事前準備

* [infura][infuraURL]のアカウントを取得
* [ETH2 Launch Pad][Eth2LaunchURL]で32ETHをデポジット
    * デポジット後、ValidatorがActivateされた後、Nimbus(に限らずValidatorクライアント)が動作していないとペナルティとなるので注意。
    * デポジットからActivateまでには、2021/1/30時点で[16日程度待たされる][PendigValidatorURL])ので、それまでにセットアップを完了させる。(ノード同期に数日-1週間程度かかる)
    * ValidatorのActivateは遅れるが、安全のためにデポジットを後回しにしても可。
    * [テストネット用のLaunch Padはこちら。](https://pyrmont.launchpad.ethereum.org/)


#RaspberryPi4のセットアップ


##64bit RaspberryPi OSのインストール

[64bit版のイメージ][RaspberryURL]をDLし、[Raspberry Pi Imager][ImagerURL]を使用してmicroSDに書き込み、起動ディスクを作成。
microSDをラズパイのスロットに挿入すれば起動できる。


##セキュリティ設定
以下を設定する。
参考：[ラズパイでやらなければいけない４つのセキュリティ対策！](https://qiita.com/nokonoko_1203/items/94a888444d5019f23a11#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB)


* rootのパスワードを設定
* 操作用のユーザーを追加
* "pi"(デフォルト)ユーザーを削除
* 自動ログインを無効化
* SSH設定変更
    * パスワード認証無効(公開鍵認証のみ有効)
    * 空パスワード無効
    * root接続無効
    * SSH接続ポート番号変更


###ファイアウォール(UFW)設定
NimbusはデフォルトでTCP&UDP 9000番ポートで待ち受けるため、このポートだけ開放する。(SSH使用する場合は、該当ポートも開放)
参考：[Raspbianにファイアウォールufwのインストールと設定](https://raspida.com/firewall4raspbian-ufw)

初期状態ではUFWはインストールされていないので、まずインストールする。

```shell:
sudo apt install ufw
```

インストール直後はdisable&受信は全て拒否なので、Nimbus待ち受けポートを開放した後有効化する。

```shell:
#TCP&UDP 9000番ポートの受信を開放
sudo ufw allow 9000
#有効化
sudo ufw enable
#再起動
reboot
```

##Nimbusの依存関係をインストール

```shell:
sudo apt-get install git
```

##パフォーマンス関連の設定

※ラズパイ上の処理が間に合っていない場合、Nimbusのログに以下出力が大量に残る。

```shell:
Catching up on validator duties
```

###Swapメモリの設定
Nimbus公式によると、2GB以上のSwapを設定すべきとのこと。
参考：[increase-swap-size-to-2gb](https://nimbus.guide/pi-guide.html#9-increase-swap-size-to-2gb)

※2021/1/30時点でNimbusでValidator実行中のメモリ消費量は700MB(GUI使用でもシステム全体で950MB)程度。
　今のところ、あまり必要ないかも。

###OSのログ出力を削減
Nimbusは大量にSSDアクセスするので、OSログを出来るだけ減らした方が良い。
参考：[【STEP-29】Raspbianのログ出力を抑制してSSDを延命化](https://www.fabshop.jp/%E3%80%90step-29%E3%80%91raspbian%E3%81%AE%E3%83%AD%E3%82%B0%E5%87%BA%E5%8A%9B%E3%82%92%E6%8A%91%E5%88%B6%E3%81%97%E3%81%A6ssd%E3%82%92%E5%BB%B6%E5%91%BD%E5%8C%96/)

##SSDから起動可能にする

[こちら][SSDBootURL]を参考に、microSDの内容をSSDにコピー。
※この段階までに、ここまでのRasperryPi OSの設定を行っておく。
　SSDにコピーした後のmicroSDを保管しておけば、
　SSDが破損したときなどに、別のSSDへコピーしなおすことで、環境を迅速に復旧できる。
　(Nimbus停止中は、動作中の報酬と同程度のETHがペナルティとして減ってゆくので、迅速に復旧が必要)


##Nimbusの実行

###ビルド

```shell:
#ソースコードを取得
git clone https://github.com/status-im/nimbus-eth2
#取得したソースのフォルダに移動
cd nimbus-eth2
#ビルド
make nimbus_beacon_node
```
※[最近のリリース][Nim1.0.6ReleaseURL]ではバイナリがUPされているので、それを使用してもよい。

###Validatorキーのインポート

"nimbus-eth2/validator_keys"下に、[ETH2 Launch Pad][ETH2LaunchURL]でデポジットした時に出力したkeystoreファイルを配置し、"nimbus-eth2"下で以下コマンドを実行。

```shell:
build/nimbus_beacon_node deposits import --data-dir=build/data/shared_mainnet_0
```

"nimbus-eth2/build/data/shared_mainnet_0"下の"secrets"と"validators"はバックアップしておく。

###Nimbus(Validator)実行
単に実行するだけなら、オプション無しの以下コマンド。

```shell:
./run-mainnet-beacon-node.sh
```
実行すると、ETH1クライアントのURLを求められるので入力。
※ETH1クライアントはGethなどを自分で立ち上げるのが理想だが、さらに大容量のSSD(2021/1時点で[350GB以上](https://etherscan.io/chartsync/chaindefault))が必要なので、[infura][infuraURL]で代替する。(フリープランで十分利用可能)

ただ、オプション無しでは以下の問題(大きいのは1)がある。

1. ラズパイがルータの背後にいる場合、他のノードから見つけられない。結果、peer(接続する他ノードの数)が低くなる。
    * peerは最大160で、正常に接続できていれば1時間かからず到達するが、この状態だと20-40程度までしか上がらなくなる。peerが少ないとattestation(検証)がネットワークに伝達されず(?)、失敗扱いになり、その分の報酬がマイナスとなる。(最悪50%程度失敗する)
2. Nimbus動作中は、結構な量のログを出力する。特に同期中は長時間化の要因になるので出力を削減した方が良い。

そのため、以下のオプションを追加してNimbusを起動する。

```shell:
#"--nat:extip:$(curl ifconfig.io)"：グローバルIPを設定
#"--log-level=NOTICE"：ログ出力量を削減
./run-mainnet-beacon-node.sh --nat:extip:$(curl ifconfig.io) --log-level=NOTICE
```

※Nimbus公式の[Log-levels](https://github.com/status-im/nimbus-eth2/wiki/Log-levels)には、利用可能なオプションが示されている。


####ルータ設定について
上記の"--nat:extip"を設定しても、ルータ側にも設定を行わないと、9000番ポートで待ち受けが出来ないので、結局peerが上がらない。

* ルータでTCP&UDP 9000番ポートをラズパイのIPアドレスのフォーワーディング設定する。
* グローバルIPアドレスを占有する。
    * ポケットWifiや、集合住宅のネット接続サービスでは、他の回線利用者とグローバルIPを共有している。
        * [WimaxルータはグローバルIPの占有設定が利用できる(有料)][UQGlobalIPURL]
        * しかし、占有してもWimaxルータのグローバルIPは定期的に変わってしまうため、都度"--nat:extip"を設定して再起動が必要。
    * 設定後、外部からアクセス可能かは[Zenmap][ZenmapURL]で確認可能。


まずノードの同期が必要(数日かかる)で、その間はValidator実行状態にならない。
ETH2 Launch Padでのデポジット後、Activateされるまで時間がある(2021/1/30時点で[16日程度待たされる][PendigValidatorURL])ので、それまでに同期を完了させる。


###Nimbusをサービスに登録
ここまででもNimbusは実行できるが、サービスに登録しておけば、OS起動時に自動実行できる。
また、次節のグローバルIP変更追従のためにもサービス登録が必要。


参考：[Set up a systemd service](https://nimbus.guide/beacon-node-systemd.html)

以下"nbc.service"を作成し、"/etc/systemd/system/"に保存する。
実行時のグローバルIPを反映するよう、ExecStartPreを追加。
参考：[systemd の Environment / EnvironmentFile では変数展開できません](https://qiita.com/kobanyan/items/f8e8a3bd5406e1d290fb#%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%81%AE%E5%AE%9F%E8%A1%8C%E7%B5%90%E6%9E%9C%E3%82%92%E5%A4%89%E6%95%B0%E3%81%A8%E3%81%97%E3%81%A6%E4%BD%BF%E3%81%84%E3%81%9F%E3%81%84%E5%A0%B4%E5%90%88)

```:/etc/systemd/system/nbc.service
[Unit]
Description=Nimbus beacon node

[Service]
WorkingDirectory=【Nimbusのルートフォルダ("nimbus-eth2")フルパス】
ExecStartPre=+/bin/sh -c "/bin/systemctl set-environment VALIDATOR_GLOBAL_IP=$(curl -s ifconfig.io)"
ExecStart=【Nimbusのルートフォルダ("nimbus-eth2")フルパス】/build/nimbus_beacon_node \
  --non-interactive \
  --network=mainnet \
  --data-dir=build/data/shared_mainnet_0 \
  --web3-url=【ETH1クライアントのURL】 \
  --rpc:on \
  --metrics:off \
  --nat:extip:${VALIDATOR_GLOBAL_IP} \
  --log-file=【ログ出力先フルパス】 \
  --log-level=NOTICE
User=【ログインユーザ名】
Group=【ログインユーザ名】
Restart=always

[Install]
WantedBy=default.target
```

上記を保存したうえで、systemctlを実行。

```shell:
sudo systemctl daemon-reload
sudo systemctl enable nbc --now
```

###グローバルIPアドレス変更に自動追従してNimbusを実行

サービス実行しても、前述のとおり、グローバルIPが定期的に変更されてしまうネット環境では、そのIPを反映してNimbusを再起動する必要がある。
グローバルIPアドレス変更をトリガに、nbcサービスを再起動するスクリプトを、
cronにサービス登録することで、自動追従する。

参考：
[Lubuntuで自宅IPの変更通知](https://qiita.com/picky-tak/items/2db32a3b35e5e5d598e7)
[ラズベリーパイ4でcronを動かす
](https://qiita.com/gdate/items/bdf6c620404679063211)

```shell:AutoRestartNBC.sh
#現在のグローバルIPを取得.
ipaddress=$(curl -s ifconfig.io)
#/tmp/global_ipaddressに前回実行時(1分前)のグローバルIPを格納.
global_ipaddress=$(cat /tmp/global_ipaddress)

#現在と前回実行時のグローバルIPを比較して,変更していたらnbcサービス再起動.
if [ "${ipaddress}" != "${global_ipaddress}" ]; then

  datetime=$(date +%Y%m%d_%H%M%S_%3N)
  echo "IP Address chenge:${datetime}  IP:${ipaddress}" >> 【ログ出力先フルパス】
  echo ${ipaddress} > /tmp/global_ipaddress  

  #nbcサービスを再起動.
  systemctl restart nbc.service
  datetime=$(date +%Y%m%d_%H%M%S_%3N)
  echo "nbc.service restart:${datetime}" >> 【ログ出力先フルパス】
fi
```


上記スクリプトをcronに登録して、定期実行する。

```shell:
sudo crontab -e
#crontabの編集モードになるので,末尾に以下を追記(毎分実行する設定になる).
* * * * * 【AutoRestartNBC.shのフルパス】
```


#その他

##SSDの消費量について

2021/1/30時点でDBサイズは4.6GB。今のところ2.3GB/Month程度増加。


[NimbusURL]:https://github.com/status-im/nimbus-eth2
[NimGuideURL]:https://nimbus.guide/
[RaspberryURL]:https://downloads.raspberrypi.org/raspios_arm64/images
[ImagerURL]:https://www.raspberrypi.org/downloads
[NimbusSwapURL]:https://nimbus.guide/pi-guide.html#9-increase-swap-size-to-2gb
[SwapURL]:https://a244.hateblo.jp/entry/2016/12/12/010429
[SSDBootURL]:https://www.tomshardware.com/how-to/boot-raspberry-pi-4-usb
[Nim1.0.6ReleaseURL]:https://github.com/status-im/nimbus-eth2/releases/tag/v1.0.6
[infuraURL]:https://infura.io/
[ZenmapURL]:https://www.websec-room.com/2014/02/08/1788#Zenmap-2
[UQGlobalIPURL]:https://www.uqwimax.jp/wimax/plan/option/global_ip/
[ETH2LaunchURL]:https://launchpad.ethereum.org/
[PendigValidatorURL]:https://beaconscan.com/validators#pending