Using Docker

Install Requirements

All types of Bifrost Network nodes can be executed easily through Docker. Docker must be pre-installed in the environment you wish to run the node. Once installed, you can proceed with the following process.

First, create a local directory to store the chain data of the Bifrost Network. This directory stores all block information collected from the genesis block to the present and additional session keys of the corresponding validator node.

# Add sudo at the beginning if it doesn't work
mkdir -p /var/lib/bifrost-data

You must set the ownership and permissions for the directory you created. If you wish to set it to a specific user, you can run the command written in “case 1” and change DOCKER_USER to the actual user name to run Docker later. If you want to set it as the currently connected user, you can run the command written in "case 2".

# case 1. chown to a specific user
chown DOCKER_USER /var/lib/bifrost-data

# case 2. chown to current user
sudo chown -R $(id -u):$(id -g) /var/lib/bifrost-data

Run the Node Container

To run the validator node, you can simply run the following command. In this case, YOUR_NODE_NAME is a parameter indicating the name of the node to be executed and should be modified to the desired name.

docker run -d --network host -v "/var/lib/bifrost-data:/data" --name "YOUR_CONTAINER_NAME" thebifrost/bifrost-node:latest \
  --base-path /data \
  --chain /specs/bifrost-testnet.json \
  --port 30333 \
  --validator \
  --state-pruning archive \
  --trie-cache-size 0 \
  --runtime-cache-size 64 \
  --name "YOUR_NODE_NAME"

Check Logs

To check your running bifrost-node container logs, execute the command below.

docker logs -f <YOUR_CONTAINER_NAME>

If the Docker image is successfully pulled, and the validator node is executed, the chain information will be shown as the following.

2023-07-19 17:02:53 BIFROST Network
2023-07-19 17:02:53 ✌️  version 1.2.3-0d1811a5e80
2023-07-19 17:02:53 ❤️  by bifrost-platform, 2022-2023
2023-07-19 17:02:53 📋 Chain specification: BIFROST Development
2023-07-19 17:02:53 🏷  Node name: jolly-grandfather-7771
2023-07-19 17:02:53 👤 Role: AUTHORITY
2023-07-19 17:02:53 💾 Database: RocksDb at /var/folders/vg/xzyl_nmd77x5kcvbryssc5gm0000gn/T/substrateutNaBp/chains/dev/db/full
2023-07-19 17:02:53   Native runtime: thebifrost-dev-301 (bifrost-dev-1.tx1.au1)
2023-07-19 17:02:53 🔨 Initializing Genesis block/state (state: 0x7c59…74e5, header-hash: 0x469c…993b)
2023-07-19 17:02:53 🔨 Running Frontier DB migration from version 1 to version 2. Please wait.
2023-07-19 17:02:53 ✔️ Successful Frontier DB migration from version 1 to version 2 (0 entries).
2023-07-19 17:02:53 👴 Loading GRANDPA authority set from genesis on what appears to be first startup.
2023-07-19 17:02:54 Using default protocol ID "sup" because none is configured in the chain specs
2023-07-19 17:02:54 🏷  Local node identity is: 12D3KooWLvfoahrVYuwGjvNKyyWgkWSvBT9TofHvNGdiexgS3hRL
2023-07-19 17:02:54 💻 Operating system: macos
2023-07-19 17:02:54 💻 CPU architecture: aarch64
2023-07-19 17:02:54 📦 Highest known block at #0
2023-07-19 17:02:54 〽️ Prometheus exporter started at
2023-07-19 17:02:54 Running JSON-RPC HTTP server: addr=, allowed origins=["*"]
2023-07-19 17:02:54 Running JSON-RPC WS server: addr=, allowed origins=["*"]

Since chain data needs to be synced starting from the genesis block, the information that it is currently syncing will be shown as the following output. You can proceed to the next steps only when the sync is complete, and it may take up to several days at most.

To quickly synchronize your chain data, follow this link.

2023-07-19 17:06:20 ⚙️  Syncing, target=#8037656 (2 peers), best: #4371 (0xd39a…4f76), finalized #4200 (0x79ee…2eec), ⬇ 485.5kiB/s ⬆ 38.0kiB/s
2023-07-19 17:06:25 ⚙️  Syncing 745.8 bps, target=#8037658 (3 peers), best: #8100 (0xac9e…cba6), finalized #7800 (0xb93d…839f), ⬇ 334.1kiB/s ⬆ 24.0kiB/s
2023-07-19 17:06:30 ⚙️  Syncing 676.0 bps, target=#8037660 (3 peers), best: #11480 (0xbdbf…85f2), finalized #11400 (0x612b…7853), ⬇ 409.8kiB/s ⬆ 23.4kiB/s
2023-07-19 17:06:35 ⚙️  Syncing 596.8 bps, target=#8037661 (3 peers), best: #14465 (0xcce8…aadb), finalized #14400 (0x8f77…7e6b), ⬇ 356.1kiB/s ⬆ 24.5kiB/s
2023-07-19 17:06:40 ⚙️  Syncing 646.8 bps, target=#8037663 (3 peers), best: #17700 (0xf0a1…36d6), finalized #17408 (0x467b…63bf), ⬇ 372.7kiB/s ⬆ 9.2kiB/s
2023-07-19 17:06:45 ⚙️  Syncing 596.4 bps, target=#8037665 (3 peers), best: #20682 (0xcc4c…2ca9), finalized #20480 (0x1d99…7288), ⬇ 340.3kiB/s ⬆ 12.3kiB/s
2023-07-19 17:06:50 ⚙️  Syncing 560.2 bps, target=#8037666 (3 peers), best: #23485 (0x83ba…6fae), finalized #23400 (0xa031…a7e0), ⬇ 399.4kiB/s ⬆ 9.9kiB/s
2023-07-19 17:06:55 ⚙️  Syncing 575.0 bps, target=#8037668 (3 peers), best: #26362 (0xb11c…7fc4), finalized #26112 (0xbaa5…6c61), ⬇ 328.7kiB/s ⬆ 12.8kiB/s
2023-07-19 17:07:00 ⚙️  Syncing 579.4 bps, target=#8037670 (3 peers), best: #29259 (0xa287…cf05), finalized #29184 (0x7ac8…55cb), ⬇ 353.6kiB/s ⬆ 7.8kiB/s
2023-07-19 17:07:05 ⚙️  Syncing 595.4 bps, target=#8037671 (3 peers), best: #32237 (0xfc62…6b12), finalized #32100 (0x95cd…0c27), ⬇ 338.3kiB/s ⬆ 14.9kiB/s
2023-07-19 17:07:10 ⚙️  Syncing 590.2 bps, target=#8037673 (3 peers), best: #35191 (0x3b06…9e27), finalized #35100 (0xd461…5ab7), ⬇ 330.9kiB/s ⬆ 8.7kiB/s

When the chain data is completely synchronized, newly generated blocks will start to synchronize one by one at every block time as follows.

2023-07-19 08:08:09  Imported #5384451 (0xd7a8…011f)    
2023-07-19 08:08:10 💤 Idle (25 peers), best: #5384451 (0xd7a8…011f), finalized #5384449 (0x1ae1…fdf3), ⬇ 47.7kiB/s ⬆ 49.5kiB/s    
2023-07-19 08:08:12  Imported #5384452 (0x9bf4…9710)    
2023-07-19 08:08:15  Imported #5384453 (0x90af…653a)    
2023-07-19 08:08:15 💤 Idle (25 peers), best: #5384453 (0x90af…653a), finalized #5384450 (0x8026…f68a), ⬇ 37.3kiB/s ⬆ 36.9kiB/s    
2023-07-19 08:08:18  Imported #5384454 (0x5c80…9b84)    
2023-07-19 08:08:20 💤 Idle (25 peers), best: #5384454 (0x5c80…9b84), finalized #5384452 (0x9bf4…9710), ⬇ 38.0kiB/s ⬆ 46.4kiB/s    
2023-07-19 08:08:21  Imported #5384455 (0x91d0…de42)    
2023-07-19 08:08:24  Imported #5384456 (0xb7e0…832e)    
2023-07-19 08:08:25 💤 Idle (25 peers), best: #5384456 (0xb7e0…832e), finalized #5384454 (0x5c80…9b84), ⬇ 46.2kiB/s ⬆ 44.2kiB/s    
2023-07-19 08:08:27  Imported #5384457 (0xcc84…0e00)    
2023-07-19 08:08:30  Imported #5384458 (0xc499…2475)    
2023-07-19 08:08:30 💤 Idle (25 peers), best: #5384458 (0xc499…2475), finalized #5384455 (0x91d0…de42), ⬇ 28.5kiB/s ⬆ 44.0kiB/s    

Key Setup and Bonding

We now proceed with the key setting that is required to allow the validator node to perform the process of block generation and finalization. From this step, the chain data synchronization of the running node must be completed.

First, validator nodes essentially require two Ethereum-style accounts, the controller and stash accounts, and in the case of full nodes, an additional relayer account is required.

A stash account is an account that holds a certain amount of self-bond that must be deposited in the system so that the delegated account can act as a validator. The role of a stash account is to deposit self-bonds and delegate one account (controller) to perform validator activities publicly on its behalf.

The controller account is the delegated target from the stash account and is the prime account that acts as a validator. The role of the controller is an account that is dedicated to all activities such as session key registration, block generation, finalization, etc., and requires minimal assets to pay transaction fees.

If you need to create a new account, you can run the following commands.

# step 1. access your docker container
docker exec -it YOUR_CONTAINER_NAME /bin/bash

# step 2. move to the tools directory
cd tools

# step 3. install required packages
npm install

# step 4. generate validator accounts

# case 1. generate accounts for basic nodes
npm run create_accounts

# case 2. generate accounts for full nodes
npm run create_accounts -- --full

After executing the command, the available new validator accounts will be printed as follows. You must send enough BFC to each account that meets the requirements to proceed to the next process.

Next, the validator node must issue and register session keys to be used in the consensus algorithm. The process can be performed by executing the following command. Make sure that you are in the tools directory.

npm run set_session_keys -- \
  --controllerPrivate "YOUR_CONTROLLER_PRIVATE_KEY"
npm run set_session_keys -- \
  --controllerPrivate 0x5fb92d6e98884f76de468fa3f6278f8807c48bebc13595d45af5bdc4da702133

This command will generate three session keys for your node. Each key has their own purpose. Aura is for block creation, grandpa is for block finalization, and ImOnline is for node liveness. The generated keys will be stored in your chain data directory. The directory path will look like this: /var/lib/bifrost-data/chains/{testnet|mainnet}/keystore.

Finally, it is necessary to deposit the self-bonds of the validator node to form the initial voting power. The process can be performed by executing the following command.

# case 1. join as a basic node
npm run join_validator_candidates -- \
  --controllerPrivate "YOUR_CONTROLLER_PRIVATE_KEY" \
  --stashPrivate "YOUR_STASH_PRIVATE_KEY" \

# case 2. join as a full node
npm run join_validator_candidates -- \
  --controllerPrivate "YOUR_CONTROLLER_PRIVATE_KEY" \
  --stashPrivate "YOUR_STASH_PRIVATE_KEY" \
  --relayerPrivate "YOUR_RELAYER_PRIVATE_KEY" \
npm run join_validator_candidates -- \
  --controllerPrivate 0x5fb92d6e98884f76de468fa3f6278f8807c48bebc13595d45af5bdc4da702133 \
  --stashPrivate 0x234871e7f7520af0cfc9f8547057b283c628be93a90b393aa19be1279ee52b4a \
  --relayerPrivate 0xcc01ee486e8717dc3911ede9293b767e29ce66f5c987da45887cb61822700117 \
  --bond 1000

If you have successfully completed every process mentioned above, the amount of BFC deposited from the stash account will be deducted from the wallet, and your controller account will participate in the active validator update process in the next round. You can check whether or not you successfully joined the validator pool on the following page.

If the tier of the validator node to be operated is a full node, it must be operated together with the relayer. The manual for relayer setup can be found in the "Setting up a Relayer" section.

Update Node Client

As Bifrost Network development continues, it will sometimes be necessary to upgrade your node client. Node operators will be notified on our Discord channel or by personal contacts when upgrades are available and whether they are necessary (some client upgrades are optional).

Before upgrading your node client, please keep a backup file of your chain data to prevent any further data, keys, or credential losses.

# First of all stop bifrost-node

# Pull the latest bifrost-node image
docker pull thebifrost/bifrost-node:latest

# Change bifrost-node version on run command
# e.g.
docker run -d --network host -v "/var/lib/bifrost-data:/data" --name "YOUR_CONTAINER_NAME" thebifrost/bifrost-node:latest \
  --base-path /data \
  --chain /specs/bifrost-testnet.json \
  --port 30333 \
  --validator \
  --state-pruning archive \
  --trie-cache-size 0 \
  --runtime-cache-size 64 \
  --name "YOUR_NODE_NAME"

Last updated