Run a Mainnet Node

Fetch / Build Binaries

You have a couple options for fetching / building binaries. The source code lives at We recommend using Docker because a lot of the behind the scenes complexities are handled for you.


git clone
cd bitbadges-docker
docker build -t bitbadgeschaind .

By default, it builds all necessary binaries for all upgrades from genesis. Of you just want the latest binary, you can add the flags --build-arg BUILD_LATEST_ONLY=true to the build command.

docker build --build-arg BUILD_LATEST_ONLY=true -t bitbadgeschaind .


Download the executable directly. For the latest releases, check the releases page. Choose the correct executable for your machine and operating system.



If this is your first time downloading, you will need to also download the Wasm VM runtime library as well. This is the file and should be placed into /usr/lib. If not, you will get "error while loading shared libraries: cannot open shared object file: No such file or directory".


mv /usr/lib/

Build from Source

If building from source, we refer you to the README of the repository.

Handling Upgrades - Cosmovisor

BitBadges handles binary upgrades using Cosmovisor, a tool for automating software upgrades in Cosmos SDK-based blockchains with zero downtime enabling the chain to continue operating. You can find detailed information in the Cosmos documentation and the Cosmovisor documentation. We use Cosmos SDK v0.47.5, so please use a compatible Cosmovisor version. It is expected all validators are using Cosmovisor.

Upgrades will be announced in the Discord and are facilitated with the x/upgrades module behind the scenes. You, as the node operator, will have until the upgrade time to successfully handle the upgrade. If not completed by upgrade time, your node will halt at the upgrade height. If your node is a validator, it will be slashed.


Setting Up

No additional setup is required.

New Upgrades

If you are running with Docker, all you need to do is simply pull the latest build and restart. All binary upgrades are handled for you within the build.

# Stop executable
git pull # from the bitbadges-docker repo
docker build -t bitbadgeschaind .
# Restart executable with same command


Installing Cosmovisor

The first step is to download Cosmovisor as an executable using their documentation. Below is the Dockerized way we do it.

FROM --platform=linux golang:1.21 AS builder

RUN apt-get update && apt-get install -y git curl
RUN apt-get install -y make wget

RUN git clone --depth 1 --branch ${COSMOS_VERSION}

WORKDIR /root/cosmos-sdk/tools/cosmovisor

RUN make cosmovisor

Installing Cosmovisor

You will then need to set the following environment variables. The DAEMON_HOME will be the home of your config files.


Initializing Executables

Then, run the following to setup your Cosmovisor directory. The executable should be named bitbadgeschaind (if not, please rename).

cosmosvisor init ./bitbadgeschaind

This will create the necessary folders and copy the executable into the DAEMON_HOME/cosmovisor/genesis/bin.

IMPORTANT: Depending on your sync method (explained later), you will need to download all relevant executables. If you are syncing from genesis, you will need all executables to be able to sync to the current state. If you are syncing from a later time, you will only need the binaries used after that time. See Adding Upgrades below. You must repeat this process for all such executables.

Adding Upgrades

For a given upgrade, it will have a new binary and a <upgrade-name>. <upgrade-name> is the name used in the x/upgrade module when proposing a new software upgrade.

Depending on your version of cosmovisor, you may be able to run the following. Again, make sure the binary name is bitbadgeschaind.

cosmovisor add-upgrade ... 

Or, to manually upgrade, do the following.

  1. Download the new binary and name it bitbadgeschaind. Do this in a separate folder to not interfere with anything currently running.

  2. Create the DAEMON_HOME/cosmovisor/upgrades/<upgrade-name> and DAEMON_HOME/cosmovisor/upgrades/<upgrade-name>/bin directory.

  3. Copy the new upgrade executable to the folder (keeping its name as bitbadgeschaind).

# upgrade name = abc123
RUN mkdir ${DAEMON_HOME}/cosmovisor/upgrades/abc123/
RUN mkdir ${DAEMON_HOME}/cosmovisor/upgrades/abc123/bin
RUN cp /path_to_executable ${DAEMON_HOME}/cosmovisor/upgrades/abc123/bin/bitbadgeschaind


Depending on your setup method, you may have different commands to run the binary. Throughout the rest of this documentation, we use RUN_COMMAND to avoid repeating ourselves. Please replace your command wherever you see RUN_COMMAND


cosmovisor run ....


./bitbadgeschaind ....


# Replace DAEMON_HOME, <moniker>, and CHAIN_ID
docker run -it \
    -p 26656:26656 \
    -p 26657:26657 \
    -p 26660:26660 \
    -p 6060:6060 \
    -p 9090:9090 \
    -p 1317:1317 \
    --mount type=bind,source="$DAEMON_HOME",target=/root/.bitbadgeschain \
    --mount type=volume,dst=/root/.bitbadgeschain/cosmovisor \
    --mount type=volume,dst=/root/.bitbadgeschain/bip322-js \
    bitbadgeschaind run ...

Initialization / Syncing

In order to catch up to the current consensus, you will need to get your node synced. This can be done from genesis (time consuming but no trust needed) or from a recent snapshot of the state (faster but requires a trusted node).

From Snapshot / State Sync

If you do not want to reconstruct the entire history of the chain from genesis, you can start from a checkpoint. This can potentially save you days of syncing but requires you to trust an existing node.

State Sync

You can configure your config.toml to use the Cosmos SDK state sync to quickly sync from a trusted node. Feel free to use the official RPC node to do this. We refer you to here or you can reference other Cosmos SDK state sync documentation.


You can get the necessary files from an existing snapshot, add them to your DAEMON_HOME, and start the chain.

From Genesis

Syncing from genesis means that you start with the blank genesis state and verify all transactions from block 1 to the current block. Thus, this may take while. Also, note that the chain binary may be upgraded over time. To continue syncing, you will always need the relevant binary for the current block. This means you must handle ALL chain upgrades (since you are syncing from genesis).

To initialize a new chain, run the following (depending on your build method). CHAIN_ID will be "bitbadges_1-2" for betanet. Initialization should only be performed once.

RUN_COMMAND init <moniker> --chain-id CHAIN_ID

You'll need to replace <moniker> with a custom username for your node and the CHAIN_ID for the chain you want (bitbadges_1-2 for betanet).

Take note of where your configuration files live. We expect it to be in /root/.bitbadgeschain but if it isn't, you will need to make sure it is correct with --home flags. We call this DAEMON_HOME.

If you are getting directories do not exist error, you may have to do the following first. These will be overwritten when the init command is executed, but it is just to get the errors out of there.

mkdir config
mkdir data
mkdir wasm

Fetching the Correct Genesis JSON

The init command creates a default genesis, but you will need to replace it with the agreed upon version.

To do this for betanet, execute the following:

cd DAEMON_HOME/config
rm genesis.json
curl -o genesis.json


Inside the DAEMON_HOME/config folder, you'll find two files: config.toml and app.toml. Both files contain extensive comments to help you customize your node settings. You can also run RUN_COMMAND start --help for explanations.

Tweak these as desired. Some important ones are highlighted below.

Setting Seed Nodes

In order to pull data from other nodes, you need to have seed nodes or peers to pull from. You may use for our node ID for betanet. To establish connections with trusted nodes, edit config.toml. For instance:

seeds = ""

These entries follow the format nodeId@listenaddress:port. Additionally, you can set up seed nodes by specifying them in the seeds field. Or, private peers at private_peer_ids.

Listen Addresses / Firewalls

Ensure that the listen address settings are correct, using your IP address or domain name if configured. Also, make sure that your firewall exposes the necessary ports (22, 1317, 9090, 26656, 26657, 26660). See here for more information and other best practices running a node in production:


This is a temporary workaround to check Bitcoin signatures. Currently, there are no Go or Rust implementations of BIP-322 (the verification algorithm). As soon as there is, we will convert to a native implementation.

In the meantime, you will have to do the following.


This is handled for you.


Clone in your DAEMON_HOME directory. You should now have a bip322-js folder on the same level as cosmovisor, config, data, etc.

Navigate into the folder and run

npm i
npm run build

You should also make sure you have the node CLI command. The chain calls the following bash command to check signatures.

node DAEMON_HOME/dist/verify.js args...

Try a test run and make sure there are no errors. It should print true. Adjust for your home path.

node ./dist/verify.js '{\"account_number\":\"12\",\"chain_id\":\"bitbadges_1-2\",\"fee\":{\"amount\":[{\"amount\":\"0\",\"denom\":\"badge\"}],\"gas\":\"84362\"},\"memo\":\"\",\"msg0\":{\"type\":\"cosmos-sdk/MsgSend\",\"value\":{\"amount\":[{\"amount\":\"1\",\"denom\":\"badge\"}],\"from_address\":\"cosmos14t3uvy3qam7td3yufpp566wjp2q6nqtrf0qpyy\",\"to_address\":\"cosmos1uy4my3dwzwv9drgq06pt433z742l9vrlnx88ds\"}},\"sequence\":\"0\"}' 0247304402205a42d1b5973ce074818119ca7d61a1af2921f60a50aeff9eb7174aa1fb0686bd02205d2ae8896d3f67c9c74f14179bf49c697673dbdb2f851347a3cdc22cceaa13bc012102e600fba403d9a923446db973522e52e4ed5374f1bfe5448dfbab41f550b353f9 cosmos14t3uvy3qam7td3yufpp566wjp2q6nqtrf0qpyy

Running the Node

Once you have the node all configured, run the following to start the chain. You should see blocks being synced if configured correctly.

RUN_COMMAND run start

Other Considerations

Setting up your node infrastructure correctly and with best practices is crucial to ensure security. There are many options for this, so below we just give some general guidelines.

  • DDoS Mitigation: Being part of a network with a known IP address can expose you to DDoS attacks. Learn how to mitigate these risks here. Consider using sentry nodes and proxies.

  • Key Management: Implement best practices for key management, including key management systems such as TMKMS. This is especially important for validators.

  • Redundancy: Plan for infrastructure failures such as power outages to ensure the continuous operation of your validator. Consider setting up your software as a service to avoid relaunching it manually every time. Refer to the Cosmos documentation for guidance on configuring your node as a service.

  • Consider also running your node + Cosmovisor as a service, so it relaunches automatically. See and

Running a Validator

Setup - Validator Keys

Follow the instructions in the Cosmos documentation and/or the Cosmos Tutorials to set up your validator keys. Replace simd with bitbadgeschaind or myproject with bitbadgeschain.

A validator handles two perhaps three, different keys. Most likely keys 2 and 3 are the same. Each has a different purpose:

  1. The Tendermint consensus key is used to sign blocks on an ongoing basis. It is of the key type ed25519, which the KMS can keep. When Bech-encoded, the address is prefixed with cosmosvalcons and the public key is prefixed with cosmosvalconspub.

  2. The validator operator application key is used to create transactions that create or modify validator parameters. It is of type secp256k1, or whichever type the application supports. When Bech-encoded, the address is prefixed with cosmosvaloper.

  3. The delegator application key is used to handle the stake that gives the validator more weight. When Bech-encoded, the address is prefixed with cosmos and the public key is prefixed with cosmospub.

Consensus Key

The consensus key is HOT, meaning it is needed on the validator node to sign blocks. It is strongly recommended that this is set up with a signing service and key management system.

By default, when you ran the init command, it creates a key for you in ..../config/priv_validator_key.json.

This is convenient if you are starting a testnet, for which the security requirements are low. However, for a more valuable network, you should not store it directly in the node's filesystem. It should be stored in a more secure manner, such as with a signing service or key management system.

Operator / Delegator Key

The application / operator key should be COLD and NOT be stored on the validator node. This is just your standard public/private key pair used to sign transactions.

This can be generated (if you don't already have one) by running the following command.

bitbadgeschaind keys --keyring-backend file --keyring-dir /root/.bitbadgeschain/keys
add <name>

Adjust the command accordingly. Note you should run this and store it on your local desktop, not the validating node.

Joining the Validator Set

If you intend to run a validator node, execute the following command adjusted accordingly to join the set of validators (assuming you're not part of the initial genesis set). Run with --help for more details. Replace bitbadgeschaind tx with your run command (dependent on your build method). This is the same command as how you started the node (but replace start with tx).

RUN_COMMAND tx staking create-validator /path/to/validator.json \
  --chain-id="name_of_chain_id" \
  --gas="auto" \
  --gas-adjustment="1.2" \
  --gas-prices="0.025badge" \

This should be signed with your normal key pair for signing transactions. Ensure you have enough $BADGE tokens to cover gas and your stake. The validator.json file should contain relevant information about your validator, including the consensus public key, moniker, website, security contact, details, commission rates, and min-self-delegation.

You can obtain the public validator consensus public key using thebitbadgeschaind tendermint show-validator command.

Last updated