Build your own private etehreum blockchain with geth

Mining, cryptocurrencies, Ethereum blockchain, crypto trading platforms (here's how to build one, by the way) - this whole relatively new blockchain thing caught my eye a few years ago and the interest only kept increasing.

I'm saying 'relatively new' because even though the actual concept was devised in 1991, the first practical implementation was effected in 2008 by the elusive Satoshi Nakamoto.

With this brief history behind us, we will focus on the second publicly available blockchain, Ethereum (a more flexible and robust implementation of the concept).

It’s going to be a 4-part series covering the workshops I'm running for my local developers community at FullStack Cluj within the following weeks:

  1. Build Your Own Private Ethereum Blockchain with Geth
  2. Build Your Own Private Ethereum Blockchain with Parity
  3. Setup Proof of Authority Consensus on Private Ethereum Blockchains
  4. Automate Blockchain Creation with Puppeth.

So let’s get this going.

Prerequisites

First off, we need to install Geth which is one of the 3 original implementations (Go, C++ and Pyhton) of the Ethereum protocol.

To install geth on Mac OS X, we assume you already have Homebrew on your machine. In case you don't, follow this link.

brew tap ethereum/ethereum
brew install ethereum

Installing geth on Ubuntu is as straightforward as installing any other package.

sudo apt install software-properties-common
sudo add-apt-repository -y ppa:ethereum/ethereum
sudo apt update
sudo apt install ethereum

And for Windows, you can follow this link.

Creating The Initial Accounts

We will now create 2 accounts, one that we'll seed at genesis and another one we'll use for the miner.

To do so, we will run the following command twice and it will ask for a passphrase on each run.

Under no circumstance should you forget the passphrase you're going to set.

This will generate a pair of password-protected public/private keys inside the <data-dir>/keystore folder. By default, Ethereum will store everything inside the <data-dir> folder except for the PoW Ethash DAG.

geth account new --datadir <path-to-data-directory>

If datadir parameter is not provided, the default paths for <data-dir> will be used.

  • Mac: ~/.ethereum
  • Linux: ~/.ethereum
  • Windows: %APPDATA%\Ethereum

From this point on, consider the following addresses as the ones generated above.

  • seed 0x6d5da05a98f04de068418051512f3e965ee8dfca
  • miner 0x632d167d2eef0f7c1fa37fcc4777d26fe6df944b

Creating The Genesis Block

The genesis block is what differentiates between all the Ethereum blockchains. Being the first block in the blockchain and having no reference to a previous one, this block is unique in its own way.

Inside the <data-dir> folder we will create a file called genesis.json with the following content:

{
   "config": {
      "chainId": 1234,
      "homesteadBlock": 0,
      "eip155Block": 0,
      "eip158Block": 0,
      "byzantiumBlock": 0
   },
   "difficulty": "400",
   "gasLimit": "2000000",
   "alloc": {
      "6d5da05a98f04de068418051512f3e965ee8dfca": {
          "balance": "100000000000000000000000"
      }
   }
}

config

  • chainId - this is your chain identifier, it can be any number at random and it will be used in replay protection.
  • homesteadBlock, eip155Block, eip158Block, byzantiumBlock - these represent the versions of the blockchain. Since we will start from scratch, all the changes in these versions will be available starting with block 0.

difficulty

This property dictates how hard is to mine a block by directly influencing the nonce applied in the discovery process.

gasLimit

This represents the maximum ammount of gas used on each block. Due to the low mining difficulty we set for the genesis block above, we still want the gas limit pretty high so we don't hit it. This way, we avoid slowing the network.

aloc

In this section we prealocate Ether to the specified accounts. Heads up: this will not create the addresses, you should already have them.

Initializing The Chain

So far, we installed all the prerequisites and configured the node, now the real fun begins.

1. Instantiate The Data Directory

geth --datadir <data-dir> init <data-dir>/genesis.json

If everything went ok you should have an output similar to this:

2. Start The Node

The networkId we set in the genesis block helps ensuring your network privacy. If other peers want to join your network, they will have to use the same networkId.

geth --datadir <data-dir> --networkid 1234 --rpc --rpccorsdomain "*" --rpcapi "db,eth,net,web3,personal" --rpcaddr "0.0.0.0" console

The output should be similar to this:

Since we created the accounts with geth inside the same <data-dir> folder and we allocated some Ether in the genesis block to one of the addreses, it was already set as the main account for this instance of the node.

Thus, we can do something like this:

> eth.getBalance(web3.eth.accounts[0])
1e+23

3. Start Another Peer

On the same machine we will start another peer for the miner and for this step we'll create a new <data-dir> (let's call it <peer-data-dir>), copy the miner private key generated above inside the keystore folder, and then start a new peer.

cp ./<data-folder>/keystore/<miner-private-key> ./<peer-data-dir>/keystore/<miner-private-key>

We will then initialize the data dir.

geth --datadir <peer-data-dir> init <data-dir>/genesis.json

Then start the second peer.

geth --datadir <peer-data-dir> --networkid 1234 --port 30304 console

The output should be similar to the one we had above, the difference being the default address which should be the miner one.

4. Connect Peers Together

To connect the peers together we require the enode address of the first peer. To get this, in the console of the initial peer we run:

admin.nodeInfo.enode

This should return something like:

enode://8fd3ca331e81bb1ed159fcc870ae08f9f21527337fc30e8cb53d1eb8fc24ca8de054c093704e5a8ee9004f56ea7ac390af1d9bf939d419b228f8decdb12bae03@[::]:30303

With this information we run in the console of the second peer:

admin.addPeer(<enode-address-of-the-first-peer>)

5. Start The Miner

Checking the initial balance of the miner account should return 0 as we did not prealocate any funds to this account.

> eth.getBalance(eth.coinbase)
0

Next, we set the miner address as the payout address for the miner.

miner.setEtherbase(web3.eth.accounts[0])

And then we start the miner.

miner.start()

After generating the DAG, the miner should start pushing blocks.

And the initial peer should start importing.

Once we stop the miner and check the balance again, we see that after 20 blocks mined the account has 60 Ether.

miner.stop()
> eth.getBalance(eth.coinbase)
60000000000000000000

Private Ethereum Blockchain Part 1: Completed

Having gotten this far, you should now have a basic understanding of how to set up you private Ethereum blockchain.

As mentioned in the introduction, you're currently reading the first article in a series so if you want to build your blockchain further, make sure you check the next one (by following Around25 on Twitter, LinkedIn, or Facebook). There, we’ll dig in a different implementation of the Ethereum protocol by parity.

Oh, and one more thing: want to challenge the ideas above, ask any questions or just learn more about how we do blockchain? Check this thing here.