Running Nethermind Post Merge

Introduction

The long awaited shift from Proof of Work (POW) to Proof of Stake (POS) in Ethereum otherwise known as The Merge adds a lot to Ethereum. The most notable change is the addition of the Beacon chain (Consensus layer) which replaces Proof of Work mining. It will coordinate and pseudorandomly select block producers from the pool of stakers / validators in a way that makes it extremely difficult for validators to coordinate attacks on the network.
The Merge also changes how operators run nodes on the Ethereum blockchain. The biggest change being that a node now consists of two clients that work together as a pair. You still need to run an Execution Layer client (EL client) such as Nethermind that will connect to the existing chain. Nethermind will still build and validate blocks similar to before except mining will not longer work after The Merge. In addition to the EL client you will need a Consensus Layer client (CL client) that connects to the Beacon chain and runs the POS algorithm.
This guide will show you everything you need to know to operate an Ethereum node after The Merge. It will show how to connect to the Kiln and Ropsten test networks as well.
An easy way to run both CL and EL clients is by using Sedge. Sedge is a one click setup tool for PoS network/chain validators and nodes. Currently, Sedge supports multiple Linux distributions and MacOS.
Hello from Sedge documentation | Sedge documentation
To do your setup manually follow the steps below.

Step 1: Installing Nethermind

Installing Nethermind is the same as before The Merge. You can choose from downloading the official release, downloading the docker image, or building Nethermind from source.
Support for post merge Ropsten is available as of Nethermind version 1.13.1

Downloading Official Release

Ubuntu

Run the following commands to enable our launchpad repository run then install Nethermind
sudo add-apt-repository ppa:nethermindeth/nethermind
sudo apt install nethermind

macOS

Run the following commands to add the Nethermind repository to your local Homebrew and install
brew tap nethermindeth/nethermind
brew install nethermind

Windows

On Windows all you have to do is install and unzip the packages. There are two sources that you can download from.
Nethermind - Downloads
Releases · NethermindEth/nethermind
GitHub

Downloading Docker Image

To download the latest Docker image run the following command to install the latest Debian biased Nethermind image.
docker pull nethermind/nethermind
Currently Nethermind only supports images for AMD64 and ARM64 CPU architectures.

Building From Source

Installing Dependencies

To build Nethermind you will need to have Git and the .NET SDK 6.0 installed.
Git - Downloads
Download .NET (Linux, macOS, and Windows)
Microsoft
Depending on the platform you are using you may need to install extra dependencies.

Windows

You may need to install Microsoft Visual C++ Redistributable

macOS

You will need to install the following packages.
brew install gmp snappy lz4 zstd

Apple Silicon (M1) users only

You will need to create symlink for homebrew dependencies.
sudo ln -s find /opt/homebrew/Cellar/snappy -name "libsnappy.dylib" /usr/local/lib/libsnappy.dylib

Ubuntu 18.04 and Debian 10

You will need to install the following packages
sudo apt-get update && sudo apt-get install libsnappy-dev libc6-dev libc6
Commands for other Linux distros can be found here.

Building Nethermind

After you have installed all of the dependencies for your platform you need to clone the Nethermind repo from GitHub.
Once the download has finished enter the nethermind/src/Nethermind directory and run the build command.
git clone --recursive https://github.com/NethermindEth/nethermind.git
cd nethermind/src/Nethermind
dotnet build Nethermind.sln -c Release

Step 2: Installing Consensus Client

On the Consensus Layer you have five client implementations to chose from. Though all CL clients are great check them out for yourself and find the client best suited to your needs.
We urge you to take client diversity into consideration when choosing your CL client and avoid majority clients.
Client Diversity | Ethereum
Client Diversity | Ethereum

Prysm

Prysmatic Labs
Prysmatic Labs

Teku

Teku | Ethereum 2.0 Client for Institutional Staking | ConsenSys
ConsenSys

Lighthouse

Lighthouse
Lighthouse

Lodestar

lodestar.chainsafe.io | Chainsafe Systems

Nimbus

Nimbus, a Lighter Ethereum Client

Step 3 : Configure JSON-RPC API

The Merge adds changes the JSON-RPC API. Such as the Engine API, JWT authentication, additional RPC ports, and additional block tags.

JWT Secrets

JSON Web Token authentication was added to the JSON-RPC API for security reasons to ensure that nothing interferes with the communication between the Execution client(Nethermind in this case) and the Consensus client. This requires you to create a .txt file containing a hexadecimal “secret” that will be passed to each .
JWT.IO
To create this “Secret File” use the following command.
openssl rand -hex 32 | tr -d "\n" > "/tmp/jwtsecret"
Install OpenSSL for Windows
Binaries - OpenSSLWiki
then simply type on your Terminal or Command Prompt (make sure you add the binaries directory to your environment variables or run the terminal from there)
where "/tmp/jwtsecret" will be the file path and name when created.
If you do not want to install OpenSSL, you may use a random hex generator website. All you need is a 64 character hex string saved to a .txt file.
fcba4ab3138530cf233568bee2d518dd960da77355333d5ac856e1f27487dc9c
We strongly recommend you use OpenSSL to generate the secret locally because it is more secure

JsonRpc Configuration Module

Nethermind has added some additional configuration settings for the JSON-RPC API.
"JsonRpc": {
"Enabled": true,
"Timeout": 20000,
"Host": "127.0.0.1",
"Port": 8545,
"EnabledModules": ["Eth", "Subscribe", "Trace", "TxPool", "Web3", "Personal", "Proof", "Net", "Parity", "Health"],
"AdditionalRpcUrls": ["http://localhost:8551|http;ws|net;eth;subscribe;engine;web3;client"],
"JwtSecretFile": "keystore/jwt-secret"
},

AdditionalRpcUrls

This setting allows you to chose which port you want to use, whether its sent over HTTP and or WebSockets, which APIs you want enabled on that port, and if you want to disable JWT authentication on that port.

JwtSecretFile

This setting is used to identify the location of the file containing the JWT secret.
Nethermind will create it's own jwtsecret file if you do not specify a location or pass the wrong location.
For more information about possible configurations for JSON RPC Please refer to the article below:

Step 4: Run Nethermind

The steps to running Nethermind after The Merge have not changed much. After you have:
  • Installed Nethermind
  • Installed Consensus client
  • Created a JWT secret file
  • Ensured that an authenticated port with the Engine module is enabled
Then you are ready to start your clients. First start up Nethermind.

Choosing the Network

Depending on the network you want to run the node for, choose the --config variable. for more on networks, check here.
--config is the config file for the network you want to connect to. For example, to run a node for the kiln testnet use --config kiln

Running Local Build

After you have built Nethermind you should be in the nethermind/src/Nethermind directory. From there you will need to run the following commands
cd Nethermind.Runner
dotnet run -c Release -- --config ropsten --JsonRpc.JwtSecretFile=PATH
Where PATH is the path to your JWT secret. ex --JsonRpc.JwtSecretFile=/tmp/jwtsecret

Running Release

You have two options when running from a release. The Nethermind.Launcher which is a simple GUI with options to configure your node, or the Nethermind.Runner where you can configure your node by hand.
You will need to be in the directory that the Nethermind.Runner and Nethermind.Launcher are in to run Nethermind.

Nethermind.Launcher

Windows
Ubuntu
macOS
./Nethermind.Launcher
nethermind
nethermind-launcher

Nethermind.Runner

Windows
Ubuntu
macOS
./Nethermind.Runner --config ropsten --JsonRpc.JwtSecretFile=PATH
nethermind --config ropsten --JsonRpc.JwtSecretFile=PATH
nethermind --config ropsten --JsonRpc.JwtSecretFile=PATH
Where PATH is the path to your JWT secret. ex --JsonRpc.JwtSecretFile=/tmp/jwtsecret

Running Docker Image

Running Nethermind from a Docker image may require more configuration depending on the situation.
The commands below should work in most situations
docker run -it -v /home/user/data:/nethermind/data nethermind/nethermind nethermind/nethermind --config ropsten --JsonRpc.Enabled true --JsonRpc.JwtSecretFile=PATH --datadir data

Docker Settings

  • -v /home/user/data:/nethermind/data sets local directory we will be storing our data to
On some OS like Amazon Linux ****you may need to increase the nofile limit by adding the following instruction to docker command -ulimit nofile=1000000:1000000 or you can take a look an alternative solution.

Nethermind Settings

  • --JsonRpc.JwtSecretFile=PATH where PATH is the location of your JWT secret ex. /tmp/jwtsecret
  • --datadir data maps the database, keystore, and logs all at once

TTD Configuration (Important)

For Nethermind to sync to Ropsten or Goerli you will have to set the MergeTotalTerminalDifficulty. You will need to edit your config or set manually during launch.
Ropsten
Goerli
There is two ways to set the TTD:
  1. 1.
    From startup arguments, make sure the following flag is added to the start up command when launching.
--Merge.TerminalTotalDifficulty="50000000000000000"
2. From config,
"Merge": {
"Enabled": true,
"TerminalTotalDifficulty": "50000000000000000"
}
There is two ways to set the TTD:
  1. 1.
    From startup arguments, make sure the following flag is added to the start up command when launching.
--Merge.TerminalTotalDifficulty="10790000"
2. From config,
"Merge": {
"Enabled": true,
"TerminalTotalDifficulty": "10790000"
}

Step 5: Run Consensus Clients

Once Nethermind has started you can start the CL client. See section below for commands to run the CL client you installed. You will need to make sure the --jwt-secret has the correct path as well or the clients will not be able to communicate.
Once both clients are running watch the logs to make sure you don’t get any Unauthorized errors to ensure the clients are communicating.
That’s about all there is to it. Easy right?

Running on Kiln

To run on the kiln testnet, lodestar, nimbus and prysm require cloning the kiln configs.
git clone https://github.com/eth-clients/merge-testnets.git
cd merge-testnets/kiln
For more detailed instructions on running the consensus clients on kiln, see here.
To sync the CL client using a checkpoint sync, see here. This is only applicable on Goerli, Ropsten or Sepolia.

Running Nimbus With Nethermind

Ropsten
Goerli
Kiln
nimbus-eth2/build/nimbus_beacon_node \
--network=ropsten \
--web3-url=http://127.0.0.1:8551 \
--rest \
--metrics \
--suggested-fee-recipient=<Enter-eth-address-here> \
--jwt-secret="/tmp/jwtsecret"
nimbus-eth2/build/nimbus_beacon_node \
--network=goerli \
--web3-url=http://127.0.0.1:8551 \
--rest \
--metrics \
--suggested-fee-recipient=<Enter-eth-address-here> \
--jwt-secret="/tmp/jwtsecret"
nimbus-eth2/build/nimbus_beacon_node \
--network=merge-testnets/kiln \
--web3-url=ws://127.0.0.1:8551 \
--rest \
--metrics \
--log-level=DEBUG \
--terminal-total-difficulty-override=20000000000000 \
--jwt-secret="/tmp/jwtsecret" \
--suggested-fee-recipient=<Enter-eth-address-here> \
--eth1.depositContractDeployBlock=0

Running Prysm With Nethermind

Ropsten
Goerli
Kiln
cd prysm
bazel run //beacon-chain -- \
--ropsten \
--datadir $db_path \
--suggested-fee-recipient=<Enter-eth-address-here> \
--http-web3provider=http://localhost:8551 \
--bootstrap-node=enr:-Iq4QMCTfIMXnow27baRUb35Q8iiFHSIDBJh6hQM5Axohhf4b6Kr_cOCu0htQ5WvVqKvFgY28893DHAg8gnBAXsAVqmGAX53x8JggmlkgnY0gmlwhLKAlv6Jc2VjcDI1NmsxoQK6S-Cii_KmfFdUJL2TANL3ksaKUnNXvTCv1tLwXs0QgIN1ZHCCIyk
--jwt-secret=/tmp/jwtsecret
cd prysm
bazel run //beacon-chain -- \
--goerli \
--datadir $db_path \
--suggested-fee-recipient=<Enter-eth-address-here> \
--http-web3provider=http://localhost:8551 \
--jwt-secret=/tmp/jwtsecret
cd prysm
bazel run //beacon-chain -- \
--genesis-state $genesis_state_path \
--datadir $db_path \
--suggested-fee-recipient=<Enter-eth-address-here> \
--http-web3provider=$execution_server \
--execution-provider=http://localhost:8551 \
--chain-config-file=$config_path \
--bootstrap-node=enr:-Iq4QMCTfIMXnow27baRUb35Q8iiFHSIDBJh6hQM5Axohhf4b6Kr_cOCu0htQ5WvVqKvFgY28893DHAg8gnBAXsAVqmGAX53x8JggmlkgnY0gmlwhLKAlv6Jc2VjcDI1NmsxoQK6S-Cii_KmfFdUJL2TANL3ksaKUnNXvTCv1tLwXs0QgIN1ZHCCIyk
--jwt-secret=/tmp/jwtsecret

Running Lighthouse With Nethermind

Ropsten
Goerli
Kiln
lighthouse \
--spec mainnet \
--network ropsten \
--debug-level info \
beacon_node \
--datadir ./testnet-lh1 \
--eth1 \
--http \
--http-allow-sync-stalled \
--metrics \
--merge \
--execution-endpoints http://127.0.0.1:8551 \
--enr-udp-port=9000 \
--enr-tcp-port=9000 \
--discovery-port=9000 \
--suggested-fee-recipient=<enter-eth-address-here> \
--jwt-secrets="/tmp/jwtsecret"
lighthouse \
--spec mainnet \
--network goerli \
--debug-level info \
beacon_node \
--datadir ./testnet-lh1 \
--eth1 \
--http \
--http-allow-sync-stalled \
--metrics \
--merge \
--execution-endpoints http://127.0.0.1:8551 \
--enr-udp-port=9000 \
--enr-tcp-port=9000 \
--discovery-port=9000 \
--suggested-fee-recipient=<enter-eth-address-here> \
--jwt-secrets="/tmp/jwtsecret"
lighthouse \
--spec mainnet \
--network kiln \
--debug-level info \
beacon_node \
--datadir ./testnet-lh1 \
--eth1 \
--http \
--http-allow-sync-stalled \
--metrics \
--merge \
--execution-endpoints http://127.0.0.1:8551 \
--enr-udp-port=9000 \
--enr-tcp-port=9000 \
--discovery-port=9000 \
--suggested-fee-recipient=<enter-eth-address-here> \
--jwt-secrets="/tmp/jwtsecret"

Running Lodestar With Nethermind

Ropsten
Goerli
Kiln
cd lodestar
./lodestar beacon \
--rootDir="../lodestar-beacondata" \
--network ropsten \
--eth1.enabled=true \
--execution.urls="http://127.0.0.1:8551" \
--network.connectToDiscv5Bootnodes \
--network.discv5.enabled=true \
--chain.defaultFeeRecipient=<Enter-eth-address-here> \
--jwt-secret="/tmp/jwtsecret" \
--network.discv5.bootEnrs="enr:-Iq4QMCTfIMXnow27baRUb35Q8iiFHSIDBJh6hQM5Axohhf4b6Kr_cOCu0htQ5WvVqKvFgY28893DHAg8gnBAXsAVqmGAX53x8JggmlkgnY0gmlwhLKAlv6Jc2VjcDI1NmsxoQK6S-Cii_KmfFdUJL2TANL3ksaKUnNXvTCv1tLwXs0QgIN1ZHCCIyk"
cd lodestar
./lodestar beacon \
--rootDir="../lodestar-beacondata" \
--network goerli \
--eth1.enabled=true \
--execution.urls="http://127.0.0.1:8551" \
--network.connectToDiscv5Bootnodes \
--network.discv5.enabled=true \
--chain.defaultFeeRecipient=<Enter-eth-address-here> \
--jwt-secret="/tmp/jwtsecret" \
cd lodestar./lodestar beacon \
--rootDir="../lodestar-beacondata" \
--paramsFile="../config.yaml" \
--genesisStateFile="../genesis.ssz" \
--eth1.enabled=true \
--execution.urls="http://127.0.0.1:8551" \
--network.connectToDiscv5Bootnodes \
--network.discv5.enabled=true \
--chain.defaultFeeRecipient=<Enter-eth-address-here> \
--jwt-secret="/tmp/jwtsecret" \
--network.discv5.bootEnrs="enr:-Iq4QMCTfIMXnow27baRUb35Q8iiFHSIDBJh6hQM5Axohhf4b6Kr_cOCu0htQ5WvVqKvFgY28893DHAg8gnBAXsAVqmGAX53x8JggmlkgnY0gmlwhLKAlv6Jc2VjcDI1NmsxoQK6S-Cii_KmfFdUJL2TANL3ksaKUnNXvTCv1tLwXs0QgIN1ZHCCIyk"

Running Teku With Nethermind

Ropsten
Goerli
Kiln
./teku/build/install/teku/bin/teku \
--data-path "datadir-teku" \
--network ropsten \
--ee-endpoint http://localhost:8551 \
--ee-jwt-secret-file "/tmp/jwtsecret" \
--log-destination console \
--validators-proposer-default-fee-recipient=<Enter-eth-address-here> \
./teku/build/install/teku/bin/teku \
--data-path "datadir-teku" \
--network goerli \
--ee-endpoint http://localhost:8551 \
--ee-jwt-secret-file "/tmp/jwtsecret" \
--log-destination console \
--validators-proposer-default-fee-recipient=<Enter-eth-address-here> \
./teku/build/install/teku/bin/teku \
--data-path "datadir-teku" \
--network kiln \
--p2p-discovery-bootnodes "enr:-Iq4QMCTfIMXnow27baRUb35Q8iiFHSIDBJh6hQM5Axohhf4b6Kr_cOCu0htQ5WvVqKvFgY28893DHAg8gnBAXsAVqmGAX53x8JggmlkgnY0gmlwhLKAlv6Jc2VjcDI1NmsxoQK6S-Cii_KmfFdUJL2TANL3ksaKUnNXvTCv1tLwXs0QgIN1ZHCCIyk" \
--ee-endpoint http://localhost:8551 \
--Xee-version kilnv2 \
--ee-jwt-secret-file "/tmp/jwtsecret" \
--log-destination console \
--validators-proposer-default-fee-recipient=<Enter-eth-address-here> \

Troubleshooting Issues

Nethermind only shows active peers after FastHeaders synced. (happens with chains that already merged to PoS)

The most likely cause for this is that the CL client is either not running or trying to connect to the wrong JSON RPC port. to solve this follow these steps:
  1. 1.
    Make sure the AdditionalRpcUrls is configured correctly and matches the port entered in your CL client. Follow this link for details.
  2. 2.
    Make sure CL client is running. Follow this link for details.

Getting engine_exchangeTransitionConfigurationV1 found but the containing module is disabled for the url .......

For this one, either the allowed modules for AdditionalRpcUrls does not include engine , or the port that you configured the CL client to use is not the same as the port configured in AdditionalRpcUrls. to solve this follow these steps:
  1. 1.
    Make sure the AdditionalRpcUrls has engine among the allowed modules. e.g : "AdditionalRpcUrls": ["http://localhost:8551|http;ws|net;eth;engine;web3;client"]
  2. 2.
    Make sure the CL client port is pointing to the same port specified in AdditionalRpcUrls

Getting Error when handling ID 1, engine_exchangeTransitionConfigurationV1

it could mean one of two things:
  1. 1.
    --Merge.Enabled not set to true on the CLI or in the Config file. refer to the this Link for more info.
  2. 2.
    Nethermind.Merge.Plugin.cs is not in the plugins folder