Private Testnets - Manual Install
How to manually set up a Peerplays private testnet.
Creating your own private Peerplays testnet has many perks. You can develop new dapps, troubleshoot network issues, or experiment on some new ideas on a chain that you can customize and fully control.
Installing a private testnet requires building the Peerplays program from source code. This is because the initial state of the blockchain is embedded into the binaries. Since we need to begin a new chain from the very first block, we'll need to build from source and (if desired) embed your own custom genesis file into the built binaries.
Building the Peerplays chain from source code is memory intensive. This means the initial hardware requirements are quite high. But after all the building is done, the requirements to run the private chain are much lower.
Here's a guideline for the hardware requirements for the running of the private testnet:
The memory requirements shown in the table above are adequate to operate the node. Building and installing the node from source code (as with this guide) will require more memory. You may run into errors during the build and install process if the system memory is too low. See Installing vs Operating for more details.
Of course, the requirements will be highly dependent on what you're using the testnet for. Intensive development of an enterprise-level application will need much more resources than simply exploring your own private testnet.
The following packages are required for this guide.
sudo apt-get update
sudo apt-get -y install autoconf bash build-essential ca-certificates cmake \
vim dnsutils doxygen git graphviz libbz2-dev libcurl4-openssl-dev \
libncurses-dev libreadline-dev libssl-dev libtool libzmq3-dev \
locales ntp pkg-config wget autotools-dev libicu-dev python-dev
Boost is a comprehensive C++ library for common development tasks. It's required for Peerplays.
sudo apt-get update
sudo apt-get install -y autotools-dev build-essential libbz2-dev libicu-dev python-dev
wget -c 'http://sourceforge.net/projects/boost/files/boost/1.67.0/boost_1_67_0.tar.bz2/download'\
tar xjf boost_1_67_0.tar.bz2
This is very similar to installing a Witness node. The key difference here is the
-DGRAPHENE_EGENESIS_JSON=""setting. This means we're choosing to not embed a genesis file (yet). It's an override because the install will embed a default genesis file unless we tell it not to.
Since we want to potentially customize the genesis file, we'll choose not to embed one now.
git clone https://github.com/peerplays-network/peerplays.git
git checkout develop
git submodule update --init --recursive
git submodule sync --recursive
cmake -DBOOST_ROOT="$BOOST_ROOT" -DGRAPHENE_EGENESIS_JSON="" -DCMAKE_BUILD_TYPE=Release .
Before entering this next command, now would be the time to move on to section 4.1. if you wish to customize hard-coded parts of the chain. Otherwise, proceed.
# the following command will install the executable files under /usr/local/bin
sudo make install
Before we install Peerplays with the
sudo make installcommand, we have the opportunity to make some customization to the hard-coded configuration. This config is located in this file:
If you edit this file, with
sudo vim $HOME/src/peerplays/libraries/chain/include/graphene/chain/config.hpp, for example, you can tweak dozens of settings. Things like:
- The symbol of the core token. (
- The prefix of the account addresses. (
- Min / Max lengths of strings.
- Various time limits.
- Token precision and decimal places.
- Many fee related settings.
- Block and transaction sizes.
These may or may not be useful for you to change given that we're making a testnet designed to roughly mimic the conditions in production, but they are interesting nonetheless. If you make any changes here, save the file and then move on to
sudo make installfrom the
We're going to create a directory to store the custom genesis file. And then use the
witness_nodeprogram to generate a genesis template in the directory.
witness_node --create-genesis-json $HOME/genesis/my-genesis.json
This will also create the
witness_node_data_dirdirectory that stores the
config.inifile we'll need later.
The generated genesis file is good enough on its own to run the testnet. But you can edit the
my-genesis.jsonfile if you wish. In this file, you can specify accounts that exist from the beginning of the chain as well as their account balance. You can add assets, change the fees for operations, add witness accounts, add committee member accounts, and change some initial parameters.
To create the keys to use for accounts in the genesis file, the
get_dev_keysprogram is used.
# To use this:
# get_dev_key <any string as a prefix> <any number of strings for suffixes>
get_dev_key test-account -owner -active
So the keys will be generated using the strings you put into the program. In the example above, the
get_dev_keyprogram will use
test-account-activeto generate a public/private key pair and address, each.
The strings don't really mean anything other than just being used as seeds to create keys and accounts. The strings are not used for account names.
Then using the output, you can make new accounts in the
my-genesis.jsonfile like the following:
sudo vim $HOME/genesis/my-genesis.json
More accounts here...
More balances here...
The most important part is to use the generated keys given to the initial witnesses for any witnesses you use. These keys are hard-coded into the program and are used for the initial block producing accounts. The public/private key pair the witnesses use will also be generated in the
config.inifile as the
private-key. It's best to leave these alone.
And of course, you should have an account with an initial balance so we can import the balance to the
While this step is not required, there are a couple of benefits to embedding the genesis file into the Peerplays build. First, you won't have to supply the genesis file location in the
config.inifile. And second, you won't have to supply the chain id to the
cli_walletprogram when interacting with the testnet.
But the cost of embedding the genesis file is that it takes a lot of time and computer resources to rebuild Peerplays. And with the genesis "baked into" the binaries, it won't be available for future customization if you wanted to make some changes and reset the chain back to block 1.
Ultimately the decision to embed the file is a matter of taste; Is it more important to have the convenience of doing so, or the flexibility of not?
In the set of commands below, we're setting the
-DGRAPHENE_EGENESIS_JSON="$HOME/genesis/my-genesis.json"option in the make cache to use this file in the build process.
cmake -DBOOST_ROOT="$BOOST_ROOT" -DGRAPHENE_EGENESIS_JSON="$HOME/genesis/my-genesis.json" -DCMAKE_BUILD_TYPE=Release .
sudo make install
We need to make a few edits to the
config.inifile to finish setting up the testnet.
sudo vim $HOME/witness_node_data_dir/config.ini
Here are the settings we need to add / change:
# Opening the p2p endpoint will make this server into a seed node.
p2p-endpoint = 127.0.0.1:11101
# Opening the rpc endpoint will make this server into an API node.
rpc-endpoint = 127.0.0.1:11201
# an IP of 127.0.0.1 will only allow connections from this machine (Localhost).
# an IP of 0.0.0.0 will allow connections from ANY machine, even from the internet.
# If you have NOT embedded the genesis file, you'll need this. Otherwise, leave it out.
genesis-json = $HOME/genesis/my-genesis.json
# Stale production is needed to produce blocks on a chain with no blocks.
enable-stale-production = true
# These are the ids of the init0 to init10 witness accounts.
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"
witness-id = "1.6.8"
witness-id = "1.6.9"
witness-id = "1.6.10"
witness-id = "1.6.11"
Everything else should be left as-is.
We'll need to tell the program not to use any seed nodes with
--seed-nodes="". If we don't do this, the program will attempt to use some hard-coded default seed nodes which don't have anything to do with our private testnet.
If the program runs successfully you'll see your own unique chain id. The chain id is a hash of the genesis file you're using when running your testnet. If you change anything in your genesis file, the chain id will be different! This is used by the
cli_walletprogram to prevent unintended transactions from happening on the wrong chain.
* ------- NEW CHAIN ------ *
* - Welcome to Graphene! - *
* ------------------------ *
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 < -- your own unique chain id will be here -- >
Take note of this chain id and keep it for your future reference. If you have not embedded the genesis file, you will need the chain id when running the
After that, your testnet should be producing blocks!
2324613ms th_a witness.cpp:185 block_production_loo ] Generated block #1 with timestamp 2016-01-21T22:38:40 at time 2016-01-21T22:38:40
2325604ms th_a witness.cpp:194 block_production_loo ] Not producing block because slot has not yet arrived
2342604ms th_a witness.cpp:194 block_production_loo ] Not producing block because slot has not yet arrived
2343609ms th_a witness.cpp:194 block_production_loo ] Not producing block because slot has not yet arrived
2344604ms th_a witness.cpp:185 block_production_loo ] Generated block #2 with timestamp 2016-01-21T22:39:00 at time 2016-01-21T22:39:00
2345605ms th_a witness.cpp:194 block_production_loo ] Not producing block because slot has not yet arrived
2349616ms th_a witness.cpp:185 block_production_loo ] Generated block #3 with timestamp 2016-01-21T22:39:05 at time 2016-01-21T22:39:05
2350602ms th_a witness.cpp:194 block_production_loo ] Not producing block because slot has not yet arrived
2353612ms th_a witness.cpp:194 block_production_loo ] Not producing block because slot has not yet arrived
2354605ms th_a witness.cpp:185 block_production_loo ] Generated block #4 with timestamp 2016-01-21T22:39:10 at time 2016-01-21T22:39:10
We are now ready to connect the CLI to your testnet witness node. Keep your witness node running and in another terminal window you'll run the CLI Wallet.
If you have not embedded the genesis file, you'll need the chain id to run this command:
cli_wallet --wallet-file=my-wallet.json --chain-id 8b7bd36a146a03d0e5d0a971e286098f41230b209d96f92465cd62bd64294824 --server-rpc-endpoint=ws://127.0.0.1:11201
Just be sure to replace the example
8b7bd36a146a03d0e5d0a971e286098f41230b209d96f92465cd62bd64294824with your own chain id from earlier.
Or if you embedded the genesis file, there's no need for the chain id in this command:
cli_wallet --wallet-file=my-wallet.json --server-rpc-endpoint=ws://127.0.0.1:11201
If you see the
new >>>prompt, you have successfully connected to your node and you're ready to create a password with
new >>> set_password yoursupersecretpassword
Now you can unlock the newly created wallet:
In Peerplays, balances are contained in accounts. To import an account into your wallet, all you need to know its name and its private key. We will now import into the wallet an account called
import_key nathan 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3
nathanhappens to be the account name defined in the genesis file. If you had edited your
my-genesis.jsonfile just after it was created, you could have put a different name there. Also, note that
5KQwrPbwdL...P79zkvFD3is the private key defined in the
Now we have the private key imported into the wallet but still no funds associated with it. Funds are stored in genesis balance objects. These funds can be claimed, with no fee, using the
import_balance nathan ["5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3"] true
As a result, we have one account (named
nathan) imported into the wallet and this account is well funded with
TESTas we have claimed the funds stored in the genesis file. You can view this account by using this command:
...and its balance by using this command:
We will now create another account (named
alpha) so that we can transfer funds back and forth between
Creating a new account is always done by using an existing account. We need it because someone (the registrar) has to fund the registration fee. Also, there is the requirement for the registrar account to have a lifetime member (LTM) status. Therefore we need to upgrade the account
nathanto LTM, before we can proceed with creating other accounts. To upgrade to LTM, use the
upgrade_account nathan true
nathanhas now a LTM status:
In the response, next to
membership_expiration_dateyou should see something similar to
2106-02-07T06:28:15. If you get
1970-01-01T00:00:00something is wrong and
nathanhas not been successfully upgraded.
We can now register an account by using
nathanas registrar. But first we need to get hold of the public key for the new account. We do it by using the
And the response should be something similar to this:
"brain_priv_key": "MYAL SOEVER UNSHARP PHYSIC JOURNEY SHEUGH BEDLAM WLOKA FOOLERY GUAYABA DENTILE RADIATE TIEPIN ARMS FOGYISH COQUET",
So in this example:
- the public key is
- the private key is
- and let's assume our new account will be called
Copy those keys as we will need them soon.
Your public and private keys will be different (as the result of the
suggest_brain_keycommand is random) so make sure you use those. Also, you are free to choose any other name different from
register_accountcommand allows you to register an account using only a public key.
register_account alpha TEST78CuY47Vds2nfw2t88ckjTaggPkw16tLhcmg4ReVx1WPr1zRL5 TEST78CuY47Vds2nfw2t88ckjTaggPkw16tLhcmg4ReVx1WPr1zRL5 nathan nathan 0 true
Make sure you replace
TEST78CuY4...WPr1zRL5with your version of it.
The new account has been created but it's not in your wallet at this stage. We need to import it using the
alpha's private key:
import_key alpha 5JDh3XmHK8CDaQSxQZHh5PUV3zwzG68uVcrTfmg9yQ9idNisYnE
Make sure you replace
5JDh3XmH...9idNisYnEwith your version of it.
As a final step, we will transfer some money from
alpha. For that we use the
transfer nathan alpha 2000000000 TEST "here is some cash" true
here is some cashis an arbitrary memo you can attach to a transfer. If you don't need a memo, just use
And now you can verify that
alphahas indeed received the money:
If you want to set up a second node (with the same genesis file) and connect it to the first node, use the p2p-endpoint of the first node as the seed-node for the second. The below are example settings.
In the first node
p2p-endpoint = 127.0.0.1:11101
# seed-node = // seed-node is intentionally left blank!
# seed-nodes = // seed-nodes is also intentionally left blank!
rpc-endpoint = 127.0.0.1:11201
In the second node
We set the first node's
p2p-endpointas the second node's
p2p-endpoint = 127.0.0.1:11102
seed-node = 127.0.0.1:11101
rpc-endpoint = 127.0.0.1:11202
Lastly, the same witness IDs can be used in the second node, but the keys used for node production must be different. This allows you to swap block production between the two nodes by updating the witness accounts' signing keys (with
Another option is to use different witnesses on each node so that block production alternates between the nodes. The log output of each node should show blocks received from the other node. (i.e.,
Last modified 1yr ago