Activating delegated harvesting manually

Share your account’s importance securely with a node and get rewarded.

Introduction

Delegated harvesting enables accounts to receive rewards from creating new blocks without running a node. At the same time, it allows nodes to benefit from an account’s (possibly higher) importance score.

Note

Node owners have access to the node’s configuration so it’s more convenient for them to use Remote harvesting instead.

This guide explains how to manually activate delegated harvesting using the SDK or the CLI interface and is therefore intended for developers. Users should use the Desktop Wallet guide instead.

Summary

Required steps:

  1. Delegate the main account (M) importance to a remote account (R) using an AccountKeyLinkTransaction.
  2. Link the main account M to a VRF account (V) for randomized block production and account selection using a VrfKeyLinkTransaction.
  3. Link the main account M to a node in order to harvest through that node using a NodeKeyLinkTransaction.
  4. Request the node to add the remote account R as a harvester using a PersistentDelegationRequestTransaction. Conversely, if the node configuration is accessible, the remote account’s private key can be set in the node configuration.

Please note that it is entirely up to the node to comply with the request. Some nodes can be asked for their current list of delegated harvesters but this information is not always available (see Verifying activation below).

Prerequisites

Before you can activate delegated harvesting, you need the following items:

  • A Main account (M) with at least 10,000 symbol.xym to be eligible and then some more to pay for transaction fees. The account also has to have an importance score greater than zero (this score is calculated every 12h). This is the account that will receive the harvesting fees. Keep its private key secret at all times.
  • A Remote account (R) that will act as a proxy between M and the node. This account must have never sent or received any transaction, and it cannot be involved in any transaction while it is a delegated account.
  • A VRF account (V) that has never sent or received any transactions. It is a regular account used to add randomness to the account selection process.
  • The node’s public TLS key. This is the key the node uses to authenticate data for transport over TLS and is typically provided by the node owner.

Refer to the Creating an account guide to know how to create new accounts if you need to.

Note

The following bash code snippets make use of symbol-cli and assume that the main account (M) is set as the default profile. Use the ‑‑profile parameter if this is not the case.

Guide

  1. Create an AccountKeyLinkTransaction to delegate M’s importance to R. Sign the transaction with M and announce it to the network.

    const accountLinkTransaction = AccountKeyLinkTransaction.create(
      Deadline.create(epochAdjustment),
      remoteAccount.publicKey,
      LinkAction.Link,
      networkType,
      UInt64.fromUint(2000000),
    );
    
    symbol-cli transaction accountkeylink \
        --linked-public-key <REMOTE_PUBLIC_KEY> \
        --action Link \
        --sync
    
  2. Create a VrfKeyLinkTransaction to link M to a VRF key. Sign the transaction with M and announce it to the network.

    const vrfLinkTransaction = VrfKeyLinkTransaction.create(
      Deadline.create(epochAdjustment),
      vrfAccount.publicKey,
      LinkAction.Link,
      networkType,
      UInt64.fromUint(2000000),
    ); // Absolute number
    
    symbol-cli transaction vrfkeylink \
        --linked-public-key <VRF_PUBLIC_KEY> \
        --action Link \
        --sync
    
  3. Create a NodeKeyLinkTransaction to link M to a node’s TLS key. Sign the NodeKeyLinkTransaction with M and announce it to the network.

    Note

    The node’s public TLS key is typically provided by the node owner. However, Dual nodes (being both Peer and API nodes) running a version of the REST Gateway higher than 2.2.0 offer this information through the nodePublicKey field of the node/info REST endpoint.

    Just point your browser to http://<NODE_URL>:3000/node/info.

    const nodeLinkTransaction = NodeKeyLinkTransaction.create(
      Deadline.create(epochAdjustment),
      nodeAccount.publicKey,
      LinkAction.Link,
      networkType,
      UInt64.fromUint(2000000),
    ); // Absolute number
    
    symbol-cli transaction nodekeylink \
        --linked-public-key <NODE_PUBLIC_TLS_KEY> \
        --action Link \
        --sync
    
  4. Once the transactions are confirmed, the next step is to share R’s private key with the node. This can be done in one of two ways depending on whether you are the node owner and have access to the node’s configuration or not.

    If you are the node owner, you simply need to set the remote account’s private signing key in the harvesterSigningPrivateKey field in the Harvesting Configuration.

    Otherwise, a PersistentDelegationRequestTransaction must be used. As the private key will be shared in an encrypted message, only the node will be able to see it. Moreover, R does not own any mosaic.

    The harvesting fees will be sent to M as it has established a link with the node through the NodeKeyLinkTransaction.

    Sign the PersistentDelegationRequestTransaction with M and announce it to the network.

    const persistentDelegationRequestTransaction = PersistentDelegationRequestTransaction.createPersistentDelegationRequestTransaction(
      Deadline.create(epochAdjustment),
      remoteAccount.privateKey,
      vrfAccount.privateKey,
      nodeAccount.publicKey,
      networkType,
      UInt64.fromUint(2000000),
    );
    
    # Optionally use --profile announcer
    symbol-cli transaction persistentharvestdelegation \
        --remote-private-key <REMOTE_PRIVATE_KEY> \
        --recipient-public-key <NODE_PUBLIC_TLS_KEY> \
        --vrf-private-key <VRF_PRIVATE_KEY> \
        --sync
    

Note

All the above transactions can be announced together in a single Aggregate Transaction.

If everything is successful, the node will receive the encrypted message through WebSockets. Once the node decrypts the private key of the potential delegated harvester, the node owner may add R as a delegated harvester if the following requirements are met:

  • The node permits delegated harvesting.
  • The node has harvesting slots available (See next section).
  • The remote account has never sent or received transactions before.

As the remote private key is saved on disk by the node, even if the node disconnects temporarily the persistent delegated harvesters will be reestablished once the node reconnects to the network.

Additionally, the use of an encrypted message creates a backup of the information for the nodes. If the disk containing the delegated keys becomes corrupted or destroyed, the node owner can still retrieve the data by querying the blockchain.

Verifying activation

When requesting delegation through a PersistentDelegationRequestTransaction instead of directly configuring the node, whether the node enables delegated harvesting depends entirely on the node and not on the network. It is entirely up to the node to comply with the request or even to lie about its state.

Therefore, there is no reliable way to know if your account has become a harvester or not (besides waiting to see if any blocks appear on the blockchain signed by your remote account and your main account starts collecting harvesting fees).

That said, nodes configured to act as Dual nodes (being both Peer and API nodes) can be queried for their current list of delegated harvesters. To reiterate, this information comes from the node and is not backed up by the blockchain, so take it with a grain of salt.

You can retrieve this list using the getUnlockedAccount API endpoint (point your browser to http://<NODE_URL>:3000/node/unlockedaccount) or the Typescript SDK for example). It contains the public keys of all registered delegated harvesters in the node, so your remote account (R) public key should appear here.

By default a node can have up to 5 delegated harvesters (harvesting slots) and excess requests can be priorized as the node sees fit. This can be configured on the node through the maxUnlockedAccounts and delegatePrioritizationPolicy Harvesting Configuration.

Final words

  • Accounts with higher importance are selected more often to perform harvesting. Even if you successfully register as a delegated harvester with a node, you will not harvest any block (nor receive any fees) unless your importance score is high enough.
  • Importance score calculation does not happen continuously. By default, account importance scores are recalculated every 1440 blocks (about every 12 hours). See the importanceGrouping property in the Configuring network properties guide.
  • Finally, as explained in Verifying activation above, announcing a Harvesting Delegation request does not guarantee being added as a delegated harvester. Nodes are free to comply with the request or even to lie about its status.

Last updated by Xavi Artigas on 2021-08-04.

Did you find what you were looking for? Give us your feedback.