Block structure in blockchain
We looked at how blockchain adjusts the difficulty of the Proof-of-Work algorithm in the last article. In this article, let’s explore the fundamentals of block in blockchain and its structure.
We have already seen that we can add a transaction to the ledger every 10 minutes. Now, how practically useful is this? Imagine the amount of time one has to spend to add their transaction to the ledger when millions of transactions occur every second! So, how can we make transactions faster?
Packing transactions into a block
To do that, we pack multiple transactions into a unit called a block. Now, instead of hashing a transaction and using it as a reference in the following transaction, we create a chain by hashing the header of a block (let’s look at the block header in a while) and referencing that in the header of the next block. This way we will be creating a chain of blocks.
Thus, after solving the puzzle, we will be adding a block of transactions to the blockchain instead of a single transaction. We call the process of solving the puzzle to add a block to blockchain mining. And we call the parties trying to mine blocks miners.
A block can consist of a maximum of 1 Mb of data and hence, on average, can include around 500 transactions. Therefore, on average, we can have 500 transactions confirmed every 10 minutes. This is a better outcome than being able to confirm just a single transaction every 10 minutes.
Now, let’s see the structure of a block. A block consists of the following fields:
- Magic Number
- Block Header
- Block size
- Transaction Counter
A block consists of five different fields, the first of which is the magic number. The magic number is a numerical constant of value 0xD9B4BEF9. We use this to identify a blockchain network. This number denotes the beginning of a block and specifies that the block belongs to the production network.
The block size indicates the size of the block. It is 1 Mb for a Bitcoin block. The transactions field consists of a list of all the transactions included in the block and the transaction counter indicates the number of transactions present in the block.
The block header
The block header consists of six fields, namely:
- Previous Block Hash
- Merkle Root
To begin with, let’s look at the version field. This field indicates the protocol version of the block. The protocol, which is the blockchain algorithm, can undergo changes and this version helps identify the version a block belongs to.
Secondly, let’s talk about the previous block hash. This is the hash of the header of the previous block. As we saw earlier, this helps build a chain of blocks by having each block reference its predecessor in its header.
Next, let’s have a look at the time field. This denotes the time at which the block’s header was hashed. As mentioned in a previous article, this helps us in calculating the time taken to mine 2016 blocks. This is, in turn, used to adjust the mining difficulty.
The next field is the bits field. Bits indicates the target. As we discussed in an earlier article, this is a 32-bit integer that can be converted to a target hash value. Miners will be trying to mine blocks with a hash value less than or equal to this target hash value.
Now, let’s talk about one of the most important fields in the header, namely the nonce field. The nonce is a 32-bit integer field. Miners adjust this field in order to try to get a hash value below or equal to the target hash value. It is also worth noting that every time the nonce is changed, the time value also changes just before hashing. This means that there are actually two fields that are modified to produce a different hash value.
The Merkle root
Finally, let’s talk about the Merkle root field. This field contains the hash of all the transactions in the block. You may wonder why we need this. Well, what do you think is actually holding me back from fraudulently adding more transactions to a block after I mine the block? The answer is Merkle root.
Since the Merkle root is a hash of all the transactions in the block, if new transactions are added to the block, then the hash of all of these transactions would be different from the Merkle root hash. So, any party in the network can hash the transactions in a block and see if it matches the Merkle root hash. If they match, then that means the block is valid. If they don’t, then that means new transactions have been added to the block after the block was mined.
But how are all the transactions hashed together? And why do we call it the Merkle root? Let’s try to find the answer.
Constructing the Merkle root
Let’s say there are 9 transactions in a block namely A, B, C, D, E, F, G, H, and I. To hash all of them together, what we do is we hash every transaction individually and pair two hashes together. If there is an odd number of transactions, which is the case with our example, we duplicate the remaining transaction and pair these two. This will give us this:
(hA, hB) – (hC, hD) – (hE, hF) – (hG, hH) – (hI, hI)
Now, let’s hash together the pairs. So, (hA, hB) will give us h(hA, hB), and so on and so forth. Let’s do this to every pair and we will end up with this:
h(hA, hB) – h(hC, hD) – h(hE, hF) – h(hG, hH) – h(hI, hI)
Now, let’s pair up these hashes.
(h(hA, hB), h(hC, hD)) – (h(hE, hF), h(hG, hH)) – (h(hI, hI), h(hI, hI))
Once done, let’s hash them again.
h(h(hA, hB), h(hC, hD)) – h(h(hE, hF), h(hG, hH)) – h(h(hI, hI), h(hI, hI))
Let’s pair these hashes again and hash the pairs once again.
(h(h(hA, hB), h(hC, hD)), h(h(hE, hF), h(hG, hH))) – (h(h(hI, hI), h(hI, hI)), h(h(hI, hI), h(hI, hI)))
h(h(h(hA, hB), h(hC, hD)), h(h(hE, hF), h(hG, hH))) – h(h(h(hI, hI), h(hI, hI)), h(h(hI, hI), h(hI, hI)))
Now, we have only two hashes. Let’s hash them together.
h(h(h(h(hA, hB), h(hC, hD)), h(h(hE, hF), h(hG, hH))), h(h(h(hI, hI), h(hI, hI)), h(h(hI, hI), h(hI, hI))))
Thus, we have just one hash now which actually contains information about all the transactions in the block. We call it the Merkle root hash. Even if one of the constituent hashes changes, it will result in a chain reaction of changes to the hashes, ultimately producing a different Merkle root hash.
The Merkle tree
Consequently, we can ensure that no transaction in the block has been tampered with. To give you a better idea about the Merkle root hashing, let’s represent the example in a tree diagram. We call this tree a Merkle tree.
Now, you may wonder why we need to pair the transactions together and hash them instead of just bundling all of them together and hashing them at once. We will look at the reason for this in the next article.
[…] looked at Merkle proof in the previous article and that concluded our discussions on blocks and their structure. In this article, we shall look at […]