The Wikipedia definition of blockchain says
A blockchain, originally block chain, is a continuously growing list of records, called blocks, which are linked and secured using cryptography.
Okay, let’s break it down to get a better understanding.
A block contains transaction data, the cryptographic hash of the previous block, the timestamp and a nonce. You must be wondering what a nonce is, It will be explained in detail later, but for now just think of it as a random number.
A block’s hash is generated using the transaction data, timestamp, previous block’s hash and the nonce as input.
For example, let’s say the hashing algorithm used is SHA-256 (more complex hashing algorithms are used in actual implementations) and assume the following as the block’s data
Transaction data : "Hello, World"
Timestamp : 1527696247729
Previous block hash : 5591ae80713bc6324cae319ddfbdbedd710aabb96a33af80b0732ecd8e42314d Nonce : 383212
We append the all the data to a string, which looks something like this
After applying SHA-256 on the above string we’ll get the value (you can experiment with SHA-256 online here)
This is the value which is going to be used in the next block’s previous block hash property.
Enough with the theory, let’s dive into code
First let’s create a helper class to return the hash of a given string using SHA-256 algorithm
Don’t worry if you don’t completely understand this method, you can replace it with any other hashing algorithm that you understand.
Now, let’s create the Block class
transactionData is a simple string and also let's not worry about the nonce for now, let it be 0, we'll be coming back to this later.
We need a class to represent a collection of blocks,
This class is pretty simple contains a List to store blocks and methods to add a block and validate the chain.
Now that we have the foundation classes, let’s create a Driver class for testing this out
On a sample run, we get the following values, the first column is the previous block’s hash value, followed by the timestamp, nonce and the transaction data.
From the output, we can see that the blockchain is valid (i,e) The previous block hashes are matching correctly.
Let’s try modifying one of the block’s
Indeed, it’s not valid because when we changed the second block’s
transactionData, the next block's
previousHash has to be updated to match the new hash. We can solve this easily by recalculating the hashes and assigning the previousHash accordingly. If changing an element is so simple, what about this statement?
By design, a blockchain is inherently resistant to modification of the data
That’s where the
nonce comes into play.
So what is a nonce?
The nonce is a number that should be predicted and acts as a proof of work, making any modification in the blockchain very hard
Blockchain implementations have a difficulty level that depends on the implementation, but to make things simpler, let’s say the produced hash should start with a specified number of zeros
For example, When difficulty is 1, the block’s hash should start with 1 zero, when the difficulty is 2, the block’s hash should start with 2 zeros and so on. The only way in which we can produce a hash that satisfies the difficulty is to try changing the nonce value and hope that some number produces a hash that meets the difficulty criteria, this method of trying every possible value to find a solution is called bruteforcing.
To add that functionality to our implementation, let’s start with adding the
mine method to the
In the method, we are incrementing the value of
nonce until the hash starts with the number of zeros specified by the
difficulty. Then we call this method in the
BlockChain class before adding a block to the chain
addBlock to mine block before adding to the blockchain
isValid method needs to check every block if it satisfies the difficulty criteria, so it should look something like this
And finally, we pass the difficulty from the main method
On a sample run, we get the following output
Nonce values, for the first block, it took 5,11,316 calls to
getHash() to find a nonce value that satisfies the difficulty criteria. We have used a difficulty of 5 which is tiny, in actual implementations the difficulty is much higher and also a much complex hashing algorithm will be used.
Imagine having a chain of about 10 blocks, if block 3 is modified, then the nonce values for blocks starting from 3 need to be recalculated which is a pretty expensive and time consuming operation. The nonce is what makes it difficult to modify the blocks in a blockchain. Try tinkering with the difficulty values and you can observe that as the difficulty increases, the time taken to calculate the nonce increases exponentially.
The full source code is available here.