Test Custom Clusters Locally With cardano-testnet
In the future, cardano-testnet will be available from cardano-node GitHub Releases page. Until then, it is obtained by building cardano-node from source.
Building cardano-testnet
We refer to the instructions for building cardano-node from source. Once you are done with these instructions, run the following to build cardano-testnet.
cabal build cardano-testnet
This should succeed 🙂 Now, define two environment variables pointing to your cardano-node and cardano-cli executables (which you can obtain from cardano-node's GitHub releases):
export CARDANO_CLI=path to your executable
export CARDANO_NODE=path to your executable
Top-level commands
cardano-testnet has the following commands:
Usage: cardano-testnet (cardano | create-env | version | help)
Available options:
-h,--help Show this help text
Available commands:
cardano Start a testnet and keep it running until stopped
create-env Create a sandbox for Cardano testnet
version Show cardano-testnet version
help Show cardano-testnet help
Options for launching a local cluster
To launch a local cluster, you should use the cardano-testnet cardano command, whose API is as follows:
Usage: cardano-testnet cardano
[ --node-env FILEPATH [--preserve-timestamps]
| [--nodes SPEC[,SPEC...] | --num-pool-nodes COUNT]
[--max-lovelace-supply WORD64]
[--num-dreps NUMBER]
[--testnet-magic INT]
[--epoch-length SLOTS]
[--slot-length SECONDS]
[--active-slots-coeff DOUBLE]
[--params-file FILEPATH | --params-mainnet]
[--output-dir DIRECTORY]
]
[--enable-new-epoch-state-logging]
[--enable-grpc]
[--use-kes-agent]
Start a testnet and keep it running until stopped
Available options:
--node-env FILEPATH Path to the node's environment (which is generated
otherwise). You can generate a default environment
with the 'create-env' command, then modify it and
pass it with this argument.
--preserve-timestamps Do not update the time stamps in genesis files to
current date.
--nodes SPEC[,SPEC...] Comma-separated node specifications. SPO nodes must
come before relay nodes. Each spec is a role (spo or
relay) optionally followed by :node-bin=<path>. If
the path contains commas, colons, double quotes, or
backslashes, wrap it in double quotes and escape any
literal double quotes as \" and backslashes as \\
within. To prevent bash from consuming the double
quotes, enclose the whole argument in single quotes.
Examples: --nodes
spo,spo:node-bin=/path/to/bin,relay,relay | --nodes
'spo:node-bin="/path,with:commas",relay'
--num-pool-nodes COUNT Number of pool nodes. Note this uses a default node
configuration for all nodes.
--max-lovelace-supply WORD64
Max lovelace supply that your testnet starts with.
(default: 100000020000000)
--num-dreps NUMBER Number of delegate representatives (DReps) to
generate. (default: 3)
--testnet-magic INT Specify a testnet magic id. (default: 42)
--epoch-length SLOTS Epoch length, in number of slots. (default: 500)
--slot-length SECONDS Slot length. (default: 0.1)
--active-slots-coeff DOUBLE
Active slots coefficient. (default: 5.0e-2)
--params-file FILEPATH File containing custom on-chain parameters in
Blockfrost format:
https://docs.blockfrost.io/#tag/cardano--epochs/GET/epochs/latest/parameters
--params-mainnet Use mainnet on-chain parameters
--output-dir DIRECTORY Directory where to store files, sockets, and so on.
It is created if it doesn't exist. If unset, a
temporary directory is used.
--enable-new-epoch-state-logging
Enable new epoch state logging to
logs/ledger-epoch-state.log
--enable-grpc [EXPERIMENTAL] Enable gRPC endpoint on all of testnet
nodes. The listening socket file will be the same
directory as node's N2C socket.
--use-kes-agent Get Praos block forging credentials from kes-agent
via the default socket path
-h,--help Show this help text
We now go over these different options as there are many interactions between them.
Using a custom node configuration file and custom genesis files
cardano-testnet has two behaviors, depending on whether you want to use defaults or not. You can either:
- Default the node configuration file, the Shelley, Alonzo, Byron, and Conway genesis files, and the topology file. In this case, don't specify
--node-env:cardano-testnetwill take care of generating all these files. - Pass a pre-generated node sandbox environment using
--node-env. This environment should be generated using thecardano-testnet create-envsub-command. In that case,cardano-testnetwill not generate any configuration file. The specifics of thecreate-envsub-command are detailed below.
Specifying nodes
There are two mutually exclusive ways to specify the nodes in the cluster:
--num-pool-nodes COUNTsimply specifies the number of SPO nodes. All nodes use the defaultcardano-nodebinary (from yourCARDANO_NODEenvironment variable or PATH).--nodes SPEC[,SPEC...]allows fine-grained control. Each spec is a role (spoorrelay), optionally followed by:node-bin=<path>to specify a customcardano-nodebinary for that node. SPO nodes must come before relay nodes in the list. For example:--nodes spo,spo,relaystarts two SPO nodes and one relay, all using the default binary.--nodes spo,spo:node-bin=/path/to/other/bin,relaystarts two SPO nodes (the second using a custom binary) and one relay.
The cardano-testnet sandbox environment
cardano-testnet stores all its keys (SPO, dreps, etc.), configuration files, and node data in a single directory.
If you don't specify --output-dir, cardano-testnet will create a fresh temporary directory to run.
If you specify --output-dir, cardano-testnet will use the specified directory to store the keys and the nodes' data. In this case we recommend using a fresh directory every time, otherwise there is a risk that one run poisons the other.
In addition, using your own directory makes it easier to inspect the logs after the testnet has finished, or while it is running.
The structure of the directory is as follows (using bash pseudo-syntax to avoid enumerations):
├── byron-gen-command
│ └── genesis-keys.00{0,1,2}.key
├── delegate-keys
│ ├── delegate{1,2,3}
│ │ ├── kes.{skey,vkey}
│ │ ├── key.{skey,vkey}
│ │ ├── opcert.{cert,counter}
│ │ └── vrf.{skey,vkey}
│ └── README.md
├── drep-keys
│ ├── drep{1,2,3}
│ │ └── drep.{skey,vkey}
│ └── README.md
├── genesis-keys
│ ├── genesis{1,2,3}
│ │ └── key.{skey,vkey}
│ └── README.md
├── logs
│ └── node{1,2,3}
│ ├── node.pid
│ ├── stderr.log
│ └── stdout.log
├── node-data
│ ├── node{1,2,3}
│ │ ├── db
│ │ │ └── <node database files>
│ │ ├── port
│ │ └── topology.json
├── pools-keys
│ ├── pool1
│ │ ├── byron-delegate.key
│ │ ├── byron-delegation.cert
│ │ ├── cold.{skey,vkey}
│ │ ├── kes.{skey,vkey}
│ │ ├── opcert.{cert,counter}
│ │ ├── staking-reward.{skey,vkey}
│ │ └── vrf.{skey,vkey}
│ └── README.md
├── socket
│ ├── node{1,2,3}
│ │ └── sock
├── stake-delegators
│ ├── delegator{1,2,3}
│ │ ├── payment.{skey,vkey}
│ │ └── staking.{skey,vkey}
├── utxo-keys
│ ├── utxo{1,2,3}
│ │ └── utxo.{addr,skey,vkey}
│ └── README.md
├── {alonzo,byron,conway,dijkstra,shelley}-genesis.json
├── genesis-input.dijkstra.json
├── configuration.yaml
└── current-stake-pools.json
We draw the reader's attention to two things:
- The nodes' logs are located in
logs/node1/,logs/node2/, etc. Those are useful for debugging. - The genesis files are at the root of the output directory, and the topology files are in the node subdirectories. This will be relevant for the next section.
Creating your own sandbox environment
cardano-testnet provides the option to create a sandbox environment as described above, without launching the node network itself. This allows the modification of configuration files, Genesis or otherwise. The API of the command is as follows:
Usage: cardano-testnet create-env
[--nodes SPEC[,SPEC...] | --num-pool-nodes COUNT]
[--max-lovelace-supply WORD64]
[--num-dreps NUMBER]
[--testnet-magic INT]
[--epoch-length SLOTS]
[--slot-length SECONDS]
[--active-slots-coeff DOUBLE]
[--params-file FILEPATH | --params-mainnet]
--output DIRECTORY
Create a sandbox for Cardano testnet
Available options:
--nodes SPEC[,SPEC...] Comma-separated node specifications. SPO nodes must
come before relay nodes. Each spec is a role (spo or
relay) optionally followed by :node-bin=<path>. If
the path contains commas, colons, double quotes, or
backslashes, wrap it in double quotes and escape any
literal double quotes as \" and backslashes as \\
within. To prevent bash from consuming the double
quotes, enclose the whole argument in single quotes.
Examples: --nodes
spo,spo:node-bin=/path/to/bin,relay,relay | --nodes
'spo:node-bin="/path,with:commas",relay'
--num-pool-nodes COUNT Number of pool nodes. Note this uses a default node
configuration for all nodes.
--max-lovelace-supply WORD64
Max lovelace supply that your testnet starts with.
(default: 100000020000000)
--num-dreps NUMBER Number of delegate representatives (DReps) to
generate. (default: 3)
--testnet-magic INT Specify a testnet magic id. (default: 42)
--epoch-length SLOTS Epoch length, in number of slots. (default: 500)
--slot-length SECONDS Slot length. (default: 0.1)
--active-slots-coeff DOUBLE
Active slots coefficient. (default: 5.0e-2)
--params-file FILEPATH File containing custom on-chain parameters in
Blockfrost format:
https://docs.blockfrost.io/#tag/cardano--epochs/GET/epochs/latest/parameters
--params-mainnet Use mainnet on-chain parameters
--output DIRECTORY Directory where to create the sandbox environment.
-h,--help Show this help text
If you want to run a testnet with custom parameters, we suggest the following workflow:
rm -rf env # Ensure there is no existing sandbox environment
cardano-testnet create-env --output env # Creates the sandbox environment in env/
# Modify the configuration files as you see fit
cardano-testnet cardano --node-env env # Run the testnet on the custom environment
Notes:
- By default,
cardano-testnet cardanoupdates the time stamps in genesis files to the current date. If you don't want this behavior (e.g., you have carefully set custom timestamps), use--preserve-timestamps. - The following configuration files are safe for modifications:
env/configuration.yaml: high-level configuration options for thecardano-nodebinaryenv/{alonzo,byron,conway,shelley}-genesis.json: the genesis files for the testnet chain.env/node-data/node{1,2,3}/topology.json: topology files for individual nodes.
Getting on-chain parameters from mainnet
By default, the create-env sub-command generates on-chain parameters at their initial value. If you want your test network to use a different set of on-chain parameters without specifying them by hand, you can use one of the following options:
- Use
--params-fileto specify a set of on-chain parameters. The file must be formatted as a JSON response from this Blockfrost endpoint. - Use
--params-mainnetto get on-chain parameters similar to the current state of mainnet. Those parameters are provisioned from this file, which is updated every epoch (i.e. every five days).
These options are also available directly on the cardano-testnet cardano command when not using --node-env.
Era-specific flags: Shelley
There are four flags that control values specified in the Shelley genesis file:
--max-lovelace-supply WORD64
Max lovelace supply that your testnet starts with.
(default: 100000020000000)
--epoch-length SLOTS Epoch length, in number of slots. (default: 500)
--slot-length SECONDS Slot length. (default: 0.1)
--active-slots-coeff DOUBLE
Active slots coefficient. (default: 5.0e-2)
Note that all of these flags are ignored when a sandbox environment is provided via --node-env.
Era-specific flags: Conway
There is one flag that control values that appear in the Conway genesis file and that's the number of dreps:
--num-dreps NUMBER Number of delegate representatives (DReps) to
generate. (default: 3)
Like the Shelley flags, this flag is ignored if a sandbox environment is provided via --node-env.
Understanding the output of cardano-testnet
When you run cardano-testnet, you will see output similar to this:
Creating environment: /tmp/testnet/
Starting testnet in environment: /tmp/testnet/
Testnet started
Waiting for shutdown (Ctrl+C)
When using --node-env with a pre-existing environment, the Creating environment line is omitted.
Once the line Testnet started appears, the testnet is running and building blocks.
To interact with the testnet using cardano-cli, set the following environment variables (adjusting paths to match your --output-dir):
export CARDANO_NODE_SOCKET_PATH=/tmp/testnet/socket/node1/sock
export CARDANO_NODE_NETWORK_ID=42
In order to shutdown the testnet, you can press Ctrl+C and cardano-testnet will kill all the nodes that were spawned when it was started.