Create Publication

We are looking for publications that demonstrate building dApps or smart contracts!
See the full list of Gitcoin bounties that are eligible for rewards.

Tutorial Thumbnail
Intermediate · 1 hour

Create A Private Instance of Algorand In A Testbed

A private instance of Algorand allows testing and experimental activities within a more controlled infrastructure. It provides full control over network and protocol components. For example, it enables stress testing and measurements on any node of the network. Moreover, controlling the nodes of the network allows changing the network topology, adding (or removing) nodes, configure rewards, fees, and more.

A private instance of Algorand is a perfect clone of the available Public Networks MainNet, TestNet, and BetaNet. It comes with the same L1 features, such as Algorand Standard Assets (ASAs), Atomic Transfers, Smart Contracts, and State Proofs.

This tutorial describes how to create a private instance of Algorand in a testbed. It assumes three independent Virtual Machines (VMs). Each VM represents a node of the Algorand network. Each VM runs the algod daemon.

Requirements

Background

A previous tutorial detailed how to create a private network in Algorand via the goal utility that supports commands to create, start, stop, and delete private networks via a predefined template. The network template simulates a multi-node network on a single computer, and automatically configures wallets and accounts.

Differently, this tutorial shows the configuration of an Algorand private network running on independent, interconnected, virtual machines (VMs). The testbed is a virtual environment with three VMs.

Wallets, accounts, and nodes are manually configured, offering full control to the system administrators.

Testbed Overview

Algorand Image

Before creating the private instance of Algorand, a testbed with three separated VMs has to be settled. Each VM acts as an Algorand nodes.

There exist two distinct types of nodes, i.e. relay nodes and non-relay nodes. At least one relay node is required to forward messages.

Non-relay nodes can participate in consensus and are classified as participation nodes. They host (at least) one consensus participation key.

The testbed includes two non-relay nodes, VM_Part1 and VM_Part2, and one relay node, VM_Rel. Non-relay nodes host respectively one wallet and one online account and a registered participation key. See how to Participate in Consensus to better understand the consensus participation rules.

Attention

Before starting this tutorial, the Algorand binaries must be installed to each node. See Installing a node for more informations.

Steps

1. Prepare the environment

A private network requires its own data directory and API token. For each node run the following commands.

  1. Create the data directory and set up the environment variable pointing that directory.

mkdir ~node/testnetdata
export ALGORAND_DATA=~node/testnetdata

  1. Generate the algod API token See the docs for more details.

./goal node generatetoken

Info

The algod.token API token will be generated and installed into the directory testnetdata.

2. Create the Genesis File

There exists four types of Algorand networks, namely betanet, devnet, testnet, and mainnet.

The genesis file of each network is located into the ~/node/genesis directory (/var/lib/algorand/genesis/) for Debian and RPM installs) with the name genesis.json. It defines the initial configuration of the network, such as the stake distribution, the consensus protocol, and more (read more here).

The genesis is a JSON file with the following structure.

    {
      "alloc": [
      {
         "addr": "7777777777777777777777777777777777777777777777777774MSJUVU",
         "comment": "RewardsPool",
         "state": {
             "algo": 125000000000000,
             "onl": 2
         }
       },
       {
         "addr": "A7NMWS3NT3IUDMLVO26ULGXGIIOUQ3ND2TXSER6EBGRZNOBOUIQXHIBGDE",
         "comment": "FeeSink",
         "state": {
             "algo": 100000,
             "onl": 2
         }
      },
      ...
      ],
      "fees": "<latest_fees_addr>",
      "id": "<net-id>",
      "network": <net-name>,
      "proto": "<latest_net_proto>",
      "rwd": "<latest_rwd_addr>",
      "timestamp": "<latest_timestamp_val>"
    }

To build a private instance one can use the fees, rwd, and timestamp parameters specified in one of the canonical networks (see the templates from the ~/node/genesis directory), together with the RewardsPool and FeeSink accounts (read more on Algorand rewards here).

Create a new new file called genesis.json and save it into the directory testnetdata of each node of the testbed.

Attention

This solution uses an outdated genesis file as a matter of example. Please refer to the latest genesis files versions on your algod node.

Make sure to set proto to the latest protocol release that can be found here.

At step 6 of this tutorial, the above genesis will be populated with all the required parameters alongside with the details on the initial stake distribution.

3. Create the Wallets

Non-relay nodes can be classified as participation nodes if there is at least one online accounts with a registered participation key.

VM_Part1 and VM_Part2 are two participation nodes.
On both VM_Part1 and VM_Part2 nodee:

  1. Create a new wallet.

mkdir ~/node/testnetdata/privatenet-v1
./goal kmd start -t 3600
./goal wallet new <wallet_name>

The first command creates the network data directory needed to host the account’s participation keys.

Info

This tutorial assumes a network called privatenet with version v1. Please make sure that this values are reflected in the genesis.json.

  1. Initialize the kmd process to create a new wallet.

Info

The kmd tool allows the creation and management of wallets and accounts’ keys, visit Creation Methods to compare the different creation methods available.

The wallet new generates a new wallet. It requires to configure a password to unlock the wallet. Afterwards, it generates the wallet’s secret 25-words mnemonic.

Info

kmd wallets have one master key used to derive other Accounts. The 25-words mnemonic allows to recover the entire wallet and all its accounts. Make sure to keep the mnemonic and the wallet’s password safe and secure.

4. Create the Accounts

`./goal account new -w <wallet_name> -f`

Create a new account. Flag -f will set the generated account as default account for the specified wallet.

Tip

Accounts are identified with their Algorand address and with a human-friendly name. By default, the account’s name is Unamed-<X>, where X is an integer. To change the default name use the command ./goal account rename Unamed-<X> <new_account_name> -w <wallet_name>.

5. Generate Participation Keys

Participation keys can be generated either online or offline.

5.1. Online Participation Key Generation

The participation key for one account can be generated with the following goal command.

./goal account addpartkey -a <address-of-participating-account> --roundFirstValid=<partkey-first-round> --roundLastValid=<partkey-last-round> [--keyDilution=<key-dilution-value>]

The keyDilution parameter is optional – by default set to 10,000. Read more on addpartkey parameters at Generating the Participation Key.

Info

To execute the goal addpartkey command a node needs to be started. Algorand accounts and their participation keys can be generated on any node and exported/imported as desired. To use the nodes of this testbed simply start the Algorand node on both VM_Part1 and VM_Part2. At this stage both nodes will use the preliminary genesis of step 2. Hence, create the partkeys and then stop the nodes. See the Start Node to learn more on how to start/stop an Algorand node.

5.2. Offline Participation Key Generation

The new CLI algokey for key management allows to create a new set of participation keys and store them in a stand-alone file.

Run the command:

./algokey part generate --first <partkey-first-round> --last <partkey-last-round> --keyfile <key-file-name> --parent <address-of-participating-account>

Info

algokey part generate does not need to start the node.

6. Update the Genesis and Distribute the Initial Stake

Update the genesis file with the participation keys of the online accounts.

Each account participating in consensus needs to be online and with a positive amount of stake.

Retrieve participation keys details as described in View Participation Key Info and complete the genesis with a JSON object as shown below.

    {
       "addr": <account_addr>,
       "comment": <some_comment>,
       "state": {
        "algo": 5000000000000000,
        "onl": 1,
        "sel": <sel_addr>,
        "vote": <vote_addr>,
        "voteKD": <key_dilution [default 10000],
        "voteLst": <last_round>
       } 
    }

Both the participation keys are marked as online at genesis (onl:1), and the stake is equally divided between the two accounts (algo:xxx).

The final genesis.json file of the private network used in this example looks as below.

{
  "alloc": [
  {
    "addr": "7777777777777777777777777777777777777777777777777774MSJUVU",
    "comment": "RewardsPool",
    "state": {
      "algo": 125000000000000,
      "onl": 2
    }
  },
  {
    "addr": "A7NMWS3NT3IUDMLVO26ULGXGIIOUQ3ND2TXSER6EBGRZNOBOUIQXHIBGDE",
    "comment": "FeeSink",
    "state": {
      "algo": 100000,
      "onl": 2
    }
  },
  {
    "addr": <addr_part1>,
    "comment": "wallet1",
    "state": {
      "algo": 5000000000000000,
      "onl": 1,
      "sel": <selkey_1>,
      "vote": <votekey_1>,
      "voteKD": 10000,
      "voteLst": 3000000
    }
  },
  {
    "addr": <addr_part2>,
    "comment": "wallet2”,
    "state": {
      "algo": 5000000000000000,
      "onl": 1,
      "sel": "<selkey_2>",
      "vote": "<votekey_2>",
      "voteKD": 10000,
      "voteLst": 3000000
    }
  }
  ],
  "fees": "A7NMWS3NT3IUDMLVO26ULGXGIIOUQ3ND2TXSER6EBGRZNOBOUIQXHIBGDE",
  "id": "v1",
  "network": "privatenet",
  "proto": "<latest-proto>",
  "rwd": "7777777777777777777777777777777777777777777777777774MSJUVU"
}

7. Nodes Configuration

Algorand nodes can be configured with different options. Explore the Node Configuration Settings to understand all the available parameters.

The configuration file for to the algod process is called config.json, and it must be located in the data directory. This file must specify whether the node is a relay or not. The configuration files of relay and non-relays nodes of this example are detailed below.

1. Participation nodes configuration

{
  "Version": <latest-version>,
  "GossipFanout": 2,
  "IncomingConnectionsLimit": 0,
  "DNSBootstrapID": "",
  "EnableProfiler": true
}

Info

The DNSBootstrapID needs to be “” to overwrite the default pool of Algorand relay nodes. A new pool will be defined in the next step.

2. Relay node configuration

{
  "Version": <latest-version>,
  "GossipFanout": 2,
  "NetAddress": ":4161",
  "DNSBootstrapID": "",
  "EnableProfiler": true
}

The NetAddress parameters determines on which port the relay node will listen for incoming connections (usually 4161). Read more on relay nodes configuration at Configure Node as Relay.

Warning

Make sure that the server VM_Rel is allowed to accept incoming traffic on port 4161.

8. Connect Participation and Relay nodes

A local IP pool is used to store relay addresses. In a private instance of Algorand, each node needs to replace the default pool with a custom one. There exist two options: either via the -p flag on node startup or via the phonebook.json file.

This tutorial specifies the VM_Rel address using the phonebook file. Create a phonebook.json file with the IP address of VM_Rel into the directory with the goal binaries (root directory). See the Node Artifacts for the phonebook.json file template.

Warning

The phonebook.json file needs to be stored into the root directory containing the Algorand binaries.

9. Start the Network

The partkeys created at step 5.1. generated synthetic DB files. These files conflict with the new genesis file and need to be removed from both non-relays as follows.

rm ~node/testnetdata/privatenet-v1/crash.*
rm ~node/testnetdata/privatenet-v1/ledger.*

Warning

If the partkeys were created offline (step 5.2) the cleanup above is not needed.

Network can now be inizialized.
Start the nodes of the network by using the goal command.

./goal node start

Info

To facilitate the synchronization be sure to start the relay node at first.

Once all the nodes started, monitor the progression of the network from any node of the testbed through the following command.

./goal node status -w 1000

This will list the status of the node and the progression of the network. An output similar to the following will be shown.

Last committed block: 2
Time since last block: 3.5s
Sync Time: 0.0s
Last consensus protocol: https://github.com/algorandfoundation/specs/tree/4a9db6a25595c6fd097cf9cc137cc83027787eaa
Next consensus protocol: https://github.com/algorandfoundation/specs/tree/4a9db6a25595c6fd097cf9cc137cc83027787eaa
Round for next consensus protocol: 3
Next consensus protocol supported: true
Has Synced Since Startup: false

10. Register Keys

(offline partkey only) Participation keys generated at step 5.2. need to be installed.

  1. Install the participation key from file

    ./goal account installpartkey --partkey <key-file-name> --delete-input

Participation keys must be registered online permanently, otherwise they will last only for key dilution rounds.

  1. Register the participation key online

    ./goal account changeonlinestatus --address=<address-of-participating-account> --online=true

Info

If the network does not synchronize after keys installation you can stop the participation nodes and restart them before running the changeonlinestatus command.

All done! A fully private instance of Algorand is now up and running on the testbed. Use it to experiment with all L1 futures in a private and controlled environment.