Setting up a relayer node
On this page, you’ll learn:
-
How to set up a relayer node on a sidechain?
-
How to set up a relayer node on a mainchain?
The process of setting up a relayer node on a mainchain and sidechain are almost identical. The subsequent sections describe the steps to set up a relayer node.
Prerequisites
To use this guide, it is assumed that the following criteria have been met:
|
1. Installing the Chain Connector plugin
The chain connector plugin comes pre-installed with any chain that has been initialized with Klayr SDK v6. However, in case it is required to install it manually, run the following command in the root folder of the client.
npm install @klayr/chain-connector-plugin
2. Configuration
To set up a relayer node, one needs to set up the node according to the following configurations:
2.1. Configuring the Chain Connector plugin
Once the plugin is installed, various configurations are available for the node operator to set. With these configurations, the details such as the receiving chain’s chainID and its IPC path or WS URL, CCU frequency, encrypted private key, etc. can be set.
The following table describes the available configuration options.
Name | Type | Description | Sample |
---|---|---|---|
|
string |
The IPC path of a receiving node |
~/.klayr/klayr-core |
|
string |
The WS URL of a receiving node |
ws://142.93.230.246:4002/rpc-ws |
|
integer |
Number of blocks after which a CCU should be created |
1 |
|
string |
Encrypted privateKey of the relayer |
|
|
string |
The fee to be paid for each CCU transaction.
It’s an optional value and is only used if the user wants to pay a fee higher than the minimum calculated fee.
In that case, the minimum calculated fee is overridden with the value passed with the |
100000000 |
|
boolean |
Flag for the user to either save or send a CCU on creation. Sending a CCU is the default option. |
false |
|
integer |
Number of CCUs to save. |
300 |
|
integer |
Maximum size of CCU to be allowed |
50 |
|
integer |
Height at the time of registration on the sending chain. |
100 |
|
integer |
Height until no fees are being applied to CCUs. |
0 |
|
string |
Chain ID of the receiving chain. |
04000000 |
{
// [...]
"plugins": {
"chainConnector": {
"encryptedPrivateKey": "kdf=argon2id&cipher=aes-256-gcm&version=1&ciphertext=da36ef64cbf2687d62b014dafdfa8ef8c823b2b1562ae78819599080e4500529b75e80093fba066879f0767e0de83abe285efb259dd9be5109b8a4ef66cfc52ec613314586c1aa1da3a6737c0f8b7f0de7fb4d1b85860cd23915bbcee774e1d85b357e342816a917e517f7c702e1a1deb28dd69a4b69ae2ac67a5c4c4236101c&mac=e253decce05dd50758400d5c7408532a162fedf583ff9cafcb7ad3e12f6b8011&salt=40ab2dcdd387e4372ed1dbb948a9ef84&iv=4559dcaee67eb2c1a0957ecf&tag=81c2c332d915454bed4be26018c598c5&iterations=1¶llelism=4&memorySize=2024",
"ccuFee": "800000",
"receivingChainIPCPath": "~/.klayr/klayr-core",
"receivingChainID": "04000000"
}
}
}
A node operator must add either the value of receivingChainIPCPath or receivingChainWsURL in the chain connector’s config.
|
2.2. Configuring the system
Before we discuss how to set up a node to act as a relayer node, we need to understand the concept of prefixes, how to retrieve them, and how to calculate inclusionProofKeys
.
2.2.1. What are Prefixes and how to get them?
We can get the MODULE_PREFIX
and the SUBSTORE_PREFIX
from the system_getMetadata endpoint.
For more information, see LIP 40.
Each module has a set of stores
and each store has a unique key
.
After invoking the aforementioned endpoint, search for the "stores"
property of the interoperability
module.
Then, look for the outbox substore of the interoperability
module and note down the value of the key
property.
The following details have been retrieved by invoking the system_getMetadata endpoint.
"stores": [
{
"key": "83ed0d250000",
"data": {
"$id": "/modules/interoperability/outbox",
"type": "object",
"required": [
"root"
],
"properties": {
"root": {
"dataType": "bytes",
"minLength": 32,
"maxLength": 32,
"fieldNumber": 1
}
}
}
},
]
Prefix | Description |
---|---|
|
The first 4 bytes of the |
|
The last 2 bytes of the |
|
The |
The MODULE_PREFIX+SUBSTORE_PREFIX is already available in the system’s metadata and it can be found in the response of system_getMetadata.
For the example above, the "key": "83ed0d250000" is equal to MODULE_PREFIX+SUBSTORE_PREFIX .
|
2.2.2. Calculating inclusionProofKeys
To save inclusion proof of outboxRoot
for a sidechain on the mainchain on the outbox
substore, do the following:
// 1. Calculate the MODULE_PREFIX using the Interoperability module.
MODULE_PREFIX = Buffer.from('83ed0d25', 'hex')
// 2. Calculate the SUBSTORE_PREFIX using the Outbox Substore.
SUBSTORE_PREFIX = Buffer.from('0000', 'hex') ()
// 3. Calculate the STORE_KEY using the Chain ID of a sidechain.
STORE_KEY = Buffer.from('04000001', 'hex') ()
// 4. Finally, calculate the inclusionProofKeys as described below:
inclusionProofKeys = Buffer.concat([MODULE_PREFIX, SUBSTORE_PREFIX, cryptography.utils.hash(STORE_KEY)]);
Once the inclusionProofKeys
value(s) is retrieved, it should be added to the system
configuration available inside the config.json file of a node.
To save inclusion proof with every new block we need to pass the following configurations:
Name | Type | Description | Sample |
---|---|---|---|
|
number |
Number of blocks for which the inclusion proofs are to be kept.
By default, inclusion proofs are kept for the latest 300 blocks.
If |
-1 |
|
string[] |
Contains the keys for which we need to store inclusion proofs against the state tree.
This can be created or deduced by the user by concatenating the following:
|
|
{
// Default configurations
"system": {
"dataPath": "~/.klayr/pos-sidechain-example-one",
"keepEventsForHeights": 300,
"logLevel": "info",
// Properties relevant to setting up a relayer node
"keepInclusionProofsForHeights": -1,
"inclusionProofKeys": [
"83ed0d250000fb5e512425fc9449316ec95969ebe71e2d576dbab833d61e2a5b9330fd70ee02"
]
},
}
The above approach should be used to configure the Chain connector plugin as the plugin requires the inclusion proof of the outbox root of the receiving chain to calculate outboxRootWitness
in CCU transaction.
3. Enabling the Chain Connector plugin
A node operator can perform the following steps to enable the chain connector plugin and turn a node into a relayer node.
3.1. Creating an encrypted private key
-
The first step is to create an encrypted private key. A node operator can use a REPL session to call the Klayr cryptography libraries.
-
The
encryptedPrivateKey
can be created by calling theencryptMessageWithPassword
function. It accepts two arguments: a private key of the account which is supposed to be used as a relayer address and a password.The account should have sufficient balance so that the encrypted private key can be used for signing and sending the transaction.
Creating an encrypted key on a sidechain nodesidechain_client> klayr.cryptography.encrypt.stringifyEncryptedMessage(await klayr.cryptography.encrypt.encryptMessageWithPassword('0d7501d3d5c9accaefb3c0b6a569473b59391ae406f6324f98fa6dd70e119368a6454f898d3b82c41b158206c72ecfe917a1071c8084b496a0c5867afc10830b', 'klayr'))
Encrypted key'kdf=argon2id&cipher=aes-256-gcm&version=1&ciphertext=57db80457db93a1abeceee5c6f951ca04579c447a06f45cf5e8b5398e207a26da53a6b191a02c479ede455950eacb48f32d6609f2cd4b5a1a51e895b210b587ef046e6c3151ef2212efd0808b45328742d09a279e7d667f1670ff02a2fd5c91f4afd0a08efb8e6e90b0b11e93b15da8daaeea543a0ff54f3dd51c66cac3b04c6&mac=7822258b12e0c787f5bd622c562914438a9d74ca1e11e11b840f3001a678b04f&salt=d4d051a123326ad2b82c022603e790b6&iv=0bb9e76cd5163d6c5af9d89d&tag=fbcdb355b5135d48df948841de5fcdf5&iterations=1¶llelism=4&memorySize=2024'
Creating an encrypted key on a mainchain nodeklayr-core> klayr.cryptography.encrypt.stringifyEncryptedMessage(await klayr.cryptography.encrypt.encryptMessageWithPassword('0d7501d3d5c9accaefb3c0b6a569473b59391ae406f6324f98fa6dd70e119368a6454f898d3b82c41b158206c72ecfe917a1071c8084b496a0c5867afc10830b', 'klayr'))
Encrypted key'kdf=argon2id&cipher=aes-256-gcm&version=1&ciphertext=f4dd49061a128d06184308a235311dc487737b7c4a688409224ed39b7d8e76a6cdd814500dd7221297ed122d277af8ba46d42ebd340d228fe6c77132543b303c97ab89e151ecd9f2739284c60c66ab68c0f3531ffc6cbdedad2acc431e8d8e48dffd7c7eda3dfe5f404e00ef7ae825d34da7787bf792b6ecb84ea1bfe10e9ca6&mac=363141e645d5564a150a2634060bd273276b0c987a65cf64513a7871565c3f2a&salt=93213d2d1c11e91d64771c173f8bf3c1&iv=0132fa14a4ed289deb07ee11&tag=7b64ed4a0453302d54bba29d4f7a68ea&iterations=1¶llelism=4&memorySize=2024'
The
encryptMessageWithPassword
function will return an encrypted key, which should be added to the config of the blockchain.
3.2. Prepare config for chain connector plugin
Each node whether a mainchain or a sidechain expects mandatory configurations as shown in the following snippets.
"chainConnector": {
"encryptedPrivateKey": "kdf=argon2id&cipher=aes-256-gcm&version=1&ciphertext=57db80457db93a1abeceee5c6f951ca04579c447a06f45cf5e8b5398e207a26da53a6b191a02c479ede455950eacb48f32d6609f2cd4b5a1a51e895b210b587ef046e6c3151ef2212efd0808b45328742d09a279e7d667f1670ff02a2fd5c91f4afd0a08efb8e6e90b0b11e93b15da8daaeea543a0ff54f3dd51c66cac3b04c6&mac=7822258b12e0c787f5bd622c562914438a9d74ca1e11e11b840f3001a678b04f&salt=d4d051a123326ad2b82c022603e790b6&iv=0bb9e76cd5163d6c5af9d89d&tag=fbcdb355b5135d48df948841de5fcdf5&iterations=1¶llelism=4&memorySize=2024",
"ccuFee": "800000",
"receivingChainIPCPath": "~/.klayr/klayr-core"
"receivingChainID": "04000000"
}
"chainConnector": {
"encryptedPrivateKey": "kdf=argon2id&cipher=aes-256-gcm&version=1&ciphertext=f4dd49061a128d06184308a235311dc487737b7c4a688409224ed39b7d8e76a6cdd814500dd7221297ed122d277af8ba46d42ebd340d228fe6c77132543b303c97ab89e151ecd9f2739284c60c66ab68c0f3531ffc6cbdedad2acc431e8d8e48dffd7c7eda3dfe5f404e00ef7ae825d34da7787bf792b6ecb84ea1bfe10e9ca6&mac=363141e645d5564a150a2634060bd273276b0c987a65cf64513a7871565c3f2a&salt=93213d2d1c11e91d64771c173f8bf3c1&iv=0132fa14a4ed289deb07ee11&tag=7b64ed4a0453302d54bba29d4f7a68ea&iterations=1¶llelism=4&memorySize=2024",
"ccuFee": "800000",
"receivingChainIPCPath": "~/.klayr/relayer",
"receivingChainID": "04000002"
}
Once the configuration is ready, update the config.json file of the respective client such as mainchain or sidechain.
3.3. Register plugin
Once the config.json has been updated, it is required to register the plugin with the client. The process differs for both sidechain and mainchain.
On a sidechain, the plugin can be enabled using the --enable-chain-connector-plugin
flag whilst starting the blockchain client.
./bin/run start --enable-chain-connector-plugin --overwrite-config
Alternatively, the plugins.ts file of the client can be updated to have the following options:
import { Application } from 'klayr-sdk';
// Import the 'ChainConnectorPlugin'
import { ChainConnectorPlugin } from '@klayr/chain-connector-plugin';
export const registerPlugins = (app: Application): void => {
// Register the ChainConnectorPlugin with the app
app.registerPlugin(new ChainConnectorPlugin());
};
The client must be rebuilt to entertain the changes to the code.
npm run build
The client can then be started with the following command:
./bin/run start --overwrite-config
On a mainchain, the plugin can be enabled using the --enable-chain-connector-plugin
flag whilst starting the blockchain client.
klayr-core start --network alphanet --enable-chain-connector-plugin --overwrite-config
Since the config of the chain is updated during the process, the node operator must update the existing config with the --overwrite-config
flag.
3.4. Result
Once the client is running, the node operators should see the following log messages, depending on the type of node.
2023-03-17T14:42:30.426Z INFO XYZ.local application 96733 No valid CCU can be generated for the height: 58
2023-03-17T14:42:30.426Z INFO XYZ.local plugin_chainConnector 96899 No valid CCU can be generated for the height: 58
Since we just set up a relayer node and haven’t sent a CCU/CCM, the aforementioned log messages are expected.
The messages suggest that the blockchain doesn’t have any finalized block height for which we can create a certificate, or there are no pending CCUs/CCMs to send across the chain.
The relayer node will start relaying CCUs to the receiving chain, once the finalized height is reached.
Once the plugin is enabled, it is essential to invoke the chainConnector_authorize endpoint to authorize the signing and sending of CCUs. |
A node can also output various warnings or error messages as log output; the details of which can be seen in the following tables:
Log message | Description |
---|---|
Warnings messages: The following log messages can be considered as warnings and they don’t require restarting a node or plugin to fix the underlying issue as such messages usually suggest problems with chain registration or |
|
|
As the log suggests, the sending chain is not registered yet on the receiving chain but at the same time, all the data related to CCU creation is saved such as |
|
In this scenario, the node is syncing with the network, hence, it cannot generate a CCU. |
|
In this scenario, the data required for CCU creation is saved and only CCU creation is delayed due to the provided |
|
In this case, the plugin is running fine and saving data for CCU creation, however, it cannot yet create or send CCU as the user has not yet registered the receiving chain on their own chain. For more information, read LIP 43. |
|
If no new certificate has been created since the last certificate and no pending CCMs are left then, no CCU can be created and the user needs to wait for the next certificate height on its sending chain. |
|
In this case, the plugin will try again on the next new block if the API issue is resolved to create/send a CCU. |
|
The log message suggests that the CCU was created successfully but its submission failed for some reason. In this case, the user needs to check the error attached to the log to debug further. |
|
This error occurs when |
Error messages: The following error-related logs should be fixed by the user and require a node restart.
In these cases, the plugin is usually missing the data required to create CCUs, and that usually happens when something goes wrong while saving data on the plugin.
Such errors also occur when the user enables the |
|
|
In this case, the plugin is looking at a different height and when it is unable to find a certificate, it logs out the aforementioned error. |
|
As the error suggests, the node is unable to retrieve the |
|
If the node is unable to find data based on the given |
|
If the node is unable to find data based on the given |
Possible ways to debug the case when the first CCU is not sent and the user sees the aforementioned errors are described below:
Sometimes if the node is very busy with syncing over a long period of time, the plugin misses out on storing information from the new block event, which might lead to the aforementioned errors. This should not usually happen, however, if it does then, the user must re-sync their node. |