Registering a Validator Node

Introduction

A Validator node is a Full Node that has registered with the Radix network to receive delegated stake and potentially be selected to participate in network consensus.

Validator nodes provide the critical infrastructure of the Radix network and may receive special incentive rewards as a result. However attempting to become one of the network’s 100 validator nodes is not a decision to be taken lightly, requiring commitment to high reliability operation and engagement with the Radix community. Registration as a validator node alone does not guarantee participation in consensus or that you will receive incentive rewards.

Once running, a validator node offers two interface endpoints on a private port:

The /core endpoint can be used to conduct transactions from the node’s account, including validator configuration, registration, and de-registration. The node’s account must hold XRD tokens to pay for network fees on these transactions.

The /system endpoint can be used to query aspects of the node and network such as current version, current peers, etc.

Prerequisites

To register a validator node, you need a Radix full node installed, running, and syncing with the network. If you haven’t yet set one, then please run through one of these guides:

1. Register the node as a validator

We’re using Amazon Web Services throughout our example, but you can install Radix nodes on any cloud service that supports Java, such as Google’s cloud platform or Microsoft Azure – or follow similar step to deploy on a private server.

There are four steps to register your node to take part in validation:

1.1. Get your node’s wallet address.

Execute the following command to fetch node address.

curl -k -u superadmin:{nginx-superadmin-password} -X POST 'https://localhost/key/list' \
--header 'Content-Type: text/plain' \
--data-raw '{
    "network_identifier": {
        "network": "mainnet"
    }
}'

This will return some basic information about your Radix instance:

{
    "public_keys": [
        {
            "public_key": {
                "hex": "0291d7f4e9a28049385da46855dc5a25184d5759ff5518b6c0746ee81a98698035"
            },
            "identifiers": {
                "account_entity_identifier": {
                    "address": "rdx1qspfr4l5ax3gqjfctkjxs4wutgj3sn2ht8l42x9kcp6xa6q6np5cqdgy70cjj"
                },
                "validator_entity_identifier": {
                    "address": "rv1q2ga0a8f52qyjwza5359thz6y5vy646ela233dkqw3hwsx5cdxqr2qktp69"
                },
                "p2p_node": {
                    "peer_id": "rn1q2ga0a8f52qyjwza5359thz6y5vy646ela233dkqw3hwsx5cdxqr2c9p3km"
                }
            }
        }
    ]
}

The public_key.hex is the node’s hex public key that your require for signing

The identifiers.account_entity_identifier.address field is that refers to node’s wallet address.

The identifiers.validator_entity_identifier.address field is that refers to node’s validator address to which wallet users will stake their xrd tokens

The identifiers.p2p_node.peer_id field is that refers to node’s p2p address that another node can use it as trusted node and connect to yours as peer

Validator addresses are prefixed with rv.
Regular node addresses are prefixed with rdx.
Validator peer to peer addresses are prefixed with {rn}

1.2. Send XRD tokens to your node

Use your Radix Desktop Wallet to send tokens to the node’s wallet address. These XRD will be used by the node to pay any transaction fees, such as for the transaction that you will submit to register your node as a validator. Registration and update transactions will cost up to 30 XRD in transaction fees. (This is higher than typical token send transactions due to the requisite processing at the epoch’s end for these types of validator transactions.)

Execute the following command to check node wallets balances. The node’s wallet address is used below to fetch the balanaces

curl -k -u admin:{nginx-admin-password} -X POST 'https://localhost/entity' \
--header 'Content-Type: application/json' \
--data-raw '{
    "network_identifier": {
        "network": "mainnet"
    },
    "entity_identifier": {
        "address": "<node's wallet address>"
    }
}'

This will return response showing balances on this node’s wallet address account. If the node is in complete sync, the balances should reflect the tokens that you sent from your wallet

{
   "balances":[
      {
         "resource_identifier":{
            "rri":"xrd_tr31qye87xgq",
            "type":"Token"
         },
         "value":"100000000000000000000000"
      }
   ],
   "data_objects":[

   ],
   "state_identifier":{
      "state_version":45937223,
      "transaction_accumulator":"147ae7f0edfdf9df43213e6affaf43986a0f0e1abda3f31483d8b1f4db586f97"
   }
}

1.3. Call endpoint to register the node as a validator

Updating validator config requires few calls. Steps would be as follows

1.3.1. Build a transaction with config changes

Make the following call to your node’s core API endpoint to build a transaction (example parameters shown):

curl -s -u admin:{nginx-admin-password} -X POST -k 'https://localhost/construction/build' -H 'Content-Type: application/json' \
-d '{
   "network_identifier":{
      "network":"mainnet"
   },
   "fee_payer":{
      "address":"<node's wallet address>"
   },
   "operation_groups":[
      {
         "operations":[
            {
               "data":{
                  "action":"CREATE",
                  "data_object":{
                     "registered":true,
                     "type":"PreparedValidatorRegistered"
                  }
               },
               "entity_identifier":{
                  "address":"<node's validator address>" (1)
               },
               "type":"Data"
            }
         ]
      },
      {
         "operations":[
            {
               "data":{
                  "action":"CREATE",
                  "data_object":{
                     "fee":1100, (2)
                     "type":"PreparedValidatorFee"
                  }
               },
               "entity_identifier":{
                  "address":"<node's validator address>"
               },
               "type":"Data"
            }
         ]
      },
      {
         "operations":[
            {
               "data":{
                  "action":"CREATE",
                  "data_object":{
                     "name":"My Validator",(3)
                     "type":"ValidatorMetadata",
                     "url":"https://my-validator.com"(4)
                  }
               },
               "entity_identifier":{
                  "address":"<node's validator address>"
               },
               "type":"Data"
            }
         ]
      },
      {
         "operations":[
            {
               "data":{
                  "action":"CREATE",
                  "data_object":{
                     "allow_delegation":true,(5)
                     "type":"ValidatorAllowDelegation"
                  }
               },
               "entity_identifier":{
                  "address":"<node's validator address>"
               },
               "type":"Data"
            }
         ]
      },
    {
         "operations":[
            {
               "data":{
                  "action":"CREATE",
                  "data_object":{
                     "owner":{
                        "address":"<new owner address>"(6)
                     },
                     "type":"PreparedValidatorOwner"
                  }
               },
               "entity_identifier":{
                  "address":"<node's validator address>"
               },
               "type":"Data"
            }
         ]
      }
   ]
}'

This build call takes a number of operations and within those operations you specify details about your validator node.

All of these details on your validator node will be displayed for the benefit of the staking public in the Radix Explorer.

1 validator: the node’s validator address.
2 validatorFee: A percentage of the total emissions XRD earned by stakers to your node, which is continuously deducted and credited to your specified owner address as your node’s fee for operation. Setting the fee to 0% means the validator node takes none of the emissions fees earned by the node’s delegators.
The validator fee may be specified to up to two decimals of precision. e.g. 1 or 1.75 are valid, but the API will truncate 1.2345 to 1.23.
3 name: the public name of your node.
4 url: a URL that points to a webpage about your node.
5 allowDelegation: Setting this to true will allow others to delegate stake to your node. Setting it to false means that only new stake from your specified owner address will be accepted. The flag defaults to false when the node is initially registered.
6 owner: The wallet address where any validator fee emissions XRD will be credited. If you are disallowing external delegation, then this is also the only address that may stake to your node.

For more detailed information on earning XRD emissions and the limits and usage of the above parameters, please refer to the Validators and Node-runner Incentives page.

If the transaction build step is successful, the node will return below response that contains unsigned transction:

{
   "payload_to_sign":"810df8578a111ee4a5f9fde5bafd9b42cbbf05c0c2ab7285400f02ac11ec6162",
   "unsigned_transaction":"07ac5ef789f9846df840921dead6e8fef3249ab8fb7a808e8804b1f92e1c23be890000000001002100000000000000000000000000000000000000000000000001180e78fb105680000200450600040291d7f4e9a28049385da46855dc5a25184d5759ff5518b6c0746ee81a98698035010000000000000000000000000000000000000000000000040d4e6d146c6480000009004554347c2a10a8f09efd8398ed4b259909a3f848cc9fa05ca20e225f8bfb1d2d1a000000030291d7f4e9a28049385da46855dc5a25184d5759ff5518b6c0746ee81a9869803502004d0b000291d7f4e9a28049385da46855dc5a25184d5759ff5518b6c0746ee81a98698035000d73746f6b656e65742d74657374001968747470733a2f2f73746f6b656e65742e746573742e636f6d0009004554347c2a10a8f09efd8398ed4b259909a3f848cc9fa05ca20e225f8bfb1d2d1a000000070291d7f4e9a28049385da46855dc5a25184d5759ff5518b6c0746ee81a9869803505004554347c2a10a8f09efd8398ed4b259909a3f848cc9fa05ca20e225f8bfb1d2d1a000000040291d7f4e9a28049385da46855dc5a25184d5759ff5518b6c0746ee81a9869803503e4e2ef38a01923861d90ff67dc17c14a4ffcb711ef1a0ea8a41831ec8cc57ffd0000007c020030100001000000000000120e0291d7f4e9a28049385da46855dc5a25184d5759ff5518b6c0746ee81a986980350000044c0009004554347c2a10a8f09efd8398ed4b259909a3f848cc9fa05ca20e225f8bfb1d2d1a000000050291d7f4e9a28049385da46855dc5a25184d5759ff5518b6c0746ee81a986980350200240e000291d7f4e9a28049385da46855dc5a25184d5759ff5518b6c0746ee81a98698035010009004554347c2a10a8f09efd8398ed4b259909a3f848cc9fa05ca20e225f8bfb1d2d1a000000080291d7f4e9a28049385da46855dc5a25184d5759ff5518b6c0746ee81a9869803503e4e2ef38a01923861d90ff67dc17c14a4ffcb711ef1a0ea8a41831ec8cc57ffd0000007c02004e110001000000000000120e0291d7f4e9a28049385da46855dc5a25184d5759ff5518b6c0746ee81a98698035040273cad5ab910b3a614b345d8aa7178a0e0da4765c4fc6976bc3bdba2109ac3c8100"
}

Notedown the value that came back in unsigned_transaction

1.3.2. Sign the transaction

To sign the transaction that was built in previous step, make the following call to api by using unsigned_transaction value captured in previous step

curl -k -u superadmin:{nginx-superadmin-password} -X POST 'https://localhost/key/sign' \
--header 'Content-Type: application/json' \
--data-raw '{
    "network_identifier": {
        "network": "mainnet"
    },
    "unsigned_transaction": "<unsigned_transaction_blob>",
    "public_key": {
        "hex": "<node's hex public key>"
    }
}'

If the signing of transaction is successful, server will return below response with signed_transaction

{'signed_transaction': '07ac5ef789f98sdsdsds46df84092dsds1dead6e8fef3249ab8fb7a808e8804b1f92e1c23be890000000001002100000000000000000000000000000000000000000000000001180e78fb105680000200450600040291d7f4e9a28049385da46855dc5a25184d5759ff5518b6c0746ee81a98698035010000000000000000000000000000000000000000000000040d4e6d146c6480000009004554347c2a10a8f09efd8398ed4b259909a3f848cc9fa05ca20e225f8bfb1d2d1a000000030291d7f4e9a28049385da46855dc5a25184d5759ff5518b6c0746ee81a9869803502004d0b000291d7f4e9a28049385da46855dc5a25184d5759ff5518b6c0746ee81a98698035000d73746f6b656e65742d74657374001968747470733a2f2f73746f6b656e65742e746573742e636f6d0009004554347c2a10a8f09efd8398ed4b259909a3f848cc9fa05ca20e225f8bfb1d2d1a000000070291d7f4e9a28049385da46855dc5a25184d5759ff5518b6c0746ee81a9869803505004554347c2a10a8f09efd8398ed4b259909a3f848cc9fa05ca20e225f8bfb1d2d1a000000040291d7f4e9a28049385da46855dc5a25184d5759ff5518b6c0746ee81a9869803503e4e2ef38a01923861d90ff67dc17c14a4ffcb711ef1a0ea8a41831ec8cc57ffd0000007c020030100001000000000000120e0291d7f4e9a28049385da46855dc5a25184d5759ff5518b6c0746ee81a986980350000044c0009004554347c2a10a8f09efd8398ed4b259909a3f848cc9fa05ca20e225f8bfb1d2d1a000000050291d7f4e9a28049385da46855dc5a25184d5759ff5518b6c0746ee81a986980350200240e000291d7f4e9a28049385da46855dc5a25184d5759ff5518b6c0746ee81a98698035010009004554347c2a10a8f09efd8398ed4b259909a3f848cc9fa05ca20e225f8bfb1d2d1a000000080291d7f4e9a28049385da46855dc5a25184d5759ff5518b6c0746ee81a9869803503e4e2ef38a01923861d90ff67dc17c14a4ffcb711ef1a0ea8a41831ec8cc57ffd0000007c02004e110001000000000000120e0291d7f4e9a28049385da46855dc5a25184d5759ff5518b6c0746ee81a98698035040273cad5ab910b3a614b345d8aa7178a0e0da4765c4fc6976bc3bdba2109ac3c81000b0047caa06cdd42841245023e063957d5f432a52af25d3f2f8f0a0943468a9e7c7162d9df9e9c3ef8d1993261e0c2d9507847d375af595ef31cb246d8a57d3d9a72'}

Note down the blob coming as signed_transaction

1.3.3. Submit the transaction

To submit the transaction that was signed in previous step, make the following call to api by using signed_transaction value captured in previous step

curl -k -u admin:{nginx-admin-password} -X POST 'https://localhost/construction/submit' \
--header 'Content-Type: application/json' \
--data-raw '{
  "network_identifier": {
    "network": "mainnet"
  },
  "signed_transaction": "<signed_transaction>"
}'

If transaction is submitted successfully, server returns following response

{
  'duplicate': False,
 'transaction_identifier':
  {
    'hash': '8aeaf660a6656927b737c6edf0d79ef4339c6ba2805e8f4105dc17beb14f2759'
  }
}

The transaction hex can be looked up in explorer for the details.

And that’s it. Your node is now registered as a validator.

While your node is registered immediately, it will not be considered for inclusion in the validator set (based on the amount of stake delegated to it) until the beginning of the next epoch. You can confirm the registration using following steps. However, on Explorer,the node will appear as Unregistered until the next epoch

2. Confirm the node’s registration

To confirm your node’s registration, you can use the node’s entity API endpoint, which will give you the node’s current validator information.

curl -k -u admin:{nginx-admin-password} -X POST 'https://localhost/entity' \
--header 'Content-Type: application/json' \
--data-raw '{
   "entity_identifier":{
      "address":"<node's validator address>"
   },
   "network_identifier":{
      "network":"mainnet"
   }
}'

which will return something like this:

{
   "balances":[],
   "data_objects":[
      {
         "name":"",
         "type":"ValidatorMetadata",
         "url":""
      },
      {
         "allow_delegation":true,
         "type":"ValidatorAllowDelegation"
      },
      {
         "registered":true,
         "type":"PreparedValidatorRegistered"
      },
      {
         "fee":0,
         "type":"PreparedValidatorFee"
      },
      {
         "owner":{
            "address":"tdx31qspeac40w2qky0gc4282wwtxdr92xcgh0u85xtys3j076kscf086lvcmp20m3"
         },
         "type":"PreparedValidatorOwner"
      },
      {
         "data":"0000000000000000000000000000000000000000000000000000000000000000",
         "type":"ValidatorSystemMetadata"
      }
   ],
   "state_identifier":{
      "state_version":45940824,
      "transaction_accumulator":"52bc2c4e41f80cd5f3774ab9948f86015f04eaf02a54f9c23f91605d1b2a7158"
   }
}

3. Update the Validator’s settings

Section 1, “Register the node as a validator” demonstrated a block of actions that can be used to register the node and set its parameters in the same REST transaction to build it alltogether. The same method can be used to update the parameters individually (or again, as a block of actions).

3.1. Change the validator’s name or URL

To change the validator’s name or URL, simply call the construction build method again with the new settings:

curl -s -u admin:{nginx-admin-password} -X POST -k 'https://localhost/construction/build' -H 'Content-Type: application/json' \
-d '{
   "network_identifier":{
      "network":"mainnet"
   },
   "fee_payer":{
      "address":"<node's wallet address>"
   },
   "operation_groups":[
      {
         "operations":[
            {
               "data":{
                  "action":"CREATE",
                  "data_object":{
                     "name":"My Validator",
                     "type":"ValidatorMetadata",
                     "url":"https://my-validator.com"
                  }
               },
               "entity_identifier":{
                  "address":"<node's validator address>"
               },
               "type":"Data"
            }
         ]
      }
   ]
}'
1 The above operation changes the name and/or URL. You change either or both settings in the same call.

Response would show unsiged_transaction. Follow the steps to sign the transaction and submit it

3.2. Change owner, validator fee and owner delegation flag

There are a number of calls that you can use to change the other settings on your validator node:

  • change owner address

  • change validator fee

  • change allow delegation flag

curl -s -u admin:{nginx-admin-password} -X POST -k 'https://localhost/construction/build' -H 'Content-Type: application/json' \
-d '{
   "network_identifier":{
      "network":"mainnet"
   },
   "fee_payer":{
      "address":"<node's wallet address>"
   },
   "operation_groups":[
      {
         "operations":[
            {
               "data":{
                  "action":"CREATE",
                  "data_object":{
                     "owner":{
                        "address":"<new owner address>"
                     },
                     "type":"PreparedValidatorOwner"
                  }
               },
               "entity_identifier":{
                  "address":"<node's validator address>"
               },
               "type":"Data"
            }
         ]
      },
      {
         "operations":[
            {
               "data":{
                  "action":"CREATE",
                  "data_object":{
                     "fee":1100, (1)
                     "type":"PreparedValidatorFee"
                  }
               },
               "entity_identifier":{
                  "address":"<node's validator address>"
               },
               "type":"Data"
            }
         ]
      }
   ]
}'
curl -s -u admin:{nginx-admin-password} -X POST -k 'https://localhost/construction/build' -H 'Content-Type: application/json' \
-d '{
   "network_identifier":{
      "network":"mainnet"
   },
   "fee_payer":{
      "address":"<node's wallet address>"
   },
   "operation_groups":[
      {
         "operations":[
            {
               "data":{
                  "action":"CREATE",
                  "data_object":{
                     "fee":1100,
                     "type":"PreparedValidatorFee"
                  }
               },
               "entity_identifier":{
                  "address":"<node's validator address>"
               },
               "type":"Data"
            }
         ]
      }
   ]
}'
curl -s -u admin:{nginx-admin-password} -X POST -k 'https://localhost/construction/build' -H 'Content-Type: application/json' \
-d '{
   "network_identifier":{
      "network":"mainnet"
   },
   "fee_payer":{
      "address":"<node's wallet address>"
   },
   "operation_groups":[
        {
         "operations":[
            {
               "data":{
                  "action":"CREATE",
                  "data_object":{
                     "allow_delegation":true,(1)
                     "type":"ValidatorAllowDelegation"
                  }
               },
               "entity_identifier":{
                  "address":"<node's validator address>"
               },
               "type":"Data"
            }
         ]
      }
   ]
}'

Remember, you can combine multiple actions in the same request, as shown in Section 1.3, “Call endpoint to register the node as a validator”

Response would show unsiged_transaction. Follow the steps to sign the transaction and submit it

4. Unregister the validator

You can unregister your validator node at any time, switching it back to a full node:

  • Current version

  • Versions before 1.1.0

curl -s -u admin:{nginx-admin-password} -X POST -k 'https://localhost/construction/build' -H 'Content-Type: application/json' \
-d '{
   "network_identifier":{
      "network":"mainnet"
   },
   "fee_payer":{
      "address":"<node's wallet address>"
   },
   "operation_groups":[
        {
         "operations":[
            {
               "data":{
                  "action":"CREATE",
                  "data_object":{
                     "registered":false,
                     "type":"PreparedValidatorRegistered"
                  }
               },
               "entity_identifier":{
                  "address":"<node's validator address>" (1)
               },
               "type":"Data"
            }
         ]
      }
   ]
}'
curl -s -u superadmin:nginx-password -X POST -k 'https://localhost/account' -H 'Content-Type: application/json' \
-d '{"jsonrpc": "2.0","method": "account.submit_transaction_single_step",
"params":
{"actions": [
{"type": "UnregisterValidator",     (1)
"validator": "rv1qthu8yn06k75dnwpkysyl8smtwn0v4xy29auzjlcrw7vgduxvnwnsnf8f0v"},
]}, "id": 1}'

Response would show unsiged_transaction. Follow the steps to sign the transaction and submit it