My goal with this post is to have cardano-node
s on both testnets – preview and preprod – and on mainnet running as a user, so I can later use them for minting, contract experiments etc. I’m not going to run a pool and this is not about setting up one.
To setup as fast and simple as possible, I’m going to use the pre-compiled binaries. Moreover, since we now have Mithril to get snapshots of the chains and do not have to synchronise from the beginning anymore, I’m going to use that.
Installing the software
I’m downloading the latest stable versions of cardano-node
(8.1.2 at the time of writing) from https://github.com/input-output-hk/cardano-node/releases and of mithril
(v2331.1 at the time of writing) from https://github.com/input-output-hk/mithril/releases. Then, I unpack those archives and put the binaries in there in the PATH
.
I won’t give copy and paste instructions here. There are far too many already out there. A Cardano forum is not the right place to give a thorough introduction to Linux, bash
, etc. You should learn a bit about that from the plethora of resources for Linux in general and your specific Linux distribution that are readily available out there.
After that, you can choose how you would like to organise your (Cardano) software. Personally, I chose to have the different packages in ~/Cardano/Software/
:
$ ls -l ~/Cardano/Software/
[…]
drwxr-xr-x 1 sean sean 540 2023-07-24 18:17 cardano-node-8.1.2/
-rw-r--r-- 1 sean sean 147644811 2023-08-12 22:57 cardano-node-8.1.2-linux.tar.gz
[…]
drwxr-xr-x 1 sean sean 410 2023-08-12 20:51 mithril-2331.1/
-rw-r--r-- 1 sean sean 60267298 2023-08-12 20:50 mithril-2331.1-linux-x64.tar.gz
Observe:
- IOG tends to pack its binary distributions such that they unpack in the current directory. So, I manually created those versioned directories, changed into them and called
tar xaf
from in there. - The binaries in the
mithril
distribution were not set to executable. I had to manuallychmod +x
them.
And I then have symbolic links in ~/.local/bin/
which for me is in the PATH
anyway:
$ ls -l ~/.local/bin/
[…]
lrwxrwxrwx 1 sean sean 53 2023-08-12 23:05 bech32 -> /home/sean/Cardano/Software/cardano-node-8.1.2/bech32*
[…]
lrwxrwxrwx 1 sean sean 58 2023-08-12 23:06 cardano-cli -> /home/sean/Cardano/Software/cardano-node-8.1.2/cardano-cli*
[…]
lrwxrwxrwx 1 sean sean 59 2023-08-12 23:06 cardano-node -> /home/sean/Cardano/Software/cardano-node-8.1.2/cardano-node*
[…]
lrwxrwxrwx 1 sean sean 57 2023-08-12 20:53 mithril-client -> /home/sean/Cardano/Software/mithril-2331.1/mithril-client*
[…]
That way, I can easily switch to new versions by changing the symbolic links, with the possibility to easily switch back as long as I have not deleted the old version.
Using Mithril to get snapshots
Mithril can be used to bootstrap nodes on mainnet as well as both testnets as described in https://mithril.network/doc/manual/getting-started/bootstrap-cardano-node.
I decided to put the chains next to each other in ~/Cardano/Chains/
. So, I’m doing in ~/Cardano/Chains/mainnet
:
$ export NETWORK=mainnet
$ export AGGREGATOR_ENDPOINT=https://aggregator.release-mainnet.api.mithril.network/aggregator
$ export GENESIS_VERIFICATION_KEY=$(curl -s https://raw.githubusercontent.com/input-output-hk/mithril/main/mithril-infra/configuration/release-mainnet/genesis.vkey)
$ mithril-client snapshot list
$ mithril-client snapshot download <latest digest>
In ~/Cardano/Chains/preprod
:
$ export NETWORK=preprod
$ export AGGREGATOR_ENDPOINT=https://aggregator.release-preprod.api.mithril.network/aggregator
$ export GENESIS_VERIFICATION_KEY=$(curl -s https://raw.githubusercontent.com/input-output-hk/mithril/main/mithril-infra/configuration/release-preprod/genesis.vkey)
$ mithril-client snapshot list
$ mithril-client snapshot download <latest digest>
And in ~/Cardano/Chains/preview
:
$ export NETWORK=preview
$ export AGGREGATOR_ENDPOINT=https://aggregator.pre-release-preview.api.mithril.network/aggregator
$ export GENESIS_VERIFICATION_KEY=$(curl -s https://raw.githubusercontent.com/input-output-hk/mithril/main/mithril-infra/configuration/pre-release-preview/genesis.vkey)
$ mithril-client snapshot list
$ mithril-client snapshot download <latest digest>
When the downloads are ready, mithril-client
verifies the signatures (after all that is what Mithril is all about) and unpacks the databases into the respective current directories ready to be used. (It leaves the quite large archive files there also, so I’ve manually removed them.)
Download and check of the two testnets was finished in around 20 minutes on my machine, while for mainnet it took around two and a half hours:
Getting and adapting the configurations
The configuration and Genesis files are obtained from https://book.world.dev.cardano.org/environments.html.
For mainnet:
$ mkdir mainnet/config
$ cd mainnet/config/
$ curl -s -O https://book.world.dev.cardano.org/environments/mainnet/config.json
$ curl -s -O https://book.world.dev.cardano.org/environments/mainnet/topology.json
$ curl -s -O https://book.world.dev.cardano.org/environments/mainnet/byron-genesis.json
$ curl -s -O https://book.world.dev.cardano.org/environments/mainnet/shelley-genesis.json
$ curl -s -O https://book.world.dev.cardano.org/environments/mainnet/alonzo-genesis.json
$ curl -s -O https://book.world.dev.cardano.org/environments/mainnet/conway-genesis.json
$ cd ../../
For preprod:
$ mkdir preprod/config
$ cd preprod/config/
$ curl -s -O https://book.world.dev.cardano.org/environments/preprod/config.json
$ curl -s -O https://book.world.dev.cardano.org/environments/preprod/topology.json
$ curl -s -O https://book.world.dev.cardano.org/environments/preprod/byron-genesis.json
$ curl -s -O https://book.world.dev.cardano.org/environments/preprod/shelley-genesis.json
$ curl -s -O https://book.world.dev.cardano.org/environments/preprod/alonzo-genesis.json
$ curl -s -O https://book.world.dev.cardano.org/environments/preprod/conway-genesis.json
$ cd ../../
For preview:
$ mkdir preview/config
$ cd preview/config/
$ curl -s -O https://book.world.dev.cardano.org/environments/preview/config.json
$ curl -s -O https://book.world.dev.cardano.org/environments/preview/topology.json
$ curl -s -O https://book.world.dev.cardano.org/environments/preview/byron-genesis.json
$ curl -s -O https://book.world.dev.cardano.org/environments/preview/shelley-genesis.json
$ curl -s -O https://book.world.dev.cardano.org/environments/preview/alonzo-genesis.json
$ curl -s -O https://book.world.dev.cardano.org/environments/preview/conway-genesis.json
$ cd ../../
Since I want to be able to run the nodes on the different chains/networks in parallel, I have to change the network ports in config.json
to be different.
Service | mainnet (leave at default) |
preprod |
preview |
---|---|---|---|
node itself (not in config.json ) |
3001 | 3002 | 3003 |
EKG | 12788 | 12789 | 12787 |
Prometheus | 12798 | 12799 | 12797 |
EDIT: After looking a bit into it, I decided that I need neither EKG nor Prometheus for my use case (local node just to submit transactions and experiment around with). The logs in journalctl
are more than enough. So, instead of changing the ports, I just removed superfluous configuration in all three configs:
$ diff -u1 config-original.json config.json
--- config-original.json 2023-08-13 05:17:26.047961728 +0200
+++ config.json 2023-08-13 05:25:16.709823144 +0200
@@ -54,3 +54,3 @@
"TracingVerbosity": "NormalVerbosity",
- "TurnOnLogMetrics": true,
+ "TurnOnLogMetrics": false,
"TurnOnLogging": true,
@@ -65,27 +65,4 @@
],
- "hasEKG": 12788,
- "hasPrometheus": [
- "127.0.0.1",
- 12798
- ],
"minSeverity": "Info",
"options": {
- "mapBackends": {
- "cardano.node.metrics": [
- "EKGViewBK"
- ],
- "cardano.node.resources": [
- "EKGViewBK"
- ]
- },
- "mapSubtrace": {
- "cardano.node.metrics": {
- "subtrace": "Neutral"
- }
- }
- },
- "rotation": {
- "rpKeepFilesNum": 10,
- "rpLogLimitBytes": 5000000,
- "rpMaxAgeHours": 24
},
Since the port the node itself listens on will be given on the command line and is not set in config.json
, I create environment files that can be read by the systemd
unit in the next section:
$ cat mainnet/env
CARDANO_NODE_PORT=3001
$ cat preprod/env
CARDANO_NODE_PORT=3002
$ cat preview/env
CARDANO_NODE_PORT=3003
Creating a systemd user unit
I want to be able to manage the nodes with systemctl
, but not as system-wide units (as in the usual setups according to CoinCashew or CNTools), but as user units.
I create the following unit file:
$ cat ~/.config/systemd/user/cnode@.service
[Unit]
Description=Cardano Node
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
WorkingDirectory=%h/Cardano/Chains/%i/
EnvironmentFile=%h/Cardano/Chains/%i/env
ExecStart=%h/.local/bin/cardano-node run --topology config/topology.json --database-path db --socket-path socket --config config/config.json --port ${CARDANO_NODE_PORT}
SyslogIdentifier=cnode@%i
KillSignal=SIGINT
RestartKillSignal=SIGINT
TimeoutStopSec=300
LimitNOFILE=32768
Restart=always
RestartSec=5
[Install]
WantedBy=default.target
That the name of the unit ends in an @
means that it is started with an instance name that is available inside the unit as %i
. That way, I can use this same unit file to manage all three networks/chains with it.
Changing into the directory for the corresponding chain makes the call to cardano-node
very simple and there are no further scripts needed.
Starting all three chains:
$ systemctl --user start cnode@mainnet
$ systemctl --user start cnode@preprod
$ systemctl --user start cnode@preview
This also organises them into a slice that can be used to query the state of all of them at once:
$ systemctl --user status app-cnode.slice
● app-cnode.slice - Slice /app/cnode
Loaded: loaded
Active: active since Sun 2023-08-13 02:45:00 CEST; 36min ago
Tasks: 36
Memory: 14.3G
CPU: 5min 28.613s
CGroup: /user.slice/user-1000.slice/user@1000.service/app.slice/app-cnode.slice
├─cnode@mainnet.service
│ └─311716 /home/sean/.local/bin/cardano-node run --topology config/topology.json --databas>
├─cnode@preprod.service
│ └─311766 /home/sean/.local/bin/cardano-node run --topology config/topology.json --databas>
└─cnode@preview.service
└─311794 /home/sean/.local/bin/cardano-node run --topology config/topology.json --databas>
Aug 13 03:20:31 nat cnode@preview[311794]: [nat:cardano.node.LedgerPeers:Info:61] [2023-08-13 01:20:31.0>
Aug 13 03:20:31 nat cnode@preview[311794]: [nat:cardano.node.PublicRootPeers:Info:61] [2023-08-13 01:20:>
Aug 13 03:20:31 nat cnode@preview[311794]: [nat:cardano.node.PublicRootPeers:Info:61] [2023-08-13 01:20:>
Aug 13 03:20:31 nat cnode@preview[311794]: [nat:cardano.node.PublicRootPeers:Info:61] [2023-08-13 01:20:>
Aug 13 03:20:31 nat cnode@preview[311794]: [nat:cardano.node.LedgerPeers:Info:61] [2023-08-13 01:20:31.0>
Aug 13 03:20:31 nat cnode@preview[311794]: [nat:cardano.node.PeerSelection:Info:64] [2023-08-13 01:20:31>
Aug 13 03:20:31 nat cnode@mainnet[311716]: [nat:cardano.node.ChainDB:Notice:194] [2023-08-13 01:20:31.36>
Aug 13 03:20:42 nat cnode@preview[311794]: [nat:cardano.node.ChainDB:Notice:43] [2023-08-13 01:20:42.33 >
Aug 13 03:21:23 nat cnode@preprod[311766]: [nat:cardano.node.ChainDB:Notice:42] [2023-08-13 01:21:23.25 >
Aug 13 03:21:23 nat cnode@mainnet[311716]: [nat:cardano.node.ChainDB:Notice:194] [2023-08-13 01:21:23.43>
$ journalctl --user -fu app-cnode.slice
[…]
Aug 13 03:22:57 nat cnode@mainnet[311716]: [nat:cardano.node.ChainDB:Notice:194] [2023-08-13 01:22:57.40 UTC] Chain extended, new tip: 071ea5aaf6881eb03dbd6da5e5000d1d08221879a4beecd660d2bfed9a88d294 at slot 100323486
Aug 13 03:22:59 nat cnode@preview[311794]: [nat:cardano.node.ChainDB:Notice:43] [2023-08-13 01:22:59.08 UTC] Chain extended, new tip: 877a4741077d51fe0e089686f75f7e572536c64aa7a3b7be95ceb9aa93cced1f at slot 25233779
Aug 13 03:23:02 nat cnode@preprod[311766]: [nat:cardano.node.ChainDB:Notice:42] [2023-08-13 01:23:02.02 UTC] Chain extended, new tip: 693b4548fee1f68837b3354cf3c232849ab383dfb3f16ea5a634025600008d66 at slot 36206581
Setting bash
aliases
Finally, I created some aliases for bash
and put them in one of my startup files to be able to use all three nodes with cardano-cli
:
$ alias | grep cardano-cli
alias cardano-cli-mainnet='CARDANO_NODE_SOCKET_PATH=/home/sean/Cardano/Chains/mainnet/socket cardano-cli'
alias cardano-cli-preprod='CARDANO_NODE_SOCKET_PATH=/home/sean/Cardano/Chains/preprod/socket cardano-cli'
alias cardano-cli-preview='CARDANO_NODE_SOCKET_PATH=/home/sean/Cardano/Chains/preview/socket cardano-cli'
$ cardano-cli-mainnet query tip --mainnet
{
"block": 9152619,
"epoch": 429,
"era": "Babbage",
"hash": "09795edf1b299b5413923bef8d994aca43935e96befe73252c03d81fb8ce347f",
"slot": 100323679,
"slotInEpoch": 358879,
"slotsToEpochEnd": 73121,
"syncProgress": "100.00"
}
$ cardano-cli-preprod query tip --testnet-magic 1
{
"block": 1264577,
"epoch": 87,
"era": "Babbage",
"hash": "a8584e677d0ba6827965aef55cdf08d7bf279cac798a151cad790ace51132191",
"slot": 36206790,
"slotInEpoch": 264390,
"slotsToEpochEnd": 167610,
"syncProgress": "100.00"
}
$ cardano-cli-preview query tip --testnet-magic 2
{
"block": 1105286,
"epoch": 292,
"era": "Babbage",
"hash": "9b00d4d23cee047dc24266bea6eb591b8c1a87d2c1b7b64f7a8436813365e1d6",
"slot": 25233954,
"slotInEpoch": 5154,
"slotsToEpochEnd": 81246,
"syncProgress": "100.00"
}
And this concludes my journey in setting up nodes on mainnet and both testnets in parallel under a user account using pre-compiled binaries and Mithril to reduce effort and time as much as possible.
To summarise, these are the files and directories, we now have for the three chains/networks:
$ tree -L 3 ~/Cardano/Chains/
/home/sean/Cardano/Chains/
├── mainnet
│ ├── config
│ │ ├── alonzo-genesis.json
│ │ ├── byron-genesis.json
│ │ ├── config-original.json
│ │ ├── config.json
│ │ ├── conway-genesis.json
│ │ ├── shelley-genesis.json
│ │ └── topology.json
│ ├── db
│ │ ├── immutable
│ │ ├── ledger
│ │ ├── lock
│ │ ├── protocolMagicId
│ │ └── volatile
│ ├── env
│ └── socket
├── preprod
│ ├── config
│ │ ├── alonzo-genesis.json
│ │ ├── byron-genesis.json
│ │ ├── config-original.json
│ │ ├── config.json
│ │ ├── conway-genesis.json
│ │ ├── shelley-genesis.json
│ │ └── topology.json
│ ├── db
│ │ ├── immutable
│ │ ├── ledger
│ │ ├── lock
│ │ ├── protocolMagicId
│ │ └── volatile
│ ├── env
│ └── socket
└── preview
├── config
│ ├── alonzo-genesis.json
│ ├── byron-genesis.json
│ ├── config-original.json
│ ├── config.json
│ ├── conway-genesis.json
│ ├── shelley-genesis.json
│ └── topology.json
├── db
│ ├── immutable
│ ├── ledger
│ ├── lock
│ ├── protocolMagicId
│ └── volatile
├── env
└── socket
$ du -h ~/Cardano/Chains/
1.1M /home/sean/Cardano/Chains/mainnet/config
4.7G /home/sean/Cardano/Chains/mainnet/db/ledger
61M /home/sean/Cardano/Chains/mainnet/db/volatile
129G /home/sean/Cardano/Chains/mainnet/db/immutable
133G /home/sean/Cardano/Chains/mainnet/db
133G /home/sean/Cardano/Chains/mainnet
3.6G /home/sean/Cardano/Chains/preprod/db/immutable
4.8M /home/sean/Cardano/Chains/preprod/db/volatile
303M /home/sean/Cardano/Chains/preprod/db/ledger
3.9G /home/sean/Cardano/Chains/preprod/db
40K /home/sean/Cardano/Chains/preprod/config
3.9G /home/sean/Cardano/Chains/preprod
5.0G /home/sean/Cardano/Chains/preview/db/immutable
1.8M /home/sean/Cardano/Chains/preview/db/volatile
504M /home/sean/Cardano/Chains/preview/db/ledger
5.5G /home/sean/Cardano/Chains/preview/db
40K /home/sean/Cardano/Chains/preview/config
5.5G /home/sean/Cardano/Chains/preview
143G /home/sean/Cardano/Chains/