Ethereum: Setting Up A Private Blockchain

Environment Setup

  1. Create a working folder/directory for this exercise. It will be used to hold binaries and configuration files.
  2. Go the Go Ethereum (geth) site and download the binary for your operating system. (the version might have changed by the time you are going through this).
Geth Website showing supported operating systems

3. Unzip and copy the geth binary to your working folder

The geth binary is the ethereum runtime, to run it you need to give some information via a configuration file. I’ll go into the details of the configuration file in the next step.

To run a private network you need to provide geth with some basic information required to create the initial block

Let’s explore the configuration file

config: This is the main blockchain configuration and it has the following properties

chainId: The chain identifier, it has to be an integer. It is also used to protect against replay attack. I will not be going into replay attach in this tutorial.

There are a host of other properties like homesteadBlock and eip155Block that can be added to the config but they are only/mostly relevant to the main network, so we’ll ignore them for now. This link provides more details.

alloc: This is used to allocate ETH to addresses i.e. to pre-fund accounts.

coinbase: also known as etherbase is the default primary account. You will get a warning if this value is not set but that can be safely ignored for now, you can set it later.

difficulty: This determines how difficult it is to mine a block. For a private blockchain it is better to set it to a low number to ensure blocks are mined quickly which utlimately translates to faster transactions.

extraData: Block extra data, it defaults to the client version if not provided.

gasLimit: This dictates the maximum amount of gas that can be used in each block. The higher the value the more transactions can be squeezed into a block.

mixHash: Not relevant to a new private network, set to 0

parentHash: Not relevant to a new private network, set to 0

Let’s fire it up

geth requires two main parameters, a folder to store the chain data (i.e. local database) and an initialisation file.

geth --datadir ./datadir init init.json

The output should look like the screenshot below

Initialisation console output

You should also notice a datadir folder created under your working folder and it’s content should be similar to the screenshot below

Local Blockchain Folder

At this point, you have a private ethereum blockchain running. Now the fun begins. The first thing you need to do to test drive this, is to create an account on the blockchain.

Creating an Account

There are two ways of creating accounts, by geth commands or by using the geth console. We will use the geth console later.

To create an account using geth commands run

geth --datadir ./datadir account new

You will be prompted for a password. Take note of the password, you’ll need it later. Once created, the new account’s address will be printed in the console as shown below.

New Account Console Dialogue

More importantly, you will notice a file in the keystore folder that contains the private key and other information about the account that was created.

New Account File

It creates a file for each new account created. if you run the create account command again, you’ll notice a new file in the keystore folder.

One important thing to note is that the accounts are generated offline and no one on the network knows of the addresses/accounts until they are included in a transaction on the network.

So, to make the network aware of these addresses we need to include them in a transaction and the transaction to a block. Lets launch the geth console by running this command.

geth --datadir ./datadir console

The console has a number of libraries you can use to interact with the blockchain. The first library we will be using is eth.

Here are a subset of the functionality the eth library provides. Try them on your console.

eth.accounts // returns the list of accounts on this blockchain
eth.getBalance(eth.accounts[0]) // returns the balance of the  first account. 
eth.blockNumber // returns the current block number. 0 for a new blockchain

If you check the balance of any accounts you have created thus far you will notice they all have balances of 0 but to do anything interesting on an ethereum blockchain you need ether. So lets go mining.

Mining

To mine, you’ll use the miner library. To start mining run

miner.start(1) // 1 means run one mining thread

and your console output should be similar to

to stop mining run

miner.stop()

After successfully mining, where does the mined Ether go? By default it gets allocated to the first account created on the blockchain. Also, as part of the mining process, new blocks would have been created and added to the blockchain (mostly empty because you have not sent any transactions). If you check the account balance of the first address eth.getBalance(eth.accounts[0]) and the current block number eth.blockNumber you will notice they are both no longer 0.

Sending Ether

If you only created one account, then create a second account. Confirm the balance of this account running eth.getBalance(‘address’) then send some ether using

eth.sendTransaction({from:”address”, to:”address”, value: web3.toWei(amount, "ether")})
e.g. eth.sendTransaction({from:eth.accounts[0], to:eth.accounts[1], value: web3.toWei(4, "ether")})

If you try running the example, you will get an authentication error. Before you transfer ether from an account, for obvious reasons you need to unlock the account first. To unlock the sender account in this scenario, we will use the personal library. Run the command below

personal.unlockAccount(eth.accounts[0], "password")

That should return true if the account was successfully unlocked. Attempt to send ether again and check the balance of both accounts.

eth.sendTransaction({from:eth.accounts[0], to:eth.accounts[1], value: web3.toWei(4, "ether")})

The last command should return a hash of the transaction. In my case it returned “0xf94ece7d159bcc750862b92396e0d98c537593bfa2ecb3a21ec49b0d439592eb”.

You would expect eth.getBalance(eth.accounts[1]) to be 4, right? Well, it will return 0 because the transaction has not been added to the blockchain yet.

Also, if you check the balance of the sender, you will notice that hasn’t changed either. In order for this transaction to take effect, i.e. the account balances reflect the new values, the transaction needs to be added to a block and the block to the blockchain i.e. mined. So, lets mine.

run miner.start() and then miner.stop()

If you look at the console output, you will notice the first block mined has one transaction. If you check the balance of the sender and receiver they should both show the expected values.

Another interesting thing you can do is, check the details of the transaction by running

eth.getTransaction("transactionId")
e.g. eth.getTransaction("0xf94ece7d159bcc750862b92396e0d98c537593bfa2ecb3a21ec49b0d439592eb")

If a transaction has been mined then getTransaction should return something similar to

This gives a lot of information about the transaction. From here, you can get more information about the block by running

eth.getBlock("blockAddress")
e.g. eth.getBlock("0x1420da4e3dc647c651135b6d2f617e7046fc748c0321c567cec5e92df352ff54")

getBlock output should be similar to

Most of the values should be self-explanatory.

Adding More Peers/Nodes

Exit out of the geth console if you still have it running then restart but this time around provide a networkid

geth --datadir ./datadir --networkid 2018 console

The last step just restarted the old blockchain with a networkid.

To add a new node, run the command below in a new terminal

geth --datadir ./datadir_new init init.json

Two important things to note here.

  1. You must use the same init.json file
  2. You must use a different datadir folder. The data dir is effectively the database/local copy of the blockchain and each node needs to have its own copy.

Now run the new node, ensure you use the same network id. You also need to specify port. The default port is already used by the first node. You need to add nodiscover to ensure that the node is discoverable, it is not required but it’s good practice.

geth --datadir ./datadir_new --networkid 2018 --port 30306 --nodiscover console

in the console of the of second node (you can use either), run admin.nodeInfo you should get something similar to this

copy the value of the enode property and in the console of the first node run

admin.addPeer(enode://f7aa5b604056ff77dc561034f12874586b44b4a00e92355e7f750cfb43717ef1d0092f208b08661b209656d09540b11f6d0c6667a611674f7a75b718424d0c9a@[::]:30306?discport=0")

This function returns true if successful but that doesn’t mean the node was added successfully. To confirm run admin.peers and you should see the details of the node you just added

if you start mining on the first node by running miner.start(1) you’ll notice the block depth/number increase on the second node.

Hope you found this useful. In the next tutorial, we’ll explore smart contracts.