Blockchain protocol part 1

This post will be the first part of a two-part article on the protocol. This section focuses on the topic of communication between nodes and the consensus algorithm.

Theory
To understand this topic, we need to introduce a few additional concepts:

  • protocol – a set of rules by which different devices can communicate with each other,
  • decentralization – no central unit supervising the entire communication process between nodes,
  • consensus (compliance) algorithm – solving the problem of reconciliation by a set of units of one value from the set of values ​​initially proposed by these units.


A protocol in the blockchain world is a set of rules by which nodes communicate with each other. In other words, it defines the rules by which nodes can become part of a network created using this technology. Each project based on the blockchain methodology can operate using a different protocol.

Decentralization and consensus algorithm


The main features that have contributed to the popularization of blockchain technology are decentralization and security. For the system to be decentralized, the network must consist of at least two nodes, none of which have an overriding structure. Such devices must be compatible in order to be equally valid, which usually involves the storage of an identical chain.

For this purpose, there is a set of rules by which the decentralized network comes to agreement on issues such as the current value of the blockchain. Such a set of rules is a consensus algorithm.

There are several popular algorithms. These include:

Proof of Work

In this algorithm, network users solve a puzzle to create a block.

The node that creates the next block first will have the longest chain, and hence will win the conflict resolution process about which chain is authoritative because the longest is considered to be.

Proof of Stake

In this algorithm, blocks are created by those users who have tokens or coins.

If there is a conflict, the nodes vote for the appropriate chain with their tokens. If a given user voted for a chain that did not win the vote, the tokens used by him to vote are taken from him,

Delegated Proof of Stake

In this algorithm, blocks are created by delegated nodes selected by network users by voting

Due to the small number of nodes creating blocks, the system is able to schedule appropriate time slots for each of the delegates to publish blocks. Selected nodes may be changed by the system by voting, if necessary, e.g. the delegated node does not fulfill its obligations correctly. In this model, the nodes cooperate with each other, instead of competing as in the PoW and PoS models,

Proof of Authority

In this algorithm, blocks are created by nodes whose accounts have been positively validated. These network elements resolve conflicts and determine the state of the system. Such a model is typically used in private networks due to some centralization that occurs in them.

I am sure that in new projects using this technology, various variations and combinations using the above-mentioned algorithms have been created or are currently being developed, or that completely new concepts are created.

In the next part, and in the example implementation, I focused on probably the most popular Proof of Work algorithm.

Proof of Work, i.e. digging, excavators and miners

As I wrote before, a decentralized network consists of at least two points. The owners of the nodes in such a network are colloquially referred to as miners because they usually have to do some work to dig up the next block. The entire process of digging takes place on a device called an excavator, the work done by miners with such equipment is colloquially called digging, and the entire process is mining because the two activities are similar to each other to some extent.

Both miners and node owners do the work with the right tools to obtain some good. In other words, they turn labor into a material that acquires value by the fact that a given unit of time or raw material has been used up to obtain it. Therefore, the virtual units created as a result of this process, i.e. cryptocurrencies or tokens, can have value and can be exchanged for other goods, as is currently the case on various exchanges.

Sample block creation process using a simple protocol

How is block building done using simple protocol?

  1. Launching the node – launching an appropriate program enabling communication with other network points,
  2. node registration – sending information about the new node to other network nodes,
  3. adding transactions,
  4. block adding (digging),
  5. conflict resolution (obtaining consensus among nodes).

A simple implementation of such a protocol is described below.

Assumptions

  • The nodes communicate with each other using the HTTP protocol in the client-server model, where everyone can be a client, and the server is the node on which the web server is running, and its url is registered on other nodes.
  • The consensus algorithm is based on the Proof of Work model.


I purposely did not focus on encryption, transaction and block validation, and transaction distribution between nodes. There is also no time quantum in the implementation below on which the creation of the block would depend.

These issues will be devoted to the next part of the article on the blockchain protocol. In the example below, the emphasis is primarily on ensuring communication between network points and on the consensus algorithm.

Building a blockchain

I had to modify the block class a bit in terms of the algorithms that I used in my protocol. Currently, a block class consists of the following properties:

  • index – block number (ordinal number),
  • time stamp – block creation time,
  • nonce – proof of work (solving the puzzle),
  • hash of the previous block,
  • transaction list.
  1. public class Block
  2. {
  3. public int Index { get; set; }
  4. public DateTime Timestamp { get; set; }
  5. public int Nonce { get; set; }
  6. public string PreviousHash { get; set; }
  7. public List TransactionList { get; set; }
  8. }

Then I created a Blockchain class which consists of the following properties:

  • node identifier – user address that can be used to send units of account,
  • empty list of current transactions – new transactions are added to this list, which are placed in a new block after its excavation,
  • empty block list – this list will contain all checked and approved blocks, creating a blockchain,
  • network node lists – lists of all nodes that have been registered in the network.
  1. public class Blockchain
  2. {
  3. public string NodeId { get; }
  4. private readonly List current TransactionList = new List();
  5. private List blockList = new List();
  6. private readonly List nodes = new List();
  7. }

Blockchain after initialization looks like this:

  1. {
  2. “blockList”:[
  3. {
  4. “Index”:0,
  5. “Timestamp”:”2018-11-01T10:52:11.7555162Z”,
  6. “Nonce”:100,
  7. “PreviousHash”:””,
  8. “TransactionList”:[]
  9. }
  10. ],
  11. “length”:1
  12. }

Create new blocks

When the blockchain is initialized, an underlying block, known as a block, is created. genesis block. It is a block that has no ancestors (previous blocks), the hash of the previous block is empty, and the proof of work is set to a fixed value (not computed).

I supplemented the Blockchain class with additional methods for attaching a new CreateNewBlock block, adding CreateTransaction transactions and generating a GetHash block hash:

 

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
private Block CreateNewBlock(int nonce, string previousHash = null)
{
    var block = new Block(this.blockList.Count, DateTime.UtcNow, nonce,
                          previousHash ?? this.GetHash(this.blockList.Last()),
                          this.currentTransactionList.ToList());
 
    this.currentTransactionList.Clear();
    this.blockList.Add(block);
    return block;
}
 
internal int CreateTransaction(string from, string to, double amount)
{
    var transaction = new Transaction
    {
        From = from,
        To = to,
        Amount = amount
    };
 
    this.currentTransactionList.Add(transaction);
    return this.LastBlock?.Index + 1 ?? 0;
}
 
private string GetHash(Block block)
{
    string blockText = JsonConvert.SerializeObject(block);
    return Helper.GetSha256Hash(blockText);
}

Block creation takes place during the mining process (Blockchain class method):

1
2
3
4
5
6
7
internal string Mine()
{
    int nonce = this.FindNonce(this.LastBlock.Nonce, this.LastBlock.PreviousHash);
 
    this.CreateTransaction("0", this.NodeId, 1);
    Block block = this.CreateNewBlock(nonce /*, _lastBlock.PreviousHash*/);
}

In the digging process, there is work to look for evidence, the so-called nonce. In this example it is done in a loop in which the nonce, starting with the value 0, is checked for correctness. If it is correct, it exits the loop, if it is not, the nonce is incremented by 1 and the operation in the loop repeats.

Validation consists in generating a string of characters consisting of the last proof of work (lastNonce), the currently checked proof (nonce) and the hash of the previous block (previousHash). The string is then hashed and checked to see if the start of the hash starts with three zeros. After finding a suitable proof, a transaction with the value of 1 unit of account, the recipient of which is the current node, is added to the new block. This is the reward for digging the block.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private int FindNonce(int lastNonce, string previousHash)
{
    int nonce = 0;
    while (!this.IsValidNonce(lastNonce, nonce, previousHash))
        nonce++;
 
    return nonce;
}
 
private bool IsValidNonce(int lastNonce, int nonce, string previousHash)
{
    string guess = $"{lastNonce}{nonce}{previousHash}";
    string result = Helper.GetSha256Hash(guess);
    return result.StartsWith("000");
}

Consensus algorithm - conflict resolution

The agreement algorithm is that each node gets the blockchain from every other registered node on the network and compares the length of its chain with the one downloaded. If the length of the downloaded string is longer, the string in the source node is overwritten. The point is that the node with the longest chain was the first to find proof of work and its block was added to the chain.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
private bool ResolveConflicts()
{
    List<Block> newChain = null;
 
    foreach (Node node in this.nodes)
    {
        var url = new Uri(node.Address, "/blockchain");
        var request = (HttpWebRequest) WebRequest.Create(url);
        var response = (HttpWebResponse) request.GetResponse();
 
        if (response.StatusCode == HttpStatusCode.OK)
        {
            var model = new
            {
                blockList = new List<Block>(),
                length = 0
            };
            Stream stream = response.GetResponseStream();
            if (stream != null)
            {
                string json = new StreamReader(stream).ReadToEnd();
                var data = JsonConvert.DeserializeAnonymousType(json, model);
 
                if (data.blockList.Count > this.blockList.Count &amp;&amp; this.IsValidBlockList(data.blockList))
                {
                    newChain = data.blockList;
                }
            }
            else
            {
                Debug.WriteLine("Unable to get response stream");
            }
        }
    }
 
    if (newChain != null)
    {
        this.blockList = newChain;
        return true;
    }
 
    return false;
}

Web server

A simple TinyWebServer library was used to implement the web server through which the nodes communicate with each other. With its help, it is possible to receive and process requests. I have prepared several methods on this server. They are used to perform the appropriate operations on the blockchain of a given node:

mine – digging – creating a new block,
transactions / new – adding a new transaction,
blockchain – blockchain download,
nodes / register – node registration,
nodes / resolve – conflict resolution.
A simple console application was written to run the server. It creates a new Blockchain object and based on it, it initializes the web server, which starts listening on the given address and port set in the appsettings.json configuration file.

1
2
3
4
5
6
7
8
9
static void Main(string[] args)
{
    IConfiguration config = Helper.GetConfigFromFile("appsettings.json");
 
    var blockchain = new Blockchain.Blockchain();
    var unused = new WebServer(blockchain, config["server"], config["port"]);
    Console.WriteLine($"Serwer o adresie {config["server"]}:{config["port"]} został uruchomiony");
    Console.Read();
}

System start-up and test

For the test, I prepared two versions of the console application that differed in the configuration file, and then launched them.

1
2
3
4
PS C:\> dotnet C:\#Temp\publish1\MySimpleBlockchainWithPoW.ServerCore.dll
Serwer o adresie localhost:12345 został uruchomiony
PS C:\> dotnet C:\#Temp\publish2\MySimpleBlockchainWithPoW.ServerCore.dll
Serwer o adresie localhost:54321 został uruchomiony

As a result, two nodes appeared – one at localhost: 12345 (number f0f673698fa04d10bd3be1c457a2f9b6) and the other at localhost: 54321 (number 54dd864a5b3444b3b30ed07568163629).

Then, using the Postman application, I send requests to the nodes. To connect these two ends in a network, I have to register them with each other by sending nodes / register requests:

1
2
REQUEST POST url: http://localhost:54321/nodes/register body: {"url": "localhost:12345"}
REQUEST POST url: http://localhost:12345/nodes/register body: {"url

As a result, they receive the answer, respectively:

RESPONSE body: “Node localhost: 12345 has been registered”
RESPONSE body: “Node localhost: 54321 has been registered”

I will copy the first block (empty):

1
REQUEST GET url: http://localhost:54321/mine

RESPONSE body:

1
2
3
4
5
6
7
8
9
10
11
12
13
{
    "Message": "Nowy blok został wygenerowany",
    "Index": 1,
    "Transactions": [
        {
            "Amount": 1.0,
            "From": "0",
            "To": "54dd864a5b3444b3b30ed07568163629"
        }
    ],
    "Nonce": 862,
    "PreviousHash": "515a53f26e8047ff2cfe84ca5a632dfb56c05099c2096a5d7cfa3801839bfb48"
}

Then I do block synchronization:

1
2
REQUEST GET url: http://localhost:12345/nodes/resolve
REQUEST GET url: http://localhost:54321/nodes/resolve

After this transaction, node number 54dd864a5b3444b3b30ed07568163629 has 1 unit and the strings are synchronized. In the next step, I add the transaction:

1
2
REQUEST POST url: http://localhost:54321/transactions/new body: { "Amount":0.5, "From":"54dd864a5b3444b3b30ed07568163629", "To":"f0f673698fa04d10bd3be1c457a2f9b6" }
RESPONSE body: Your transaction will be added to block 2
1
REQUEST GET url: http://localhost:54321/mine

RESPONSE body:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
    "Message": "Nowy blok został wygenerowany",
    "Index": 2,
    "Transactions": [
        {
            "Amount": 0.5,
            "From": "54dd864a5b3444b3b30ed07568163629",
            "To": "f0f673698fa04d10bd3be1c457a2f9b6"
        },
        {
            "Amount": 1.0,
            "From": "0",
            "To": "54dd864a5b3444b3b30ed07568163629"
        }
    ],
    "Nonce": 1593,
    "PreviousHash": "1e582c742100802ee887497ad69c6a69abe520ce57d0061aeaeebf8987c7bf3e"
}

Finally, I’m doing block synchronization again:

1
REQUEST GET url: http://localhost:54321/nodes/resolve

RESPONSE body:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
{
    "Message": "Nasz blockchain jest autorytatywny",
    "BlockList": [
        {
            "Index": 0,
            "Timestamp": "2018-11-12T10:02:55.7210083Z",
            "Nonce": 100,
            "PreviousHash": "",
            "TransactionList": []
        },
        {
            "Index": 1,
            "Timestamp": "2018-11-12T10:11:18.5521277Z",
            "Nonce": 862,
            "PreviousHash": "515a53f26e8047ff2cfe84ca5a632dfb56c05099c2096a5d7cfa3801839bfb48",
            "TransactionList": [
                {
                    "Amount": 1.0,
                    "From": "0",
                    "To": "54dd864a5b3444b3b30ed07568163629"
                }
            ]
        },
        {
            "Index": 2,
            "Timestamp": "2018-11-12T10:33:20.1480628Z",
            "Nonce": 1593,
            "PreviousHash": "1e582c742100802ee887497ad69c6a69abe520ce57d0061aeaeebf8987c7bf3e",
            "TransactionList": [
                {
                    "Amount": 0.5,
                    "From": "54dd864a5b3444b3b30ed07568163629",
                    "To": "f0f673698fa04d10bd3be1c457a2f9b6"
                },
                {
                    "Amount": 1.0,
                    "From": "0",
                    "To": "54dd864a5b3444b3b30ed07568163629"
                }
            ]
        }
    ]
}
1
REQUEST GET url: http://localhost:12345/nodes/resolve

RESPONSE body:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
{
    "Message": "Nasz blockchain został zamieniony",
    "BlockList": [
        {
            "Index": 0,
            "Timestamp": "2018-11-12T10:02:55.7210083Z",
            "Nonce": 100,
            "PreviousHash": "",
            "TransactionList": []
        },
        {
            "Index": 1,
            "Timestamp": "2018-11-12T10:11:18.5521277Z",
            "Nonce": 862,
            "PreviousHash": "515a53f26e8047ff2cfe84ca5a632dfb56c05099c2096a5d7cfa3801839bfb48",
            "TransactionList": [
                {
                    "Amount": 1.0,
                    "From": "0",
                    "To": "54dd864a5b3444b3b30ed07568163629"
                }
            ]
        },
        {
            "Index": 2,
            "Timestamp": "2018-11-12T10:33:20.1480628Z",
            "Nonce": 1593,
            "PreviousHash": "1e582c742100802ee887497ad69c6a69abe520ce57d0061aeaeebf8987c7bf3e",
            "TransactionList": [
                {
                    "Amount": 0.5,
                    "From": "54dd864a5b3444b3b30ed07568163629",
                    "To": "f0f673698fa04d10bd3be1c457a2f9b6"
                },
                {
                    "Amount": 1.0,
                    "From": "0",
                    "To": "54dd864a5b3444b3b30ed07568163629"
                }
            ]
        }
    ]
}

As we were digging on the localhost: 54321 node, there was a longer string there and therefore it was authoritative and at the end of localhost: 12345 it was replaced. As you can see, after resolving the conflicts, both chains are identical and contain the transactions I added.

Summary

In this text, the theory and implementation of the blockchain protocol was centered around communication between nodes and the consensus algorithm.

It presents the use of the basic algorithms and mechanisms that make up the protocol, which are currently used in the practical application of blockchain technology. The most important features of the methodology are preserved, i.e. immutability and decentralization.

In the next part, I will add additional mechanisms such as validation, encryption and synchronization of transactions based on private key algorithms. I will introduce certain chunks of time to create blocks.

Posted in Blockchain, DevelopementTags:
3 Comments
  • James Rodri

    If it’s fast and cheap, it will never be good. If it’s cheap and good, it will never work out quickly. And if it is good and fast, it will never come cheap. But remember: of the three you still have to always choose two.

    14:38 26 January 2020 Reply
  • Jack Morrison

    Think about the content that you want to invest in a created object, and only then will form. The thing is your spirit. A spirit unlike forms hard copy.

    14:38 26 January 2020 Reply
    • admin

      I love the feel and sophistication of its superiority. I like people with a keen mind and at the same time easy to talk to.

      14:38 26 January 2020 Reply
Write a comment