Set up BitShares Private Testnet

This chapter provides for instructions for preparing BitShares Private Testnet.

Table of Contents

In this chapter, we define our base directory $HOME/ and create two directories inside of $HOME directory.


uses for downloading BitShares Core files and build the programs


uses for your BitShares Private Testnet Project


For the private testnet, you MUST create and set up own genesis file and also, set parameters’ values into a database configuration file (config.ini). You should not connect to the mainnet nor the public testnet.

Downloading BitShares Core (testnet branch) and Build

This section includes instructions for the following:

  • Downloading BitShares Core

  • Building two application program files (witness_node and cli_wallet)

1.Downloading BitShares Core – Testnet branch – source files

  1. Open a command window and move to $HOME directory

  2. Run the following commands to connect Github BitShares Care repository, create a directory bitshares-testnet for the source code. Move the directory to the bitshares-testnet folder, and checkout a testnet branch.

git clone bitshares-testnet
cd bitshares-testnet/
git checkout testnet
git submodule update --init --recursive
  1. Review the source files/folders in the $HOME/bitshares-testnet directory.

2. Building two application program files (witness_node and cli_wallet)

  1. Make sure $HOME/bitshares-testnet directory is your current directory

  2. Perform the initial compilation to build two program files

  3. Run the following commands

cmake .
  1. Make sure if the application files were created successfully

  • File locations

cli_wallet program


witness_node program


Preparing a genesis file for the Private Testnet

This section provides instructions for preparing the genesis file for the Private Testnet. The genesis file is the initial state of the network. For the private testnet preparation, you must set up (generate) each key value in the genesis file.

  • Creating my-genesis.json file

  • Customizing my-genesis.json

  • Embedding my-genesis.json after completed customization of a genesis file (Optional)

Customizing a genesis file allows to control the followings:
  • The accounts that exist at genesis, their names and public keys

  • Assets and their initial distribution (including core asset)

  • The initial values of chain parameters

  • The account / signing keys of the init witnesses (or in fact any account at all).

  • For a Private Testnet setup, a genesis-dev.json file can be used as a template. However, you must replace each key value for the private testnet. Each key starts with “TEST” prefix.

  • The core token symbol in testnet is “TEST” (hardcoded in binaries, cannot be changed in genesis file).

1.Creating my-genesis.json file

  1. Create genesis directory

  • Make sure your current directory is $HOME/bitshares-testnet

  • Create a genesis directory

# For example:
mkdir genesis
  1. Create my-genesis.json file as a blank file

  • Move to the genesis directory (i.e., $HOME/bitshares-testnet/genesis/)

  • Create a file and name “my-genesis.json”

  1. Copy a template genesis-dev.json file. If you have created my-genesis.json file already, skip this step.

  • Use the genesis-dev.json file as a guide to prepare genesis file parameter values.

  • Each Private Testnet should prepare own my-genesis.json file to run.

  • The genesis-dev.json locates $HOME/bitshares-testnet/libraries/egenesis/genesis-dev.json. Copy this file to the genesis directory (It was created in step A).

# For example:

cp -p $HOME/bitshares-testnet/libraries/egenesis/genesis-dev.json  $HOME/bitshares-testnet/genesis/my-genesis.json


Do NOT use (or copy) a genesis.json file from the Mainnet repository.

2.Customizing my-genesis.json

  1. View my-genesis.jon and familiar with parameters.

  1. Generate private and public key pairs by get_dev_key function. The get_dev_key function can be used by using ../programs/genesis_util/.

    Note: This get_dev_key function is simply combine the prefix with all given suffixes, compute a hash over each combination, and use that hash as a private key, from which the matching public key and address are generated.

  • Move to the $HOME/bitshares-testnet/programs directory

  • Run the command

# For example:
./genesis_util/get_dev_key wxyz- testkey1 testkey2 testkey3

See, How to Generate Key Pairs for more information

3.Embedding my-genesis.json file (Optional)

IMPORTANT: Before you embed my-genesis.json, ensure the genesis file setting has been completed, otherwise skip this section.


Embedding the genesis copies the entire content of genesis.json into the witness_node binary, and additionally copies the chain ID into the cli_wallet binary. Embedded genesis allows the following simplifications to the subsequent instructions:

  • You do not need to specify the my-genesis.json file on the witness node command line, or in the witness node configuration file.

  • You do not need to specify the chain ID on the cli_wallet command line when starting a new wallet.

  1. Make sure a current directory is $HOME/bitshares-testnet/

  2. Run the following command. Use the full path to the my-genesis.json

# For example:
    cmake -DGRAPHENE_EGENESIS_JSON="$HOME/bitshares-testnet/genesis/my-genesis.json"
  1. Rebuild the programs


Note: Embedded genesis is a feature designed to make life easier for consumers of pre- compiled Binaries, in exchange for slight, optional complication of the process for producing binaries.

INFORMATION: If getting trouble to embed a genesis file. Clean the build and Make cache variables for GRAPHENE_EGENESIS_JSON to take effect.

# For example:
make clean
find . -name "CMakeCache.txt" | xargs rm -f
find . -name "CMakeFiles" | xargs rm -Rf
cmake -DGRAPHENE_EGENESIS_JSON="$(pwd)/genesis/my-genesis.json" .

Warning: Deleting caches will reset all cmake variables, so if you have used instructions like build-ubuntu which tells you to set other cmake variables, you will have to add those variables to the cmake line above.

Creating Another Directory for the BitShares Private Testnet Project

This section includes instructions for the following:

  • Creating another directory for BitShares Private Testnet Project

  • Copying two application files into the BitShares Private Testnet Project directory

  • Creating a genesis directory for this Private Testnet

  • Copying a genesis file that completed in the previous section

1.Creating another directory for BitShares Private Testnet Project

  1. Make sure, your current directory is $HOME

  2. Create a directory name “Testnet-Home”

# For example:
mkdir Testnet-Home

2.Copying the two program files (witness_node and cli_wallet) in the Testnet-Home directory

  1. Use the below as examples

cp -p $HOME/bitshares-testnet/programs/cli_wallet/cli_wallet $HOME/Testnet-Home/cli_wallet

cp -p $HOME/bitshares-testnet/programs/witness_node/witness_node $HOME/Testnet-Home/witness_node
  1. Ensure the two program files are in $HOME/Testnet-Home/ directory

3.Creating a genesis directory for the Private testnet

If your genesis file has been embedded, you do not need to move the genesis file. Skip to the next section (Setting up a Blockchain Data Directory).

  1. Make sure, your current directory is $HOME/Testnet-Home/

  2. Create a directory and name “genesis”

# For example:
mkdir genesis

4.Copying a prepared genesis file

  1. Use the below as an example

cp -p $HOME/bitshares-testnet/genesis/my-genesis.json $HOME/Testnet-Home/genesis/my-genesis.json
  1. Ensure the my-genesis.json is in $HOME/Testnet-Home/genesis/ directory

Setting up a Blockchain Data Directory

This section provides instructions for preparing a blockchain data directory and obtaining a configuration file. The configuration file will be created (if it’s not existed) during witness_node start up and found in the data directory to setup the project environment parameters.

  • Creating a Data directory for the Private Testnet Project

  • Obtaining a configuration file (config.ini)

  • Viewing the data directory

  • Viewing the configuration file parameters

  • Setting up the configuration parameters


  • witness_node startup will create a witness_node_data_dir as a default data directory. A configuration file will be created in the data directory. To obtain the config.ini file, start the witness_node and stop (CTRL + C). And setup the configuration file values.

  • The data directory can be created to a different location and name by using --data-dir option in a witness_node startup command line.

  • If do not want to use the default data directory witness_node_data_dir, use the --data-dir option to point the data directory path, every time witness_node start running again.

1.Creating a Data directory for the Private Testnet Project

  1. Make sure, a current directory is $HOME/Testnet-Home/

  2. Create a data directory for the Private Testnet blockchain

# For example:
mkdir data-bts

2.Obtaining a configuration file (config.ini)

  1. Make sure, your current directory is $HOME/Testnet-Home/

  2. Run one of the following command lines:

./witness_node --data-dir data-bts/my-blocktestnet --genesis-json genesis/my-genesis.json --seed-nodes "[]"

 // OR

./witness_node --data-dir=data-bts/my-blocktestnet --genesis-json=genesis/my-genesis.json --seed-nodes="[]"
  • --data-dir : defines the data directory and a blockchain folder

  • --genesis-json : defines the genesis file directory and my-genesis.json file for this Private Testnet

  • --seed-nodes : with “[]” (*double quotes are required). This creates a list of empty seed nodes to avoid connecting to default hardcoded seeds.

Known issue: Missing = (equal sign) between input parameter and value. –> This is due to a bug of a boost 1.60. If you compile with boost 1.58, the = (equal sign) can be omitted.


If my-genesis.json file has been embedded, you do not need to specify the path ro the genesis file. Omit, --genesis-json genesis/my-genesis.json

  1. Stop the witness_node. Use CTRL + C.

  2. Review the screen output. You will find a Chain ID like the below (your Chain ID should be different).

# For example:
3501235ms th_a main.cpp:165 main] Started witness node on a chain with 0 blocks.
3501235ms th_a main.cpp:166 main] Chain ID is cf307110d029cb882d126bf0488dc4864772f68d9888d86b458d16e6c36aa74b

3.Viewing the data directory

  1. Move to the data directory

# For example:
cd data-bts/my-blocktestnet
  1. Review the output and ensure the blockchain data folder has been created successfully

# For example:

4.Viewing the configuration file parameters

  1. Open the configuration file (config.ini) with your editor.

5.Setting up the configuration file parameters

  1. Uncomment parameters if necessary and set each value

  • Example:

# Endpoint for P2P node to listen on
p2p-endpoint =

# Endpoint for websocket RPC to listen on
rpc-endpoint =

###--> For Private Testnet, add a seed node of your own
# P2P nodes to connect to on startup (may specify multiple times)
# seed_node =

###--> For Private Testnet, this value set needs to overwrite default checkpoint.
checkpoint = []
# Pairs of [BLOCK_NUM,BLOCK_ID] that should be enforced as checkpoints.
## checkpoint = ["22668518", "0159e4e600cb149e22ef960442ca331159914617"]

# File to read Genesis State from
genesis-json = genesis/my-genesis.json

# ==============================================================================
# witness plugin options
# ==============================================================================

# Enable block production, even if the chain is stale.
enable-stale-production = false

# Percent of witnesses (0-100) that must be participating in order to produce blocks
# required-participation = 33
# If start a private testnet with the default number 33, the node won't produce blocks
####--> For Private testnet, set 0
required-participation = 0

###--> For Private Testnet, set own key pairs
# Tuple of [PublicKey, WIF private key] (may specify multiple times)
private-key = ["-- generated key --","5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3"]

# ID of witness controlled by this node (e.g. "1.6.5", quotes are required, may specify multiple times)
# witness-id =
witness-id = "1.6.1"
witness-id = "1.6.2"
witness-id = "1.6.3"
witness-id = "1.6.4"
witness-id = "1.6.5"
witness-id = "1.6.6"
witness-id = "1.6.7"


  • [private-key] options must match the witness block_signing_key in the genesis file.

  • [witness-id] numbers refer to the initial witnesses from the genesis file, starting with “1.6.1” for the first witness.

  • The witness-id is not given explicitly in the genesis file. The IDs are assigned sequentially starting from 1, i. e. the first listed witness will have “1.6.1”, the second “1.6.2” and so on.

  • The tuples for “private-key” must contain the public block signing key and the corresponding private key of a witness. The node will start generating blocks only if it has one or more “witness-id” options and the corresponding private-keys of these witnesses.

This authorizes the witness_node to produce blocks on behalf of the listed witness-id’s, and specifies the private key needed to sign those blocks. Normally each witness would be on a different node, but for the purposes of this testnet, we will start out with all witnesses signing blocks on a single node.


It’s important to activate a 2/3 majority of the witnesses defined in the genesis file.

Starting a witness_node

This section provides instructions for starting a witness_node to produce blocks

  • Starting witness_node with parameter options

1.Starting witness_node with parameter options

  1. Make sure, a current directory is $HOME/Testnet-Home/

  2. Start witness_node with parameter options

# For example:

./witness_node --data-dir=data-bts/my-blocktestnet --enable-stale-production --seed-nodes "[]"
  • Note

    • If you have set a my-genesis.json file path in a configuration file (config.ini) or embedded the genesis file, do not need to use the --genesis-json option in this witness_node start up.

    • The --enable-stale-production flag tells the witness_node to produce on a chain with zero blocks or very old blocks. We specify the --enable-stale-production parameter on the command line as we will not normally need it (although it can also be specified in the configuration file).

    • The empty --seed-nodes is added to avoid connecting to the default seed nodes hardcoded for production. (i.e., # seed-node = )

    • Subsequent runs which connect to an existing witness node over the p2p network, or which get blockchain state from an existing data directory, do not need to have the --enable-stale-production flag.

Starting cli_wallet to create Cli Wallet

This section includes instructions for the following:

  • Obtaining the Chain ID

  • Starting a cli_wallet

  • Setting a password and Unlock the cli wallet


Each wallet wallet.json is specifically associated with a single chain, specified by its chain ID. This is to protect the user from (e.g., unintentionally) using a testnet wallet on the real chain. The Chain ID passed to the cli_wallet needs to match the Chain ID generated and used by the witness node.

Chain ID:: The chain ID is a hash of the genesis state. All transaction signatures are only valid for a single chain ID. So, editing the genesis file will change your chain ID, and make you unable to sync with all existing chains (unless one of them has exactly the same genesis file you do).

wallet.json:: Each wallet has a wallet.json (this is a default wallet file name. It can be changed) file that is associated with a specific chain-id. (i.e., When connecting to a new or different test network you must also use a new or different wallet.json.)

1.Obtaining the Chain ID

When we started the witness_node, the Chain ID appeared on the screen. If you have saved the Chain ID, skip this step.

If you are not sure about the chain ID, it can be obtained by using the API to query a running witness node with the get_chain_properties API call.

  1. Obtain the Chain ID by using API call. This curl command will return a short JSON object including the chain_id

# For example:
curl --data '{"jsonrpc": "2.0", "method": "get_chain_properties", "params": [], "id": 1}' && echo

Note: For testing purposes, the --dbg-init-key option will allow you to quickly create a new chain against any genesis file, by replacing the witnesses’ block production keys.

2.Starting a cli_wallet

This will connect a new wallet to your Private Testnet witness node. You must specify a chain ID (if you did not embed a genesis file) and server. Keep your witness node running. Open another Command Prompt window and move to your Private Testnet Project directory.

  1. Make sure, a current directory is $HOME/Testnet-Home/

  2. Start a cli_wallet

# For example:
./cli_wallet --wallet-file my-wallet.json
                   --chain-id cf30711----USE-OWN-CHAIN-ID---68d9888d86b458d16e6c36aa74b
                   --server-rpc-endpoint ws:// -u '' -p ''

# For example: (if a genesis file has been embedded)
./cli_wallet --wallet-file my-wallet.json
                   --server-rpc-endpoint ws:// -u '' -p ''


  • --wallet-file : define the wallet file path (if it does not exist, it will be created when close the cli_wallet).

  • chain-id : Obtained Chain ID from the witness_node startup.

  • server-rpc-endpoint : The port number is how you defined (opened) --rpc-endpoint for the witness_node.

If it connected (executed) successfully, it will prompt new >>> to set a password.

3.Setting a password and Unlock the cli wallet

  1. First you need to create a new password to the cli wallet.

Gaining Access to the Genesis Stake

This section provides instructions for accessing accounts and asset in a genesis file

  • Importing key and account name into cli wallet

  • Importing a balance into cli wallet

  • Viewing the imported account information

  • Listing the account balance

1.Importing key and account name into cli wallet

To process this step, we prepared initial accounts and initial balances information in my-genesis.json. We use “TEST” as initial_balances asset_symbol and “init30-test” account user who has the balance.

  1. Make sure your witness_node is running.

  2. Connect to your cli_wallet and unlock the wallet

  3. Import “private key” and “name“. (Importing init30-test ‘s private key of the active key).

# For example:
import_key init30-test "5JG5thpLiuTG1ANiV9j4EyDHCXjvM67NRLtYSRGhusL5wg9CahY" # active_key

import_key init30-test "5JU3yZnDy5Gf9gS4iQwSS1zDLzP3ECmRfWv6kx76WxnufTQRAqr"  # owner_key


In our example, the active key is equal to the memo key, which is required for transfers with a memo. To review an account information, use get_account. It will show each key value.

2.Importing a balance into cli wallet

We prepared the genesis file for this example. So, we know that the init30-test account has “TEST” asset balance to import.

# For example:
import_balance init30-test ["5JU3yZnDy5Gf9gS4iQwSS1zDLzP3ECmRfWv6kx76WxnufTQRAqr"] true

3.Viewing the imported account information

We imported one account information into the cli wallet. Review the account information.

# For example:
get_account init30-test

4. Listing the account balance

View the user account balance.

# For example:
list_account_balances init30-test

Creating Another Account

This section provides instructions for creating new account. We will create new account alpha-test and transfer funds “TEST” between init30-test and alpha-test.

  • Checking a lifetime membership status

  • Registering new account

  • Transferring funds between accounts

  • Finding the private key

  • Upgrading an account


Creating a new account is always done by using an existing account (e.g., init30-test). When creating new account, someone (i.e., the register) has to fund the registration fee. Also, there is the requirement for the register account to have a LifeTime Membership (LTM) status

1.Checking a lifetime membership status

  1. View the register account information to see if it has the lifetime membership status.

# For example:
get_account init30-test
  1. Check membership_expiration_date; you should see a future date (e.g., “membership_expiration_date”: “2106-02-07T06:28:15”). If you get 1970-01-01T00:00:00 something is wrong, or the register does not have a lifetime membership yet.

  2. Upgrade an account status to a lifetime member.

# For example:
upgrade_account init30-test true

Note: The account to be upgraded must have funds to pay a lifetime membership fee as specified in the genesis file.

2.Registering new account

We register new account alpha-test by using init30-test account as a registrar. First, we generate public and private key pairs for new account.

  1. Generate new key pairs. Use suggest_brain_key function

# For example:
unlocked >>> suggest_brain_key
  "wif_priv_key": "5Jr5C8fxniR7n2B1ipfZPpw39FReeSBAQVTi4cAQANxuT96eWiT",
  "pub_key": "TEST721w2dfphe1uChWPdpotYqwxzPavzzoTf3dBdq8pahrd1rK1su"
  1. Register new account. The register_account command allows you to register an account by using only a public key.

# For example:
register_account alpha-test TEST721w2dfphe1uChWPdpotYqwxzPavzzoTf3dBdq8pahrd1rK1su TEST721w2dfphe1uChWPdpotYqwxzPavzzoTf3dBdq8pahrd1rK1su init30-test init30-test 0 true
  1. View new account information. Examine the output, check each key (owner, active, and memo_key).

# For example:
get_account alpha-test

3. Transferring funds between accounts

  1. Transfer funds (30,500 TEST) from init30-test to alpha-test, without memo. And check the balance.

# For example:
transfer init30-test alpha-test 30500 TEST "" true

list_account_balances alpha-test
  1. Transfer funds with “memo”. We need to import a private key of the memo key. The memo key is the same as the active key (in this example).

# For example:
import_key init30-test "5JG5thpLiuTG1ANiV9j4EyDHCXjvM67NRLtYSRGhusL5wg9CahY"
  1. Transfer funds (4,000 TEST) from init30-test to alpha-test, with memo. And check the balance.

# For example:
transfer init30-test alpha-test 4000 TEST "Your memo here" true
list_account_balances alpha-test

Note: “active_key == memo_key” applies to genesis accounts, it’s not a general rule.

4.Finding a Private Key

There is a function to find a private key from a public key.

  1. Use get_private_key function to find a private key. Run the command.

# For example:
get_private_key  TEST6G5BQQfPLRGzBjFUZ87BfSdYL8DgkWk3BLfHu6crznc94BfrJS


This works only for private keys stored in your wallet, and get_private_key command is useful if you want to import the key into a different wallet (e.g., web wallet).

5.Upgrading an account

New account alpha-test has received enough funds to upgrade a membership from Basic to LifeTime.

  1. Try upgrade_account to give a LifeTime Membership and review the outputs.

# For example:
upgrade_account alpha-test true

get_account alpha-test

Creating Committee Members (optional)

This section provides instructions for creating committee members’ account.

  • Creating a Committee Account

  • Transfer funds

  • Upgrade a Membership

  • Registering as committee members

  • Voting for the committee accounts

You would need the committee if you want to change some chain settings, like fees.

1.Creating a Committee Account

  1. Use create_account_with_brain_key to create committee accounts and examine the account.

# For example:
create_account_with_brain_key com0-test com0-test init2-test init2-test true
create_account_with_brain_key com1-test com1-test init2-test init2-test true
create_account_with_brain_key com2-test com2-test init2-test init2-test true

get_account com0-test

2.Transfer Funds

  1. Transfer enough funds to set up a lifetime membership.

# For example:
transfer init2-test com0-test 21000 TEST "" true
transfer init2-test com1-test 21500 TEST "" true
transfer init2-test com2-test 30000 TEST "" true

3.Upgrade a Membership

  1. Transfer funds to set a lifetime membership.

# For example:
upgrade_account com0-test true
upgrade_account com1-test true
upgrade_account com2-test true

4.Registering as committee member

  1. Create Committee Members

# For example:
create_committee_member  com0-test "http://www.com0-test" true
create_committee_member  com1-test "http://www.com1-test" true
create_committee_member  com2-test "http://www.com2-test" true

5.Voting for the committee accounts

  1. Vote for our own committee members. Elect them and wait for the maintenance interval, the votes become active.

# For example:
vote_for_committee_member init2-test com0-test true true
vote_for_committee_member init2-test com1-test true true
vote_for_committee_member init2-test com2-test true true

Setting up the Second Node

If you want to set up a second node (with the same genesis file) and connect it to the first node by using the p2p-endpoint of the first node as the seed-node for the second. The below are example settings.

Node-001: config.ini

p2p-endpoint =
# seed-node =                // add a seed node of your own

rpc-endpoint =

Node-002: config.ini

  • Set the Node-001’s p2p-endpoint as the Node-002’s seed-node.

p2p-endpoint =
seed-node =

rpc-endpoint =


  • The configuration files can use the same witness IDs but not the keys; use different keys in different nodes, which can be used to “hot-switch” among production nodes.

  • Each node should use only a subset of the witnesses, so block production alternates between them.

  • The log output of each node should show blocks received from the other node. (i.e., got_block….)