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.7.3 at the time of last update) from https://github.com/input-output-hk/cardano-node/releases and of mithril
(v2347.0 at the time of last update) 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 ~/.local/cardano/software/
:
$ ls -l ~/.local/cardano/software/
drwxr-xr-x 1 sean sean 308 2023-12-15 17:40 cardano-node-8.7.3/
-rw-r--r-- 1 sean sean 114627802 2024-01-15 14:30 cardano-node-8.7.3-linux.tar.gz
drwxr-xr-x 1 sean sean 414 2024-01-04 09:10 mithril-2347.0/
-rw-r--r-- 1 sean sean 61720079 2024-01-04 09:08 mithril-2347.0-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 45 2024-01-15 14:33 bech32 -> ../cardano/software/cardano-node-8.7.3/bech32*
lrwxrwxrwx 1 sean sean 50 2024-01-15 14:33 cardano-cli -> ../cardano/software/cardano-node-8.7.3/cardano-cli*
lrwxrwxrwx 1 sean sean 51 2024-01-15 14:33 cardano-node -> ../cardano/software/cardano-node-8.7.3/cardano-node*
lrwxrwxrwx 1 sean sean 49 2024-01-04 09:15 mithril-client -> ../cardano/software/mithril-2347.0/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 ~/.local/cardano/chains/
. So, I’m doing in ~/.local/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 ~/.local/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 ~/.local/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>
mithril-client
downloads the databases into db/
directories in the current directory and, when the downloads are ready, verifies the signatures (after all that is what Mithril is all about).
Download and check of preprod
was finished in less than six minutes, of preview
in less than eight minutes, and of mainnet
in 74 minutes:
Getting and adapting the configurations
The configuration and Genesis files are obtained from https://book.world.dev.cardano.org/environments.html.
In ~/.local/cardano/chains/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
In ~/.local/cardano/chains/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
In ~/.local/cardano/chains/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
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, I removed superfluous configuration in all three configs:
$ diff -u1 config-original.json config.json
--- config-original.json 2024-01-04 10:25:32.232620424 +0100
+++ config.json 2024-01-04 10:26:16.619097477 +0100
@@ -63,3 +63,3 @@
"TracingVerbosity": "NormalVerbosity",
- "TurnOnLogMetrics": true,
+ "TurnOnLogMetrics": false,
"TurnOnLogging": true,
@@ -74,27 +74,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 I want to be able to run the nodes on the different chains/networks in parallel and 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 ~/.local/cardano/chains/mainnet/env
CARDANO_NODE_PORT=3001
$ cat ~/.local/cardano/chains/preprod/env
CARDANO_NODE_PORT=3002
$ cat ~/.local/cardano/chains/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/.local/cardano/chains/%i/
EnvironmentFile=%h/.local/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
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 Mon 2024-01-15 14:37:15 CET; 8h ago
Tasks: 48
Memory: 24.6G (peak: 25.7G swap: 1.5G swap peak: 1.5G zswap: 830.1M)
CPU: 8h 15min 53.907s
CGroup: /user.slice/user-1000.slice/user@1000.service/app.slice/app-cnode.slice
├─cnode@mainnet.service
│ └─72665 /home/sean/.local/bin/cardano-node run --topology config/topology.json --database>
├─cnode@preprod.service
│ └─72688 /home/sean/.local/bin/cardano-node run --topology config/topology.json --database>
└─cnode@preview.service
└─72710 /home/sean/.local/bin/cardano-node run --topology config/topology.json --database>
Jan 15 22:49:30 nat cnode@preview[72710]: [nat:cardano.node.ChainDB:Notice:20] [2024-01-15 21:49:30.32 U>
Jan 15 22:49:36 nat cnode@preprod[72688]: [nat:cardano.node.ChainDB:Notice:20] [2024-01-15 21:49:36.22 U>
Jan 15 22:49:38 nat cnode@preprod[72688]: [nat:cardano.node.ChainDB:Notice:20] [2024-01-15 21:49:38.14 U>
Jan 15 22:49:56 nat cnode@preprod[72688]: [nat:cardano.node.ChainDB:Notice:20] [2024-01-15 21:49:56.52 U>
Jan 15 22:50:12 nat cnode@preprod[72688]: [nat:cardano.node.ChainDB:Notice:20] [2024-01-15 21:50:12.09 U>
Jan 15 22:50:19 nat cnode@mainnet[72665]: [nat:cardano.node.ChainDB:Notice:22] [2024-01-15 21:50:19.36 U>
Jan 15 22:50:20 nat cnode@preprod[72688]: [nat:cardano.node.ChainDB:Notice:20] [2024-01-15 21:50:20.14 U>
Jan 15 22:50:21 nat cnode@mainnet[72665]: [nat:cardano.node.ChainDB:Notice:22] [2024-01-15 21:50:21.87 U>
Jan 15 22:50:27 nat cnode@preprod[72688]: [nat:cardano.node.ChainDB:Notice:20] [2024-01-15 21:50:27.17 U>
Jan 15 22:50:27 nat cnode@mainnet[72665]: [nat:cardano.node.ChainDB:Notice:22] [2024-01-15 21:50:27.84 U>
$ journalctl --user -fu app-cnode.slice
Jan 15 22:50:54 nat cnode@preview[72710]: [nat:cardano.node.ChainDB:Notice:20] [2024-01-15 21:50:54.45 UTC] Chain extended, new tip: e02ce08ebe0b38e929f3850ce49a38a3e3f84abe466cee401d3a98bc8e5208f3 at slot 38699454
Jan 15 22:51:06 nat cnode@mainnet[72665]: [nat:cardano.node.ChainDB:Notice:22] [2024-01-15 21:51:06.56 UTC] Chain extended, new tip: 141eb03ad77650bb9af77f191e4f3f537762aa9a1917defa316955df8d5695c8 at slot 113789175
Jan 15 22:51:17 nat cnode@mainnet[72665]: [nat:cardano.node.ChainDB:Notice:22] [2024-01-15 21:51:17.20 UTC] Chain extended, new tip: ee3e9f6afe03bb79f518f0a2de1b2dad55c0d5b45f351d270300f623ad552f1a at slot 113789185
Jan 15 22:51:19 nat cnode@preprod[72688]: [nat:cardano.node.ChainDB:Notice:20] [2024-01-15 21:51:19.17 UTC] Chain extended, new tip: b83c3c1c9f823224688b4d02827266eb93b5d27a4ddd0c49b278ac905addee31 at slot 49672279
^C
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 ~/.local/cardano/chains/
/home/sean/.local/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
19 directories, 33 files
$ du -h ~/.local/cardano/chains/
1.1M /home/sean/.local/cardano/chains/mainnet/config
4.7G /home/sean/.local/cardano/chains/mainnet/db/ledger
133M /home/sean/.local/cardano/chains/mainnet/db/volatile
151G /home/sean/.local/cardano/chains/mainnet/db/immutable
156G /home/sean/.local/cardano/chains/mainnet/db
156G /home/sean/.local/cardano/chains/mainnet
40K /home/sean/.local/cardano/chains/preprod/config
5.2G /home/sean/.local/cardano/chains/preprod/db/immutable
5.6M /home/sean/.local/cardano/chains/preprod/db/volatile
475M /home/sean/.local/cardano/chains/preprod/db/ledger
5.7G /home/sean/.local/cardano/chains/preprod/db
5.7G /home/sean/.local/cardano/chains/preprod
40K /home/sean/.local/cardano/chains/preview/config
6.4G /home/sean/.local/cardano/chains/preview/db/immutable
2.4M /home/sean/.local/cardano/chains/preview/db/volatile
602M /home/sean/.local/cardano/chains/preview/db/ledger
7.0G /home/sean/.local/cardano/chains/preview/db
7.0G /home/sean/.local/cardano/chains/preview
169G /home/sean/.local/cardano/chains/
Changelog
2024-01-15:
- Updated to Mithril v2347.0 and Cardano Node 8.7.3.
- Changed location of software and chains to
~/.local/cardano/
.