Add a Validator

Introduction

The Primary Network is inherent to the Avalanche platform and validates Avalanche’s built-in blockchains. In this tutorial, we’ll add a node to the Primary Network and a subnet on Avalanche.

The P-Chain manages metadata on Avalanche. This includes tracking which nodes are in which subnets, which blockchains exist, and which subnets are validating which blockchains. To add a validator, we’ll issue transactions to the P-Chain.

Note that once you issue the transaction to add a node as a validator, there is no way to change the parameters. You can’t remove your stake early or change the stake amount, node ID, or reward address. Please make sure you’re using the correct values in the API calls below. If you’re not sure, browse the Developer FAQ's or ask for help on Discord.

Requirements

You've completed Getting Started and are familiar with the Avalanche's architecture. In this tutorial, we use Avalanche’s Postman collection to help us make API calls.

In order to ensure your node is well-connected, make sure that your node can receive and send TCP traffic on the staking port (9651 by default) and that you started your node with command line argument --public-ip=[YOUR NODE'S PUBLIC IP HERE]. Failing to do either of these may jeopardize your staking reward.

Add a validator with Avalanche Wallet

First, we show you how to add your node as a validator by using Avalanche Wallet.

Get your node’s ID by calling info.getNodeID:

curl -X POST --data '{
"jsonrpc":"2.0",
"id" :1,
"method" :"info.getNodeID"
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/info

The response has your node’s ID:

{
"jsonrpc": "2.0",
"result": {
"nodeID": "NodeID-5mb46qkSBj81k9g9e4VFjGGSbaaSLFRzD"
},
"id": 1
}

Open the wallet, and go the Earn tab. Choose Add Validator.

Fill out the staking parameters. They are explained in more detail below. When you’ve filled in all the staking parameters and double-checked them, click Confirm. Make sure the staking period is at least 2 weeks, the delegation fee rate is at least 2%, and you’re staking at least 2,000 AVAX.

You should see this success message, and your balance should be updated.

Calling platform.getPendingValidators verifies that our transaction was accepted.

Go back to the Earn tab, and click Estimated Rewards.

Once your validator’s start time has passed, you will see the rewards it may earn, as well as its start time, end time, and the percentage of its validation period that has passed.

That’s it!

Add a validator with API calls

We can also add a node to the validator set by making API calls to our node. To add a node the Primary Network, we’ll call platform.addValidator.

This method’s signature is:

platform.addValidator(
{
nodeID: string,
startTime: int,
endTime: int,
stakeAmount: int,
rewardAddress: string,
changeAddr: string, (optional)
delegationFeeRate: float,
username: string,
password: string
}
) -> {txID: string}

Let’s go through and examine these arguments.

nodeID

This is the node ID of the validator being added. To get your node’s ID, call info.getNodeID:

curl -X POST --data '{
"jsonrpc": "2.0",
"method": "info.getNodeID",
"params":{},
"id": 1
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/info

The response has your node’s ID:

{
"jsonrpc": "2.0",
"result": {
"nodeID": "NodeID-LMUue2dBBRWdDbPL4Yx47Ps31noeewJji"
},
"id": 1
}

startTime and endTime

When one issues a transaction to join the Primary Network they specify the time they will enter (start validating) and leave (stop validating.) The minimum duration that one can validate the Primary Network is 24 hours, and the maximum duration is one year. One can re-enter the Primary Network after leaving, it’s just that the maximum continuous duration is one year. startTime and endTime are the Unix times when your validator will start and stop validating the Primary Network, respectively. startTime must be in the future relative to the time the transaction is issued.

stakeAmount

In order to validate the Primary Network, one must stake AVAX. This parameter defines the amount of AVAX staked.

rewardAddress

When a validator stops validating the Primary Network, they will receive a reward if they are sufficiently responsive and correct while they validated the Primary Network. These tokens are sent to rewardAddress. The original stake will be sent back to an address controlled by username.

A validator’s stake is never slashed, regardless of their behavior; they will always receive their stake back when they’re done validating.

changeAddr

Any change resulting from this transaction will be sent to this address. You can leave this field empty; if you do, change will be sent to one of the addresses your user controls.

delegationFeeRate

Avalanche allows for delegation of stake. This parameter is the percent fee this validator charges when others delegate stake to them. For example, if delegationFeeRate is 1.2345 and someone delegates to this validator, then when the delegation period is over, 1.2345% of the reward goes to the validator and the rest goes to the delegator.

username and password

These parameters are the username and password of the user that pays the transaction fee, provides the staked AVAX, and to whom the staked AVAX will be returned.

Now let’s issue the transaction. We use the shell command date to compute the Unix time 10 minutes and 30 days in the future to use as the values of startTime and endTime, respectively. (Note: If you’re on a Mac, replace $(date with $(gdate. If you don’t have gdate installed, do brew install coreutils.) In this example we stake 2,000 AVAX (2 x 1012 nAVAX).

curl -X POST --data '{
"jsonrpc": "2.0",
"method": "platform.addValidator",
"params": {
"nodeID":"NodeID-LMUue2dBBRWdDbPL4Yx47Ps31noeewJji",
"startTime":'$(date --date="10 minutes" +%s)',
"endTime":'$(date --date="30 days" +%s)',
"stakeAmount":2000000000000,
"rewardAddress":"P-avax1d4wfwrfgu4dkkyq7dlhx0lt69y2hjkjeejnhca",
"changeAddr": "P-avax103y30cxeulkjfe3kwfnpt432ylmnxux8r73r8u",
"delegationFeeRate":10,
"username":"USERNAME",
"password":"PASSWORD"
},
"id": 1
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/P

The response has the transaction ID, as well as the address the change went to.

{
"jsonrpc": "2.0",
"result": {
"txID": "6pb3mthunogehapzqmubmx6n38ii3lzytvdrxumovwkqftzls",
"changeAddr": "P-avax103y30cxeulkjfe3kwfnpt432ylmnxux8r73r8u"
},
"id": 1
}

We can check the transaction’s status by calling platform.getTxStatus:

curl -X POST --data '{
"jsonrpc": "2.0",
"method": "platform.getTxStatus",
"params": {
"txID":"6pb3mthunogehapzqmubmx6n38ii3lzytvdrxumovwkqftzls"
},
"id": 1
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/P

The status should be Committed, meaning the transaction was successful. We can call platform.getPendingValidators and see that the node is now in the pending validator set for the Primary Network:

curl -X POST --data '{
"jsonrpc": "2.0",
"method": "platform.getPendingValidators",
"params": {},
"id": 1
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/P

The response should include the node we just added:

{
"jsonrpc": "2.0",
"result": {
"validators": [
{
"nodeID": "NodeID-LMUue2dBBRWdDbPL4Yx47Ps31noeewJji",
"startTime": "1584021450",
"endtime": "1584121156",
"stakeAmount": "2000000000000",
}
]
},
"id": 1
}

When the time reaches 1584021450, this node will start validating the Primary Network. When it reaches 1584121156, this node will stop validating the Primary Network. The staked AVAX will be returned to an address controlled by username, and the rewards, if any, will be given to rewardAddress.

Adding a Subnet Validator

Issuing a Subnet Validator Transaction

Now let’s add the same node to a subnet. The following will make more sense if you’ve already done this tutorial on creating a Subnet. Right now you can only add validators to subnets with API calls, not with Avalanche Wallet.

Suppose that the Subnet has ID nTd2Q2nTLp8M9qv2VKHMdvYhtNWX7aTPa4SMEK7x7yJHbcWvr, threshold 2, and that username holds at least 2 control keys.

To add the validator, we’ll call API method platform.addSubnetValidator. Its signature is:

platform.addSubnetValidator(
{
nodeID: string,
subnetID: string,
startTime: int,
endTime: int,
weight: int,
changeAddr: string, (optional)
username: string,
password: string
}
) -> {txID: string}

Let’s examine the parameters:

nodeID

This is the node ID of the validator being added to the subnet. This validator must validate the Primary Network for the entire duration that it validates this Subnet.

subnetID

This is the ID of the subnet we’re adding a validator to.

startTime and endTime

Similar to above, these are the Unix times that the validator will start and stop validating the subnet. startTime must be at or after the time that the validator starts validating the Primary Network, and endTime must be at or before the time that the validator stops validating the Primary Network.

weight

This is the validator’s sampling weight for consensus. If the validator’s weight is 1 and the cumulative weight of all validators in the subnet is 100, then this validator will be included in about 1 in every 100 samples during consensus.

changeAddr

Any change resulting from this transaction will be sent to this address. You can leave this field empty; if you do, change will be sent to one of the addresses your user controls.

username and password

These parameters are the username and password of the user that pays the transaction fee. This user must hold a sufficient number of this Subnet’s control keys in order to add a validator to this Subnet.

We use the shell command date to compute the Unix time 10 minutes and 30 days in the future to use as the values of startTime and endTime, respectively. (Note: If you’re on a Mac, replace $(date with $(gdate. If you don’t have gdate installed, do brew install coreutils.)

curl -X POST --data '{
"jsonrpc": "2.0",
"method": "platform.addSubnetValidator",
"params": {
"nodeID":"NodeID-LMUue2dBBRWdDbPL4Yx47Ps31noeewJji",
"subnetID":"nTd2Q2nTLp8M9qv2VKHMdvYhtNWX7aTPa4SMEK7x7yJHbcWvr",
"startTime":'$(date --date="10 minutes" +%s)',
"endTime":'$(date --date="30 days" +%s)',
"weight":1,
"changeAddr": "P-avax103y30cxeulkjfe3kwfnpt432ylmnxux8r73r8u",
"username":"USERNAME",
"password":"PASSWORD"
},
"id": 1
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/P

The response has the transaction ID, as well as the address the change went to.

{
"jsonrpc": "2.0",
"result": {
"txID": "2exafyvRNSE5ehwjhafBVt6CTntot7DFjsZNcZ54GSxBbVLcCm",
"changeAddr": "P-avax103y30cxeulkjfe3kwfnpt432ylmnxux8r73r8u"
},
"id": 1
}

We can check the transaction’s status by calling platform.getTxStatus:

curl -X POST --data '{
"jsonrpc": "2.0",
"method": "platform.getTxStatus",
"params": {
"txID":"2exafyvRNSE5ehwjhafBVt6CTntot7DFjsZNcZ54GSxBbVLcCm"
},
"id": 1
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/P

The status should be Committed, meaning the transaction was successful. We can call platform.getPendingValidators and see that the node is now in the pending validator set for the Primary Network. This time, we specify the subnet ID:

curl -X POST --data '{
"jsonrpc": "2.0",
"method": "platform.getPendingValidators",
"params": {"subnetID":"nTd2Q2nTLp8M9qv2VKHMdvYhtNWX7aTPa4SMEK7x7yJHbcWvr"},
"id": 1
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/P

The response should include the node we just added:

{
"jsonrpc": "2.0",
"result": {
"validators": [
{
"nodeID": "NodeID-LMUue2dBBRWdDbPL4Yx47Ps31noeewJji",
"startTime":1584042912,
"endTime":1584121156,
"weight": "1"
}
]
},
"id": 1
}

When the time reaches 1584042912, this node will start validating this Subnet. When it reaches 1584121156, this node will stop validating this Subnet.

Whitelisting the Subnet

Now that the node has been added as a validator of the subnet, let’s add it to the whitelist of subnets. The whitelist prevents the node from validating a subnet unintentionally.

To whitelist the subnet, restart the node and add the parameter --whitelisted-subnets with a comma separated list of subnets to whitelist.

The full command is:

./build/avalanchego --whitelisted-subnets=nTd2Q2nTLp8M9qv2VKHMdvYhtNWX7aTPa4SMEK7x7yJHbcWvr