One good way to understand Ethereum is by creating your own Ethereum private network. I have been trying to understand Ethereum in the past few weeks and I learned a lot of things just by creating it. I’ll now write down what I got from creating Ethereum private network. And I’ll update this post as I learn new things… hopefully
First of all, Ethereum client works by connecting to a network specified by its networkid
. The normal network where people usually connecting to is public network with networkid=1
(you can see it here). But it is not the only network you can connect to, you can also create your own Ethereum network.
Typical Ethereum network consists of:
Bootnode
You might be wondering how an Ethereum node can connect to other nodes and broadcast messages. It turns out they have special nodes called bootnode. Basically, they works as node discovery where you can join and ask for other nodes addresses that you can connect to.
You can see the default bootnodes value here.
Normal node
They are just normal node people usually run.
Miner
They are strong miners who make money out of thin air.
Actually you can run a node as normal node and miner at the same time. But in this post I’m going to run them separately so we can understand better what they are doing.
Requirements
I’ll use Golang version of Ethereum clients. I haven’t tried other client implementations but they should also work, maybe…
You can download pre-built binary here: https://geth.ethereum.org/downloads/, please download the latest one with name: Geth & Tools
. Unlike Geth
, it contains geth
and bootnode
binaries needed for this post.
Please download and add the binaries to your PATH
, in this post I assume all of those binary are already included in PATH
.
Create accounts
Ethereum doesn’t need you to register in order to join the network. What you need to do is just create an account which consists of a private key and a public key, with a password for security, then you can just use the address. If you use geth
to generate an account, both private and public key will be hidden in a weird looking json
file.
Creating account in Ethereum is simple, let’s use geth
to create one:
|
|
You will then asked to type password. The created account information will be saved in accounts/keystore/UTC--{year}-{month}--{account}
.
Make sure to SAVE THE PASSWORD SECURELY, because there is no way to retrieve your password once you lost it
Example account:
|
|
The important part is address
, as its name implies it is the address of the account. To understand better what’s stored in there you can read this.
Create genesis block
If you are not familiar with blockchain, basically blockchain consists of many blocks and each block has the hash of previous block in it. But wait, what about the very first block in the blockchain? Which block should it refers to?
The first block in a blockchain is a special block, called genesis block. Unlike other blocks, it doesn’t need the hash of the previous block (well, there is no block before it). It sets the hash of the previous block with 0
. It also can give some balance to some addresses.
You can see Ethereum genesis block here: https://etherscan.io/block/0. Notice it has
Parent Hash=0
.
Genesis block in Ethereum is just an json
file:
|
|
Short explanation about above genesis file:
config.chainId
I am not really sure about this. But it is used for preventing replay attack accross Ethereum networks. I also see most private network examples set this to thenetworkid
of the private network. We will use 9999 as ournetworkid
in this post.config.homesteadBlock
,eip155Block
andeip158Block
do not really matter in a private networkalloc
specifies initial balance for some addressesdifficulty
specifies how difficult mining should be
Create file genesis.json
containing above json snippet (please change the address in the alloc
to be your own account address). We’ll back to this later when we are creating nodes.
Setup bootnode
As I said before, bootnode works as a node discovery. Nodes would need bootnode to join and discover other nodes in the network so they can do whatever they want, e.g: syncing blockchain, create transaction, mining etc.
Setting up a bootnode is easy. First you need to create a nodekey. Essentially nodekey is an address where the bootnode run.
|
|
You should save your bootnode’s nodekey. If the value is changed, you will have to update your other nodes to point to the new bootnode’s address.
Technically, nodekey is not the real address of the bootnode. Nodekey is just a public key and it needs to be hashed first to get the real address. See this for further explanation.
It will create a nodekey and save it to boot.key
.
You will also need the real address of bootnode so other nodes can use it as their bootnode. You can get it by:
|
|
Setup nodes
Now we need to setup Ethereum nodes. Since we are going to use our own private network we will need to initialize our nodes with our genesis block.
You have to do this for all nodes in our private network
You can initalize a node by:
|
|
Please replace nodeX
with a path where the node will save its data. Let’s create a node and a miner, so run the above command with --datadir=node
and --datadir=miner
. It will initialize the nodes using our own genesis block definition in genesis.json
.
We don’t need to specify genesis block when initalizing nodes in main network. Because genesis block for the main network is already hard coded in
geth
, see here.
We need to initialize all of our nodes with our genesis block because if they use the default genesis block they will not be able to sync to our private network’s blocks.
Running all together
Let’s put everything together. First we run the bootnode:
|
|
I added --verbosity=9
so we can easily see if the bootnode is working and other nodes are able to connect to bootnode. If it runs ok it should output something like:
INFO [10-31|21:26:21] UDP listener up self=enode://157e68e800266d39015a125f3c20a499cd190940e2a665854e0fb80f62f7c00734acc6eb277c06f0b5cb5840436b0ab3980761e7c58a27bfa052c10560db2bc7@[::]:30301
enode://...
is the bootnode’s address and @[::]:30301
means that it runs on all interfaces at port 30301.
Next we run the node. We can run it by:
|
|
Please make sure to adjust the bootnode address from bootnode’s logs. I added --port=9001
so that we can run multiple nodes in a host, they will run on different ports. If it runs ok the bootnode will output something like:
TRACE[10-31|21:40:08] >> PONG/v4 addr=127.0.0.1:9001 err=nil
TRACE[10-31|21:40:08] << PING/v4 addr=127.0.0.1:9001 err=nil
TRACE[10-31|21:40:08] Starting bonding ping/pong id=4b2c152d338bdff6 known=false failcount=0 age=419294h40m8.013456s
TRACE[10-31|21:40:08] >> PING/v4 addr=127.0.0.1:9001 err=nil
TRACE[10-31|21:40:08] << PONG/v4 addr=127.0.0.1:9001 err=nil
TRACE[10-31|21:40:08] >> NEIGHBORS/v4 addr=127.0.0.1:9001 err=nil
TRACE[10-31|21:40:08] << FINDNODE/v4 addr=127.0.0.1:9001 err=nil
Last, let’s run the miner node:
|
|
--miner
makes the node to start mining after it is ready, --minerthreads
sets how many threads will be used for mining and --etherbase
will store the reward of mining to the specified address. If it runs ok it should have output like:
INFO [10-31|21:48:48] Starting mining operation
INFO [10-31|21:48:48] Commit new mining work number=1 txs=0 uncles=0 elapsed=164.218µs
INFO [10-31|21:48:49] Successfully sealed new block number=1 hash=d13118…8fadfb
INFO [10-31|21:48:49] 🔨 mined potential block number=1 hash=d13118…8fadfb
INFO [10-31|21:48:49] Commit new mining work number=2 txs=0 uncles=0 elapsed=115.035µs
INFO [10-31|21:48:57] Successfully sealed new block number=2 hash=8c7c30…f6871b
INFO [10-31|21:48:57] 🔨 mined potential block number=2 hash=8c7c30…f6871b
INFO [10-31|21:48:57] Commit new mining work number=3 txs=0 uncles=0 elapsed=194.539µs
INFO [10-31|21:48:59] Successfully sealed new block number=3 hash=f688ba…303090
Notice the node’s logs, you should see something like this whenever the miner successfully mine a new block:
INFO [10-31|21:46:45] Imported new chain segment blocks=2 txs=0 mgas=0.000 elapsed=1.234ms mgasps=0.000 number=2 hash=c9b5ea…2c638c
INFO [10-31|21:46:45] Fast sync complete, auto disabling
INFO [10-31|21:46:48] Imported new chain segment blocks=1 txs=0 mgas=0.000 elapsed=4.415ms mgasps=0.000 number=3 hash=b53689…b40d46
INFO [10-31|21:47:14] Imported new chain segment blocks=1 txs=0 mgas=0.000 elapsed=3.285ms mgasps=0.000 number=4 hash=e69fd2…5cabe7
It shows us that the node just updated its blockchain. Remember, miner can find other nodes via bootnode. So whenever miner successfully mine a new block, it can ask some nodes addresses from bootnode then broadcast the new block to them.
Great! Our private network is now working well. We can see our current balance using console:
|
|
Now we can check balance of the address used for mining:
|
|
Check this to learn about what you can do in the console: https://github.com/ethereum/wiki/wiki/JavaScript-API
Okay that’s all for this post. I hope now you understand, at least, how to setup your own Ethereum private network. I’ll cover more topics later about creating more secure private network and transfering ether… probably