Staking on Ethereum with Rocketpool
To participate as a validator in Ethereum consensus, we have to stake 32 ETH, which is a lot. With Rocketpool, node operators only require 16 ETH to get started, and since that's all I have right now, this is what this document covers. This guide assumes a Linux machine, and I'm using Ubuntu 20.04 LTS.
#
Execution Node: ErigonFor our execution node, we'll go with Erigon. Erigon is a modular Ethereum archive node with a very efficient initial sync that runs in stages, and a relatively small, flat key-value database store. Erigon is written in Go, and there are some other clients on the way that follow this new architecture, e.g. Silkworm (C++) and Akula (Rust).
Archive nodes store and validate the complete Ethereum chain, right from block 0. This can be interesting if you want to inspect historical events, and do historical transaction tracing. There are some cool projects that build on these properties of Erigon:
- Trueblocks, a chain indexer to query the Ethereum blockchain
- Otterscan, a block explorer like Etherscan, but local (and faster)
Another fact about Erigon is that it is built in a modular way - you can run the RPC API, the transaction pool, or even the p2p stack as different processes that communicate back to the main erigon process over gRPC.
The modular architecture brings with it some great benefits, including the ability to run multiple rpcdaemons at once, or run the rpcdaemon on another machine. We'll just do it because there are some RPC methods that require a separate rpcdaemon. You can find more info on their Github Wiki.
#
StatisticsSyncing an Erigon archive node took around 76 hours in total on the following machine:
- CPU: AMD Ryzen 9 3900x (12 cores, 4.6 GHz)
- SSD: logical volume of 1 2TB Corsair Force MP600 and one 2TB Seagate Ironwolf 510
- RAM: 64GB of DDR4 (Corsair Vengeance, 2x 32 GB modules)
The sync consumed 700 GB of network traffic, and the total database size is 1.6 TB. If you run a geth node in archive mode, you'll need more than 6 TB of disk space.
#
Prerequisites#
Installationgit clone --recurse-submodules -j8 https://github.com/ledgerwatch/erigon.gitcd erigongit checkout stablemake erigon
We'll run the RPC API, rpcdaemon
in Erigon lingo, as a separate process, so we have to build that too:
make rpcdaemon
After building, we'll move the erigon directory to /srv
:
sudo mv erigon /srv/
This is the location where our systemd services will start the processes from.
#
Consensus Node: LighthouseAs a consensus node, we're going to install Lighthouse, built with Rust.
#
Prerequisites#
Installationgit clone https://github.com/sigp/lighthouse.gitcd lighthousegit checkout stablemake
# Move to system directorysudo mv lighthouse /srv/
To update:
cd /srv/lighthousegit fetchgit checkout ${VERSION}make
#
RocketpoolRocket Pool is the base layer protocol for decentralised and trustless ETH2 staking.
With Rocketpool, node operators can collaborate with stakers to create validators. A node operator (us) runs the infrastructure (execution, beacon node and validator), and stakes 16 ETH of his own together with some RPL tokens (10% of staked ETH) as collateral for slashing and performance insurance. Stakers can more easily participate because they only require a small amount of ETH to get started. Essentially, Rocketpool splits the difference between those who have the technical skills to run and maintain a node and those who lack the financial capacity to own 32 ETH.
As a node operator, you'll also get more ROI in the form of the slashing insurance premiums (RPL) and a commission rate (ETH).
#
SetupWe're going to run the execution and consensus clients as systemd services, each with their own service accounts. The service accounts will have limited access to the rest of the system, so if one of the clients is compromised, the damage will be contained. The Rocketpool smart node stack will run in Docker containers. This is the Hybrid Rocket Pool Node configuration.
Storage
The disks you will use as storage should be SSDs, HDD won't cut it. I've mounted some NVMe drives as logical volumes, so that I can easily increase capacity in the future. Stats:
- Erigon drive: 4 TB (right now, state is about 1.6 TB) NVMe
- Lighthouse drive: 1 TB NVMe
#
Setting up the servicesLet's start by creating the service accounts (without login) and service groups:
# -r is for system account, -s specifies shellsudo useradd -r -s /sbin/nologin erigonsudo useradd -r -s /sbin/nologin lighthouse
# service groupsudo groupadd ethereum
Next, change the ownership of the client directories:
sudo chown -R erigon:ethereum /srv/erigonsudo chown -R lighthouse:ethereum /srv/lighthouse
We have to be part of the ethereum
group with our main account to have write access
to the directories (for updating):
sudo usermod -aG ethereum $USER
#
Systemd service filesWe'll need the following systemd services:
- Erigon execution client
- Rpcdaemon for Erigon
- Lighthouse beacon node
[Unit]Description=ErigonAfter=network.target
[Service]Type=simpleUser=erigonRestart=alwaysRestartSec=5ExecStart=/srv/erigon/build/bin/erigon --datadir /mnt/eth-archive --maxpeers 100
[Install]WantedBy=multi-user.target
[Unit]Description=RpcdaemonAfter=network.target erigon.serviceWants=erigon.servicePartOf=erigon.service
[Service]Type=simpleUser=erigonRestart=alwaysRestartSec=5ExecStart=/srv/erigon/build/bin/rpcdaemon --datadir /mnt/eth-archive --ws --http.addr 0.0.0.0 --http.api eth,net,trace,erigon,web3
[Install]WantedBy=multi-user.target
[Unit]Description=Lighthouse Beacon NodeAfter=network.target rpcdaemon.serviceWants=rpcdaemon.servicePartOf=rpcdaemon.service
[Service]Type=simpleUser=lighthouseRestart=alwaysRestartSec=5ExecStart=/srv/lighthouse/target/release/lighthouse beacon --network mainnet --datadir /mnt/evo/lighthouse --port 9001 --discovery-port 9001 --eth1 --eth1-endpoints http://localhost:8545 --http --http-address 0.0.0.0 --http-port 5052 --eth1-blocks-per-log-query 150 --disable-upnp
[Install]WantedBy=multi-user.target
Listening addresses
The HTTP addresses on rpcdaemon and Lighthouse were changed to 0.0.0.0, because the Rocketpool node, which runs in a Docker container, otherwise can't reach them. But beware, these APIs are now listening on public interfaces, so make sure your firewall is running.
#
Installing Rocketpool#
Installing the CLIWe download the CLI following this Rocketpool guide:
wget https://github.com/rocket-pool/smartnode-install/releases/latest/download/rocketpool-cli-linux-amd64 -O ./rocketpool# Mark as executable and move to somewhere in $PATHchmod +x ./rocketpool && sudo mv ./rocketpool /usr/local/bin
Test running it with the --version
flag, which should output something like this:
$ rocketpool --version
rocketpool version 1.1.0
#
Installing the Smartnode StackWe can install the Smartnode Stack for mainnet like this:
rocketpool service install
Next, add yourself to the docker
group to use Docker without root privileges:
sudo usermod -aG docker $USER
You will have to restart your SSH session for these changes to take effect.
Docker installation
This will download Docker and docker-compose for you, if you already have these installed, run:
rocketpool service install -d
This will tell rocketpool to skip the dependencies.
#
Basic ConfigurationRun the following command:
rocketpool service config
This will start an interactive process to help with the configuration. For our ETH1 client, even though we're using Erigon, you can select Geth (1) and leave all the default options. We will later modify these.
For the ETH2 configuration, make sure to select Lighthouse. This is important, since the validator node is part of the Smartnode Stack and needs to be the same client as our Beacon Node. The default settings will do, but you can add your own custom Graffiti! This will be included on every block your validator produces, which is pretty cool.
As we've seen, the Smartnode Stack runs with docker-compose. We'll need to change the original compose file:
version: "3.4"services: eth1: image: ${ETH1_IMAGE} ... eth2: image: ${ETH2_IMAGE} ... depends_on: - eth1 validator: image: ${VALIDATOR_IMAGE} ... depends_on: - eth2 api: image: ${SMARTNODE_IMAGE} ... depends_on: - eth1 entrypoint: /bin/sleep command: "infinity" node: image: ${SMARTNODE_IMAGE} ... depends_on: - eth1 - eth2 watchtower: image: ${SMARTNODE_IMAGE} ... depends_on: - eth1 - eth2
Delete both the eth1
and eth2
sections of the configuration, and if they are in another services' depends_on
section,
remove them there too.
#
Creating Docker NetworksRight now, we're going to start and stop the smartnode stack. It won't work yet, but it will create the necessary Docker networks, which we need for later configuration.
rocketpool service startrocketpool service stop
This will have created a Docker network rocketpool_net
. Find the subnet with:
docker inspect rocketpool_net | jq .[0].IPAM.Config[0].Subnet
# Example:SUBNET="172.18.0.0/16"
We can now configure the firewall.
#
Firewall (using UFW)We need to open the correct ports on our machine:
# Erigonsudo ufw allow 30303 comment "Erigon eth65 p2p"sudo ufw allow 30304 comment "Erigon eth66 p2p"
# where $SUBNET is the Docker subnet you noted beforesudo ufw allow from $SUBNET to any port 8545 comment "Rocketpool to Erigon"# Lighthousesudo ufw allow 9001 comment "Lighthouse p2p"
sudo ufw allow from $SUBNET to any port 5052 comment "Rocketpool to Lighthouse beacon node"
Right now the APIs are only reacheable from inside the Docker containers. If you want to reach them from other machines on your network, configure the firewall accordingly.
Port forwarding
If your machine is behind a router or firewall, make sure to configure port forwarding. This is important for maintaining good connectivity and allowing other peers to discover you.
#
Configuring RocketpoolWe've already done some basic configuration in ~/.rocketpool/docker-compose.yml
, but we're not done yet.
The next file we need to configure is ~/.rocketpool/config.yml
:
rocketpool: ...smartnode: ...chains: eth1: provider: http://eth1:8545 wsProvider: ws://eth1:8546 ... eth2: provider: http://eth2:5052 ...
The hosts that are filled in by default (eth1
, eth2
) are normally resolved inside of the Docker network.
Since we're not running these services as Docker containers, we'll need to modify them. Replace
all the providers with the gateway IP of $SUBNET
(if your SUBNET was 172.18.0.0/16
, your http provider will
be http://172.18.0.1:8545
). Your ws provider will be ws://172.18.0.1:8545
, since Erigon uses the same ports
for both HTTP and WebSockets. Do the same for the eth2
provider.
This networking setup will work since we configured UFW to accept connections coming from the Docker network.
#
Running#
Starting the Rocketpool ServiceWe have done enough configuration for now, and can finally start the service. Use this command:
rocketpool service start
Creating network "rocketpool_net" with the default driverCreating rocketpool_api ... Creating rocketpool_api ... doneCreating rocketpool_watchtower ... Creating rocketpool_node ... Creating rocketpool_validator ... Creating rocketpool_validator ... doneCreating rocketpool_node ... doneCreating rocketpool_watchtower ... done
I have included the output, and this is more or less what your output should look like as well.
If you need to stop the service to do some system maintenance or upgrade the rocketpool stack, use:
rocketpool service stop
Are you sure you want to pause the Rocket Pool service? Any staking minipools will be penalized! [y/n]y
Stopping rocketpool_node ... Stopping rocketpool_validator ... Stopping rocketpool_watchtower ... Stopping rocketpool_api ... Stopping rocketpool_validator ... doneStopping rocketpool_node ... doneStopping rocketpool_watchtower ... doneStopping rocketpool_api ... done
#
Checking the ServicesWe can check the service version and networks with rocketpool service version
.
Checking if all the containers are running can be done with docker ps
:
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMEScc23bb9f1f7c sigp/lighthouse:v2.0.1 "sh /setup/start-val…" 2 days ago Up 2 days rocketpool_validator0cbe6a5f4997 rocketpool/smartnode:v1.1.0 "/go/bin/rocketpool …" 2 days ago Up 2 days rocketpool_nodea4223e20252e rocketpool/smartnode:v1.1.0 "/go/bin/rocketpool …" 2 days ago Up 2 days rocketpool_watchtower681f8a9744c1 rocketpool/smartnode:v1.1.0 "/bin/sleep infinity" 2 days ago Up 2 days rocketpool_apib1dc152f1391 grafana/grafana:8.1.1 "/run.sh" 8 weeks ago Up 2 days 3000/tcp, 0.0.0.0:3100->3100/tcp, :::3100->3100/tcp rocketpool_grafanafcfa50d3f3bf prom/node-exporter:v1.2.2 "/bin/node_exporter …" 8 weeks ago Up 2 days rocketpool_exportere274309e596a prom/prometheus:v2.28.1 "/bin/prometheus --w…" 8 weeks ago Up 2 days 9090/tcp rocketpool_prometheus
info
This might look different if you didn't configure for analytics during the setup.
Further logs can be obtained with rocketpool service logs
for all logs, or rocketpool service logs <service>
, to get the logs
for a specific service (validator
or node
for example).
#
Setting up a WalletNow that all the services are running, we need to set up an ETH1 wallet for the node. This wallet will
- Hold ETH to pay for various actions on the network (creating a new minipool, staking your RPL)
- Hold the ETH that you're going to send to your minipool to start staking
- Hold the RPL that you're going to stake
We're going to use the rocketpool
cli to create this wallet:
rocketpool wallet init
This will prompt you for a password to protect your private key and give you back a 24-word mnemonic that
is your recovery phrase. Your password will be written to ~/.rocketpool/data/password
in CLEARTEXT, so make sure
there's no one else on your system. Your wallet private key is at ~/.rocketpool/data/wallet
.
warning
Please write down your recovery phrase, but KEEP IT SAFE. This phrase can be used to import your wallet and all validators attached to a new machine, and anyone that has this phrase has full control over your private key.
#
Loading up the FundsBefore we can create a minipool, we need 16 ETH, extra ETH for gas fees, and some RPL in our node wallet. The RPL value should be at least 10% of the value of your ETH in USD. You can read more about the purpose of RPL in [3].
#
Registering the NodeOnce the funds are in the wallet, we can register our node with the Rocketpool network:
rocketpool node register
This will prompt you for your timezone, as well as sending a transaction. Make sure the gas price is not ridiculously high. You can now check your RPL and ETH balances:
rocketpool node status
By default, all your RPL rewards, as well as your staked ETH and RPL will be sent to your wallet address when claiming the rewards or exiting your validator. If you want to change this, follow this guide.
#
Setting up a MinipoolThis is where things get interesting, and potentially dangerous. Make sure you're ready to stake 16 or 32 ETH, as well as a non-trivial amount of RPL. Also make sure your secrets are secret, and be diligent about it.
#
Staking RPLThe first step in setting up a validator is to stake your RPL. This should be at least 10% of the value of your ETH, and the more you stake, the more you earn (capped at 150% of your ETH value).
info
This stake counts for your entire node, so if you want to run multiple minipools, this is possible without buying and staking more RPL.
Start staking with the following command:
rocketpool node stake-rpl
This will prompt you for the amount you want to stake, so you don't have to calculate it yourself:
Please choose an amount of RPL to stake:1: The minimum minipool stake amount (284.477473 RPL)?2: The maximum effective minipool stake amount (4267.162095 RPL)?3: Your entire RPL balance (1440.000000 RPL)?4: A custom amount
On confirmation, you'll have to allow 2 transactions. Once these are confirmed, you can check your staked balance:
rocketpool node status
The node has a total stake of 11763.477483 RPL and an effective stake of 11763.477483 RPL, allowing it to run 41 minipool(s) in total.This is currently a 10.88% collateral ratio.The node must keep at least 10810.143971 RPL staked to collateralize its minipools and claim RPL rewards.
Make sure your collateral ratio is above 10%, or you won't be able to collect any RPL staking rewards.
warning
Your nodes should be synced before moving on to the next step, or you will lose rewards.
#
Staking ETH and Creating a MinipoolWe're now ready to finally stake our ETH and put our node up to become a validator:
rocketpool node deposit
You will be prompted to deposit either 16 or 32 ETH, we'll be going with 16. This will put us in the minipool queue, where we wait for 16 ETH to become available from stakers in the rETH staking pool. Once we hit the front of the queue and the ETH is available, it will be combined with our own 16 ETH to create a minipool and deposit the 32 ETH to the Beacon Chain deposit contract. Thus our validator is born!
First we have to confirm the transaction though. You will have to set a commission slippage rate, but chances are the commission rate is 5%, which is the lowest it can go. So just accept the suggested slippage rate. If this is not the case, you can read more about it here.
caution
This is an expensive transaction, and the total cost in ETH will be displayed in the prompt. Make sure you're okay with the cost before confirming.
#
Confirming Minipool CreationConfirming the succesful creation of the minipool can be done with the following command:
rocketpool minipool status
Your minipool will go through a couple stages before being finalized. First, it will enter the initialized
stage,
which means your minipool is currently in the queue waiting to be assigned 16 ETH from the network. You can check your
position in the queue here, where you can enter your node address.
Once the ETH is received and 32 of it is sent to the Beacon Chain contract, you will enter the prelaunch
state. This is currently
a period of 12 hours wherein all kinds of checks are performed. After this period, your validator will be activated and the
minipool will enter the staking
stage. You can also follow this process on beaconcha.in (find
your validator public key by looking up your node minipool creation transaction on etherscan).
info
If at any time during the process something didn't work as expected, I suggest you to check your logs with rocketpool service logs
.
Also look at the logs of your Erigon and Lighthouse, as something might be wrong in that part of the stack as well.
If you got here, you're now officially a validator on the Ethereum network, congratulations! There are a couple ways to check your rewards:
- You can look at beaconcha.in, but this will only show rewards for the whole validator, or
- You can check out the Grafana dashboard that's running on port
3100
(if you set it up), which will show you all kinds of cool metrics. Read more about them here. I highly recommend setting this up!
#
Sources[1] Rocketpool Docs