The rapid progress of Blockchain technology is showing no signs of slowing down. One by one it solves many issues of the existing digital ecosystem. The main feature of blockchain technology is decentralization. Organizations can exploit this feature to make their entire system of operations or services into a more reliable, distributive, and automated environment.
So changing the current centralized mechanism into more decentralized and thereby exploiting many features of blockchain technology while keeping proper control over the system, that what we are building today.
We are using Hyperledger Besu to create the blockchain.
Hyperledger Besu is an Ethereum client designed to be enterprise-friendly for both public and private permissioned network use cases. It can also be run on test networks such as Rinkeby, Ropsten, and Görli. Hyperledger Besu includes several consensus algorithms including PoW, and PoA (IBFT, IBFT 2.0, Etherhash, and Clique). Its comprehensive permissioning schemes are designed specifically for use in a consortium environment.
We are creating a Private blockchain with 4 nodes (Because IBFT requires a minimum of 4 nodes to operate). In these 4 nodes, one will be bootnode and others will be validators. We will be running besu from docker image for easiness. We can use the source code also. In that case, clone the source code from repo and add /bin/besu
to the path.
First, we are setting up the directory as shown:
The first block of the blockchain is called the Genesis block. So we need to create a genesis file and from that, we will start our network. We can use besu to generate a genesis file from a configuration file. Create a file named ibftConfigFile.json
inside IBFT-Network/
and add the below code to it:
{ "genesis": { "config": { "chainId": 15, "muirglacierblock": 0, "ibft2": { "blockperiodseconds": 2, "epochlength": 30000, "requesttimeoutseconds": 4 } }; "nonce": "Ox0", "timestamp": "0x0", "gasLimit": "Oxlfffffffffffff", "difficulty": "0x1", "mixHash": "0x63746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365", "coinbase": "0x0000000000000000000000000000000000000000" , "alloc": { "1D0a9BCD31fEE726726d5Fa3f9971Bd2e38215d0": { "balance": "10000000000000000000000000000" } } }, "blockchain": { "nodes": { "generate": true, "count": 4 } } }
chainId
can be according to your preference. Please make it a chainId that you aren’t already using in any wallet. Because if you have already connected your wallet to a network with the same chain id and had done some transactions in it, then you will get an incorrect nonce in this network. That will cause issues and transactions will not be confirmed. gasLimit
is set to a higher value because this will be a free gas network. In alloc
you can specify some accounts or smart contracts (predeployed) to which the initial amount of native coins will be allocated (Basically ETH because we are forking from Ethereum, but you can consider it as your own coin and can be addressed with a different name).
Now if you are using besu from source code run :
besu operator generate-blockchain-config --config-file=ibftConfigFile.json --to=networkFiles --private-key-file-name=key
If you are using docker image of Besu create a docker-compose.yaml
file with the following content, then run docker-compose up
.
version: "3" services: besu: image: hyperledger/besu:22.1.0-RC5-SNAPSHOT container_name: "genesis-generator" volumes: - .:/usr/app/ command: operator generate-blockchain-config --config- file=/usr/app/ibftConfigFile. json --to=/usr/app/networkFiles --private-key-file-name=key volumes:
This will generate a folder named networkFiles
. Inside that, there will be a genesis file and another directory named keys
with 4 directories inside. Inside all these directories there will be 2 files key
and key.pub
. These are the key pairs for our 4 nodes.
From networkFiles
copy the genesis file to all the node directories (Node-1, Node-2, etc). Then copy a set of key
and key.pub
to Node-1/data
. Similarly another set of key
and key.pub
to all other Nodes.
Now we need a config.toml
for configuring each node. Place it inside each Node-
directory.
data-path="/usr/app/data" rpc-http-enabled=true rpc-http-api=["ETH", "NET", "IBFT"] rpc-http-port=8546 p2p-port=30304 host-allowlist=["*"] rpc-http-cors-origins=["all"] genesis-file="/usr/app/genesis. json" min-gas-price=0
You can add many more options. I am just keeping it simple. Please remember if you are setting up the network in the same host change the different ports for each node. For the time being keep the same configuration for each node, only ports will be different. Now we have everything to start our network. So create a docker-compose.yaml
inside each node so that we can start nodes individually too.
version: "3" services: node: image: hyperledger/besu:22.1.0-RC5-SNAPSHOT container_name: "node-1" volumes: - .:/usr/app/ command: --config-file=/usr/app/config.toml volumes:
Since I am going to run all 4 nodes in a single machine I need to start all nodes in a single command. So I am going to combine all the nodes via another docker-compose.
version: "3" services: node-1: network_mode: host extends: file: "./node-1/docker-compose. yaml" service: node node-2: network_mode: host extends: file: "./node-2/docker-compose.yaml" service: node node-3: network_mode: host extends: file: "./node-3/docker-compose. yam" service: node node-4: network_mode: host extends: file: "./node-4/docker-compose.yaml" service: node
I am using network mode as host so that each node can establish a p2p connection without complication. If you want to you create a custom network and connect all the nodes to it also.
We are not done yet! We are at the final stage. Currently, nodes don’t have any idea about the other nodes. So what we have to do is to start the bootnode and copy its enode url and provide it in the other nodes config file. You also start bootnode alone to copy enode URL. But I am starting all of them together and restarting it later.
We have included the combined docker-compose.yaml
at IBFT-Network/
. Inside that directory I run docker-compose up -d
. Now all 4 nodes will be up and running. Now every nodes will console its public key, address, enode URL, opened URLs for different services, and all. We copy bootnode’s enodeUrl alone and specify it in other nodes config.toml
like this.
data-path="/usr/app/data" bootnodes= ["enode: //9f97524a45e8b737989ef45c7d9ddeb95f 0c6b113627088ec faeb15583f 1aac448 61207d8fdel6cf8fdd34c2115992de8a3fc627 fa710F4034c261f [email protected]:303 03"] rpc-http-enabled=true rpc-http-api=["ETH", "NET", "IBFT"] rpc-http-port=8546 p2p-port=30304 host-allowlist=["*"] rpc-http-cors-origins=["all"] genesis-file="/usr/app/genesis. json" min-gas-price=0
If you are not using network_mode as host please change the last part of enode url (127.0.0.1:30303) to bootnode’s assigned IP.
The final folder structure will be like this (removed networkFiles
after copying):
Now we all set. Just restart all the containers and you will see from the logs, nodes will be communicating with bootnode. Within a few times network will be ready and start mining blocks. For further information check the official documentation of Besu
This article was originally published by Prasanth on his personal blog. View original article