Raspberry Pi4

Ethereum Full Node on a Raspberry Pi4

The following is a list of steps to follow to have you own fully operational Ethereum full node (note: not an archive node) runnnin on geth on a Raspberry Pi4.

In order to follow this guide a little experience with Linux is recomended. 

Hardware Requirements:

You can easylly find those at Amazon, total cost is under 180€

Initial steps

There are a few initial steps that require you to set up the Raspberry so that it boots properly and works. There are tons of tutorials and a nice official documentation about that so I won’t go over it here.

Here they are:

  • download the most recent image of the OS
  • use balena etcher to write it to the SD card
  • boot and login as root
  • run an “apt-get update” + “apt-get upgrade”
  • setup networking so that you can navigate
  • connect the SSD
  • format and partition as 1 single ext4 partition
  • create a folder /mnt/Ethereum
  • edit fstab to mount the ssd under /mnt/Ethereum

At this point you should have a Raspberry working. Reboot and check that you can access internet and have the ssd partition mounted.

 

Optimizations for Raspberry Pi4

Decrease the RAM allocated to the GPU. Edit /boot/config.txt and add or edit the following line:

gpu_mem=16

Invoke 64 bits kernel. Edit /etc/systemd/system.conf, and add or edit the following line:

arm_64bit=1

Reboot for the changes to take effect

SSD speed Requirements  

Before moving forward, your setup requires a very high-speed disk IO throughput. You can test the performance of your SSD disk using the following commands:

Disk write:

$ dd if=/dev/zero  of=/mnt/Ethereum/deleteme.dat bs=32M count=64 oflag=direct
64+0 records in
64+0 records out
2147483648 bytes (2.1 GB, 2.0 GiB) copied, 13.6021 s, 158 MB/s

Disk read:

$ dd if=/mnt/Ethereum/deleteme.dat of=/dev/null bs=32M count=64 iflag=direct
64+0 records in
64+0 records out
2147483648 bytes (2.1 GB, 2.0 GiB) copied, 22.3361 s, 96.1 MB/s

Below 50MB/s (write/read), I wouldn’t recommend trying to syncing a Geth node because you might never be able to reach the head and complete the sync.

Remove /mnt/ssd/deleteme.dat after the performance test.

Move swap to SSD   

Geth can consume a lot of memory during the syncing process so it is highly suggested that you create a swap file (overflow RAM) to prevent any kind of OutOfMemory error. It is also strongly advised to put the swap file on the fastest disk, which is the SSD in our case.

Edit the file /etc/dphys-swapfile

  • replace CONF_SWAPSIZE=100 by CONF_SWAPSIZE=8192 to allocate a 8GB SWAP with CONF_SWAPSIZE=8192
  • replace CONF_SWAPFILE=/var/swap to locate the swap on the SSD CONF_SWAPFILE=/mnt/Ethereum/swap.file 
$ sudo vi /etc/dphys-swapfile
CONF_SWAPSIZE=8192
CONF_MAXSWAP=8192
CONF_SWAPFILE=/mnt/Ethereum/swap.file
  • Restart the swap
$ sudo /etc/init.d/dphys-swapfile restart

Install Geth

You can use a pre-build binary or compile from source. Unless you have specific need just go with the prebuild stable version.

Prebuild binary (easy peasy)

Head to https://geth.ethereum.org/downloads/ and download the right stable version for your architecture (ARM).

Congratulations, you are almost done

Geth form source (are you sure?)

First you have to download and install Go.

Get your CPU and OS version Navigate to https://golang.org/dl/ and get the last available release for ARM

wget https://golang.org/dl/go1.15.3.linux-armv6l.tar.gz
sudo tar -C /usr/local -xvf go1.15.3.linux-armv6l.tar.gz
sudo chown root:root /usr/local/go
sudo chmod 755 /usr/local/go

Add GO to your path. Depending on the shell you are using you might need to change a different .rc file (/etc/profile, .bashrc, .zshrc…). Change the configuration file, reload it and test. Somehow like this:

export PATH=$PATH:/usr/local/go/bin
echo $PATH
go version

Then

sudo apt install unzip git sysstat ntpdate
sudo apt install make htop build-essential

Get the last version of geth from the git repo and compile it

git clone https://github.com/ethereum/go-ethereum.git
cd go-ethereum
make geth

… wait some minutes …

The running environment

Folder structure

Assuming that your SSD partition is mounted under /mnt/Ethereum, proceed to make a similar working directory structure for geth

├── bin
│ ├── geth -> geth-1.9.23-stable
│ └── geth-1.9.23-stable
├── datadir
│ ├── geth
│ │ └── chaindata
│ └── keystore
└── geth.sh


Add geth to your system path (make sure /usr/local/bin is in that path)

cd /usr/local/bin
ln -s /mnt/Ethereum/geth/bin/geth . 

Launch Script

Now we write the geth.sh script you saw before. This launch script is a convenient way to run geth with all the configurable parameters you want.

Have a look at https://github.com/ethereum/go-ethereum/wiki/Command-Line-Options for all the options.

Write this file as /mnt/Ethereum/geth/geth.sh

#!/bin/bash

## DEFINE PARAMS
SYNCM="--syncmode fast"
CACHE="--cache 256"
GARBC="--gcmode full"
DATAD="--datadir /mnt/Ethereum/geth/datadir"

IDENT="--identity BlockchainCaffe"
#ETHST="--ethstats should be nodename:secret@host:port"

RPC='--rpc --rpccorsdomain "*" --rpcapi="db,eth,net,web3,personal,web3" --allow-insecure-unlock'
WSC='--ws --wsaddr "localhost" --wsport "8546" --wsorigins "*" --wsapi="db,eth,net,web3,personal,web3"'

GETH_PARAMS="$SYNCM $CACHE $GARBC $DATAD $IDENT $ETHST $RPC $WSC"

## SET TIME
ntpdate -s time.nist.gov

## START GETH
eval "/usr/local/bin/geth ${GETH_PARAMS}"


Systemctl Service

We will start the node as a service, so that it starts at boot in the background.

First we create the service script:


cat > /etc/systemd/system/eth-node.service <<'EOF'
Description=Ethereum (geth) Node Service
After=network.target

[Service]
Type=simple
User=root
WorkingDirectory=/mnt/Ethereum/geth
ExecStart=/mnt/Ethereum/geth/geth.sh
Restart=on-failure
RestartSec=60
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=Geth

[Install]
WantedBy=default.target
EOF

Them we enable and start the script

systemctl start eth-node
systemctl enable eth-node


Then check the status with

systemctl status eth-node

Running The node

Open a couple of shells (tmux is your friend) and monitor the node activity 

journalctl -f | grep -i geth

start the node with

systemctl start/stop/restart eth-node

allow some time to connect to another node (peer-2-peer/UDP) or provide some boot-nodes. Then the Block sync will Start

Each new block downloaded will show in a new journalctl log line and look like this:

Oct 19 12:56:45 cloudpi Geth[30657]: INFO [10-19|12:56:45.545] 
Imported new block receipts count=2048 elapsed=2.181snumber=1272935 hash="f64f40…85c7f1" age=4y7mo1w size=3.79MiB


the age parameters will gradually shorten and go to zero

 

Now just wait

Once all this is up and running (even afther a reboot) it will take some time to have a fully operational node. There are a few steps that will take quite some time:

  • connecting to peers
  • download the chain to disk
  • sync the status

At the time of the writing of this post (October 2020) the numbers are:

  • size of the chaindata folder : 320Gb
  • time to download the chaindata : about 28 hrs
  • time to complete the sync : about 10 days.

You can connect to the node and use CLI commands to check on it

/mnt/Ethereum/geth/datadir
geth attach geth.ipc

Once in the CLI mode some usefull commands are:

net.listening   # are we able to get connections?
net.peerCount  # how many other nodes are we connected to
admin.peers  # list of peers we are connected to
admin.nodeInfo  # info about the node
eth.syncing  # are we syncing? how much work left to do?