Symbolのハーベスティング周りの情報を整理する 

#はじめに

パブリックブロックチェーンプラットフォームのSymbol。そのブロック生成処理であるハーベスティング。イマイチハーベスティング周りのトランザクションやアカウント達が理解できないという意見をよく聞きます。ガイドを見て全て理解できる人はあまり多くないかもしれません。(自分も含めて)
なので、イメージを掴みやすいように解説します。
似たような記事を[こちら](https://qiita.com/GodTanu2/items/60ed86c3552051265a2b)に書いたことがありますが、今回はローカルやリモート、デリゲーテッドとは切り離した記事になります。

ざっくりです。イメージを掴めるように。

また、以下記事も併せて読んでみてください
[次世代NEMブロックチェーン、Symbolに迫る(11)〜委任ハーベスト編〜](https://note.com/daokasweep/n/na3157cf1ede6)



#アカウント

アカウントにはアドレスが存在し、パブリックキー(公開鍵)、プライベートキー(秘密鍵)を所有します。
また、最低1万XYM以上保有しているアドレスの残高に応じてインポータンス(重要度)が付与されます。これはネットワーク全体側から付与される値になります。

#アカウントの種類

symbol-bootstrapでノードを建てた後、
`target/addresses.yml`を覗いてみると以下のように表示されると思います。
※Votingノード以外はVotingは表示されません

```

$ less target/addresses.yml

version: 2
networkType: 152
nemesisGenerationHashSeed: 45FBCF2F0EA36EFA7923C9BC923D6503169651F7FA4EFC46A8EAF5AE09057EBD
nodes:
    -
        name: api-node
        friendlyName: (ノードの名前）
        roles: 'Peer,Api,Voting'(※Votingは任意)
        main:
            privateKey: B55F1AF84xxx例：こんな感じのキーxxxxxxxxxx2739F5EAE4ABBFDA315DC0
            publicKey: 975865AE20xxx例：こんな感じのキーxxxxxxxxx0F78C82E159781CAE30FBE9
            address: TABCDEF例：こんな感じのアドレスxxxxxxxxxxxxxxx
        transport:
            privateKey: B55F1AF84xxx例：こんな感じのキーxxxxxxxxxx2739F5EAE4ABBFDA315DC0
            publicKey: 975865AE20xxx例：こんな感じのキーxxxxxxxxx0F78C82E159781CAE30FBE9
            address: TABCDEF例：こんな感じのアドレスxxxxxxxxxxxxxxx
        remote:
            privateKey: B55F1AF84xxx例：こんな感じのキーxxxxxxxxxx2739F5EAE4ABBFDA315DC0
            publicKey: 975865AE20xxx例：こんな感じのキーxxxxxxxxx0F78C82E159781CAE30FBE9
            address: TABCDEF例：こんな感じのアドレスxxxxxxxxxxxxxxx
        voting:
            privateKey: B55F1AF84xxx例：こんな感じのキーxxxxxxxxxx2739F5EAE4ABBFDA315DC0
            publicKey: 975865AE20xxx例：こんな感じのキーxxxxxxxxx0F78C82E159781CAE30FBE9
            address: TABCDEF例：こんな感じのアドレスxxxxxxxxxxxxxxx
        vrf:
            privateKey: B55F1AF84xxx例：こんな感じのキーxxxxxxxxxx2739F5EAE4ABBFDA315DC0
            publicKey: 975865AE20xxx例：こんな感じのキーxxxxxxxxx0F78C82E159781CAE30FBE9
            address: TABCDEF例：こんな感じのアドレスxxxxxxxxxxxxxxx
addresses.yml (END)
```


###Main
このノード自身が持つアカウントです。
通常、ハーベスティングをしたいアカウントになります。つまり重要度を持たせるアカウントです。
極論ですが、このアカウントを使う必要はありません。他にインポータンスを持つアドレスがあればそれを使ってハーベスティングできます。後述します。

###transport
委任のデリゲーテッドハーベスティングでノード以外のユーザーが使用するアカウントです。
外部公開されており、
`http://ノードのIPアドレス:3000/node/info`
で、誰でもこのアカウントのパブリックキーを取得可能です。
委任する人は委任設定の処理で`NODE_KEY_LINK`トランザクションを発行する必要がありますが、その時に指定するパラメータにこのパブリックキーが必要になります。

###remote
ノードがリモートハーベスティングを行う時に使うアカウントです。
通常、ノードユーザーがハーベスティングを行う場合はリモートハーベスティングで実施します。
リモートアカウントを有効にする際は`ACCOUNT_KEY_LINK`トランザクションを実施する必要があります。
`ACCOUNT_KEY_LINK`トランザクションを実施するのは、インポータンスを持ち、実際にハーベスティングを行いたいアカウントが発行する必要があります。`ACCOUNT_KEY_LINK`発行者はリモートアカウントのパブリックキーを指定して発行します。
なお、`ACCOUNT_KEY_LINK`トランザクションが実施された後はこのアカウントはロックされ操作を行うことができなくなります。

###voting(Votingノードのみ)
Voting(投票)処理で使用するアカウントです。いわゆるスーパーノードと条件は同じなのですが、300万XYMを保有したアカウントがVoting機能を有効にしている場合にVotingノードになれます。投票プロセスなどに参加できファイナライズなどに関与します。
投票アカウントを有効にする際には`VOTING_KEY_LINK`トランザクションを実施する必要があります。
`VOTING_KEY_LINK`トランザクションを実施するのは、実際に300万XYMを保有し投票が可能になる資格を持つアカウントが発行する必要があります。`VOTING_KEY_LINK`発行者は投票アカウントのパブリックキーを指定して発行します。

###vrf
VRF(VerifiableRandomFunction)で使用するアカウントです。
VRFが何なのか、はこの記事がとても分かりやすいです。
[symbol(catapult)におけるVRF(VerifiableRandomFunction)](https://mijinc0.github.io/blog/post/20201210_vrf_catapult/)

**極論ですが、このVRFをネットワークに通知する事がハーベスティング実施のトリガーになります。**
そう覚えておけば大丈夫です。誤解を恐れずに言うならば、残高があるアドレスを見て、そのアドレスがVRF_KEY_LINKしてたらそのアドレスはハーベスティングをしているだろうな、と判断して良いぐらいの感じです。(厳密には違いますがだいたいそう)

VRFアカウントを有効にする際には`VRF_KEY_LINK`トランザクションを実施する必要があります。
`VRF_KEY_LINK`トランザクションを実施するのは、実際にハーベスティングを行いたいアカウントが発行する必要があります。`VRF_KEY_LINK`発行者はVRFアカウントのパブリックキーを指定して発行します。



#ハーベスティングをする場所
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/856241/21784c0f-95db-b3a5-0f55-d707b6a4e9f5.png)

基本的に各ノードには土地のような場所があり、そこでハーベスティングを行うイメージです。
その農地がどうなっているのか分かりにくいという意見があります。

まず、改めて`config-harvesting.properties`を見てみます。

```

$ less target/nodes/api-node/userconfig/resources/config-harvesting.properties

[harvesting]

harvesterSigningPrivateKey = いずれかの秘密鍵
harvesterVrfPrivateKey = VRFアカウントの秘密鍵

enableAutoHarvesting = true(ハーベスティングをやるノードだよ、という意味 デフォルトtrue)
maxUnlockedAccounts = 5(農場で働ける人の数、デフォルト5人)
delegatePrioritizationPolicy = Age(先着順:Age/重要度順:Importance デフォルト重要度)
beneficiaryAddress = 委任アカウントから徴収した報酬の格納アドレス：未設定時は徴収なし
```

`harvesterSigningPrivateKey`にはハーベスティングを行うノード、つまり「地主」の秘密鍵を設定する必要があります。
ここに「リモートアカウントの秘密鍵」を設定すれば**リモートハーベスティング**になり、
ここに「ハーベスティングを行うアカウントの秘密鍵」を直接書き込むと**ローカルハーベスティング**となります。
コンフィグ設定値に秘密鍵を直接書くのはセキュリティ的にもよろしくありません。そのためデフォルト設定ではリモートアカウントの秘密鍵が記述されています。

`harvesterVrfPrivateKey `には地主の使っているVRFアカウントの秘密鍵を設定する必要があります。こちらはリモートでもローカルでも使っているVRFアカウントは同じになるので同じ秘密鍵になるかと思います。


`maxUnlockedAccounts `ですが、こちらに地主が含まれるか含まれないのか検証してみたところ、地主も含まれるようです。ですので小作人の土地は4人分確保されています。もちろんノードを建ててハーベスティングを行わないノードもいますのでそうなると5人分の土地です。

小作人の委任側としては土地が空いているかどうか気になるところですが、その情報は
`http://ノードのIPアドレス:3000/node/unlockedaccount`
で確認が可能です。

例えば

```
$ curl http://localhost:3000/node/server |jq

{
  "unlockedAccount": [
    "7A29C64227A26B9383E63C66A3654587911224ACADDA21C4D65F21C961401838",
    "BE79680EF11141CEE807057A29C64227F2946ABCDC7A29C64227731EE82F8FB5"
  ]
}

```
このような表示になっていた場合は2つの土地が使用されており、3つの枠が空いている事になります。
この場合はスムーズに委任を行うことが可能ですが、満杯の場合は`delegatePrioritizationPolicy `の設定値次第で挙動が変わります。早い者勝ちか、インポータンスが高いアカウントによる割込みが発生するかです。
なお、ノードとしてはインポータンスが高いアカウントが小作人になってくれた方がハーベスティング回数が多くなり報酬を得る機会があるので基本的にデフォルトのまま重要度順になると思われます。



`beneficiaryAddress `
通常、ノードを経由したハーベスティングには25％の徴税がかかります。これが小作人と言われる所以ですが、それでもインフレーション報酬があるのでかなり刈り取れます。
もちろんノード所有者はこの徴税した額も自分の懐に入るので100%入ります。(厳密にはシンクアドレスに数%抜かれてしまうのですが微々たるものです)

ですが、この`beneficiaryAddress `を設定しないと**25%の徴収が無効**になるようです。
必ず設定しておきましょう。そもそも納税の際にはここの数字が分からないと面倒なので記録しておくためにも必ず設定しておきましょう。



#ノード管理者のハーベスティング対応の小技

前述しましたが、ノードを建てた後に生成される`address.yml`に出てくる各アドレスですが、これにとらわれる必要は無いです。

例えば、
・自前でヴァージンアドレスを2つ用意(リモート用とVRF用)
・気に入ってるアドレスをメインアカウントとして用意
して

1.`config-harvesting.properties`のハーベスティング署名アドレスにヴァージンアドレス1の秘密鍵を設定
2.`config-harvesting.properties`のVRF署名アドレスにヴァージンアドレス2の秘密鍵を設定
3.CLIかSDKでお気に入りアドレスから1で設定したアカウントの公開鍵を指定してACCOUNT_KEY_LINK
4.CLIかSDKでお気に入りアドレスから2で設定したアカウントの公開鍵を指定してVRF_KEY_LINK

でOKです。スーパーノード代理業務なんかもこの辺りを駆使すればできますね。
残高保有している秘密鍵に関与しないのでカストデイ規制にも引っ掛かりません！
注意：bootstrapのlinkコマンドを使う場合は`address.yml`のデータを元に自動発行しているので必ずCLIかSDKでやる事