Building A Blockchain In .NET Core - P2P Network

Introduction

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 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 the 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.

Blockchain in .NET Core

In a P2P network, a computer is both a server and 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 connects 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

  1. GET /chat HTTP/1.1  
  2. Host: example.com:8000  
  3. Upgrade: websocket  
  4. Connection: Upgrade  
  5. Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==  
  6. Sec-WebSocket-Version: 13  

Server Handshake Response

When a server gets the request, it will send a standard HTTP response

  1. HTTP/1.1 101 Switching Protocols  
  2. Upgrade: websocket  
  3. Connection: Upgrade  
  4. Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=  

Then a full-duplex connection is established and 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.

  1. public class P2PServer: WebSocketBehavior  
  2. {  
  3.     bool chainSynched = false;  
  4.     WebSocketServer wss = null;  
  5.   
  6.     public void Start()  
  7.     {  
  8.         wss = new WebSocketServer($"ws://127.0.0.1:{Program.Port}");  
  9.         wss.AddWebSocketService<P2PServer>("/Blockchain");  
  10.         wss.Start();  
  11.         Console.WriteLine($"Started server at ws://127.0.0.1:{Program.Port}");  
  12.     }  
  13.   
  14.     protected override void OnMessage(MessageEventArgs e)  
  15.     {  
  16.         if (e.Data == "Hi Server")  
  17.         {  
  18.             Console.WriteLine(e.Data);  
  19.             Send("Hi Client");  
  20.         }  
  21.         else  
  22.         {  
  23.             Blockchain newChain = JsonConvert.DeserializeObject<Blockchain>(e.Data);  
  24.   
  25.             if (newChain.IsValid() && newChain.Chain.Count > Program.PhillyCoin.Chain.Count)  
  26.             {  
  27.                 List<Transaction> newTransactions = new List<Transaction>();  
  28.                 newTransactions.AddRange(newChain.PendingTransactions);  
  29.                 newTransactions.AddRange(Program.PhillyCoin.PendingTransactions);  
  30.   
  31.                 newChain.PendingTransactions = newTransactions;  
  32.                 Program.PhillyCoin = newChain;  
  33.             }  
  34.   
  35.             if (!chainSynched)  
  36.             {  
  37.                 Send(JsonConvert.SerializeObject(Program.PhillyCoin));  
  38.                 chainSynched = true;  
  39.             }  
  40.         }  
  41.     }  
  42. }  

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.

  1. public class P2PClient  
  2. {  
  3.     IDictionary<string, WebSocket> wsDict = new Dictionary<string, WebSocket>();  
  4.   
  5.     public void Connect(string url)  
  6.     {  
  7.         if (!wsDict.ContainsKey(url))  
  8.         {  
  9.             WebSocket ws = new WebSocket(url);  
  10.             ws.OnMessage += (sender, e) =>   
  11.             {  
  12.                 if (e.Data == "Hi Client")  
  13.                 {  
  14.                     Console.WriteLine(e.Data);  
  15.                 }  
  16.                 else  
  17.                 {  
  18.                     Blockchain newChain = JsonConvert.DeserializeObject<Blockchain>(e.Data);  
  19.                     if (newChain.IsValid() && newChain.Chain.Count > Program.PhillyCoin.Chain.Count)  
  20.                     {  
  21.                         List<Transaction> newTransactions = new List<Transaction>();  
  22.                         newTransactions.AddRange(newChain.PendingTransactions);  
  23.                         newTransactions.AddRange(Program.PhillyCoin.PendingTransactions);  
  24.   
  25.                         newChain.PendingTransactions = newTransactions;  
  26.                         Program.PhillyCoin = newChain;  
  27.                     }  
  28.                 }  
  29.             };  
  30.             ws.Connect();  
  31.             ws.Send("Hi Server");  
  32.             ws.Send(JsonConvert.SerializeObject(Program.PhillyCoin));  
  33.             wsDict.Add(url, ws);  
  34.         }  
  35.     }  
  36.   
  37.     public void Send(string url, string data)  
  38.     {  
  39.         foreach (var item in wsDict)  
  40.         {  
  41.             if (item.Key == url)  
  42.             {  
  43.                 item.Value.Send(data);  
  44.             }  
  45.         }  
  46.     }  
  47.   
  48.     public void Broadcast(string data)  
  49.     {  
  50.         foreach (var item in wsDict)  
  51.         {  
  52.             item.Value.Send(data);  
  53.         }  
  54.     }  
  55.   
  56.     public IList<string> GetServers()  
  57.     {  
  58.         IList<string> servers = new List<string>();  
  59.         foreach (var item in wsDict)  
  60.         {  
  61.             servers.Add(item.Key);  
  62.         }  
  63.         return servers;  
  64.     }  
  65.   
  66.     public void Close()  
  67.     {  
  68.         foreach (var item in wsDict)  
  69.         {  
  70.             item.Value.Close();  
  71.         }  
  72.     }  
  73. }  

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 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.

Blockchain in .NET Core

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

Blockchain in .NET Core

 And then, I open a new CMD window and run the following command to start the second “node”

> dotnet BlockchainDemo.dll 6001 Mahesh

Blockchain in .NET Core

Switch back to the first “node”, I display Blockchain on screen by select #3 first

Blockchain in .NET Core

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”

Blockchain in .NET Core

It returns with a handshake message to the second “node”

Blockchain in .NET Core

I display Blockchain on the second “node” by select #3

Blockchain in .NET Core

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.

Blockchain in .NET Core

From the display of the Blockchain on the second “node”, I can see a new block is created to contain the new transaction.

Blockchain in .NET Core

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.

Blockchain in .NET Core

This is because of nodes in the network broadcast changes of 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.

Summary

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 can be improved for this Blockchain. I will continue to improve it in my next article.