symbol-bootstrapからshoestringへ移行


:::note warn
当記事の内容は、執筆時点における情報に基づいており、技術的な正確性や完全性を保証するものではありません。
記事内で紹介されている技術、手法、コード例は、あくまで個人的な検証であり、実際に利用する際には読者自身の判断と責任で行ってください。
:::

# この記事の目指すところ

今後はsymbol-bootstrapのメンテナンスが行われないので、コアデブの作成したツールshoestringでノードを運用する必要があります。
その際に、symbol-bootstrapからshoestringで構築したノードに素早く移行するためのノウハウの共有です。
shoestringで一からノードを同期させると（ある程度は）委任者が復元されますが時間がとてもかかります。
すでに同期済みのノードデータを使用しかつ委任者の復元は未だ手法が確立されていないので、その一助になればと思い執筆しました。



# 前提条件

- symbol-bootstrapでノードを運用していること
- gitが使えること（コマンドが使えたら良い）
- shoestringが実行できる環境があること

# 改良版shoestring

いきなりですが、現在のshoestringでは委任者の復元に失敗する（まだ誰も成功していない）ので、私が独自に検証し、公式ツールを修正した改良版shoestringツールで作業を行います。

- 公式shoestringのソースコードは[こちら](https://github.com/symbol/product/tree/dev/tools/shoestring)

- Python Package Index（PyPI）は[こちら](https://pypi.org/project/symbol-shoestring/
)

## Githubからソースコードを取得

- https://github.com/ishidad2/product/tree/dev/tools/shoestring

```bash
# リポジトリをクローン（ただし、ファイルをダウンロードしない）
git clone --no-checkout -b shoestring/feature/use-node-key-for-node-cert [git@github.com](mailto:git@github.com):ishidad2/product.git
cd product/

# sparse-checkout の初期化
git sparse-checkout init --cone

# 必要なフォルダを指定
git sparse-checkout set tools/shoestring/

# リポジトリの更新
git checkout shoestring/feature/use-node-key-for-node-cert
```

## インストール

```bash
# shoestringフォルダへ移動
cd tools/shoestring

# ローカルインストール
pip install .

Defaulting to user installation because normal site-packages is not writeable
Processing /home/xxx/product/tools/shoestring
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Preparing metadata (pyproject.toml) ... done
Building wheels for collected packages: shoestring
  Building wheel for shoestring (pyproject.toml) ... done
  Created wheel for shoestring: filename=shoestring-0.0.0-py3-none-any.whl size=67491 sha256=947741ebeb6ed6ccf190e6af23e16c910edef95ac126e23a10a0b3d05dfb58eb
  Stored in directory: /tmp/pip-ephem-wheel-cache-gw2gr9ie/wheels/dd/7f/20/9912afaf260129605b78640b6b1868bdafe41e6241e3827bd5
Successfully built shoestring
Installing collected packages: shoestring
  Attempting uninstall: shoestring
    Found existing installation: shoestring 0.0.0
    Uninstalling shoestring-0.0.0:
      Successfully uninstalled shoestring-0.0.0
Successfully installed shoestring-0.0.0
```

改良版shoestringのインストールは以上です。

# symbol-bootstrapから必要なデータを取得

少なくともcustom-preset.yml、harvesters.datがあればOKです。

ただし、以下の情報がなければ委任者の引き継ぎはできません。

```yaml
mainPrivateKey: 70736F7314FD1xxxxxxxxx
transportPrivateKey: A47623A15A332Exxxxxxx
remotePrivateKey: 00D1906388AAA250BD1xxxxxxx
vrfPrivateKey: A9F6F17F1FF07DC7319C57xxxxxxxxx
```

## 事前作業

shoestring用のノードを作るのですが、まずは委任者引き継ぎ用に必要なファイルを事前に作成しておきます。

まずは作業フォルダを作成します。

```bash
# homeへ移動
cd 

# 作業フォルダ作成&移動
mkdir src; cd src

# ca.key.pemの作成
# ca.key.pemはmainPrivateKeyより作成します
# hoestring.wizardを使うことでも作成できますが、ここではコマンドで作成します

# mainPrivateKyeというファイルを作る
touch mainPrivateKye

# mainPrivateKyeにcustom-preset.ymlのmainPrivateKyeの値を入れる
echo '70736F7314FD1xxxxxxxxx' > mainPrivateKye

# 確認
cat mainPrivateKye 
 70736F7314FD1xxxxxxxxx

# ca.key.pemの生成
# shoestringのpemtoolコマンドを使用します
python -m shoestring pemtool --output ca.key.pem --input mainPrivateKye

# 作業ディレクトリにca.key.pemファイルが出来ていると思います。
 
# node.key.pemの作成
# 作成方法はca.key.pemと同じです

# transportPrivateKeyというファイルを作る
touch transportPrivateKey

# transportPrivateKeyにcustom-preset.ymlのtransportPrivateKeyの値を入れる
echo 'A47623A15A332Exxxxxxx' > transportPrivateKey

# 確認
cat transportPrivateKey 
 A47623A15A332Exxxxxxx

# node.key.pemの生成
# shoestringのpemtoolコマンドを使用します
python -m shoestring pemtool --output node.key.pem --input transportPrivateKey

# 作業ディレクトリにnode.key.pemファイルが出来ていると思います。

```

一旦、事前作業はここまで。（後ほど使うファイルなので削除しない様にしてください）

## shoestirng用のノードを構築（起動はしない）

wizardを使ってサラのノードを構築します。

```bash
# ディレクトリを新たに作成します
cd
mkdir symbol; cd symbol

# wizardの起動
python -m shoestring.wizard
```

![image (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/934471/28970db0-b859-04ee-9f37-79c5938ccd27.png)

ca.key.pemは事前に作成したもの指定します（import main private key in hexでmainPrivateKyeを入力して作成しても良い）

![スクリーンショット 2024-09-05 22.55.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/934471/f68ffca0-f9e5-01fd-12b2-14314de7965f.png)

ネットワークタイプを選びます。

![image (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/934471/60cc177d-264c-d67a-e5a5-cd52b9cfec26.png)

ノードのタイプを選びます。

![image (7).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/934471/e049d1ab-7511-4d56-a043-05e98b672db3.png)

ハーベスト設定を行います。

以下の情報を参考にcustom-preset.ymlから必要な情報をコピペして入力してください。

harvesterSigningKey には remotePrivateKey を指定
harvesterVrfKey にはvrfPrivateKey を指定

![スクリーンショット 2024-09-05 22.58.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/934471/09745c35-72c8-f9c7-1b2e-fd0298f77aa8.png)

Votingの設定（特に設定しなくていいと思います）

![image (8).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/934471/f8071b3f-8ba7-fec5-f318-75e713222d7c.png)

ノードの設定（必要であればSSLの設定もしてください）

![image (9).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/934471/53aca4ff-110f-4916-acb9-4f69015fdf05.png)

このままで良いです。

![image (10).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/934471/a3db107f-dd06-a413-7488-2ba4a16b654c.png)

OKならFinish!

![image (11).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/934471/f388232d-ab32-4493-6309-e5e1462d5e2e.png)


# Cert関連のファイルの修正

今のままでは(Rest API)の`node/info` （nodePublicKey）がランダムで生成されたものになりますので、ここを修正します。

```bash
# 不要なnode.key.pem,node.crt.pem,node.full.crt.pemを削除する
rm -r keys/cert/node.*

# 新しいキーを生成する
python -m shoestring renew-certificates --config shoestring/shoestring.ini --directory $HOME/symbol/keys/cert --ca-key-path $HOME/src/ca.key.pem --node-key-path $HOME/src/node.key.pem
```

### パラメータの説明

:::note info
 引数
 --config：shoestringのコンフィグを指定
 --directory：生成したキーを出力する場所を指定
 --ca-key-path：事前準備したca.key.pemを指定
 --node-key-path：事前準備したnode.key.pemを指定（このオプションは公式のshoestringにはありませんのでご注意ください）

:::


成功すると `keys/cert/` フォルダ以下に新しい `node.crt.pem` と `node.full.crt.pem` が出来上がっていると思います。

このままでは `node.key.pem` が足りないので元の`node.key.pem`をコピーして追加します。

```bash
cp $HOME/src/node.key.pem $HOME/symbol/keys/cert
```

これで以下の様なフォルダ構成になっていると思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/934471/40e1328a-5b4f-cb12-2a08-50bad46655f9.png)

## 委任者の復元

さて、いよいよ本番です。
実はここはすごく簡単で、symbol-bootstrapの`target`フォルダ以下、

- databases
- nodes/node/data

をリネームして持ってくるだけです。（harvesters.datも一緒に）

```bash
# target/databases/db を dbdata にしてコピー先のフォルダへ移動
cp -r $HOME/symbol-bootstrap/target/databases/db $HOME/symbol/dbdata
# target/nodes/node/data をそのままコピー先の data へコピー
cp -r $HOME/symbol-bootstrap/target/nodes/node/data $HOME/symbol/data
```

:::note info
$HOME/symbolは今回新しく作成したshoestringのフォルダです
:::

最後に、`overrides.ini`の設定をします。
`overrides.ini`は`shoestring`フォルダ以下にあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/934471/c7786cf6-be3c-fd21-189e-1c25df72e3d8.png)

```ini
harvesterSigningPrivateKey = [remotePrivateKey]
harvesterVrfPrivateKey = [vrfPrivateKey]
enableAutoHarvesting = true
```

ノードの構築時にも説明した様に、

`harvesterSigningKey` には `remotePrivateKey`
`harvesterVrfKey` には `vrfPrivateKey`

を指定します。

# ノードの起動

ここまで出来たらノードを起動します。
ノードの起動は`docker-compose.yaml`のある場所（ここではsymbolフォルダ直下）で以下のコマンドを実行します。

```bash
docker compose up -d
```

あとは、ご自身のノードの`http://IP:3000/node/info`や`http://IP:3000/node/node/unlockedaccount`にアクセスして問題がないか確認してください。

# その他

エラーなど。

## docker compose up -dでエラーが出る

これはsymbol-bootstrapを使用していた場合よく出るエラーかもしれません。
ネットワークが重複しているので以下のコマンドで綺麗さっぱり削除しましょう。

```bash
docker system prune
```

## apiNodeが落ちる

node.key.pemやca.crt.pemなどのキーで不整合が起こっている可能性があります。最初から落ち着いて作業してみましょう。
それでもダメな場合、私までご連絡いただくか、素直に諦めましょう。

# 最後に

証明書関連の更新についてはまだ未検証です。
もしかしたら証明書更新時にnode.key.pemが変わる可能性があります（コアデブは定期的に変わるのが仕様だと言っていたので）
とりあえず、委任者含めたノード移行の一助になればと思います。

# 証明書のアップデート

ヘルスチェクで確認したら証明書関連で怒られましたｗ

```bash
python -m shoestring health --config shoestring/shoestring.ini --directory $HOME/work/symbol
     ...    | running health agent for peer certificate
    [!!!]   | node.full.crt.pem does not look like a product of node and CA certificates
     ...    | running health agent for peer API
      i     | peer API accessible, height = 1710536
     ...    | running health agent for REST API
      i     | REST API accessible, height = 1710536
     ...    | running health agent for REST websockets
      i     | websocket connected to ws://203.215.228.25:3000/ws, subscribing and waiting for block
      i     | websocket received a block with height 1710537
```

証明書をアップデートしてみます。

:::note info
ca.key.pemが必要です。
以下のコマンドの場合、ca.key.pemを$HOME/work/symbol/keysに移動してから指定しています。
直接最初に作成したフォルダ`src`を指定しても大丈夫です。
:::


```bash
python -m shoestring renew-certificates --config shoestring/shoestring.ini --ca-key-path keys/ca.key.pem --renew-ca --directory $HOME/work/symbol

Using configuration from ca.cnf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName            :ASN.1 12:'dai-test 203.215.228.25'
Certificate is to be certified until Sep 17 04:05:11 2025 GMT (375 days)

Write out database with 1 new entries
Data Base Updated
```

再度確認してみます。

```
$ python -m shoestring health --config shoestring/shoestring.ini --directory $HOME/work/symbol
     ...    | running health agent for peer certificate
      i     | ca certificate not near expiry (7299 day(s))
      i     | node certificate not near expiry (374 day(s))
/home/ishida/work/symbol/keys/cert/ca.crt.pem: OK
/home/ishida/work/symbol/keys/cert/node.crt.pem: OK
     ...    | running health agent for peer API
      i     | peer API accessible, height = 1710549
     ...    | running health agent for REST API
      i     | REST API accessible, height = 1710549
     ...    | running health agent for REST websockets
      i     | websocket connected to ws://203.215.228.25:3000/ws, subscribing and waiting for block
      i     | websocket received a block with height 1710550
```

OKそうですね。
※CA（認証局）証明書の有効期限が残り7,299日あるのは気になりますが...