Writing a Simple Blockchain
Creating the Blockchain#
To kick things off, let's open VSCode.
From here we will select
Open. This will take you to a file explorer. From here, create a new folder and call it
Now that we have the empty folder open, let's get VSCode ready for the next few steps. We want to get a
terminal up and be able to see the
To enable the terminal view, click through from the main menu:
New Terminal. If you cannot see the
file explorer, click
Show Sidebar from the main menu.
Your view should now look something like this:
Now that our development environment is ready, we will run
npm init in the terminal. This will trigger a script that allows you to create a
package.json file our project.
To keep things simple to start with, hit
enter through the prompts of this script. Once completed, you should see a
package.json file has been created with the following content:
As we won't need any dependencies just yet, we will leave this file for the moment.
Now, let's create a file called
blockchain.js in the folder we are working in. To do this, right-click (or two-finger click on Mac OS) to open a menu in the Visual Studio Code side bar. You can select
New File from the menu that appears.
A blockchain is a "chain of blocks". Let us start off by writing a class for a
Now that we have the block class, we will add a set of functions that will give us what we need to represent a block. The values of a block that we will be capturing include a timestamp, the data we want on the blockchain, a reference to a previous block and a reference of the current block. In addition, we will have a value that allows us to index the block.
We will add a function called
calculateHash that takes in the values being captured for the block, and generates and returns a hash. A hash is a function that converts one value to another. To calculate the hash for our block, we will import a library called SHA256. To have it available for our code, we will have to run it in the code directory.
Once we have this package saved, we will import a SHA256 library. Add the following line of code to the top of your file (before you declare the
Now that you have the SHA256 function available, let's start writing the
calculateHash function in the
To capture the required values, we will create a constructor to instantiate variables for them. We will be passing in the variables mentioned and then setting them in the constructor function. To generate the hash for this block, we will be calling the
calculateHash function that we just created.
At this point, code should look something like this:
Now that we have a
Block class, let's create the
Blockchain class. For this class, we will need the following functions:
We will start off by declaring the
Constructor and createGenesisBlock Function#
The constructor function starts the blockchain. The first block in a blockchain is referred to as a genesis block. Let's create a function
createGenesisBlock that will help us create a genesis block with an index set to 0.
Now that we have a function to create the genesis block, let's create our constructor. We will be setting a variable called
chain to be equal to the function we created. We will treat the
chain variable as an array of
Our constructor now starts our blockchain for us, so let's add some functionality around adding blocks, reading block information, and checking that the blockchain we have is valid.
We will write a function to get the latest block,
getLatestBlock. Since the chain is an array, we will return the last value of the array.
The next function,
addBlock will allow additional
blocks to be added to the
To create a new block, the block's values will be passed into the function, which will then set a
previousHash variable and a new block
Once we set those variables, we will push the new block into the
Since we now have blocks with hashes that point to the hash of the block that came before it, we can write a function to check if the
chain variable is valid.
We will create a function called
isChainValid which will loop through all the blocks to confirm if the hashes all correspond as they should. In the blockchain that we are building, we simply need the block we are looking at to have the hash of the block that precedes it. If the hash doesn't correspond, then the function will return
The other thing that we can check as we are looping through the blocks is whether the hash that is created for the current block is the hash that gets created if we call the
calculateHash function that we wrote for the block class.
We now have a simple blockchain function that will behave as basic blockchains do.
Test the Functions#
To test this functionality, let's run some code to see how the blockchain works.
To ensure that the code that we have created makes sense, let's run through some simple tests to validate the code and functionality. To start this process, let's initialize the simple blockchain we are working on.
We can add a block to the blockchain we created with the following function.
Let's add one more block...
Now we can call
isChainValid on the blockchain that we created. Try changing some parameters around and see if the function calls give you the results that you expect.
Adding Proof of Work Consensus#
To enhance the blockchain that we wrote in the previous section, we now have to upgrade the protocol at which blocks can be added upon.
The protocol that is most common in blockchains nowadays is called proof of work consensus. This protocol is used to confirm transactions and produce new blocks to the chain. With proof of work, miners compete against each other to complete transactions on the network and get rewarded.
Miners are users who are responsible for adding transactions to a blockchain.
Adding the Nonce to Blocks#
A nonce is an abbreviation for "number only used once," which is a number added to a hashed or encrypted block in a blockchain that, when rehashed, meets the difficulty level restrictions as described below. Since miners will be adding blocks to our blockchain, the
nonce is something that we need to add to our blocks.
Update the block constructor to include a
We will also need to update the
calculateHash function to include the