In honor of Cardano on the rocks
This article is meant as an update on the excellent “CARDANO on the ROCKS” article, historic recap and video by Markus Gufmar from 2019. Here Markus showed that a RockPi 4 with 8GB RAM could run Cardano Node extremely efficiently with under 5watts of energy consumption per node.
If you like this article, consider staking to Ada North Pool (Ticker ANP) either through decentralized wallet staking, or if you are trading on an exchange you can stake directly on nbx.com as well.
Recently the Rock Pi 5b started shipping, and I was lucky enough to get a few as I have been on the waiting list for it for quite long. It can go up to 32 GB of PDDR4x RAM, but the model mostly available goes up to 16GB ram. The CPU has 4 cores that run at 2.4GHZ and 4 cores that run at 1.8GHZ. Luckily this is exactly within the specifications of the Cardano-node that requires a minimum of 16GB RAM and 1.8GHZ from the CPU.
Assembly and installation of OS.
Assembly is fairly straightforward. You can use an SD card or an eMMC card. You will need to be able to flash it with an image through software, in my case, I flashed the Ubuntu 20.04 server image. I had some hiccups in booting up the device at first, as many others have. This is natural with a very new device and will get better once drivers improve. The problem was in how the board auto-negotiated power and could be fixed by booting up first with a “dumb” USB power plug that did not support auto-negotiation. With that, you could boot and access the board from SSH. Then it was a matter of upgrading Ubuntu (sudo apt update, then sudo apt upgrade), and it would work fine on any power device after this. There was also this bug with the fan that you could fix by installing a fan controller. To add the NVME I used lsblk to find the /dev/ path of my NVME and then used mkfs -t ext4 /dev/nvme0n1 to make a file system for the NVME. To mount it I found the UUID with ls -l /dev/disk/by-uuid and then in the file /etc/fstab I added that UUID=*your uuid* /opt ext4 defaults,noatime 0 0
To test I simply ran as sudo mount -a.
Setting up the OS for success.
I installed Glances to be able to view resource usage, as well as jq curl and ne (sudo apt install jq curl ne glances). I use nice editor as my text editor as I am weird and don't use the default Linux text editor :)
To tune the device I installed tuned (sudo apt install tuned tuned-utils tuned-utils-systemtap), enabled it (sudo systemctl enable — now tuned) and selected profile for network latency (sudo tuned-adm profile network-latency). I also added a timesync server with chrony (sudo apt-get install chrony -y) and configured it with my own timesync server together with time.cloudflare.com as shown in the image:
Then I added in /etc/sysctl.conf settings to tune TCP performance and make it more secure:
# Use Google's congestion control algorithm
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
#Prevent SYN attack, enable SYNcookies (they will kick-in when the #max_syn_backlog reached)
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_max_syn_backlog = 4096# Disables IP source routing
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
# Add if ip6 used:
net.ipv6.conf.all.accept_source_route = 0
net.ipv6.conf.default.accept_source_route = 0# Enable IP spoofing protection, turn on source route verification
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1# Disable ICMP Redirect Acceptance
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0# Enable Log Spoofed Packets, Source Routed Packets, Redirect #Packets
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1# Don't relay bootp
net.ipv4.conf.all.bootp_relay = 0# Don't proxy arp for anyone
net.ipv4.conf.all.proxy_arp = 0# Turn on the tcp_timestamps, accurate timestamp make TCP congestion # control algorithms work better
net.ipv4.tcp_timestamps = 1# Enable ignoring broadcasts request
net.ipv4.icmp_echo_ignore_broadcasts = 1
# Enable bad error message Protection
net.ipv4.icmp_ignore_bogus_error_responses = 1# Enable a fix for RFC1337 - time-wait assassination hazards in TCP
net.ipv4.tcp_rfc1337 = 1# Accept packets with SRR option? No
net.ipv4.conf.all.accept_source_route = 0# Ignore all ICMP ECHO and TIMESTAMP requests sent to it via
net.ipv4.icmp_echo_ignore_broadcasts = 1# Ignore bad ICMP errors
Then I reloaded the sysctl config by:
sudo sysctl -p /etc/sysctl.conf
Compiling cardano-node and cardano-cli
I followed the guide from developers.cardano.org, but in the step to build the files, I added in the cabal.project.local two lines:
I also built with the -O2 flag, meaning to compile it with more optimization where it would “Apply every non-dangerous optimization, even if it means significantly longer compile times”.
I also had to fix symbol linking to one of the libraries used by running:
sudo ln -s /usr/local/lib/libsecp256k1.so.0/usr/lib/libsecp256k1.so.0
The files had to be moved from inside the dist-newstyle folder (I could probably have set the install folder when building), and I copied the cardano-node and cardano-cli binaries to /opt/cardano/bin that I had created and appended the version number 1.35.4. I then made the user rock the owner with sudo chown -R rock:rock /opt/cardano. (I could also have created a cardano user for this).
Setting up scripts and services for cardano-node
I then created the folders db sockets config/node1 and scripts inside the /opt/cardano folder.
In the config folder I grabbed the mainnet configuration files inside /config/node1. I then set up a systemd service with sudo ne /etc/systemd/system/adarelay.service and the following configuration:
To enable the systemd for reboots you just run sudo systemctl enable adarelay.service, and you can start and restart it with systemctl restart adarelay.service.
To view the node in the script folder I grabbed the Guild LiveView script.
I then edited its env files and made sure it pointed to my renamed binaries as well as the correct port (in my case 8013).
At this point, you would have a live node contributing to the network after the initial synching period, and that would be fairly optimized for the Rock Pi 5b with the settings in the example above. Here is an example of running a timesync server together with 3 Rock Pi 5b boards that I am using for the different testnets:
Further things to do:
I would next secure SSH, add UFW firewall settings and in general harden and optimize the server. I could also then make this a core node (pool validator), configure the topology and configuration files of the node further, and another fun thing to do would be to add mithril signer support. (Perhaps I will show this in another guide on the preprod testnet).