How to run a Validator node

Registering and running a validator node requires a few steps to be followed.

  • Setup the node and wait for it to fully sync up. This node will be setup with a node wallet (not the same as validator wallet for security reasons) that will be used to sign blocks and consensus.
  • Create a wallet for the validator and register it on the chain as a validator by paying the registration fee.
  • Register the node with the validator public key on the chain by calling setPRepNodePublicKey method.

This guide will help you set up a validator node using Docker.

Prerequisites

Get the official Docker Image: iconloop/icon2-node

System Requirements

CPU:  minimum 4core, recommend 8core +
RAM:  minimum 16GB, recommend 32GB +
DISK : minimum SSD 2.5TB, recommend SSD 3TB +
Network: minimum 1Gbps, recommend 2Gbps +

External Communications
TCP 7100: TCP port used for peer-to-peer connection between peer nodes.
TCP 9000: JSON-RPC or RESTful API port serving application requests.P-Rep must allow TCP connections to port 7100 and 9000 of an external host. ( Use 0.0.0.0/0 for a source from any network )

Creating a wallet for the validator and the node

The first step is to create a wallet and keystore file. You can follow the instructions in this guide to create a wallet.

This wallet you define as the one to manage the validator, needs to be funded with enough ICX to be able to register as a validator, the registration fee is 2,000 ICX and you will also need a small amount of ICX to pay for the transaction fees.

Setting up the node

Following the instructions for creating a wallet, you will need to create a new wallet that will be used to operate the node.

Once you have the new wallet (node wallet) create a working folder in your server on a disk with enough space as detailed in the system requirements previously mentioned.

For this tutorial we will use the following folder structure:

mkdir ~/icon-node

Change to the newly created directory

cd ~/icon-node

Create inside the folder the following directories and files:

mkdir config
touch docker-compose.yml

Save the node keystore file (the node wallet) that was previously created in the config directory.

At this point your folder structure should look like this:

.
ā”œā”€ā”€ config
ā”‚   ā””ā”€ā”€ keystore.json
ā””ā”€ā”€ docker-compose.yml

Open docker-compose.yml in a text editor and add the following content:

version: "3"
services:
   prep:
      image: iconloop/icon2-node
      container_name: "icon2-node"
      network_mode: host
      restart: "always"
      environment:
         SERVICE: "MainNet"  # MainNet, SejongNet  ## network type
         GOLOOP_LOG_LEVEL: "debug" # trace, debug, info, warn, error, fatal, panic
         KEY_STORE_FILENAME: "keystore.json"
         KEY_PASSWORD: "INPUT_YOUR_KEY_PASSWORD"
         FASTEST_START: "true"    # It can be restored from latest Snapshot DB.

         ROLE: 3 # Validator = 3, API Endpoint = 0

      cap_add:
         - SYS_TIME

      volumes:
         - ./data:/goloop/data # mount a data volumes
         - ./config:/goloop/config # mount a config volumes ,Put your used keystore file here.
         - ./logs:/goloop/logs
      ports:
         - 9000:9000
         - 7100:7100

Run the following command to start the ICON2 node and wait for the entire ledger to locally sync up.

$ docker-compose pull && docker-compose up -d

you can monitor the process by checking the logs file that are created in the logs directory.

$ tail -f logs/booting.log


$ tail -f logs/goloop.log

The following folder structure will be created:

.
ā”œā”€ā”€ docker-compose.yml
ā”œā”€ā”€ config              # configuration files
ā”‚   ā””ā”€ā”€ keystore.json   # Import your keystore file

ā”œā”€ā”€ data                # block data
ā”‚   ā”œā”€ā”€ 1
ā”‚   ā”œā”€ā”€ auth.json
ā”‚   ā”œā”€ā”€ cli.sock
ā”‚   ā”œā”€ā”€ ee.sock
ā”‚   ā””ā”€ā”€ rconfig.json
ā”œā”€ā”€ logs                # log files
ā”‚   ā”œā”€ā”€ booting.log
ā”‚   ā”œā”€ā”€ health.log      # health check log
ā”‚   ā”œā”€ā”€ chain.log       # goloop chain action logs
ā”‚   ā”œā”€ā”€ dowload.log
ā”‚   ā””ā”€ā”€ dowload_error.log
ā”‚   ā””ā”€ā”€ goloop.log

Docker environments settings

Namedefaulttyperequireddescription
SERVICEMainNetstrfalseService Name - (MainNet, SejongNet)
ROLE3inttrueRole of running node. 0: Citizen, 3: P-Rep
CONFIG_URLstrfalse
CONFIG_URL_FILEdefault_configure.jsonstrfalse
CONFIG_LOCAL_FILEconfigure.jsonstrfalse
IS_AUTOGEN_CERTfalseboolfalseAutomatically generate certificates
FASTEST_STARTfalseboolfalseDownload snapshot DB
KEY_STORE_FILENAMEkeystore.jsonstrtruekeystore.json file name
KEY_PASSWORDstrtruepassword of keystore.json file
USE_NTP_SYNCTrueboolfalseWhether to use NTP in container
NTP_SERVERstrfalseNTP Server
NTP_REFRESH_TIMEintfalsentp refresh time
SLACK_WH_URLstrfalseslack web hook url - If a problem occurs, you can receive an alarm with a slack.
USE_HEALTH_CHECKTrueboolfalseWhether to use health check
CHECK_TIMEOUT10intfalsesec - TIMEOUT when calling REST API for monitoring
CHECK_PEER_STACK6intfalsesec - Stack value to check the peer for monitoring.
CHECK_BLOCK_STACK10intfalsesec - Stack value to check the block for monitoring.
CHECK_INTERVAL10intfalsesec - check interval for monitoring
CHECK_STACK_LIMIT360intfalsecount - count- Restart container when stack value is reached
GOLOOP_LOG_LEVELdebugstrfalseLog Level - (trace,debug,info,warn,error,fatal,panic
LOG_OUTPUT_TYPEfilestrfalsesec - check interval for monitoring

Registering a validator on chain

Registering a validator node by calling the registerPrep function

Once the wallet is funded you can register as a validator node using the registerPrep (opens in a new tab) function from the JSON-RPC API.

This can be done directly from the tracker, using goloop or calling the RPC method directly.

Using the tracker

The easiest way to sign this transaction is to load up the keystore in a browser wallet (Hana Wallet (opens in a new tab)) and sign the transaction directly from the tracker by login in first with your wallet and then going to the contract page and calling the registerPrep function.

https://tracker.icon.community/contract/cx0000000000000000000000000000000000000000#contract (opens in a new tab)

registerPrep

Using goloop cli or preptools

Goloop CLI and the preptools are 2 command line utilities that can be used to interact with the ICON blockchain.

These can be used to sign the transaction and call the registerPrep function.

https://github.com/icon-project/goloop/blob/master/doc/goloop_cli.md#goloop-rpc-sendtx-call (opens in a new tab)

https://github.com/icon-project/preptools/blob/master/README.md#registerprep (opens in a new tab)

The docker container for the node has goloop CLI installed internally, if you dont want to install goloop CLI in your system you can run the following command to call the registerPRep method inside the docker container:

docker exec -it icon2-node goloop rpc sendtx call --to cx0000000000000000000000000000000000000000 --method registerPRep --param city=seoul --param country=KOR --param details=https://yourdomain.com/path/to/logo256.png --param email=test@mail.com --param name=testPRep --param nodeAddress=hx123...4566 --param p2pEndpoint=127.0.0.1:9000 --param website=https://yourdomain.com/path/to/logo256.png --key_store config/keystore.json --key_password "KEYSTORE_PASSWORD" --uri https://ctz.solidwallet.io/api/v3 --nid 1 --value 0x6c6b935b8bbd400000 --step_limit 0x30000

The following is an example using preptools:

(venv) $ cat registerPRep.json
{
    "name": "banana node",
    "country": "USA",
    "city": "New York",
    "email": "banana@example.com",
    "website": "https://icon.banana.com",
    "details": "https://icon.banana.com/json",
    "p2pEndpoint": "node.example.com:7100",
    "nodeAddress": "hxef73db5d0ad02eb1fadb37d0041be96bfa56d4e6"
}
 
(venv) $ preptools registerPRep -k test_keystore --prep-json registerPRep.json
> Password:
[Request] ======================================================================
{
    "from_": "hxef73db5d0ad02eb1fadb37d0041be96bfa56d4e6",
    "to": "cx0000000000000000000000000000000000000000",
    "value": 2000000000000000000000,
    "step_limit": 268435456,
    "nid": 3,
    "nonce": null,
    "version": 3,
    "timestamp": null,
    "method": "registerPRep",
    "data_type": "call",
    "params": {
        "name": "banana node",
        "country": "USA",
        "city": "New York",
        "email": "banana@example.com",
        "website": "https://icon.banana.com",
        "details": "https://icon.banana.com/json",
        "p2pEndpoint": "node.example.com:7100",
        "nodeAddress": "hxef73db5d0ad02eb1fadb37d0041be96bfa56d400"
    }
}
 
> Continue? [Y/n]
request success.
[Response] =====================================================================
{
    "jsonrpc": "2.0",
    "result": "0xe667b8de967e4c5e2cc5f4fc2775766f87517935e0875a8c4d0b9c8c2ce01846",
    "id": 1234
}
 

Using the JSON-RPC API

Calling the method from the JSON-RPC API directly requires sending a signed transaction with the following parameters:

Request

{
  "jsonrpc": "2.0",
  "id": 1234,
  "method": "icx_sendTransaction",
  "params": {
    "value": "0x6c6b935b8bbd400000",
    "data": {
      "method": "registerPRep",
      "params": {
        "name": "ABC Node",
        "country": "KOR",
        "city": "Seoul",
        "email": "abc@example.com",
        "website": "https://abc.example.com/",
        "details": "https://abc.example.com/details/",
        "p2pEndpoint": "abc.example.com:7100",
        "nodeAddress": "hxe7af5fcfd8dfc67530a01a0e403882687528dfcb"
      }
    },
    ...
  }
}

Parameters

KeyVALUE TypeRequiredDescription
nameT_STRINGtrueP-Rep name "ABC Node"
emailT_STRINGtrueP-Rep email "abc@example.com"
countryT_STRINGtrueISO 3166-1 ALPHA-3 (opens in a new tab) "KOR", "USA", "CHN"
cityT_STRINGtrue"Seoul", "New York", "Paris"
websiteT_STRINGtrueP-Rep homepage url "https://abc.example.com (opens in a new tab)"
detailesT_STRINGtrueUrl including P-Rep detail information "https://abc.example.com/details/ (opens in a new tab)"
p2pEndpointT_STRINGtrueNetwork info used for connecting among P-Rep nodes "123.45.67.89:7100", "node.example.com:7100"
nodeAddressT_STRINGFalseNode Key for only consensus "hxe7af5fcfd8dfc67530a01a0e403882687528dfcb"

The following guide explains how to interact with the ICON JSON-RPC API: ICON JSON-RPC API

Node Grades

Node grades are another term for node levels.

After successfully registering as a validator node using registerPrep (opens in a new tab) the grade of the node will be set to "0x2".

There are 3 node grades, detailed below. You can also check the grade return parameter from getPrep (opens in a new tab) function from the JSON-RPC API for more info

Grade numberUsageDescription
0x2Validator CandidateRegister your node as a candidate to become a block validator and network governance delegate
0x1Sub-ValidatorRegister your node as a sub-validator for block production and validation and network governance delegate
0x0Main ValidatorRegister your node as a validator for block production and validation and network governance delegate

Registering a validator node public key

After the node is up and running, you can register the public key of the node by following the instructions in this guide.

Final steps

After completing the above steps your validator node should become an active validator on the ICON network after 48 hours of being registered.

If you need any help or assistance during the process you can reach out to the ICON community in our discord channel: ICON Discord

CTRL + M