Creating Simple Cryptocurrency using .NET and C# — Part 4. Block Header
In this post, I will write about the block header, which is very important, where the block header is the building block of the block hash. The block hash itself is the unique identity of the block or block fingerprint.
To make it easier to understand this post, I advise you to read my previous posts here: the first post, the second post, and the third post.
In the previous post, we have made transactions, blocks, and block hashes, but it’s still simple. At this time, I am improving our crypto project to be closer to real Crypto.
This article will cover:
- Block Header
- Unix Time / Epoch Time
- Cryptographic Hash Function
- Merkle Root
- Coinbase Transaction
- Stake
- Block Validator
- Number of Transactions
- Total Amount
- Transaction Fee
- Block Hash
- Create a Block
- Video Tutorial
- Conclusion
Block Header
Block header is some data belonging to a block that is used as a unique identity of the block. The block hash was created by hashing the block header through the SHA256 algorithm. It is essentially a digital fingerprint of the block. Below is the block header for Bitcoin.
As you can see, Version, Previous hash, Merkel hash, Timestamp, and the Difficulty are part of the block header, but Block number, Block size, Transaction counter, Transaction list are not included in the Block header.
Now we modify Block.cs and it will look like this:
public int Version { get; set; }
public long Height { get; set; }
public long TimeStamp { get; set; }
public string PrevHash { get; set; }
public string Hash { get; set; }
public string MerkleRoot { get; set; }
public IList<Transaction> Transactions { get; set; }
public string Validator { get; set; }
public int NumOfTx { get; set; }
public double TotalAmount { get; set; }
public float TotalReward { get; set; }
public int Difficulty { get; set; }
Unix Time / Epoch Time
Unix time or Epoch time refers to the starting point used to calculate the number of seconds that have passed. The Unix operating system started on January 1, 1970.
Timestamps are one of the most important parts of the Blockchain, which are used to compute block hashes and transaction hashes. As with Bitcoin, I will use Unix timestamps or Epoch timestamps.
long epochTicks = new DateTime(1970, 1, 1).Ticks;
long nowTicks = DateTime.UtcNow.Ticks;
long tmStamp = ((nowTicks - epochTicks) / TimeSpan.TicksPerSecond);
Console.WriteLine("Unix Timestamp: {0}", tmStamp);#result
1612623961# It was:
# Saturday, 6 February 2021 15:06:01
# Saturday, 6 February 2021 23:06:01 GMT+08:00#It means there are 1612623961 seconds since January 1, 1970.
Cryptographic Hash Function
According to Wikipedia, a cryptographic hash function (CHF) is a mathematical algorithm that maps data of arbitrary size (often called the “message”) to a bit array of a fixed size (the “hash value,” “hash,” or “message digest”). It is a one-way function, that is, a function that is practically infeasible to invert.
There are several hash functions that mostly used in Cryptocurrency: RIPEMD-160, SHA-2, and SHA-3.
For a more concrete example, let’s make a function to generate a hash of a string.
public static string GenHash(string data)
{
byte[] bytes = Encoding.UTF8.GetBytes(data);
byte[] hash = SHA256.Create().ComputeHash(bytes);
return Convert.ToHexString(hash)
}
Now we are trying to generate a hash of two strings, where the first string is less than 64 characters and the second string is more than 64 characters. After going through the hash process, the two strings will produce two hashes of length 64 characters.
// generate hash of str
var hash = GenHash(str);Console.WriteLine("Hash: {0}", hash);
Console.WriteLine("Prev Length: {0}", str.Length);
Console.WriteLine("Length: {0}", hash.Length);str = "A hash function is any function that can be used to map data of arbitrary size to a fixed size value. The value that the hash function returns is called the hash value, hash code, digest, or simply hash.";// generate hash of str
hash = GenHash(str);Console.WriteLine("Hash: {0}", hash);
Console.WriteLine("Prev Length: {0}", str.Length);
Console.WriteLine("Length: {0}", hash.Length);
The result will be like this:
Hash: 04ff6334d28f1f801e846c8639c57913d44fc42e8f905c2b344161b5ff8a359aPrev Length: 19
Length: 64Hash: 365f9961f44232dcb10f74bfb5f754a10d2c5bd6aca71efb383c0af7eb76bfc8
Prev Length: 203
Length: 64
You can change the str variable with whatever string you like, the hash (SHA256) of the string will always have a length of 64 characters.
Merkle Root
Merkle root or Merkle hash is the hash of all the hashes of all transactions within a block on the blockchain network. The Merkle root, which is the top of the Merkle Tree, was discovered by Ralph Merkel in 1979. You can read more about the Merkle tree here.
Each transaction has an ID which is the result of hashing the transaction itself. All transactions in a block are processed to produce a Merkle root. This Merkle root is part of the block header and is used as a parameter to create a block hash.
Let's create a function that does jobs like Merkle root, but to easily check the result, we don’t use the hash function.
public static string CreateMerkleRoot(IList<string> trxs)
{ // if transaction only 1
if (trxs.Count == 1)
{
var firstTrx = trxs.First();
return firstTrx;
} // if the number of transaction is odd
if (trxs.Count % 2 == 1)
{
var lastTrx = trxs.Last();
trxs.Add(lastTrx);
} // looping to create branches
var branches = new List<string>();
for (int i = 0; i < trxs.Count; i += 2)
{
// concat each pair
var pair = string.Concat(trxs[i], trxs[i + 1]);
Console.Write(trxs[i] + "+" + trxs[i+1]); Console.Write( " ");
branches.Add(pair);
}
Console.WriteLine();
var rslt = CreateMerkleRoot(branches);
return rslt;
}
Assuming we have an array of transactions “1,” “2,” “3,” “4” and then we create the Merkle Root using the above function.
string[] txs = { "1", "2", "3", "4"};
var root = CreateMerkleRoot(txs.ToList());
Console.WriteLine(root);#Result
1+2 3+4
12+34
Root: 1234
Let's try another
string[] txs = { "1", "2", "3", "4", "5" };
var root = CreateMerkleRoot(txs.ToList());
Console.WriteLine("Root: {0}", root);1+2 3+4 5+5
12+34 55+55
1234+5555
Root: 12345555
Now we implement Merkle Root for our crypto project. Let’s create a function which names CreateMerkleRoot, and hash of the transaction as an input.
Here is an algorithm for how to calculate Merkle Root:
- Get a hash of every transaction, which is the transaction ID.
- Create a pair for every two hashes. If the number of items in the list is odd, make a copy of the last item.
- Generate a new hash for each hash pair by applying the SHA256 function twice (same as bitcoin): SHA256 (SHA256 (hash0 + hash1)).
- Repeat steps 2 and 3 for new hash lists, repeat until the list has only one item.
- Merkle root is the end result of the above steps.
Coinbase Transaction
Coinbase transactions are special transactions provided to nodes creating new blocks. Transactions contain Block rewards and accumulated transaction fees. Coinbase transactions are always at the top of the order of transactions in the block.
On Consensus Proof of Stake, there is no Block Reward, but what if there are no transactions? For now, let's make the assumption that if there are no transactions the Block maker still gets a reward, we call it a coin reward.
const float COIN_REWARD = 0.01f;
Now create a function to calculate the total fees for all transactions inside the block.
private float GetTotalFees()
{
var totFee = Transactions.AsEnumerable().Sum(x => x.Fee);
return totFee;
}
Stake
According to the Proof of Stake consensus, users need to stake tokens to participate in the verification and creation of blocks in the blockchain.
I’ll be discussing specifically the PoS consensus in an upcoming post. This time I will make assumptions in order to approach PoS. We assumed that initially, there were a number of nodes (accounts) participating in the stake.
Let’s create a Stake class.
- Line number 8 to 12 is Staker class.
- Line number 17 is the list of Staker, this field will be used when choosing the winner randomly.
- Line number 19 -25 is a function to add a Staker.
- Line numbers 27 to 31 are a function to get All Stakers.
- Line numbers 33 to 72 is to Initialize the Staker list.
- Lines number 75 to 84 is a function to randomly select the validator.
Block Validator
Block validator is nodes that are selected as block creators. The validator will process the transactions, storing data, and adding new blocks to the blockchain.
How are validators selected? Validators are selected based on one or more criteria such as randomness, number of coins, age of coins, or hash calculation. Validators will get a reward from the accumulated transaction fees.
For now, to simplify the validator will be chosen randomly from the list of stakes above.
Here is the function GetValidator. The function will select validator randomly from the Staker list.
Number of Transactions
In the block body, there is information about the number of transactions inside the block.
NumOfTx = Transactions.Count;
Total Amount
The total amount is calculated from the summary of the amount for all transactions in the block.
Transaction Fee
When user transfer coins to someone else, they pay a transaction fee, it's the same as in a bank if you transfer money to someone through ATM, they charge a transaction fee.
As you know, blocks will be created in a certain period. All transactions will be merged into a block, and all transaction fees will be accumulated and given to those who make the block.
Block Hash
Block hash is the fingerprint of the block. We can generate block hash after we finish provide all block header data: Version, PrevHash, MerkleRoot, TimeStamp, Difficulty and creator. I will improve it on next post.
Below is the function for generate hash of the block.
Create a Block
After we make all the functions for providing data for the block header, we now make a build function to populate all fields that are related to the block header.
Video Tutorial
Conclusion
Block header is the property of the block that is used as parameters when calculating Block hash. This is part of the block header: version, previous hash, Merkle root, Timestamp, Difficulty, Validator.
What is Next?
Blockchain is the technology behind all cryptocurrencies. One of the main features of the blockchain is the peer-to-peer (p2p) network. P2P networks are a model of decentralized communication between nodes / peers in a blockchain network. My upcoming post is about P2P.
Thank you for reading my post. If this post is helpful please give me a bunch of claps.
Post List:
Source code for this post:
https://github.com/jhonkus/UbudKusCoin/tree/part4_block_header