Set up a network
In this topic, you'll learn how to set up your own blockchain network by studying a concrete example. You can set up a private network for development and testing. It provides an easy way to develop and test your dapps. You might also want to create a private network for learning and understanding the Chromia blockchain network.
The Postchain Management Console (PMC) creates and interacts with the network. This guide uses an example project that lets you quickly start a local network and manage multiple providers. You can expand the network by adding more providers, nodes, and clusters.
The network provided by this example contains four providers and three nodes. In a public Chromia network, a provider is represented by a person or an organization. However, in this case, the providers are represented by different key pairs on your machine that are specified in the PMC config. It means that to run commands by a specific provider; the command must be executed with the PMC config of that provider.
The first provider is the initializer of the network. The first node in the network is called the genesis node and hosts the management chain (BC0). When the network is initialized, the initial provider can add more providers to the network. Providers can belong to different provider tiers, which define what changes they can make to the network.
Some actions on the network need consensus among the providers in the network. A proposal requests such actions from a provider. The system node tier providers then vote on the proposals to reach a consensus.
Get example
Download directory1-example-0.2.0-dist.tar.gz
from here.
Content
This sample contains:
├── app
│ ├── chromia.yml
│ └── src
│ └── main.rell
├── chromia-cli-0.1.2-dist.tar.gz
├── config
│ ├── c0-deploy.xml
│ ├── common.properties
│ ├── config.0.properties
│ ├── config.1.properties
│ ├── config.2.properties
│ ├── config.3.properties
│ ├── docker.db.properties
│ └── localhost.db.properties
├── directory1-3.7.0-SNAPSHOT-sources.tar.gz
├── docs
│ ├── README.md
│ ├── multi-provider.md
│ └── single-provider.md
├── pmc-directory-3.7.0-SNAPSHOT-dist.tar.gz
├── provider
│ ├── alpha
│ ├── beta
│ ├── delta
│ └── gamma
└── scripts
├── find-ip
├── setup.sh
└── wipe-db
app
is the city tracker, which can be deployed to the network.config
contains node configurations for four nodes. By default, they're pointing todocker.db.- properties
which useshost.docker.internal:5432
. Update this path to the actual database that you are using.provider
contains configurations for four providers. They're all pointing toward node 0-3, respectively. Change this using thepmc config
command.scripts
contain utility scripts.setup.sh
unpacks all tarballs and generate blockchain configurations.
We recommend installing direnv to access all scripts in the scripts folder and the management console directly from the path.
Prerequisites
- Docker
- direnv (this isn't mandatory, but the examples assume that all scripts are available on this path)
If you are on a Mac, it's recommended to install coreutils
to ensure that the scripts in this distribution is working correctly
brew install coreutils
Setup
Run the script scripts/setup.sh
to initiate this project.
scripts/setup.sh
If you want, you can manually specify which IP you have and which blockchain to use:
IP=<my-ip> BLOCKCHAIN=manager scripts/setup.sh
The script unpacks PMC, the deployment tool, and BC0 sources. It also generates the blockchain configurations for the build
and app/build
folders.
In the configuration file directory1/rell/chromia.yml
for BC0, we've:
initial_provider: x"03ECD350EEBC617CBBFBEF0A1B7AE553A748021FD65C7C50C5ABB4CA16D4EA5B05"
that's configured to the provider alpha
(found in the providers/alpha directory). alpha
is the initial provider of the network.
Postgres
You must have a Postgres server running to be able to run nodes. You can start a Postgres server using Docker.
$ docker run --name postgres -e POSTGRES_INITDB_ARGS="--lc-collate=C.UTF-8 --lc-ctype=C.UTF-8 --encoding=UTF-8" -e POSTGRES_PASSWORD=postchain -e POSTGRES_USER=postchain -p 5433:5432 postgres
Configure config/docker.db.properties
to point to the Postgres instance by replacing {DOCKER_HOST}
with the Docker host.
On Mac, the Docker host is host.docker.internal
, whereas on Linux/Windows, it's typically 172.17.0.1
.
You have now set up a Docker container with a Postgres instance and generated the needed configuration files to set up a network.
Starting over
If you want to restart and give up your progress, you must wipe the database. You might never want to do this in a production environment, but it can be helpful when practicing or testing. You can do this in two ways:
- Delete the Postgres container and all its data
- Wipe the database schema associated with the node in question
$ scripts/wipe-db config/config.0.properties
Starting network and managing multiple providers
In this section, we set up and use a few nodes and providers with different roles.
The providers are called alpha
, beta
, gamma
, and delta
. Their configurations are available in the provider
folder.
alpha$
means that the command is executed from the provider/alpha
folder.
As previously mentioned, a provider is a unique keypair in a PMC config. It's already done for the given providers, but if you want to create a new provider, you must use PMC to create a new keypair (pmc keygen
).
The goal of the providers in this example is to illustrate the different roles a provider can have on the network.
alpha - system provider and owner of node 0
beta - system provider and owner of node 1
gamma - node provider and owner of node 2
delta - dapp provider/community node provider who does not own a node
Initializing the network
Start the genesis node and two other nodes.
All nodes have the management chain deployed. Each node has a node config inside the /config
folder. The config files contain unique keypairs for the node and database schema. Each config includes common properties such as database name, password, and information to the genesis node to connect to the existing network. The genesis node is the node that gets started first below.
$ docker run --name postchain0 \
--mount type=bind,source="$(pwd)/config",target=/config,readonly \
--mount type=bind,source="$(pwd)/directory1/rell/build",target=/build,readonly \
-e POSTCHAIN_DEBUG=true \
-p 9870:9870/tcp \
-p 7740:7740/tcp \
registry.gitlab.com/chromaway/postchain-chromia/chromaway/chromia-server:3.8.0 \
run-node --node-config /config/config.0.properties --chain-id 0 --blockchain-config /build/manager.xml
$ docker run --name postchain1 \
--mount type=bind,source="$(pwd)/config",target=/config,readonly \
--mount type=bind,source="$(pwd)/directory1/rell/build",target=/build,readonly \
-e POSTCHAIN_DEBUG=true \
-p 9871:9870/tcp \
-p 7741:7740/tcp \
registry.gitlab.com/chromaway/postchain-chromia/chromaway/chromia-server:3.8.0 \
run-node --node-config /config/config.1.properties --chain-id 0 --blockchain-config /build/manager.xml
$ docker run --name postchain2 \
--mount type=bind,source="$(pwd)/config",target=/config,readonly \
--mount type=bind,source="$(pwd)/directory1/rell/build",target=/build,readonly \
-e POSTCHAIN_DEBUG=true \
-p 9872:9870/tcp \
-p 7742:7740/tcp \
registry.gitlab.com/chromaway/postchain-chromia/chromaway/chromia-server:3.8.0 \
run-node --node-config /config/config.2.properties --chain-id 0 --blockchain-config /build/manager.xml
alpha
then initializes the network on node 0.
The pmc network initialize
command creates the resources needed to start the D1 management chain. Furthermore, an initial provider is created with the key pair from the PMC config, and a genesis node is registered pointing to the node api-url
stated in the PMC config.
alpha$ pmc network initialize --anchoring-config directory1/rell/build/cluster_anchoring.xml
Verify that the network is initialized by noting non-zero values from
alpha$ pmc network summary
Inviting providers
alpha
then invites beta
and gamma
as node providers
alpha$ pmc provider register --enable --pubkey $(pmc config --get pubkey --file ../beta/.pmc/config) -sp
alpha$ pmc provider register --disable --pubkey $(pmc config --get pubkey --file ../gamma/.pmc/config) -np
A provider is only enabled if it fulfills certain conditions.
- SP enables NP and CNP
- NP enables CNP
- SP proposes SP
In this case, alpha
is the only SP that can enable beta
immediately. If a second SP is added, both alpha
and beta
must reach a consensus in voting.
Verify the states of the providers
alpha$ pmc providers
Adding a node to the system cluster
beta
has the right to add a node to the system cluster as a newly joined system provider. It can do that by registering the node to the network.
When registering a new node, the PMC config needs to have an api-url
pointing to a D1 in the network. When the node is added, this api-url
can be changed back to the node hosted by the provider.
beta$ pmc config --set api.url=http://localhost:7740 # points to the rest api of node 0
beta$ pmc node add --pubkey 035676109c54b9a16d271abeb4954316a40a32bcce023ac14c8e26e958aa68fba9 --host $(find-ip) --port 9871 --api-url http://localhost:7741 --cluster system
beta$ pmc config --set api.url=http://localhost:7741 # Change back to point to node 1
Verify that the node is indeed added to the cluster (may take more than 10 seconds since this has a delay of 5 blocks)
beta$ pmc cluster info --name system
Promoting a System Provider through voting
Now that we've two system providers, we can promote gamma
to become a system provider through voting.
Making a proposal
A system provider can do some operations directly on the network, such as creating a cluster, but some require consensus. Promoting an NP to SP is one of them:
beta$ pmc provider promote --pubkey $(pmc config --get pubkey --file ../gamma/.pmc/config) --system
Verify that gamma
is still not a system provider:
beta$ pmc provider info --pubkey $(pmc config --get pubkey --file ../gamma/.pmc/config)
Voting
alpha
must now vote on the proposal to accept it. To view which proposals are present and show more information about them, use the following:
alpha$ pmc proposals
alpha$ pmc proposal info # shows latest proposal, use --id to see info about a specific
alpha
can now vote on the proposal:
alpha$ pmc proposal vote --id <id> --accept # or --reject
Verify that gamma
is promoted to a system node and let gamma
add its node:
alpha$ pmc provider info --pubkey $(pmc config --get pubkey --file ../gamma/.pmc/config)
gamma$ pmc config --set api.url=http://localhost:7740 # points to the rest api of node 0
gamma$ pmc node add --pubkey 03f811d3e806e6d093a4bcce49c145ba78f9a4b2fbd167753ecab2a13530b081f8 --host $(find-ip) --port 9872 --api-url http://localhost:7742 --cluster system
gamma$ pmc config --set api.url=http://localhost:7742 # Change back to point to node 1
You should now be able to see that the system cluster has three nodes and providers:
gamma$ pmc cluster info --name system
Launch a blockchain
You can deploy your dapp directly to the system container, but in this tutorial, we'll create a new container to contain the resource usage of the dapp.
To create a new container, use the following:
$ pmc container add --name cities --cluster system --pubkeys $(pmc config --get pubkey --file provider/alpha/.pmc/config)
and see whether it was added using:
$ pmc containers
Launch a new blockchain using the pmc blockchain add
command. After running the setup script, you can find a test blockchain configuration in the app-out
folder.
$ CITY_DAPP_BRID=$(pmc blockchain add --quiet --name city_tracker --container cities --blockchain-config app/build/city.xml)
In this example project, PMC is used to deploy a dapp. The Chromia CLI is currently not supported in this private network due to incompatibility between software, but it'll be supported soon. When deploying a dapp to the official network, a dapp developer needs to use the Chromia CLI instead.
To verify whether your blockchain is running, use the following:
$ pmc blockchains
Convenient voting
Here, we provide a script to automate voting in your local network. It can be helpful if you have several proposals to vote on and want to avoid manually switching between keypairs. The script iterates over each sub-directory in the provider
that you provide as input. If no provider sub-directory is provided, the script iterates in each sub-directory to provider
that exists. Furthermore, you give a proposal ID that it should vote on.
To use the script, create a file called auto-vote.sh
in the scripts
directory. Paste the following script in the auto-vote.sh
file:
#!/bin/bash
id=""
providers=()
while getopts "i:p:" opt; do
case $opt in
i) id="$OPTARG";;
p) IFS=',' read -ra providers <<< "$OPTARG";;
*) echo "Usage: $0 [-i <proposal ID>] [-p <provider1>,<provider2>,...]" >&2
exit 1;;
esac
done
if [[ -z $id ]]; then
echo "Error: proposal ID is required." >&2
exit 1
fi
if [[ ${#providers[@]} -eq 0 ]]; then
providers=( $(find provider -mindepth 1 -maxdepth 1 -type d -exec basename {} \;) )
fi
for dir in "${providers[@]}"; do
full_dir="provider/$dir"
if [[ -d $full_dir ]]; then
echo "Voting as provider '$dir':"
(cd $full_dir; pmc proposal vote --id $id --accept)
else
echo "Error: provider directory $full_dir does not exist." >&2
fi
done
Make the script executable by running the following:
chmod +x scripts/auto-vote.sh
First, use the script to navigate in a terminal to the project's root directory. Run the script with the following command:
scripts/auto-vote.sh -i <proposal ID> -p <provider1>,<provider2>,...
Make sure that the providers that you are trying to vote from exist as a sub-directory in provider
with an existing key pair.
Usage examples
This command votes on the proposal with ID 123
with provider alpha
, beta
, and gamma
:
scripts/auto-vote.sh -i 123 -p alpha,beta,gamma
This command votes on the proposal with ID 123
with each provider (that's, sub-directory) that exists in the directory provider
:
scripts/auto-vote.sh -i 123