(Writing in progress, I’m not a very good writer though)

My friend requested me to write a tutorial for basic setup when developing a DApp (decentralized application on Ethereum). I like to do it manually, setup and script everything by my own so that I can understand things more clearly. However, there’re plenty of tutorials out there with regards to virtual containers and automated scripts, you might want to check out those to avoid all the dirty works coming. Now let’s get started.

1. Architecture

Our little project will involve several things:

  • Setup a private Ethereum network
  • Write and deploy a smart contract on your private net
  • Some Java code to interact with the contract from a third party application

The reason is quite simple. A test network allows you to simulate different things. For example, in my research, I have to simulate the situation when malicious miners try to provide clients a fake blockchain. You don’t really find this situation randomly on Mainnet. Another good reason is that you don’t need any token for bulding and testing your smart contracts.

As you already know, Ethereum uses a Peer-to-peer (P2P) architecture. That is, instead of every peers connects to a centralized server, a peer acts both as a client and a server and exchange information directly with each other via tcp connections. There are,in fact, 4 different types of peer in Ethereum network:

  1. bootnode: A coordinator which has information about other peers in the network. It works like an index server in a torrent network as a boostraping point. Basically, when a peer join the P2P the network by connect to a bootnode, the bootnode returns a list of available other peers so that the newcomer can connect to.
  2. miner: Peer that perform validation for transactions and mining blocks.
  3. wallet: End user’s peer that creates and sends transactions.
  4. light wallet: End user’s peer that uses light client protocol

Our private network architecture will have 3 out of 4 types of those clients. A bootnode for coordinator purpose, some miners to do the mining and a wallet to simulate an end-user. We can have a light wallet though it is not the main focus of this article.

The private net workflow is straightforward. We setup a bootnode and keep it running. We then start some miners that share the same configuration that connect to the same bootnode sothat they can discover each other. Later on, we connect our wallet to the bootnode as user joining the Ethereum network.

2. Private network

We are going to use Geth, the official Ethereum implementation in Go. We can download the binary releases here and install the development tools as well.

Bootnode setup

You’ll find a bootnode executable on the newly installed Geth directory. We’ll need to generate a private key by running

bootnode.exe -genkey bootnode.key

Then run the bootnode

bootnode.exe -nodekey bootnode.key -verbosity 9
I1208 01:27:54.617968 p2p/discover/udp.go:227] Listening, enode://e5ce9dde1d2ebf129ff69cf59a6f0813ec54caec9f90ddd4dda191c44c399eeae6c114f54b3b69e288c6630290814049b7619508e93a6d02967bdd3e7086029e@[::]:30301

enode://e5...[::]:30301 is the address of the bootnode, write down this url.

Node setup

The bootnode is the bootstraping point. From here, we can create other node to complete the network. Let’s start creating our first miner.

First, we need a genesis block specification. This is also block number 0 that the network will base on to mine. We can create a file call genesis.json with the following content.

{
    "alloc"      : {},
    "coinbase"   : "0x0000000000000000000000000000000000000000",
    "difficulty" : "0x4000",
    "extraData"  : "Test Net Genesis Block",
    "gasLimit"   : "0x2fefd8",
    "nonce"      : "0x0000000000000042",
    "mixhash"    : "0x0000000000000000000000000000000000000000000000000000000000000000",
    "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
    "timestamp"  : "0x00"
}

The most important attribute that we should take care of is difficulty. This determine how difficult it is to mine a block. If the difficulty is too low, we will get new block very fast, which sometimes annoy me since it is not similar to how MainNet works. On the contrary, high difficulty results in longer block time. The average time for a block in Mainnet is around 17 seconds while on a private net it can be around 13 because all my miners only use local network. Although the mining algorithm will alternate the difficulty if the block time is longer or shorter, it would be the best that we don’t mess thing up from the start.

Then, we can create our first node with:

geth.exe --datadir=.\alice init genesis.json

This will create a directory alice that contains all blockchain data for the node. From here, we can launch the node with:

geth.exe --datadir=.\alice --identity alice --bootnodes=enode://e5ce9dde1d2ebf129ff69cf59a6f0813ec54caec9f90ddd4dda191c44c399eeae6c114f54b3b69e288c6630290814049b7619508e93a6d02967bdd3e7086029e@127.0.0.1:30301 --port 30304  --ipcpath alice\geth.ipc --networkid 101 --rpc --nodiscover

Remember the bootnode address? Copy it here and replace [::] with 127.0.0.1. Somehow geth cannot distinguish those 2. You can replace 30304 with your choice for the port. Also, if you want to run multiple nodes on 1 machine like me, you need to specify a different ipcpath for each node. It can be anything though.

If you check the bootnode commandline, you will find that the new node that we created had connected to the bootnode.

Now you can repeat the process to create a second node called Bob with the same genesis file and bootnode. However, Bob must use differnt datadir, port, identity and ipcpath.

geth.exe --datadir=.\bob init genesis.json
geth.exe --datadir=.\bob --identity bob --bootnodes=enode://e5ce9dde1d2ebf129ff69cf59a6f0813ec54caec9f90ddd4dda191c44c399eeae6c114f54b3b69e288c6630290814049b7619508e93a6d02967bdd3e7086029e@127.0.0.1:30301 --port 30305  --ipcpath bob\geth.ipc --networkid 101 --rpc --nodiscover