February 2018.

updates:

geth 1.8 was released a few days after this guide was published and fortunately does not break anything. This post is then valid and was tested for both geth 1.7.3 and geth 1.8. Awesome :) I’ve learned a posteriori that the gas limit per block is dynamic. Therefore I’ve updated the section 2.3 to give more information about this particular case. In my private network where blocks are most of the time empty, I don’t what the gas limit to decrease at all ! Clique requires int(N/2+1) sealers (where N is the number of sealers defined in the genesis file — in extraData field) to be online in order to run. thx to Ivica Aracic for pointing out that clique PoA DOES WORK with a single node. For any reason I missed that and I apologize for the confusion. With a single node, we just need (A) create genesis file with only one sealer (only 1 address in extraData ) (B) create an account (C) init geth (D) run geth, unlock account and mine. No bootnode is required then. with geth 1.8 if you get the error “invalid host specified”, try adding the option --rpcvhosts value to the geth command. See geth --help

Goal: step by step guide to help you setup a local private ethereum network using the Proof-of-Authority consensus engine (also named clique).

In a nutshell: we will setup two nodes on the same machine, creating a peer-to-peer network on our localhost. In addition to the two nodes, a bootnode (discovery service) will also be setup.

It took me quite some time and extensive research and googling to finally have a solid ethereum development environment for testing my smart contracts and my DApps.

In this post, I’ve decided to share how I am setting a Proof-of-Authority network using the clique consensus engine of Geth. It’s my way to thank the community by giving back and hopefully making life easier for anyone willing exploring the Ethereum universe.

OS and Software

My OS is Ubuntu 16.04 LTS (this tuto was done in a fresh virtual machine).

For the Ethereum client, I am using Geth (the Go implementation of the Ethereum protocole). I believe that Geth is easy to install with plenty of great tutorials out there, so I am not gonna cover any installation here. I am currently running Geth 1.7.3-stable:

$ geth version

Geth

Version: 1.7.3-stable

Git Commit: 4bb3c89d44e372e6a9ab85a8be0c9345265c763a

Architecture: amd64

Protocol Versions: [63 62]

and Geth 1.8.1-stable

$ geth version

Geth

Version: 1.8.1-stable

Git Commit: 1e67410e88d2685bc54611a7c9f75c327b553ccc

Architecture: amd64

Protocol Versions: [63 62]

I strongly recommend to check the Geth Command Line Interface documentation. You’re gonna need it. A lot.

1. Let’s get started

1.0 overview

Let’s start by the end… For clarity, this is what you are supposed to get when you will have completed Chapter 1.

devnet$ tree -L 2

.

├── accounts.txt

├── boot.key

├── genesis.json

├── node1

│ ├── geth

│ ├── keystore

│ └── password.txt

└── node2

├── geth

├── keystore

└── password.txt

1.1 create a workspace

$ mkdir devnet

$ cd devnet

devnet$ mkdir node1 node2

1.2 create your accounts

The accounts (also called wallet) hold a private-public key pair that are required for interacting with any blockchain. Any mining node (strictly speaking our nodes will not be mining but voting) needs to be able to sign transactions (using their private key) and to identify itself on the network (the address is derived from the public key). Therefore we need at least two accounts, one per node.

In Geth jargon, a voting node is called a Sealer.

for node 1 :

devnet$ geth --datadir node1/ account new

Your new account is locked with a password. Please give a password. Do not forget this password.

Passphrase: pwdnode1 (for example)

Repeat passphrase: pwdnode1

Address: {87366ef81db496edd0ea2055ca605e8686eec1e6}

for node 2 :

devnet$ geth --datadir node2/ account new

Your new account is locked with a password. Please give a password. Do not forget this password.

Passphrase: pwdnode2 (for example)

Repeat passphrase: pwdnode2

Address: {08a58f09194e403d02a1928a7bf78646cfc260b0}

This creates the keystore/ folder containing your account file. Notice that the last part of the file name in keystore/ is the address of your account (also printed in the terminal just above).

I suggest to copy these two addresses from the terminal screen and to save them in a text file. That will ease some copy-pasting job later on. However remember that you can read those addesses from the UTC-datetime-address file in keystore/ .

devnet$ echo '87366ef81db496edd0ea2055ca605e8686eec1e6' >> accounts.txt

devnet$ echo '08a58f09194e403d02a1928a7bf78646cfc260b0' >> accounts.txt

For each node, I propose to save your password in a file. That will ease some process for later on (such as unlocking your account)

devnet$ echo 'pwdnode1' > node1/password.txt

devnet$ echo 'pwdnode2' > node2/password.txt

1.3 create your Genesis file

A genesis file is the file used to initialize the blockchain. The very first block, called the genesis block, is crafted based on the parameters in the genesis.json file.

Geth comes with a bunch of exectuables such as puppeth or bootnode . You can find the complete list on the Geth github. Puppeth removes the pain of creating a genesis file from scratch (and does much more). Start puppeth :

devnet$ puppeth

and happily answer the questions (every value can be updated by hand later on, so don’t spent too much time engineering it for your first trials).

Please specify a network name to administer (no spaces, please)

> devnet

What would you like to do? (default = stats)

1. Show network stats

2. Configure new genesis

3. Track new remote server

4. Deploy network components

> 2 Which consensus engine to use? (default = clique)

1. Ethash - proof-of-work

2. Clique - proof-of-authority

> 2 How many seconds should blocks take? (default = 15)

> 5 // for example Which accounts are allowed to seal? (mandatory at least one)

> 0x87366ef81db496edd0ea2055ca605e8686eec1e6 //copy paste from account.txt :)

> 0x08a58f09194e403d02a1928a7bf78646cfc260b0 Which accounts should be pre-funded? (advisable at least one)

> 0x87366ef81db496edd0ea2055ca605e8686eec1e6 // free ethers !

> 0x08a58f09194e403d02a1928a7bf78646cfc260b0 Specify your chain/network ID if you want an explicit one (default = random)

> 1515 // for example. Do not use anything from 1 to 10 Anything fun to embed into the genesis block? (max 32 bytes)

> What would you like to do? (default = stats)

1. Show network stats

2. Manage existing genesis

3. Track new remote server

4. Deploy network components

> 2 1. Modify existing fork rules

2. Export genesis configuration

> 2 Which file to save the genesis into? (default = devnet.json)

> genesis.json

INFO [01-23|15:16:17] Exported existing genesis block What would you like to do? (default = stats)

1. Show network stats

2. Manage existing genesis

3. Track new remote server

4. Deploy network components

> ^C // ctrl+C to quit puppeth

Side note : from Clique PoA EIP#225

PoA doesn’t have mining rewards

So I would highly suggest that you allocate some ethers (defined in the unit of wei) to a bunch of addresses in the genesis file, otherwise you’ll hand up without any ether and thus will not be able to pay for your transactions. You could have a gasPrice of zero but that sometimes leads to undesired behavior from the nodes that could go under the radar (like not broadcasting pending transaction depending on the config of the other nodes on the network). I encourage you nevertheless to play with every parameter :)

1.4 Initialize your nodes

Now that we have the genesis.json file, let’s forge the genesis block ! Each node MUST be initialize with the SAME genesis file.

devnet$ geth --datadir node1/ init genesis.json

devnet$ geth --datadir node2/ init genesis.json

tada ! done.

Side note : how does your node know about the genesis parameters when joining the Ethereum Mainnet or the Ropsten testnet, or the Rinkeby testnet ? They are already defined in the source code in params/config.go .

1.5 Create a bootnode

A bootnode only purpose is to helping nodes discovering each others (remember, the Ethereum blockchain is a peer-to-peer network). Nodes could have dynamic IP, being turned off, and on again. The bootnode is usually ran on a static IP and thus acts like a pub where nodes know they will find their mates.

Initialize the bootnode :

devnet$ bootnode -genkey boot.key

This creates a value called the enode uniquely identifying your bootnode (more on this soon) and we store this enode in the boot.key file.

1.6 Midway celebration

Congrats ! Chapter 1 is done :) try

devnet$ tree -L 2

and compare the output with the section 1.0. Hopefully you should get the same tree.

At this point the setup is done and we are ready to make this blockchain live.

2. Make it live

2.1 Start the bootnode service

devnet$ bootnode -nodekey boot.key -verbosity 9 -addr :30310

INFO [02-07|22:44:09] UDP listener up self=enode://3ec4fef2d726c2c01f16f0a0030f15dd5a81e274067af2b2157cafbf76aa79fa9c0be52c6664e80cc5b08162ede53279bd70ee10d024fe86613b0b09e1106c40@[::]:30310

I like to have some verbosity for my bootnode as it is nice to see when the nodes are playing ping-pong on the network (meaning it’s working!).

Feel free to use any port you like but please avoid the mainstream ones (like 80 for HTTP). 30303 is used for the public ethereum networks.

2.2 Starting your nodes

Big time ! Finally (but usually here the troubles arrive too).

Everything in one huge command ! I am gonna cover some options but please do your homework and refer to the doc.

starting node 1

devnet$ geth --datadir node1/ --syncmode 'full' --port 30311 --rpc --rpcaddr 'localhost' --rpcport 8501 --rpcapi 'personal,db,eth,net,web3,txpool,miner' --bootnodes 'enode://3ec4fef2d726c2c01f16f0a0030f15dd5a81e274067af2b2157cafbf76aa79fa9c0be52c6664e80cc5b08162ede53279bd70ee10d024fe86613b0b09e1106c40@127.0.0.1:30310' --networkid 1515 --gasprice '1' -unlock '0x87366ef81db496edd0ea2055ca605e8686eec1e6' --password node1/password.txt --mine

--syncmode 'full' helps preventing the error Discarded Bad Propagated Block.

helps preventing the error Discarded Bad Propagated Block. --port 30311 is the enode port for node1 and has to be different from the bootnode port (that is 30310 if you followed my command) because we are on a localhost. On a real network (one node per machine), use the same port.

is the enode port for node1 and has to be different from the bootnode port (that is if you followed my command) because we are on a localhost. On a real network (one node per machine), use the same port. --rpcapi allows the listed modules to be used over RPC calls (see section 3.3 for an example). See the Geth Management APIs for more info. Be mindful about hacks as everyone can call your RPC methods if no firewall is protecting your node.

allows the listed modules to be used over RPC calls (see section 3.3 for an example). See the Geth Management APIs for more info. Be mindful about hacks as everyone can call your RPC methods if no firewall is protecting your node. --bootnodes tells your node at what address to find your bootnode. Replace [::] with the bootnode IP. No domain name are allowed ! Only IPs. Check enode URL format.

tells your node at what address to find your bootnode. Replace with the bootnode IP. ! Only IPs. Check enode URL format. --networkId as defined in the genesis.json file. Please use the same id !

as defined in the file. Please use the same id ! --gasprice '1' I don’t like to pay on my own network :) be careful with gasprice. If your transactions are not being broadcasted to the network but only the node receiving the transactions is processing them, this means you sent a transaction with a gasprice that is not accepted (too low) by the other nodes on the network. No error will be return. If you have two nodes, only one will be processing the transactions. This is sneaky and reduces your network throughput by a factor 2.

I don’t like to pay on my own network :) be careful with gasprice. If your transactions are not being broadcasted to the network but only the node receiving the transactions is processing them, this means you sent a transaction with a gasprice that is not accepted (too low) by the other nodes on the network. No error will be return. If you have two nodes, only one will be processing the transactions. This is sneaky and reduces your network throughput by a factor 2. --unlock --password --mine tell the node to unlock this account, with the password in that file and to start mining (i.e. voting/sealing for Proof-of-Authority)

tell the node to unlock this account, with the password in that file and to start mining (i.e. voting/sealing for Proof-of-Authority) --targetgaslimit value see the update in section 2.3.

same for node 2 (update parameters specific to the node)

devnet$ geth --datadir node2/ --syncmode 'full' --port 30312 --rpc --rpcaddr 'localhost' --rpcport 8502 --rpcapi 'personal,db,eth,net,web3,txpool,miner' --bootnodes 'enode://3ec4fef2d726c2c01f16f0a0030f15dd5a81e274067af2b2157cafbf76aa79fa9c0be52c6664e80cc5b08162ede53279bd70ee10d024fe86613b0b09e1106c40@127.0.0.1:30310' --networkid 1515 --gasprice '0' --unlock '0x08a58f09194e403d02a1928a7bf78646cfc260b0' --password node2/password.txt --mine

At this point your bootnode should stream connections coming from node1 (port 30311) and node2 (port 30312) as shown in the upper terminal window. Node1 (middle terminal) and node2 (lower terminal) should be happily mining and signing blocks. Here I have a period of 1 second (defined in the genesis file) therefore the fast block creation.