How to setup a Nethermind only Clique based chain
Set of validators sealing blocks on private clique network

TL;DR

Download a script that will do all the steps described below for you. It will prompt you 2 things:
  • Confirm installation of required packages
  • The number of Validators you wish to run in your private network
Script can be found here:
nethermind/clique-validators.sh at master · NethermindEth/nethermind
GitHub
or use this command to download it:
1
wget https://raw.githubusercontent.com/NethermindEth/nethermind/master/scripts/private-networking/clique-validators.sh
Copied!
Finally give the script permissions and run it (script requires sudo privileges):
1
chmod +x clique-validators.sh
2
./clique-validators.sh
Copied!

Prerequisites

  • Linux bash shell
  • Docker-compose
  • Docker
  • jq
  • pwgen
1
sudo apt-get install -y docker-compose docker.io jq pwgen
Copied!

Manual setup

All these steps are automated and written in the above clique-validators.sh script.
In this setup we will create a private network of 3 Nethermind nodes running Clique consensus algorithm.
  • create separate directory where we will store all files
1
mkdir private-networking
2
cd private-networking
Copied!
  • create folders for each node and genesis
1
mkdir node_1 node_2 node_3 genesis
Copied!
  • download chainspec file with clique engine and place it in genesis folder (we will be using goerli chainspec in this example)
1
wget https://raw.githubusercontent.com/NethermindEth/nethermind/09389fc28b37605acc5eaed764d3e973969fe319/src/Nethermind/Chains/goerli.json
2
cp goerli.json genesis/goerli.json
Copied!
  • create subfolders in each node folder
1
mkdir node_1/configs node_2/configs node_3/configs
Copied!
  • create a static-nodes.json file and place it in working directory
1
cat <<EOF > static-nodes.json
2
[
3
4
]
5
EOF
Copied!
  • create config.cfg file and place it in node_1/configs subfolders (do this for node_2 and node_3 as well)
1
cat <<EOF > node_1/configs/config.cfg
2
{
3
"Init": {
4
"WebSocketsEnabled": false,
5
"StoreReceipts" : true,
6
"EnableUnsecuredDevWallet": true,
7
"IsMining": true,
8
"ChainSpecPath": "/config/genesis/goerli.json",
9
"BaseDbPath": "nethermind_db/clique",
10
"LogFileName": "clique.logs.txt",
11
"StaticNodesPath": "Data/static-nodes.json"
12
},
13
"Network": {
14
"DiscoveryPort": 30300,
15
"P2PPort": 30300,
16
"LocalIp": "10.5.0.2",
17
"ExternalIp": "10.5.0.2"
18
},
19
"JsonRpc": {
20
"Enabled": true,
21
"Host": "10.5.0.2",
22
"Port": 8545
23
},
24
"KeyStoreConfig": {
25
"TestNodeKey": "8687A55019CCA647F6C063F530D47E9A90725D62D853F4B973E589DB24CA9305"
26
}
27
}
28
EOF
Copied!
For each node you will need to change following items in configuration:
  • TestNodeKey should be a 64 character length alphanumeric string. Can be generated with pwgen tool for example.
  • LocalIp, ExternalIp and Host should have the same value and be incremented for each node e.g. 10.5.0.3, 10.5.0.4 and so on and so forth.
Copy docker-compose file and place it in working directory.
1
version: "3.5"
2
services:
3
4
node_1:
5
image: nethermind/nethermind:1.10.17
6
command: --config config
7
container_name: node_1
8
volumes:
9
- ./genesis:/config/genesis
10
- ./node_1/configs/config.cfg:/nethermind/configs/config.cfg
11
- ./static-nodes.json:/nethermind/Data/static-nodes.json
12
- ./node_1/db/clique:/nethermind/nethermind_db/clique
13
- ./node_1/keystore:/nethermind/keystore
14
ports:
15
- 0.0.0.0:8547:8545
16
networks:
17
vpcbr:
18
ipv4_address: 10.5.0.2
19
20
node_2:
21
image: nethermind/nethermind:1.10.17
22
command: --config config
23
container_name: node_2
24
volumes:
25
- ./genesis:/config/genesis
26
- ./node_2/configs/config.cfg:/nethermind/configs/config.cfg
27
- ./static-nodes.json:/nethermind/Data/static-nodes.json
28
- ./node_2/db/clique:/nethermind/nethermind_db/clique
29
- ./node_2/keystore:/nethermind/keystore
30
ports:
31
- 0.0.0.0:8548:8545
32
networks:
33
vpcbr:
34
ipv4_address: 10.5.0.3
35
36
node_3:
37
image: nethermind/nethermind:1.10.17
38
command: --config config
39
container_name: node_3
40
volumes:
41
- ./genesis:/config/genesis
42
- ./node_3/configs/config.cfg:/nethermind/configs/config.cfg
43
- ./static-nodes.json:/nethermind/Data/static-nodes.json
44
- ./node_3/db/clique:/nethermind/nethermind_db/clique
45
- ./node_3/keystore:/nethermind/keystore
46
ports:
47
- 0.0.0.0:8549:8545
48
networks:
49
vpcbr:
50
ipv4_address: 10.5.0.4
51
52
networks:
53
vpcbr:
54
driver: bridge
55
ipam:
56
config:
57
- subnet: 10.5.0.0/16
Copied!
  • run each node separately so that we can copy Enode and Node address for each node, we will use them later
1
docker-compose run node_1
Copied!
Stop the node when Nethermind initialization completes Ctrl +C. Copy This node and Node address (without 0x prefixes) values to a text file. Continue with node_2 and node_3.
You can use Nethermind.Cli to fetch these values from nodes by executing the following. Nethermind.Cli can be found in packages on Github Releases or Download Page.
1
node.switch("http://localhost:8547")
2
node.enode
3
node.address
Copied!
  • the file should look similar to this:
1
SIGNER_1="b5bc4d9e63eb1cb16aeeb0fd08e8344283b45b0d"
2
STATIC_NODE_1="enode://2281549869465d98e90cebc45e1d6834a01465a990add7bcf07a49287e7e66b50[email protected]10.5.0.2:30300"
3
SIGNER_2="c4e3a14d33f765faaca31672bd90d0c325bfa0cf"
4
STATIC_NODE_2="enode://37878ec16a5ed87c9c80b4648e5428f5c768eddd79483be118319c49d11c4e535[email protected]10.5.0.3:30300"
5
SIGNER_3="0076873eb11c627057834fdbdc7b391a33eb9f81"
6
STATIC_NODE_3="enode://6067f06d84c207e6233dacf1f3ef961bd7231f71d5425cbaf843cf19cfd5f7e13[email protected]10.5.0.4:30300"
Copied!
  • copy & paste above variables into your terminal and create EXTRA_VANITY and EXTRA_SEAL variables
1
EXTRA_VANITY="0x22466c6578692069732061207468696e6722202d204166726900000000000000"
2
EXTRA_SEAL="0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
Copied!
1
EXTRA_DATA=${EXTRA_VANITY}${SIGNER_1}${SIGNER_2}${SIGNER_3}${EXTRA_SEAL}
Copied!
  • in goerli.json chainspec file, modify extraData property in genesis field
You can do this either manually or using below command
1
cat goerli.json | jq '.genesis.extraData = '\"$EXTRA_DATA\"'' > genesis/goerli.json
Copied!
  • Modify the content of static-nodes.json files by appending Enodes to it
1
cat <<EOF > static-nodes.json
2
[
3
"$STATIC_NODE_1",
4
"$STATIC_NODE_2",
5
"$STATIC_NODE_3"
6
]
7
EOF
Copied!
  • remove databases for each node
1
sudo rm -rf node_1/db/clique node_2/db/clique node_3/db/clique
Copied!
  • finally run docker-compose file
1
docker-compose up
Copied!
You should see the private network working and nodes sealing blocks in Clique consensus algorithm
🎉
Clique validators sealing blocks in private network