The Blockchain we did so far runs on one computer and creates one instance. It is time to run our Blockchain on multiple computers as a network. Because a Blockchain has no central authority to store data and manage the data exchange process, each computer should have a full copy of the Blockchain application and use a P2P protocol to communicate with each other.
What is a P2P network?
P2P stands for Peer-To-Peer. In plain English, a P2P network is created when two or more computers are connected and share resources without going through a separate server computer. All computers in a P2P network have an equal privilege. There is no need for central coordination. A computer in a P2P network is usually called a node. One of the most famous P2P systems is Napster, a file-sharing system.
In a P2P network, a computer is both a server and a client. Use BitTorrent, an application layer protocol for P2P file sharing, as of example. After a BitTorrent application is installed on a computer. The computer can connect to other BitTorrent computers to get files and it also serves local files to any computers on the BitTorrent network.
What is the benefit of a P2P network?
A P2P network has the following benefits:
- It is resilient. If one computer is down in the network, other computers can continue to work and communicate. There is no single point of failure.
- It is efficient. Because any computer on the network is both a client and a server, so a computer can get data from the closest peer computer.
The blockchain is a decentralized, distributed database. The data in a Blockchain will reside at every single node of the Blockchain network. There are always computers join the network and computers left the network, so we can’t rely on a particular computer for storing data and exchanging data. Therefore, a P2P network is the best option for building a Blockchain network.
WebSocket
There are a lot of ways to implement a P2P network, for demo purposes, I decided to use a high-level protocol, WebSocket. WebSocket provides full-duplex communication channels over a single TCP connection. It is located at layer 7 in the OSI model. The WebSocket handshake uses the HTTP Upgrade header to change from the HTTP protocol to the WebSocket protocol.
WebSocket Handshake
First of all, a server must listen for incoming socket connections using a standard TCP socket. For example, let’s assume that your server is listening on example.com, port 1234 and your socket server responds to GET requests on /chat.
Client Handshake Request
A client will start the WebSocket handshake process by sending a standard HTTP GET request
- GET /chat HTTP/1.1
- Host: example.com:8000
- Upgrade: websocket
- Connection: Upgrade
- Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
- Sec-WebSocket-Version: 13
Server Handshake Response
When a server gets the request, it will send a standard HTTP response
- HTTP/1.1 101 Switching Protocols
- Upgrade: websocket
- Connection: Upgrade
- Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Then a full-duplex connection is established and the client and server can send messages to each other. For our demo purpose, we will use .NET WebSocket to deal with all the handshake details.
Implementation
To add P2P capability into our Blockchain, we need to make the following changes
P2PServer
P2P Server is used to listen for client connections via WebSocket.
- public class P2PServer: WebSocketBehavior
- {
- bool chainSynched = false;
- WebSocketServer wss = null;
-
- public void Start()
- {
- wss = new WebSocketServer($"ws://127.0.0.1:{Program.Port}");
- wss.AddWebSocketService<P2PServer>("/Blockchain");
- wss.Start();
- Console.WriteLine($"Started server at ws://127.0.0.1:{Program.Port}");
- }
-
- protected override void OnMessage(MessageEventArgs e)
- {
- if (e.Data == "Hi Server")
- {
- Console.WriteLine(e.Data);
- Send("Hi Client");
- }
- else
- {
- Blockchain newChain = JsonConvert.DeserializeObject<Blockchain>(e.Data);
-
- if (newChain.IsValid() && newChain.Chain.Count > Program.PhillyCoin.Chain.Count)
- {
- List<Transaction> newTransactions = new List<Transaction>();
- newTransactions.AddRange(newChain.PendingTransactions);
- newTransactions.AddRange(Program.PhillyCoin.PendingTransactions);
-
- newChain.PendingTransactions = newTransactions;
- Program.PhillyCoin = newChain;
- }
-
- if (!chainSynched)
- {
- Send(JsonConvert.SerializeObject(Program.PhillyCoin));
- chainSynched = true;
- }
- }
- }
- }
After a server established a connection with a client, the server will receive a copy of the Blockchain on the client computer. The server verifies it and compares it with its own Blockchain. If the client blockchain is valid and it is longer than the server Blockchain, the server uses the client blockchain, otherwise, the server will send a copy of its own Blockchain to the client.
P2PClient
P2P Client is used to initializing a connection with a server via WebSocket.
- public class P2PClient
- {
- IDictionary<string, WebSocket> wsDict = new Dictionary<string, WebSocket>();
-
- public void Connect(string url)
- {
- if (!wsDict.ContainsKey(url))
- {
- WebSocket ws = new WebSocket(url);
- ws.OnMessage += (sender, e) =>
- {
- if (e.Data == "Hi Client")
- {
- Console.WriteLine(e.Data);
- }
- else
- {
- Blockchain newChain = JsonConvert.DeserializeObject<Blockchain>(e.Data);
- if (newChain.IsValid() && newChain.Chain.Count > Program.PhillyCoin.Chain.Count)
- {
- List<Transaction> newTransactions = new List<Transaction>();
- newTransactions.AddRange(newChain.PendingTransactions);
- newTransactions.AddRange(Program.PhillyCoin.PendingTransactions);
-
- newChain.PendingTransactions = newTransactions;
- Program.PhillyCoin = newChain;
- }
- }
- };
- ws.Connect();
- ws.Send("Hi Server");
- ws.Send(JsonConvert.SerializeObject(Program.PhillyCoin));
- wsDict.Add(url, ws);
- }
- }
-
- public void Send(string url, string data)
- {
- foreach (var item in wsDict)
- {
- if (item.Key == url)
- {
- item.Value.Send(data);
- }
- }
- }
-
- public void Broadcast(string data)
- {
- foreach (var item in wsDict)
- {
- item.Value.Send(data);
- }
- }
-
- public IList<string> GetServers()
- {
- IList<string> servers = new List<string>();
- foreach (var item in wsDict)
- {
- servers.Add(item.Key);
- }
- return servers;
- }
-
- public void Close()
- {
- foreach (var item in wsDict)
- {
- item.Value.Close();
- }
- }
- }
A client creates a new instance of WebSocket and initializes a connection with a Server. After the connection is established. The client sends a copy of its own Blockchain to a server and receives a copy of the server’s blockchain. Same as the server, the client will take the server’s blockchain if it is valid any longer.
Execution
To simulate two nodes on the same computer, I gave different port numbers for different instances.
Start Nodes
I run the following command in CMD window
> dotnet BlockchainDemo.dll 6001 Henry
It started the first “node”. The first “node” was running at port 6001 and owned by Henry
And then, I open a new CMD window and run the following command to start the second “node”
> dotnet BlockchainDemo.dll 6001 Mahesh
Switch back to the first “node”, I display Blockchain on-screen by select #3 first
The display shows there is only one block in the Blockchain, Genesis block.
Switch to the second “node”. I connect the second “node” to the first “node” by select #1 and enter the Url of the first “node”. The first “node” received a handshake message from the second “node”
It returns with a handshake message to the second “node”
I display Blockchain on the second “node” by select #3
Same as the first node, there is only one block, Genesis block.
Add A Transaction
I add a new transaction for the second “node” by choose option #2 and provides a receiver name and amount.
From the display of the Blockchain on the second “node”, I can see a new block is created to contain the new transaction.
I switch to the first “node” and display the blockchain. I can also see a new node and a new transaction in the new node.
This is because nodes in the network broadcast changes in their blockchain. Nodes receive the broadcast will compare the received Blockchain with their local Blockchain. If the received Blockchain is valid and has a longer chain than the local chain, then it will replace the local Blockchain with the received Blockchain.
Our basic Blockchain is one step closer to a real-world Blockchain now. We can see how two “nodes” communicate with each other and update changes. There are still a lot of things that can be improved for this Blockchain. I will continue to improve it in my next article.