Symbol Shoestringでのノード構築備忘録

# 構築したノード
Dual Node（Peer Node + API Node）
・将来的にRest改造を試してみたかったためAPI Nodeの機能が欲しかった

# サーバ
レンタルしたサーバ：Contabo Cloud VPS L

https://contabo.com/en/vps/vps-l-ssd/?image=ubuntu.267&qty=1&contract=1&storage-type=vps-l-800-gb-ssd

推奨に近いスペックで安価だったため選択
※2024年からスペック、料金体系が変わっている模様

https://contabo.com/en/vps-c/

| 項目 | 推奨 | 使用したもの |
|:-----------|:------------|:------------|
| CPU |8 Core | 8 Core |
| RAM | 32GB | 30 GB |
| Disk Size | 750 GB | 800 GB |
| Disk IOPS | 1500 IOPS SSD | 詳細な記載なし |

# 構築の前に
contaboサーバにデフォルトでインストールされていたPythonバージョンは3.8でしたがsymbol-shoestringの新しいバージョン（0.1.0）を利用するには3.9が必要なようなので何かしらの方法でPythonバージョンアップをお願いします。
※symbol-shoestringの旧バージョン（0.0.5）はPython3.8で動作することを確認しています。


https://qiita.com/dusanjp/items/53d440fa38cb2fabab10

# 環境情報
* Ubuntu 20.04.6 LTS
* Python 3.9.18
* pip 23.3.1
* Docker version 24.0.7, build afdd53b

# 構築手順
下記ページを参考に実施

https://symbol-community.com/ja/docs/5

https://symbol-community.com/ja/docs/33

### 操作用アカウント追加（usernameはお好きなものに変更してください）
```sh
adduser username
usermod -aG sudo username
su - username
```

### rootアカウントによるログイン禁止設定
※「vi チートシート」などで検索するとviコマンドの基本的な操作方法が分かると思います。
```shell
sudo vi /etc/ssh/sshd_config

# ファイル内に存在する下記設定を yes から no に変更
PermitRootLogin no
```
### 上記設定を反映
```shell
sudo systemctl restart ssh
```

### ミドルウェア追加
```shell
sudo apt install -y libssl-dev gettext
pip install PyOpenSSL --upgrade
pip install symbol-shoestring
```
### docker インストール
```shell
curl https://get.docker.com | sh
sudo usermod -aG docker username
sudo reboot
sudo systemctl start docker
sudo systemctl enable docker
```
### 作業用ディレクトリ（/symbol）作成
```shell
cd ~
mkdir symbol
```

### Wizard実行（ノードの設定項目入力）
```shell
python3 -m shoestring.wizard
```
Wizard内の詳細な設定は下記動画が大変参考になりました。

https://www.youtube.com/watch?v=f_TADrMYEx0

※ノードの[ハーベスト報酬](https://docs.symbol.dev/ja/concepts/harvesting.html#rewards)を受け取りたい方はbeneficiary addressの設定をお忘れなく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2239577/6ac97491-3408-7e5e-341e-261f980d25e4.png)


### ノード起動
```shell
cd ~/symbol
docker compose up -d
```

# ファイアウォール設定
公開したポート：80、3000、3001、7900、SSH用ポート

# 設定を変更したい場合の操作（upgrade）

### ノード停止
```shell
docker compose down
```

### 設定更新
`shoestring/overrides.ini`ファイルを更新
```shell
sudo vi ~/symbol/shoestring/overrides.ini
```
Wizardでupgrade実行
```shell
python3 -m shoestring.wizard
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2239577/81384335-180a-88a3-32d5-d8dc1a7e1f8d.png)

### ノード起動
```shell
docker compose up -d
```

※上記は[づ～さん](https://qiita.com/dusanjp)に教えていただきました。ありがとうございます！
shoestringに関する操作をまとめてくださってますのでこちらもご参照ください。

https://qiita.com/dusanjp/items/77a31056f04f2f95b4fb

https://x.com/dusanjp/status/1742548907903566068?s=20

https://x.com/dusanjp/status/1742551104678760692?s=20


# +αの設定
### NFT-DriveやCOMSAのエクスプローラー検索速度やXEMBookの表示速度向上

https://qiita.com/nem_takanobu/items/8e39cc02df1b7adccfee

コンテナ起動
```shell
cd ~/symbol
docker compose exec db bash
```
インデックス作成
```shell
mongo --host db
use catapult
db.transactions.createIndex({'transaction.mosaics.id' : 1});
db.transactionStatements.createIndex({'statement.receipts.targetAddress' : 1});
db.transactionStatements.createIndex({'statement.receipts.senderAddress' : 1});
db.transactions.reIndex();
db.transactionStatements.reIndex();
exit
exit
```
反映確認
```shell
cd ~/symbol
docker compose exec db bash
mongo --host db
use catapult
db.transactions.find({'transaction.mosaics.id': NumberLong("-6242235878428273386")}).explain('executionStats');
```
explain('executionStats')を実行してwinningPlanを確認して"stage" : "IXSCAN"　が表示されていればOK
```
> db.transactions.find({'transaction.mosaics.id': NumberLong("-6242235878428273386")}).explain('executionStats');
{
        "explainVersion" : "1",
        "queryPlanner" : {
                "namespace" : "catapult.transactions",
                "indexFilterSet" : false,
                "parsedQuery" : {
                        "transaction.mosaics.id" : {
                                "$eq" : NumberLong("-6242235878428273386")
                        }
                },
                "maxIndexedOrSolutionsReached" : false,
                "maxIndexedAndSolutionsReached" : false,
                "maxScansToExplodeReached" : false,
                "winningPlan" : {
                        "stage" : "FETCH",
                        "inputStage" : {
                                "stage" : "IXSCAN",★
                                ...
```
■検証
https://node.exymlab.com:3001/transactions/confirmed?embedded=true&transferMosaicId=0F2AFAE62B575AB3

インデックス見直し前の検索速度：5230 ms
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2239577/03366b69-3508-1125-7661-8b2be996b463.png)


見直し後の検索速度：995 ms
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2239577/9d566641-94a4-18fc-9e89-6e99b64011e2.png)

# ノードが停止してしまった際のワークアラウンド
### dockerステータス確認
```shell
cd ~/symbol
docker ps -a
```

### ノード停止
```shell
docker compose stop
```
docker compose downでも復旧自体はできた（元々あったコンテナは消えるので注意）

### 不要な.lockファイルを削除
```shell
rm data/broker.lock
rm data/server.lock
```

### ノード起動
```shell
docker compose up -d
```

### ステータス確認
起動から約1分後に実行する。STATUSがUPになっていればOK（起動が上手くいっていないケースだと、起動から約30秒経過した時点でclientおよびbrokerがExitedになっている）
```shell
docker ps -a
```
shoestringのコマンドからも確認

```shell
python -m shoestring health --config shoestring/shoestring.ini --directory $HOME/symbol
```
正常な時の出力例
```shell
     ...    | running health agent for peer certificate
      i     | ca certificate not near expiry (xxx day(s))
      i     | node certificate not near expiry (xxx day(s))
/home/user/symbol/keys/cert/ca.crt.pem: OK
/home/user/symbol/keys/cert/node.crt.pem: OK
     ...    | running health agent for peer API
      i     | peer API accessible, height = 4169702
     ...    | running health agent for REST HTTPS certificate
      i     | HTTPS certificate looks ok: valid from 25-01-10 to 25-04-10
     ...    | running health agent for REST API
      i     | REST API accessible, height = 4169702
     ...    | running health agent for REST websockets
      i     | websocket connected to wss://nodeurl.com:3001/ws, subscribing and waiting for block
      i     | websocket received a block with height 4169703
```

少し経った後にnode listで確認し、自身のノードが表示されていればOK（30分近くかかることもある）

https://symbolnodes.org/nodes/

その他、必要に応じてnode/healthやnode/unlockedaccoutを確認

https://node.exymlab.com:3001/node/health

https://node.exymlab.com:3001/node/unlockedaccount