Pair the miners (4/6)

This tutorial is part of a series of articles introduced here.

Become a Blockchain Developer!

Sign up now and you will receive 25% off our online course on Udemy!

We will never give away, trade or sell your email address. You can unsubscribe at any time.

In part 3, we configured the miners of our private blockchain.

NB: It is important that what we mean by “private Ethereum blockchain” in this context has absolutely nothing to do with the “private blockchain” championed by Hyperledger, Eris/Monax, or the recently announced Enterprise Ethereum Alliance. These are different codebases with different client applications, so they correspond to different implementations of a different set of concepts. They are private in the sense that they limit who has access to their chain. They are also called permissioned blockchains, and to be perfectly transparent, we wish they were not even called blockchains at all. In this series of articles, what we call “private blockchain” is a private instance of the Ethereum implementation. Same code base, same client application, different network identifier and genesis block. In other words, what we will come to create in this series is a chain with the same rules as the main chain, the same consensus algorithm too, but a different root block. This will become clearer in part 3. For more information about the 3-layer model and differences between concepts, implementations and instances, you can also watch our Devoxx talk and read this article.

We saw that transactions are not propagated from miner #1 to miner #2.

Remember that a blockchain is a peer-to-peer network. This means that our miners need to see each other in order to propagate transactions.

In addition, the discovery protocol is not working on a private blockchain. This means that we have to configure each node to specify the identity and the location of its peers.

This part describes how to pair our miners.

Let’s start by retrieving the node information that uniquely identify each node deployed in the blockchain.

Step 1 Clean your miners

We noticed some issues when we tried to synchronise our miners having several thousand blocks. Sometimes, miners were not able to pair or the synchronization process became too slow.

The easiest way is to reset the chaindata of the private blockchain installed on each miner.

Step 1.1 – Stop miners

First ensure that your miners are stopped.

As a reminder, you can either press ^C on the miner’s console, or search and kill the “geth” process:

computer$ ps aux | grep geth

eloudsa 43872 0.0 2.2 556717632 363492 s001 S+ 3:49PM 1:58.01 geth --identity miner1 --dev

computer$ kill -INT 43872

Step 1.2 – Delete the chaindata

Delete chain data for miners:

computer$ rm -rf ~/ChainSkills/miner1/geth
computer$ rm -rf ~/ChainSkills/miner2/geth

 

 Step 1.3 – Initialize miners

We initialize our miners with the genesis block.

Start with the miner #1:

computer$ cd ~/ChainSkills
computer$ geth --datadir ~/ChainSkills/miner1 init genesis.json

Then the miner #2:

computer$ cd ~/ChainSkills
computer$ geth --datadir ~/ChainSkills/miner2 init genesis.json

Step 2 Get IP address

Get the IP address of your computer running miners.

computer$ ipconfig getifaddr en0
192.168.1.39

Replace the interface according to your network settings:

  • en0: wired/ethernet
  • en1: wireless

Step 3 Get Node info from miner #1

Step 3.1 Node info for miner #1

Let’s start the miner #1:

computer$ cd ~/ChainSkills/miner1

computer$ ./startminer1.sh
...
 Open a second terminal and start the Geth console:
computer$ geth attach
...
>

Stop the mining to avoid generating too much blocks before the synchronisation process:

> miner.stop()
true

Retrieve the node information:

> admin.nodeInfo.enode

"enode://b8863bf7c8bb13c3afc459d5bf6e664ed4200f50b86aebf5c70d205d32dd77cf2a888b8adf4a8e55ab13e8ab5ad7ec93b7027e73ca70f87af5b425197712d272@[::]:30303?discport=0"

Step 3.2 Get Node info from miner #2

Repeat the process to retrieve the node information from the second miner.
Start the miner #2:
computer$ cd ~/ChainSkills/miner2

computer$ ./startminer2.sh
...
 Open a second terminal and start the Geth console:
computer$ geth attach ipc:./miner2/geth.ipc 
...
>

Stop the mining to avoid generating too much blocks before the synchronisation process:

> miner.stop()
true

Retrieve the node information:

> admin.nodeInfo.enode

"enode://41be9d79ebe23b59f21cbaf5b584bec5760d448ff6f57ca65ada89c36e7a05f20d9cfdd091b81464b9c2f0601555c29c3d2d88c9b8ab39b05c0e505dc297ebb7@[::]:30304?discport=0"

Step 4 – Pair the nodes

There are different ways to pair nodes.

Here, we illustrate how to define permanent static nodes stored in a file called “static-nodes.json“. This file will contain the node information of our miners.

Based on our environment, we will have the following content:

[
"enode://b8863bf7c8bb13c3afc459d5bf6e664ed4200f50b86aebf5c70d205d32dd77cf2a888b8adf4a8e55ab13e8ab5ad7ec93b7027e73ca70f87af5b425197712d272@192.168.1.39:30303",
"enode://41be9d79ebe23b59f21cbaf5b584bec5760d448ff6f57ca65ada89c36e7a05f20d9cfdd091b81464b9c2f0601555c29c3d2d88c9b8ab39b05c0e505dc297ebb7@192.168.1.39:30304"
]

You will notice that we have replaced the placeholder [::] with the IP address of our computer. The last part (?discport=0) has been removed.

Each node information is separated by a comma character.

Based on our example, the file “static-nodes.json” must be stored under the following location:

  • ~/ChainSkills/miner1
  • ~/ChainSkills/miner2

When the miner starts, the Geth process will process the file automatically.

Step 5 – Restart your miners

Stop and start the miners to ensure that they will properly reload the “static-nodes.json” file.

If you check the console of your miners, you should see a line mentioning the synchronisation process (“Block synchronisation started”):

...
I1219 01:12:03.223537 eth/downloader/downloader.go:326] Block synchronisation started
...

Step 6 – Check the synchronisation process

We check if the miners are properly paired.

Step 6.1 – Check from miner #1

Open the Geth console linked to the miner #1:

computer$ geth attach
...
>

Check which nodes are paired to miner #1:

> admin.peers
[{
 caps: ["eth/62", "eth/63"],
 id: "41be9d79ebe23b59f21cbaf5b584bec5760d448ff6f57ca65ada89c36e7a05f20d9cfdd091b81464b9c2f0601555c29c3d2d88c9b8ab39b05c0e505dc297ebb7",
 name: "Geth/miner2/v1.5.5-stable-ff07d548/darwin/go1.7.4",
 network: {
 localAddress: "192.168.1.39:59153",
remoteAddress: "192.168.1.39:30304"
 },
 protocols: {
 eth: {
 difficulty: 96831214,
 head: "0x0f8a3318a47429aee7a442cd1c3258eab7427b7fa1cb3c2a3e4bdf70ed6d8cf8",
 version: 63
 }
 }
}]

We can see that our node is paired to miner #2 identified by its IP address and its port number (30304).

Step 6.2 – Check from miner #2

Open the Geth console linked to the miner #2:

computer$ geth attach ipc:./miner2/geth.ipc 
...
>

Check which nodes are paired to miner #2:

> admin.peers
[{
 caps: ["eth/62", "eth/63"],
 id: "b8863bf7c8bb13c3afc459d5bf6e664ed4200f50b86aebf5c70d205d32dd77cf2a888b8adf4a8e55ab13e8ab5ad7ec93b7027e73ca70f87af5b425197712d272",
 name: "Geth/miner1/v1.5.5-stable-ff07d548/darwin/go1.7.4",
 network: {
 localAddress: "192.168.1.39:30304",
 remoteAddress: "192.168.1.39:59153"
 },
 protocols: {
 eth: {
 difficulty: 88045328,
 head: "0xa084d0c7f1a18120780c44bd4ba6c3ec237eb3feb0912bffd74ac1030246a723",
 version: 63
 }
 }
}]

We can see that our node is paired to miner #1 identified by its IP address and its port number (59153).

Step 7 -Validate the synchronisation

Let’s validate the synchronisation process by sending some ethers between accounts defined on each miner.

We are going to send 10 ethers between the following accounts:

  • miner #1(eth.coinbase) -> miner #2(eth.accounts[1])

eth.coinbase is the default account that receive the rewards for the mining process. In the miner #1, eth.coinbase is the same as eth.accounts[0].

First, make sure that the mining process is running on both miners.

Step 7.1 – Send ethers from Miner #1 to Miner #2

Start a Geth console linked to the miner #2, retrieve the address of the account[1] and check its initial balance:

computer$ geth attach ipc:./miner2/geth.ipc 
...
> eth.accounts[1]
"0xfa919b49ef34a821fb4cadfdfa5cc6593cb46fe1"

>  web3.fromWei(eth.getBalance(eth.accounts[1]))
0

The account #1 has no ether.

From the Geth console linked to the miner #1, send 10 ethers from the default account to the address of the account[1]:

computer$ geth attach
...
> eth.sendTransaction({from: eth.coinbase, to: "0xfa919b49ef34a821fb4cadfdfa5cc6593cb46fe1", value: web3.toWei(10, "ether")})

From the miner #1, check if the recipient has received the ethers:

> web3.fromWei( eth.getBalance("0xfa919b49ef34a821fb4cadfdfa5cc6593cb46fe1"))
10

From the miner #2, check that you have the same balance:

> web3.fromWei( eth.getBalance(eth.accounts[1]))
10

Step 7.2 – Send ethers from Miner #2 to Miner #1

We are going to send 2 ethers between the following accounts:

  • miner #2(eth.accounts[1]) -> miner #1(eth.accounts[1])

From the Geth console linked to the miner #1, check the initial balance of the account that will receive ethers:

computer$ geth attach 
...
> eth.accounts[1]
"0xae3ab39b3ebc425289dad620aece197a4a3f8940"

>  web3.fromWei(eth.getBalance(eth.accounts[1]))
0

The account #1 has 0 ether.

From the Geth console linked to the miner #2, send 2 ethers from the account #1:

computer$ geth attach ipc:./miner2/geth.ipc 
...
> eth.sendTransaction({from: eth.accounts[1], to: "0xae3ab39b3ebc425289dad620aece197a4a3f8940", value: web3.toWei(2, "ether")})

Error: account is locked
 at web3.js:3119:20
 at web3.js:6023:15
 at web3.js:4995:36
 at <anonymous>:1:1
Oops! We cannot send the transaction because the account #1 is locked.
To send transactions from an account, Ethereum requires that you unlock this account. The coinbase account is unlocked by our startminer.sh script thanks to the password file. But all other accounts are locked.
From the miner #2, unlock the account #1 with its password:
> personal.unlockAccount(eth.accounts[1], 'type your password')
true

From the miner #2, we are ready to send our transaction:

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

From the miner #2, check that our balance has changed (2 ethers plus some transaction fees):

> web3.fromWei( eth.getBalance(eth.accounts[1]))
7.99958

From the miner #1, check that the recipient has received the ethers:

> web3.fromWei( eth.getBalance(eth.accounts[1]))
2

Summary

Congratulations! You have synchronised your miners.

In part 5, we will synchronise the RPi node with these miners.

Shameless plug

While you are waiting for the next part of this series, we just wanted to let you know that we are currently preparing a full-blown online training about the development of distributed applications on Ethereum and we are looking for your feedback to figure out what you would like to see in this training. If you want to help us, you can take a few minutes to answer a survey here.

And if you just want us to keep you informed when the full online training program will be available, you can register to our mailing list on beta.chainskills.com.

11 thoughts on “Pair the miners (4/6)

Add yours

  1. Hi Said,

    Many thanks for the tutorial, very helpful indeed 🙂

    However I ran into a problem when I trie to sync up the two miners. Neither static-nodes.json nor admin.addPeer works. My miners just won’t find each other :/

    Any idea why? I strictly followed your tutorial and was able to successfully finish most of the steps before this point.

    Thanks,
    Billie

    1. Hi Billie

      Can you please share your static-nodes.json file?

      My static-nodes.json file is the following:
      [
      “enode://99ad3eb7d00fc1acec8a347961b5f2447cfeab93d2f7c9ce070d357eb300f4bd213411f2e28fe277bb43163790bd8fd7dffb6c279757fc674959b1c8c91afccc@192.168.1.39:30303”,
      “enode://192bbf6a845c3c996ddf3cbdc1eac7a8468c5ad8c4c05a5b970e4fea85e0867a9fab843e4ae0b93e360a97227c2b1c141a3bd196c4ad4b00567b1e07e1d9c2b7@192.168.1.39:30304”
      ]

      You will notice the comma character between each enode information.

      If this comma character is missing, the pairing will not work.

      Cheers

      Said

      1. Hi Said,

        Thanks for getting back to me.

        I have the comma in between the two nodes, please see the code below:

        [
        “enode://d3773bd98b93179c0512b77d65733ed18e4922522d468b6595398cec44604cd50b6b009f01148fc4d6a746c7c596be2ac8f067f77bb55b5bba017e307b1894d0@127.0.0.1:30303”,
        “enode://f21f1bbe03d60dc144acd4662e16b2b6ba2d3b6de6c3949b73957b39cebcc002380bce624ec5d7e5f72e2560590e1b3adec98a6ed4938f95b19f924ad982f6c5@127.0.0.1:30304”
        ]

        I used both my external IP and the localhost IP and neither of these worked.

        Also do you know why admin.addPeer() doesn’t work either?

        Many thanks,
        Billie

      2. If you don’t mind me asking another question.

        How does it work when two miners trying to sync with each other when they already have their own chain? When I started mining, they were building their own blocks already, so then how do they sync with each other?

        After I’ve placed the static-nodes.json file in both the data directoies, I started the two miners again, but I always get the same warning: blockchain not empty, fast synch diabled.

        I’m not sure if it has anything to do with the static-nodes.json file?

        Thanks a lot,
        Billie

        1. Interesting questions!

          First, the miner that has the longest chain will be the reference. The second miner will rebuild its chain according the reference one. At the end of this process, both chains will be synchronised.

          About your second question, don’t be surprised regarding the warning. The fast synchronisation is disabled while the synchronisation process is running between both chains.

          Btw, have you been able to sync your miners?

          1. Hi Said,

            I managed to! I’ve realized that you need to make sure both the instances are running while you use admin.adPeer. If only one is running it won’t be able to find it.

            Also for people out there who has managed to connect the two nodes using static-nodes.json bu couldn’t find them using admin.peers, you need to again make sure both nodes are running. If one is down, even if they have been connected previously admin.peers will still return an empty array.

            Cheers,
            Billie

  2. Hi,

    I enjoyed the series of articles very much. It helped me a lot in creating two nodes in sync and mining.

    I do have following questions, it would be extremely helpful if you can answer them:
    1. The process mentioned in the 4th article of the series “pair the miners…”, you have used “static-nodes.json” file. Does this file have to be copied only in nodes who will be working as minors?
    2. How do I create a non-minor node and add it in the network and also keep in sync with others?(basically is there any point in creating a node who is part of the network but isn’t a minor?)
    3. Am I correct in assuming that this process will get tedious every time we add a minor node in the network i.e. we have to update “static-nodes.json” file in each previous nodes? Is there any solution to this?
    4. I was reading about my question 3, I came across a concept called “bootnodes”. Can you please explain it to us? is there anyway or advantage of using it here in this step?

    1. Hi Pratik

      Thanks for your feedback.

      You will find my answers for each of your questions:

      1. The process mentioned in the 4th article of the series “pair the miners…”, you have used “static-nodes.json” file. Does this file have to be copied only in nodes who will be working as minors?

      The file “static-nodes.json” has to be installed in each node (miners and not miners) that are part of your private testnet. In this way, they will be able to discover themselves as part of the same network.

      2. How do I create a non-minor node and add it in the network and also keep in sync with others?(basically is there any point in creating a node who is part of the network but isn’t a minor?)

      This point is explained in this tutorial: http://chainskills.com/2017/03/27/synchronize-the-raspberry-pi-with-the-private-blockchain-56/

      The RPi is a no-miner node and needs to join the private testnet.

      3. Am I correct in assuming that this process will get tedious every time we add a minor node in the network i.e. we have to update “static-nodes.json” file in each previous nodes? Is there any solution to this?

      The tutorial focused on a “simple” approach to set-up a private testnet with a set of well know nodes that are parts of your network.

      There are different ways to set-up such networks as described here: https://github.com/ethereum/go-ethereum/wiki/Connecting-to-the-network

      4. I was reading about my question 3, I came across a concept called “bootnodes”. Can you please explain it to us? is there anyway or advantage of using it here in this step?

      “bootnodes” is the same concept as “static-nodes.json” file. The difference is that you identify your nodes in the command line of Geth. This technique is more flexible than adding a static-nodes.json file mainly if the ID of one of your nodes may change.

      Does that help?

      Cheers

      Said

Leave a Reply

Your email address will not be published. Required fields are marked *

Proudly powered by WordPress | Theme: Baskerville 2 by Anders Noren.

Up ↑