Skip to content

Becoming a Validator

This guide will walk you through the process of setting up a Nimiq validator in the Albatross network.


This guide assumes the proof-of-stake network client (the node) has been compiled, or that you are running the node through other means, such as Docker. Check this guide for more information on compiling the code yourself.

This guide provides two methods for sending JSON-RPC commands to your node:

  1. arpl, an RPC client specific to Nimiq's PoS node
  2. curl, a general-purpose network request tool
Install ARPL

To install arpl, use npm or a compatible package manager:

npm install -g @sisou/albatross-remote
Install CURL

If the curl command is not already installed on your machine, try installing it through your software center or check out for installation instructions.

Configure and run your node

Generating your validator address and keys

For running a validator you need the following items wich we are generating now:

  • A validator address: Nimiq address
  • A voting keypair: BLS keypair
  • A signing keypair: Schnorr keypair
  • Optionally a fee keypair: Schnorr keypair

Note that we will use these in the following steps to configure your validator.


Keep your public and private keys accessible by writing them down or saving them on your computer. Make sure you save the private keys securely, there is no way to recover them!

We are generating these keys with utilities included in the nimiq/core-rs-albatross repository. Refer to Setup above for installation instructions.

To generate the Schnorr keypairs and the validator address, you can use:

cargo run --release --bin nimiq-address


Since we will need at least one Schnorr keypair and a Nimiq address, the command must be run 2 separate times and the output must be saved because it will be needed later in this guide.

Run the command a third time, if you want to set a specific fee keypair - otherwise it will be auto-generated when you start your node, which will still work for sending control transactions without a fee.

To generate a BLS keypair, you can use:

cargo run --release --bin nimiq-bls


The output must be saved because it will be needed later in this guide.


Run the node once. It will generate an example configuration file in the default config folder. On Linux, that's ~/.nimiq. You need to copy ~/.nimiq/client.toml.example to ~/.nimiq/client.toml. You can leave most configuration options as they are for now to start a basic full node.

To be able to control your node and to stake and validate, you need to enable the JSON-RPC server in your client.toml. Make sure the RPC section called [rpc-server] in the configuration file is enabled by uncommenting it.

Note that you can also configure your node to use history as the sync_mode. For that, you could change the consensus section of your config file to set sync_mode like in the following example:

sync_mode = "history"


History sync mode uses much more storage (disk) space and can take very long to sync. As such, we recommend opting for a full node setup to get started quicker.

The next step is to set up your validator address and keys in the [validator] section of your config file:

signing_key_file = "signing_key.dat"
voting_key_file = "voting_key.dat"
fee_key_file = "fee_key.dat"
signing_key = "Schnorr Private Key"
fee_key = "Schnorr Private Key"
voting_key = "BLS Private Key"
automatic_reactivate = true

Replace the validator address and keys generated accordingly:

  • The validator_address corresponds to the address output of a nimiq-address command. Paste your generated validator address here.
  • Ignore the three lines specifying file names. These files are automatically generated by the node and filled with the data from in the next settings.
  • The signing_key corresponds to the private key of a nimiq-address command. Paste your Schnorr secret key here.
  • The fee_key corresponds to the private key of a nimiq-address command. If you don't want to specify your own, comment that line out.
  • The voting_key in the config file corresponds to the secret key of the nimiq-bls command. Paste your BLS secret key here.
  • Leave automatic_reactivate as is.


As previously mentioned, if you are creating a new validator from scratch, and you need to generate all those keys, then you will need to use the nimiq-address command three times and the nimiq-bls command one time.

The fee_key is used to pay the fees for automatic reactivate transactions (if enabled). Since these fees default to 0 NIM, having the node auto-generate a fee key is safe.

TLS Certificate

It is strongly recommended to set up a TLS certificate for your node, because the browser-based Nimiq Wallet can only connect to it via secure connections. In order to maintain a healthy decentralization level within the network, it is advisable for the Nimiq Wallet to connect to as many diverse nodes as possible.

There are different services where a TLS certificate can be obtained, such as Let's Encrypt.

Once the certificate is obtained, it can be specified in the Network-TLS section within the config file:

private_key = "/path/to/private_key_file.pem"
certificates = "/path/to/full_certificates_file.pem"

Start your node and sync the blockchain

After you finish your configuration, run the client from inside the core-rs-albatross directory with cargo run —release —bin nimiq-client. It will connect to the seed node(s), then to other nodes in the network, and start syncing the blockchain. Next, we will query your node for its status.


When running your node through other means, such as a Docker container, refer to their respective documentation on how to start you node with your own config.

Check your status with JSON-RPC

If you enabled the JSON-RPC Server in your node’s configuration, you can query your node and send commands with arpl or curl, as installed in step 1.


To check the status of your client, first open an interactive session using the port set in your configuration. If you did not change it, the default port is 8648 and the host is localhost:

arpl repl -u ws://<host>:<port>/ws
# -u is short for --url

# With default settings:
arpl repl -u ws://locahost:8648/ws

# You can also use other ways of specifying the connection parameters:
arpl repl -h localhost -p 8648
# -h is short for --host, -p is short for --port

# The defaults of the node configuration are also the defaults for
# arpl, so just this would work, too:
arpl repl

Once in the session, check the status with this command:


It will reply with a list of performance indicators, such as the consensus state, the current block height and number of connected peers.


To check the status of your client with curl, send RPC requests to the port set in your configuration. If you did not change it, the default port is 8648 and the host is localhost:

With curl, you need to query the various properties of your node individually:

Query the consensus state:

curl 'http://localhost:8648' -H 'Content-Type: application/json' \
    --data-raw '{"method": "isConsensusEstablished", "params": [], "jsonrpc": "2.0", "id": 1}'

The result is the value.

Query the node's current block height:

curl 'http://localhost:8648' -H 'Content-Type: application/json' \
    --data-raw '{"method": "getBlockNumber", "params": [], "jsonrpc": "2.0", "id": 1}'

Query the number of connected peers:

curl 'http://localhost:8648' -H 'Content-Type: application/json' \
    --data-raw '{"method": "getPeerCount", "params": [], "jsonrpc": "2.0", "id": 1}'

Become a Validator

To become a validator, you need to register it in the staking contract by sending a create_validator transaction. For that you need to have an account with at least the validator deposit fee (100 000 NIM). This guide assumes that this amount is already present in the validator address. To check if that is the case, use this command:


In the arpl session:

account:get <your_validator_address>
curl 'http://localhost:8648' -H 'Content-Type: application/json' \
    --data-raw '{"method": "getAccountByAddress", "params": ["<your_validator_address>"], "jsonrpc": "2.0", "id": 1}'

Note that the balance returned is in Luna. Devide by 100'000 to get NIM.

Import your validator keypair

To sign and send transactions from your validator account, you need to import its keypair.

In the following commands, validator_private_key is the private key of the Schnorr keypair you generated for the validator address.

account:import <validator_private_key> --unlock

Accounts are generally imported locked. The addition of the --unlock parameter to the above command unlocked the account for us already. If you forgot to add --unlock to the command above, or for any other reason, you can unlock your account in your node like this:

account:unlock <address>

Import your validator private key:

curl 'http://localhost:8648' -H 'Content-Type: application/json' \
    --data-raw '{"method": "importRawKey", "params": ["<validator_private_key>", null], "jsonrpc": "2.0", "id": 1}'

Then unlock it:

curl 'http://localhost:8648' -H 'Content-Type: application/json' \
    --data-raw '{"method": "unlockAccount", "params": ["<address>", null, null], "jsonrpc": "2.0", "id": 1}'


In case you are wondering, the null as the second parameter is an optional password. You can set a password to lock the account when you import it, which you then need to provide during unlocking, too. The other null as the third parameter for unlocking is an unused duration parameter, that nontheless needs to be provided.

Send a validator-creation transaction

Finally, to register your validator, run this with all the keys generated in the beginning:

validator:new <validator_address> <signing_private_key> <voting_private_key>

Where signing_private_key is the private key of the Schnorr keypair generated for signing_key, and voting_private_key is the private key of the BLS keypair generated for voting_key.


The manual way with curl requires a few more parameters:

  1. The address of the account you are sending from
  2. The address of the validator you are creating
  3. The private signing Schnorr key you generated
  4. The private voting BLS key you generated
  5. The reward payout address (can be the same as the validator address)
  6. Signalling data (usually empty)
  7. The fee for the transaction (can be zero)
  8. The validity start height of the transaction (+0 means the node takes the current block height)
curl 'http://localhost:8648' -H 'Content-Type: application/json' \
    --data-raw '{"method": "sendNewValidatorTransaction", "params": ["<validator_address>", "<validator_address>", "<signing_private_key>", "<voting_secret_key>", "<reward_address>", "", 0, "+0"], "jsonrpc": "2.0", "id": 1}'


Your node must have established consensus and be up-to-date with the blockchain for the transaction to send successfully. Remember, you can check your node's status with the status command.


When sending the create transaction, the validator deposit will be deducted from the wallet linked to the validator address.


Validators are only selected to produce blocks at the start of every epoch (every election block), so it may take some time for your validator to be elected to produce blocks.

Query your validator state

You can now query the staking contract for your validator registration:

validator:get <validator_address>
curl 'http://localhost:8648' -H 'Content-Type: application/json' \
    --data-raw '{"method": "getValidatorByAddress", "params": ["<validator_address>"], "jsonrpc": "2.0", "id": 1}'

It will tell your the public keys of your registered signing and voting keys, as well as which reward address is set to receive block rewards. It'll also tell you your validator's staking balance (which should be the same as the deposit for now), how many stakers are staking with your validator (none yet) and if the validator is inactive or retired (it should not be).


If the command responds with an error, your validator creation transaction was likely not successfull. You can ask for support in our Telegram channels, in our Github, or in the community forum.

Add stake to your validator

A validator itself can only maintain the validator deposit as stake. To stake more than that, you need to add stake to your validator as a staker.


You can stake your NIM on behalf of any registered validator. Your staked NIM then count towards that validator's stake, increasing their (randomly) assigned number of block production slots and thus rewards. Importantly, all staking rewards are received by the validator's reward address, not the stakers. The arrangement of distributing rewards among a validator's stakers is made off-chain and is usually handled by a pool operator or the people who are operating the validator themselves.

Stake from the Nimiq Wallet

You can stake with your validator from the Nimiq Wallet. Go to the staking menu in your NIM address and search for and select your validator's address from the list of validators. Then assign as much NIM to it as you like.

Stake from your node with JSON-RPC

You can also send the staking transactions from your node with JSON-RPC. For that, you need to import and unlock the account that holds the NIM you want to stake. Then run the following command to start staking:

stake:start <staker_address> <validator_address> <amount_NIM>

The manual way with curl requires a few more parameters:

  1. The address of the account you are sending from
  2. The address of the staker you are creating
  3. The address of the validator you are delegating to
  4. the amount (in Luna) you want to stake
  5. The fee for the transaction (can be zero)
  6. The validity start height of the transaction (+0 means the node takes the current block height)
curl 'http://localhost:8648' -H 'Content-Type: application/json' \
    --data-raw '{"method": "sendNewStakerTransaction", "params": ["<staker_address>", "<staker_address>", "<validator_address>", <amount_luna>, 0, "+0"], "jsonrpc": "2.0", "id": 1}'