Enabling forging

How to enable forging on a node as a delegate. For more information about forging, please check the forging explanations on the DPoS module page.

1. Registering a delegate

Before it is possible to enable forging on a node, it is required to register as a delegate. This is achieved by choosing a unique delegate name, and posting a corresponding Register Delegate transaction to the network.

There are many possibilities to post the transaction, use the one you prefer: Lisk Desktop, Lisk Elements, or the Dashboard plugin.

An option is to create the transaction object with the application CLI:

1.1. Start the blockchain application

  • Lisk Core

  • Lisk app

lisk-core start
./bin/run start

1.2. Create the Delegate Registration transaction

  • Lisk Core

  • Lisk app

lisk-core transaction:create 5 0 1100000000 --asset='{"username":"myname"}'
? Please enter passphrase:  [hidden]
? Please re-enter passphrase:  [hidden]
{"transaction":"0805100018032080d6c28c042a20bad983c72bed43fd274f852658c298b74c71ab6fc50508879fef309e3836384b32080a066d796e616d653a4045afdd04d0c0bc6e548c0915d5fabef1311b1b75b1eb919a43b88dab539e7b6a99b9075f5d6382ec3bbebfca3301651a15d8af3f999d5b6fa7873b3969cd3d0c"}
./bin/run transaction:create 5 0 1100000000 --asset='{"username":"myname"}'
? Please enter passphrase:  [hidden]
? Please re-enter passphrase:  [hidden]
{"transaction":"0805100018032080d6c28c042a20bad983c72bed43fd274f852658c298b74c71ab6fc50508879fef309e3836384b32080a066d796e616d653a4045afdd04d0c0bc6e548c0915d5fabef1311b1b75b1eb919a43b88dab539e7b6a99b9075f5d6382ec3bbebfca3301651a15d8af3f999d5b6fa7873b3969cd3d0c"}

1.3. Send the transaction

  • Lisk Core

  • Lisk app

lisk-core transaction:send 0805100018032080d6c28c042a20bad983c72bed43fd274f852658c298b74c71ab6fc50508879fef309e3836384b32080a066d796e616d653a4045afdd04d0c0bc6e548c0915d5fabef1311b1b75b1eb919a43b88dab539e7b6a99b9075f5d6382ec3bbebfca3301651a15d8af3f999d5b6fa7873b3969cd3d0c
Transaction with id: '1809da284fe26dba90d34dc3aab837a32d3c291a4ca78a9bfa263f927c69598a' received by node.
./bin/run transaction:send 0805100018032080d6c28c042a20bad983c72bed43fd274f852658c298b74c71ab6fc50508879fef309e3836384b32080a066d796e616d653a4045afdd04d0c0bc6e548c0915d5fabef1311b1b75b1eb919a43b88dab539e7b6a99b9075f5d6382ec3bbebfca3301651a15d8af3f999d5b6fa7873b3969cd3d0c
Transaction with id: '1809da284fe26dba90d34dc3aab837a32d3c291a4ca78a9bfa263f927c69598a' received by node.

1.4. Check account details

Use the account:get command to verify the account has now registered a delegate name:

  • Lisk Core

  • Lisk app

lisk-core account:get ed86183c22f8399f7aa28f7d2c2f1680224f7281 --pretty
./bin/run account:get ed86183c22f8399f7aa28f7d2c2f1680224f7281 --pretty

The new delegate name should be displayed under dpos.delegate.username:

{
  "address": "ed86183c22f8399f7aa28f7d2c2f1680224f7281",
  "token": {
    "balance": "8888869000"
  },
  "sequence": {
    "nonce": "4"
  },
  "keys": {
    "numberOfSignatures": 0,
    "mandatoryKeys": [],
    "optionalKeys": []
  },
  "dpos": {
    "delegate": {
      "username": "myname",
      "pomHeights": [],
      "consecutiveMissedBlocks": 0,
      "lastForgedHeight": 2467,
      "isBanned": false,
      "totalVotesReceived": "0"
    },
    "sentVotes": [],
    "unlocking": []
  },
  "hello": {
    "helloMessage": "Greetings World!"
  }
}

2. Add delegate data to config

This step only needs to be performed when a delegate is enabling forging on a node for the first time.

To enable your node to forge for a particular delegate, firstly it is required to insert some data into the config file under the forging.delegates array as described below:

  • address: The address of the delegate as a hex string.

  • encryptedPassphrase: The symmetrically encrypted 12 word mnemonic passphrase of the delegate account.

  • hashOnion: The hash onion stores the random seeds of the delegate for each forging round.

To create the delegate configuration data,

  1. First create a custom config file

  2. Then use one of the following alternatives to generate the delegate config data:

  3. Lastly, add the delegate config data to the custom config file.

2.1. Creating a custom config file

First copy the existing config file for the respective network.

  • Lisk Core

  • Lisk app

cp ~/lisk-core/config/mainnet/config.json ~/lisk-core/config/mainnet/custom-config.json

Navigate to the app root folder, then

cp config/default/config.json config/default/custom-config.json

2.2. Option 1: via application CLI

If the blockchain application was bootstrapped with Lisk Commander, it is possible to conveniently generate the relevant forging data using the command forging:config.

  • Lisk Core

  • Lisk app

$ lisk-core forging:config --output ./delegate_config.json
? Please enter passphrase:  [hidden]        (1)
? Please re-enter passphrase:  [hidden]
? Please enter password:  [hidden]          (2)
? Please re-enter password:  [hidden]
$ ./bin/run forging:config --output ./delegate_config.json
? Please enter passphrase:  [hidden]         (1)
? Please re-enter passphrase:  [hidden]
? Please enter password:  [hidden]           (2)
? Please re-enter password:  [hidden]
1 Passphrase of the delegate account.
2 Password to encrypt the passphrase of the delegate account.

The command will ask for the delegate passphrase, and in order to symmetrically encrypt the passphrase for the config, it will also ask for a password.

Store the password you used for the encryption somewhere safe. It will be required everytime you wish to enable forging, in order to decrypt the delegates' passphrase in the config.

After providing the required inputs, the delegate configuration data will be saved in the file delegate_config.json.

Example of delegate_config.json
{
  forging: {
    delegates: [ (1)
        {
            address: "86555265f0110b4ed5a8cb95dbc732e77732c474",
            encryptedPassphrase: "iterations=1&salt=476d4299531718af8c88156aab0bb7d6&cipherText=663dde611776d87029ec188dc616d96d813ecabcef62ed0ad05ffe30528f5462c8d499db943ba2ded55c3b7c506815d8db1c2d4c35121e1d27e740dc41f6c405ce8ab8e3120b23f546d8b35823a30639&iv=1a83940b72adc57ec060a648&tag=b5b1e6c6e225c428a4473735bc8f1fc9&version=1",
            hashOnion: {
                "count": 1000000,
                "distance": 1000,
                "hashes": [
                    "ff2156e33c4aefa4a5a790edbe329f4a",
                    "5f86db180d4e63be6412d42d444dfb49",
                    "10fc37bb42d7f77030138e45795fef65",
                    "f04a306a73c5d7d94cc4f262b4d5ebb4",
                    //[...]
                    "ca41d52225f4b76140fc7f277731d326",
                    "fde61109609b74ba16d5ebd72a8b446f",
                    "9752dc2228492466d7c2046354d5fdfd"
                ]
            }
        }
    ]
  }
}
1 The list of delegates who are allowed to forge on this node.

2.3. Option 2: with Lisk Commander

Please ensure that the Lisk Commander is installed in a secure environment. Upon completion, please follow these commands to generate the encrypted passphrase:

$ lisk
lisk passphrase:encrypt --json
Please enter your secret passphrase: *****     (1)
Please re-enter your secret passphrase: *****
Please enter your password: ***                (2)
Please re-enter your password: ***
{
        "encryptedPassphrase": "iterations=1000000&cipherText=30a3c8&iv=b0d7322bf24e0dfe08462f4f&salt=aa7e26c9f4317b61b4f45b5c6909f941&tag=a2e0eadaf1f11a10b342965bc3bafc68&version=1",
}
1 Enter the secret passphrase here that needs to be encrypted.
2 Enter the password here that will be required to decrypt the passphrase again.

Ensure a strong password is used.

See the Guidelines for password strength at Wikipedia for reference.

The hash onion can be generated with Lisk Commander in the following manner:

lisk hash-onion --json
  • Add the hash onion and the delegate address in hexadecimal representation to the object with the encryptedPassphrase.

  • Add the JSON object to the config under forging.delegates as shown below:

{
  "forging": {
    "force": false,
    "delegates": [    (1)
        {
            "address": "86555265f0110b4ed5a8cb95dbc732e77732c474",
            "encryptedPassphrase": "iterations=1&salt=476d4299531718af8c88156aab0bb7d6&cipherText=663dde611776d87029ec188dc616d96d813ecabcef62ed0ad05ffe30528f5462c8d499db943ba2ded55c3b7c506815d8db1c2d4c35121e1d27e740dc41f6c405ce8ab8e3120b23f546d8b35823a30639&iv=1a83940b72adc57ec060a648&tag=b5b1e6c6e225c428a4473735bc8f1fc9&version=1",
            "hashOnion": {
              "count":1000000,
              "distance":1000,
              "hashes":[
                "a623885d5422ce0f2aad3ee128e447ce",
                "91e7ecad63bafdf36a5b02556ea77fe7",
                "4a66b400290185cba622f8c9f5d37181",
                //[...]
                "fb8eee95e630e812cdf90d054acc903a"
              ]
            }
        }
    ]
  }
}
1 The list of delegates who are allowed to forge on this node.

Restart the node to apply the changes in the config.

For more information about the configuration of the Lisk SDK check out the configuration guide.

2.4. Updating the custom configuration

Add the JSON object to the config file of the application.

forging.delegates stores the list of delegates who are allowed to forge on this node:

Merge the delegate config with the custom config which was created in step 2.1 above, to add the delegate information to the application configuration:

TEMP_FILE=$( mktemp )
jq --slurp '.[0] * .[1]' custom-config.json delegate_config.json > $TEMP_FILE
mv $TEMP_FILE custom-config.json

Open custom-config.json to verify it was updated correctly.

Besides adding the delegate config data, the other options in the config can be adjusted as desired. Examples of config options that might be interesting to update can be found below.

Example: custom-config.json file
custom-config.json
{
  //...
  "logger": {
    "fileLogLevel": "error",
    "consoleLogLevel": "info" (1)
  },
  "rpc": {
    "enable": true, (2)
    "mode": "ipc"
  },
  "forging": {
    "delegates": [ (3)
        {
            "address": "86555265f0110b4ed5a8cb95dbc732e77732c474",
            "encryptedPassphrase": "iterations=1&salt=476d4299531718af8c88156aab0bb7d6&cipherText=663dde611776d87029ec188dc616d96d813ecabcef62ed0ad05ffe30528f5462c8d499db943ba2ded55c3b7c506815d8db1c2d4c35121e1d27e740dc41f6c405ce8ab8e3120b23f546d8b35823a30639&iv=1a83940b72adc57ec060a648&tag=b5b1e6c6e225c428a4473735bc8f1fc9&version=1",
            "hashOnion": {
                "count": 1000000,
                "distance": 1000,
                "hashes": [
                    "ff2156e33c4aefa4a5a790edbe329f4a",
                    "5f86db180d4e63be6412d42d444dfb49",
                    "10fc37bb42d7f77030138e45795fef65",
                    "f04a306a73c5d7d94cc4f262b4d5ebb4",
                    //[...]
                    "ca41d52225f4b76140fc7f277731d326",
                    "fde61109609b74ba16d5ebd72a8b446f",
                    "9752dc2228492466d7c2046354d5fdfd"
                ]
            }
        }
    ],
  },
  //...
}
1 Set the console log level to info to view all relevant logs on the console.
2 Enable IPC to be able to use all commands of the Lisk Core CLI (see Command line interface)
3 Add the delegate config info here, under forging.delegates of the node configuration.

3. Forger_info data

The forger_info data contains the following three properties:

  • height: Last forged block height.

  • maxHeightPreviouslyForged: Delegates largest previously forged height.

  • maxHeightPrevoted: Delegates largest prevoted height for a block.

For each of these properties, the forger config contains the value used in the last block forged by the node.

These three variables are required for enabling forging for the corresponding delegate.

4. Checking the forging status

To check the forging status of a Lisk Core node, execute the following command:

  • Lisk Core

  • Lisk app

lisk-core forging:status
./bin/run forging:status
Example output
[{"address":"89aa5fc8861d392f60662f76a379cc348fe97d28","forging":true,"height":670237,"maxHeightPrevoted":670159,"maxHeightPreviouslyForged":670187}]

The command returns a list of delegates, based on the list under forging.delegates in the application config, (based on the details added to the config in the previous step, Add delegate data to config). The following information is displayed for each delegate:

  • The hexadecimal representation of the delegate address.

  • If the delegate has forging enabled or not.

  • The Forger_info data.

5. Enable forging

  1. Ensure the node is fully synchronized with the network, before enabling forging on this node.

  2. If forging is enabled for a delegate for the first time, use 0 as the value for HEIGHT, MAXHEIGHTPREVIOUSLYFORGED, and MAXHEIGHTPREVOTED. Afterwards, it is always required to use the latest values of the forger_info info data.

  3. To avoid being punished by the network, ensure to adhere to the following points:

    1. Never use outdated Forger_info data.

    2. Never activate forging for the same delegate on two or more nodes at the same time, (a.k.a double-forging).

5.1. via application CLI

If the blockchain application was bootstrapped with Lisk Commander, it is possible to conveniently generate the relevant forging data using the command forging:enable.

The blockchain application needs to be running to successfully enable forging on the node.
  • Lisk Core

  • Lisk app

Enable forging
lisk-core forging:enable 9bd82e637d306533b1e1ad66e19ca0047faa1a6a --use-status-values (1)
Enable forging
./bin/run forging:enable 9bd82e637d306533b1e1ad66e19ca0047faa1a6a --use-status-values (1)
1 Replace 9bd82e637d306533b1e1ad66e19ca0047faa1a6a with the hex string representation of your delegate address, which was displayed while Checking the forging status.

This will automatically use the currently saved forger_info data to enable forging on the node. Verify the correctness of the values height, maxHeightPrevoted, and maxHeightPreviouslyForged by answering yes, and use your password to decrypt the passphrase for forging.

Don’t trust Forger_info data from public APIs or explorers, make sure to always use your local data! You can use your data automatically by setting the flag --use-status-values.
 Current forging status for delegate account 331e287263c8166febde9d77a5f333df75056c74 is:
{"height":14814092,"maxHeightPrevoted":14814017,"maxHeightPreviouslyForged":14814025}
? Do you want to use the above values to enable forging? yes
? Enter password to decrypt the encrypted passphrase:  **********
Updated forging status:
{"address":"331e287263c8166febde9d77a5f333df75056c74","forging":true}
Reference for the forging:enable command
Enable forging for the given delegate address.

USAGE
  $ lisk-core forging:enable ADDRESS [HEIGHT] [MAXHEIGHTPREVIOUSLYFORGED] [MAXHEIGHTPREVOTED]

ARGUMENTS
  ADDRESS                    Address of an account in hex format.
  HEIGHT                     Last forged block height.
  MAXHEIGHTPREVIOUSLYFORGED  Delegates largest previously forged height.
  MAXHEIGHTPREVOTED          Delegates largest prevoted height for a block.

OPTIONS
  -d, --data-path=data-path  Directory path to specify where node data is stored. Environment variable "LISK_DATA_PATH" can also be
                             used.

  -w, --password=password    Specifies a source for your secret password. Command will prompt you for input if this option is not
                             set.
                             	Examples:
                             	- --password=pass:password123 (should only be used where security is not important)

  -y, --yes                  Do you want to use these values to enable forging.

  --overwrite                Overwrites the forger info.

  --pretty                   Prints JSON in pretty format rather than condensed.

  --use-status-values        Use delegates forging status values.

EXAMPLES
  forging:enable ab0041a7d3f7b2c290b5b834d46bdc7b7eb85815 --use-status-values
  forging:enable ab0041a7d3f7b2c290b5b834d46bdc7b7eb85815 --use-status-values --yes
  forging:enable ab0041a7d3f7b2c290b5b834d46bdc7b7eb85815 100 100 10
  forging:enable ab0041a7d3f7b2c290b5b834d46bdc7b7eb85815 100 100 10 --overwrite
  forging:enable ab0041a7d3f7b2c290b5b834d46bdc7b7eb85815 100 100 10 --data-path ./data
  forging:enable ab0041a7d3f7b2c290b5b834d46bdc7b7eb85815 100 100 10 --data-path ./data --password your_password

5.2. via the updateForgingStatus action

Invoke the following action to enable the forging for a delegate:

Enable forging
const { createWSClient } = require('@liskhq/lisk-api-client');

export const enableForging = async () => {
    let apiClient = await createWSClient('ws://localhost:8080/ws');
    let response;

    const { data } = await apiClient.invoke('app:updateForgingStatus', {
      address: string, (1)
      password: string, (2)
      forging: true, (3)
      height?: number, (4)
      maxHeightPrevoted?: number, (5)
      maxHeightPreviouslyForged?: number, (6)
      override?: boolean (7)
    });

    try {
      response = await apiClient.transaction.send(tx);
    } catch (error) {
      response = error;
    }
};
1 Address as hex string.
2 Password that was used above to encrypt the passphrase in the configuration.
3 When enabling forging, the value should be true.
4 Not required, when enabling forging for a delegate for the first time. Height of the last forged block by the delegate.
5 Not required, when enabling forging for a delegate for the first time. Height of the previously prevoted block by any delegate. Must match the value in the forger_info data.
6 Not required, when enabling forging for a delegate for the first time. Height of the previously last forged block. Must match the value in the forger_info data.
7 Optional: If true, overrides maxHeightPreviouslyForged and maxHeightPrevoted values in the forger_info data.

6. Disable forging

Sometimes it is necessary to disable forging, for example to update to the latest Lisk Core version, or if you are moving your node to a different server.

If you would like to completely stop forging without being punished by the network, make sure to unvote yourself, see:

6.1. with the application CLI

  • Lisk Core

  • Lisk app

Disable forging
lisk-core forging:disable 9bd82e637d306533b1e1ad66e19ca0047faa1a6a (1)
Disable forging
./bin/run forging:disable 9bd82e637d306533b1e1ad66e19ca0047faa1a6a (1)
1 Replace 9bd82e637d306533b1e1ad66e19ca0047faa1a6a with the hexadecimal representation of your delegate address, which was displayed while Checking the forging status.
Reference for the forging:disable command
Disable forging for the given delegate address.

USAGE
  $ lisk-core forging:disable ADDRESS

ARGUMENTS
  ADDRESS  Address of an account in a hexadecimal format.

OPTIONS
  -d, --data-path=data-path  Directory path to specify where node data is stored. Environment variable "LISK_DATA_PATH" can also be used.

  -w, --password=password    Specifies a source for your secret password. Command will prompt you for input if this option is not set.
                             	Examples:
                             	- --password=pass:password123 (should only be used where security is not important)

  --overwrite                Overwrites the forger info

  --pretty                   Prints JSON in pretty format rather than condensed.

EXAMPLES
  forging:disable ab0041a7d3f7b2c290b5b834d46bdc7b7eb85815
  forging:disable ab0041a7d3f7b2c290b5b834d46bdc7b7eb85815 --data-path ./data
  forging:disable ab0041a7d3f7b2c290b5b834d46bdc7b7eb85815 --data-path ./data --password your_password

6.2. via the updateForgingStatus action

Invoke the following action to disable the forging for a delegate:

Disable forging
const { createWSClient } = require('@liskhq/lisk-api-client');

export const disableForging = async () => {
    let apiClient = await createWSClient('ws://localhost:8080/ws');
    const { data } = await apiClient.invoke('app:updateForgingStatus', {
      address: string,
      password: string,
      forging: false (1)
    });
};
1 Change forging to false to disable forging for a delegate on the node.

7. Safely enabling forging on another node

To safely enable forging on another node, please ensure to follow the steps below:

  1. Setup a new node on another server.

  2. Start the node and let it synchronize with the network. If available, it is recommended to synchronize from snapshots to speed up the synchronization process.

  3. Login to the server with the old node.

  4. Disable forging on the old node.

  5. Stop the old node.

  6. Dump the data in the forger_info table of the db of your node.

    lisk-core forger-info:export
  7. Login to the server with the new node.

  8. Restore the forger_info table.

    lisk-core forger-info:import ./forger.db.tar.gz
  9. Add delegate data to config.

  10. Ensure the node is fully synchronized with the network. The height of your node should be equal to the current network height.

    lisk-core node:info
  11. Fetch the forging data needed to enable forging by Checking the forging status.

  12. Enable forging.

8. Safely enabling forging without forger_info data

Configurable Constants
  • BLOCK_TIME = 10: The block time of the considered blockchain in seconds, i.e., 10 for Lisk Mainnet.

  • MAX_FORK_DEPTH = 8640: An upper boundary on the largest chain of off-chain blocks for which the validator generated a block, i.e., for every block at height h generated by the validator, the parent block at height h - MAX_FORK_DEPTH must be contained in the canonical chain that is eventually finalized. It is recommended to use MAX_FORK_DEPTH = 8640 = 24*60 *6 (number of blocks generated in 24 h).

Required Delegate Input
  • lastHeightActive: Unix timestamp of the last height when the validator node could have possibly been active and forging, (over estimate with a larger number when uncertain about the exact time).

Instructions
  1. Start a new node with forging deactivated and synchronize with the Lisk blockchain until there is a block finalizedBlock that is finalized, and that the finalized block header timestamp is greater than the last active height: finalizedBlock.header.timestamp > lastHeightActive

  2. Obtain a block parentBlock which is a parent block of finalizedBlock at height finalizedBlock.header.height - MAX_FORK_DEPTH.

    parentBlock.header.height = finalizedBlock.header.height - MAX_FORK_DEPTH
  3. Compute the number of missed blocks in the current chain between the finalizedBlock and the parentBlock, i.e., as shown below:

    missedBlocks = ceil((finalizedBlock.header.timestamp - parentBlock.header.timestamp)/BLOCK_TIME) - (finalizedBlock.header.height - parentBlock.header.height)
  4. Use the following forging configuration and activate forging:

    height = finalizedBlock.header.height
    maxHeightPreviouslyForged = finalizedBlock.header.height + missedBlocks
    heightPrevoted = finalizedBlock.header.height