Adding a Validator Node to Existing Cosmos SDK Chain
A simple step by step tutorial. Great for those who have built a chain using ignite CLI and want to add additional validators to a (pre-)production level chain.
This tutorial assumes you are using Linux/Mac for Bash shell commands. You can do all of these commands on a $5 a month Linode Ubuntu(or the like) server. Just FYI.
For starters, there are some basic concepts here to understand. Note — this process is not to be confused with setting up initial validators for launching a chain — which is a completely different process! (For that I recommend launching with the ignite network cli commands for first-timers).
Embarrassingly, when I started doing this myself the biggest surprise to me was that you needed to sync the node before upgrading to a validator node, as I think this was assumed in the documentation but didn’t see it written anywhere.
Key concepts:
1) You will need the binary for your chain. I will assume you have your chains on github, that would allow someone to join as a node or validator node(Cosmos seems to default to 100 max validators in the active set).
2) You need to initialize the node with the chain id of the chain and moniker to name the chain. After initializing their will be a private_validator.json file created that contains the keys to your node(potential validator).
3) You need to Sync your node. This requires an extra step if you’re adding an another node to your (native) blockchain. The extra step needs to be performed on the current nodes so they can bootstrap additional nodes. More on that later. Once your node is synced, you can send it query requests.(you can view a list of available endpoints by setting the enable = true & swagger = true in your .app/config/app.toml file under [api] section. they can then be viewed when the chain is running at 0.0.0.0:1317
4) Validator creation requires a transaction to be sent to the chain. This will require creating an operator account, funding that account, then submitting the create-validator transaction.
Let’s get started.
I don’t like to tutorials that leave parts out, so I will show how to do it all, if you already have your node’s server ready, you can skip the following.
ssh into your server, if root no need for sudo, if not root add sudo.
sudo adduser user_name
sudo usermod -aG sudo user_namesudo visudo
#add this below %ADMIN or %SUDO to allow for no passwords
usesrname ALL=(ALL:ALL) NOPASSWD: ALLsudo rebootssh user_name@your.nodes.ip.address
sudo apt update
sudo apt install build-essential
sudo apt install gcc
sudo apt install wget
sudo apt install curl #You will need golang installed
#On Linux
sudo wget https://go.dev/dl/go1.19.linux-amd64.tar.gz
#unpack it
sudo tar -C /usr/local -xzf go1.19.linux-amd64.tar.gzcd
#into your home directory
sudo nano ~/.bashrcAdd these to your .bashrc file
export GOROOT=/usr/local/go
export PATH=$PATH:$GOROOT/bin
export PATH=$PATH:~/go/bin#Update your current shell to use these environment variables
source ~/.bashrc
go version
#should output golang 1.19Now lets install Ignite CLI. https://github.com/ignite/cli
sudo curl https://get.ignite.com/cli | sudo bash
sudo mv ignite /usr/local/bin/Now lets open the ports you will need and shut the ones you wont. https://docs.cosmos.network/main/run-node/run-production
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 26656/tcp
sudo ufw allow 26660/tcp
sudo ufw allow 26657/tcp
sudo ufw allow 9090/tcp
sudo ufw allow 1317/tcp
sudo ufw enableDownload your binary to your new node. I assume you know what Binary means, but incase you don’t. It is the name we use for the application specific blockchain (the CLI command library that you most likely created using the “ignite scaffold chain your_application_name” command). This proprietary software CLI program allows you to manipulate control and execute commands for your application/blockchain to function.
git clone https://github.com/your_user_name/(your_apps_name)app.git
cd app
ignite chain build
#please note I use the name app alot for simplicity,
#if your app was called app, then your apps binay would be called appd.
Make sure it is installed properly.
appd --helpThe first part of making a validator node, is creating the node itself. That can we done with one command
appd init mynodesname --chain-id appname-1Where “mynodesname” can be whatever you want it to be. Also, you can either input the chain-id here or can do in a separate command like so…
appd config chain-id appname-1Where “appname-1” is the name of your blockchain application and network(usually they are the same thing). I add the -1 because even when I named my application “gold” the network name was almost always automatically converted to “gold-1”. Be sure to check these match when relavant or transactions will fail.
Get Himitsu CTO’s stories in your inbox
Join Medium for free to get updates from this writer.
You may need to give your node a separate node address for your appd commands(such as queries) to work, otherwise it wont have access to the chain’s data to return. So I suggest doing this later if you can.
# we need to give it a node to send transactions to.
appd config node https://your.other.nodes.ipaddress:26657For your chain to sync, it will need a copy of the chains genesis.json file.
#copy the chains genesis file to your .app/config folder
curl your.other.nodes.ip_address:26657/genesis | jq '.result.genesis' > ~/.app/config/genesis.json#Next let’s open up our .app/config/config.toml files and make sure they are set correctly.
[p2p]
# Comma separated list of seed nodes to connect to
seeds = "19459a05a078cd30701cf776b061fbb23922226e@your.other.nodes1.ip_address:26656,a1ae712841b5b348bee3cb40bc00b21763ae3e5a@your.other.nodes2.ip_address:26656"
# Comma separated list of nodes to keep persistent connections to
persistent_peers = "19459a05a078cd30701cf776b061fbb23922226e@your.other.nodes1.ip_address:26656,a1ae712841b5b348bee3cb40bc00b21763ae3e5a@your.other.nodes2.ip_address:26656"
[statesync]
enable = true
rpc_servers = "your.other.node1.ip_address:26657,your.other.node2.ipaddress:26657"
trust_height = 90802(You need to find a height. Also those nodes need to have state sync turned on AFAIK)
trust_hash = "97F84FF7E27306686AA574DE50714A28CDD9332BFEA5F4D2775A5BA6B93B2371" (YOU NEED TO GET THIS HASH BY LOOKING IT UP FROM THE API SWAGGER)
trust_period = "168h0m0s"
#Now you can try to start your node to see if it will sync.
cd appfolder
appd start
$To check if your node is synced
your_username@localhost:~$ curl -s 127.0.0.1:26657/status | jq '.result.sync_info.catching_up'
which will respond false or true
#IF IT SAYS FALSE YOU HAVE BEEN SUCCESSFULNow lets make an account to control the validator with (This step can be skipped if only operating a node, not a validator node).
appd keys add myvalidatoryou will see the mnemonic below & the address for the account. This account needs to be funded in order to start the validator
You will see an output like below:
- address: appname1j3547ecvsg6v72ujlvn4awtlkcgd08q9fsqj9s. <======= YOUR VALIDATOR OPERATORS ADDRESS WILL BE HERE
name: myvalidator
pubkey: ‘{“@type”:”/cosmos.crypto.secp256k1.PubKey”,”key”:”A0eBl1/IV4GtahuR40TFdnczwW31gBU0C2+PcDX”}’
type: local
Write the Mnemonic down and keep it safe.
Now we need to send it funds from one of our other accounts. I am assuming you have access to the funds on the other nodes you would have created. You will need to have funds for the validator to work.
appd tx bank send (from whatever account you have the keys for that has funds - dont include the ()) the_address_for_the_account_you_created_above token_amount(no spaces)token_name
Now to create the validator.
appd tx staking create-validator \
--amount=989999993578himitsu \
--pubkey=$(appd tendermint show-validator) \
--moniker=myvalidator \
--chain-id=yourchainname-1 \
--commission-rate="0.10" \
--commission-max-rate="0.20" \
--commission-max-change-rate="0.01" \
--min-self-delegation=1 \
--from=myvalidator \
--gas=auto \
--gas-adjustment=1.5 \
--gas-prices="0.025token_name"
#If your node is not synced, you can send the transaction to another node with the flag below
--node "http://your.other.nodes.ip_address:26657"You should see something like the one below pop up.
gas estimate: 256845
auth_info:
fee:
amount:
- amount: "6422"
denom: token_name
gas_limit: "256845"
granter: ""
payer: ""
signer_infos: []
tip: null
body:
extension_options: []
memo: ""
messages:
- '@type': /cosmos.staking.v1beta1.MsgCreateValidator
commission:
max_change_rate: "0.010000000000000000"
max_rate: "0.200000000000000000"
rate: "0.100000000000000000"
delegator_address: app1j3547ecvsg6v72ujlvn4awtlkcgd08q9fsqj9s
description:
details: ""
identity: ""
moniker: myvalidator
security_contact: ""
website: ""
min_self_delegation: "1"
pubkey:
'@type': /cosmos.crypto.ed25519.PubKey
key: vpDtrh+lBzBRhahYhcTd1uq04GIqHezsgojZFmrIArI=
validator_address: appnamevaloper1j3547ecvsg6v72ujlvn4awtlkcgd08q9c9qr5m
value:
amount: "1000000000000"
denom: token_name
non_critical_extension_options: []
timeout_height: "0"
signatures: []
confirm transaction before signing and broadcasting [y/N]: yselect yes and hit enter.
It will return a transaction hash like this:
code: 0
codespace: ""
data: ""
events: []
gas_used: "0"
gas_wanted: "0"
height: "0"
info: ""
logs: []
raw_log: '[]'
timestamp: ""
tx: null
txhash: 3068ED7C9867D9DC926A200363704715AE9470EE73452324A32C2583E62B1D79Now you can check and see if your validator was accepted.
appd query tendermint-validator-setAlso, you can look up the transaction with the tx hash to see if it was accepted.
Message me here or on the CosmosSDK, Ignite or DM on Discord if issues or leave a comment below. Hope this was useful.









