Thoughts: Simply, I was extremely excited when writing this post! The blockchain has so much potential, so I am excited to share this with you. However, I did notice that it hasn't been explained well or it's easily confused with Bitcoin. I was most interested in how to actually create a blockchain so I can use this technology! I hope you enjoy this as much as I enjoyed writing it. Also, please check out the code on Github if you don't feel like following along :)
Some Quick Prep
Create a folder and name it, I named mine SirreleCoin :)
Within your terminal, change directories into your project folder and run npm init and follow the command prompts
Install the only dependency that we will soon need by running `npm install crypto-js`
Implementing the Blockchain
Create a class called Block with a constructor which takes 5 properties:
index (optional): Where the block sits within the chain
timestamp: When the block was created
data: Any type of data that we would like to store in the block. It may be useful to store the details of the transaction here, such the sender and receiver
previousHash: A string that contains the hash of the block before. This is how we verify integrity of our blockchain
hash: Contains the hash of our block
Create a function that can calculate the hash function of a block. This is done by taking the properties of the block and running them through a hash function and return the hash. This is how we can identify the block on the blockchain. For this example, we will use sha-256 as a hash function which we previously install via npm. We now will need to import this library within our main.js file so we can use it within our calculateHash() function which takes all the parameters of the Block constructor.
Now lets create a new class for our blockchain called Blockchain and give it a constructor that's responsible for initializing our blockchain. We will store our blockchain within an array called chain.
The first block on a blockchain is called the gensis block which should be created manually. We can create a method to do this called createGenesisBlock(), which will return a new Block like the following with some dummy data. Since we haven't had a pervious hash, we will just put 0.
We can now update our constructor so that we initialize the chain not as an empty array but as an array that contains our Gensis block
Now we can create some other methods that will be useful for us later called getLatestBlock(), and addBlock() which will receive a newBlock.
The getLatestBlock method simply returns the latest block within the chain
The addBlock() method is responsible for adding a new block onto the chain but it needs to do some work before it can just push blocks on the array. First is needs to set the perviousHash property of newBlock to the last block's hash on our chain. So we get the lastest block and its hash by doing the following
Next thing that we need to do since we have changed our block, we need to recalculate it's hash. Anytime we change any properties of our block, the hash function should be changed as well. Finally we can add this newBlock onto the chain array.
One thing to note, is that in reality it not this easy to add a block because there are numerous checks in place. However, just for our blockchain this is enough to demonstrate how a blockchain actually works. To test this, at the bottom of main.js create an instance of our blockchain, add a few blocks, and console a stringify version of our chain so its easier to read.
Go ahead and run the our main.js file and see what our blockchain looks like within the terminal. We can see how the blocks reference each other!
Blockchains are powerful because once they have been added, they cannot be changed without invalidating the rest of the blockchain. Our current implementation does not verify the integrity of our blockchain. Lets correct this by added a new method to our class called isChainValid(), which will return true or false depending on if its valid or not. In order to verify the integrity we will need to loop over all the blocks within our blockchain. Note that will wont start with block 0 since that's our gensis block.
Within our loop we will compare the currentBlock and the previousBlock in order to verify if that they are linked together correctly. First we test if the hash of the block is still valid. If the following are not equal we know something is wrong and we need to return false. We also we need to check if it points to the correct previousBlock hash. If its completes the loop without any issues then we can return true.
Now in the case its been detected that something broke the chain or something is wrong with it then we should have some mechanism that rolls back the changes and then puts the blockchain back in a correct state. Sadly, that is beyond the scope of this blog. We are also lacking some features such as a peer to peer network to communicate with other miners and it doesn't check if we have what is needed (maybe funds) in order to make the transaction. So there are pitfalls of this blockchain but it does demonstrate how a blockchain works behind the scenes.
Proof of Work
In the current state we can create new blocks really quickly by creating a transaction, compute it's hash, and add it to an array. Modern computers can do this extremely fast, however we don't want people to create hundreds of thousand blocks per second and spam our blockchain. Also, we have a security issue by being able to change the contents of a block and then recalculate the hashes for all the blocks after that. You will end up with a valid chain even though it was tampered with. To resolve this, blockchains use something called proof of work.
With the proof of work mechanism, you have to prove that you have put a lot of computing power into making a block. For example, bitcoin requires the hash of a block to begin with a certain amount of zeros. Since you cannot influence the output of a hash function, you simply have to try a lot of combinations and hope you get lucky with the hash that has a sufficient number of zeros in front of it. This requires a lot of computing power and is also called the difficulty. The difficulty is set so there is a steady amount of blocks. In Bitcoin's case, the goal is to create one new block every 10 minutes. As computers get faster over time they will require less time to mine a new block. In order to compensate for this, the difficulty will simply be increased. So let's now implement this!
Within our Block class, lets add a new method called mineBlock() that takes a property called difficulty. In this method we will try to make the hash of our block begin with a certain amount of 0's. Below is a quick way to make a string of zeros that is the exact length of the difficulty. We will also calculate the hash of the block and log this so we can see the output of the hash that was just mined.
We currently have an issue... The hash won't change unless we change the contents of our block, meaning what we currently have an endless loop! What can we change inside of our block? Since we dont want to change in of the current properties of the block, we can do this by adding a nonce value. A nonce value is random and doesn't have anything to do with your block, but can be changed to something random. Lets add this to our class.
Within our while loop we will increment the value as long as our hash doesn't start with enough 0's.
We need to take the nonce value into account when we are getting our hash as well.
Lets update our addBlock method and add the difficulty as a property of the Blockchain class. Also lets comment out some of the code that we were using before and add some different logs within our code.
After you run this again, you will now see that our hashes start with two 0's and this was due to us setting the difficulty to 2. However, we also saw that this was done really fast, making it easy for a spammer to generate fake blocks or tamper with the entire chain. To counteract this, we just have to increase the difficulty. Try increases the difficulty to 4 and see how long it takes...
Now our blocks start with four 0's instead of two. Using this mechanism we can control how fast new blocks can be added to our blockchain.
I hope that you found this blog interesting and useful! I would love to explore how to make this more complex or build on this over time. I have put this code on Github so if you are interested, please send me some pull requests or let me know if there are some features you would like me to implement!