DEV Community

Cover image for Creating a blockchain in 60 lines of Javascript
FreakCdev
FreakCdev

Posted on • Updated on

Creating a blockchain in 60 lines of Javascript

In recent years, cryptocurrencies and blockchains are two uprising fields, so today, I will share my way of creating a blockchain in Javascript in just 60 lines of codes.

There's also my full tutorial on Youtube. You can check it out for more details.

Also, my new article is released, check it out! It's about creating transactions for our blockchain, basically the first step of building a cryptocurrency.

If two of those are already too familiar for you, consider checking out the third article about how to create a p2p network and release your cryptocurrency. Consider checking it out!

What is a blockchain?

Before we do any coding, we need to understand what a blockchain is. Technically, a blockchain at its bare minimum is just a list containing objects that have some basic information on it like timestamp, transactions, hash,... Its data must be immutable and unhackable. Modern platforms like Ethereum, Cardano, Polkadot,... have way more complex stuff, but we are staying simple in this article.

Setup

We are using Node.js for this project, so be sure to install it if you haven't.

Throughout the article, I will be using the object-oriented programming style, so I expect you to know basic knowledge about it.

Creating a block

As I have said, a block is just an object that has some information on it, so we should have a Block class like this:

class Block {
    constructor(timestamp = "", data = []) {
        this.timestamp = timestamp;
        // this.data should contain information like transactions.
        this.data = data;
    }
}
Enter fullscreen mode Exit fullscreen mode

So we have our timestamp and data, but a blockchain needs immutability. We can gain that effect by using a hashing function that hashes all of our properties in the block. I suggest reading about hasing on wikipedia, it plays an essential role in a blockchain. Basically, it takes in a message and outputs a "hashed" one with fixed length, a slight change to the message will make the output completely different.

I'm using the sha256 algorithm. To implement its hashing function, I'll just going to use the Nodejs' built-in crypto package:

const crypto = require("crypto"), SHA256 = message => crypto.createHash("sha256").update(message).digest("hex");
Enter fullscreen mode Exit fullscreen mode

The code above should give us what we wanted, but if you want to know how it works, check out Node.js's official doc about the hash class.

We should have something like this:

// Get the sha256 hash function.
const crypto = require("crypto"), SHA256 = message => crypto.createHash("sha256").update(message).digest("hex");

class Block {
    constructor(timestamp = "", data = []) {
        this.timestamp = timestamp;
        this.data = data;
        this.hash = this.getHash();
        this.prevHash = ""; // previous block's hash
    }

    // Our hash function.
    getHash() {
        return SHA256(this.prevHash + this.timestamp + JSON.stringify(this.data));
    }
}
Enter fullscreen mode Exit fullscreen mode

Because every time anything is changed, SHA256 will throw out something completely different, so that can some what ensures the immutability.

The prevHash property also plays a big role in immutability, it ensures that the blocks will stay unchanged along the blockchain's lifespan. It contains the hash of the previous block, so you can assure the immutability of that previous block since a slight change will make the current block's getHash be different. You can see that it's empty, but we will do something with it later in this article.

The blockchain

Let's move over to the blockchain class.

Like I have said, a blockchain is a list with blocks, so we can have a basic form like this:

class Blockchain {
    constructor() {
        // This property will contain all the blocks.
        this.chain = [];
    }
}
Enter fullscreen mode Exit fullscreen mode

You must have a genesis block, which is technically just the first block:

class Blockchain {
    constructor() {
        // Create our genesis block
        this.chain = [new Block(Date.now().toString())];
    }
}
Enter fullscreen mode Exit fullscreen mode

Just for convenience, I'll create a function to get the latest block:

    getLastBlock() {
        return this.chain[this.chain.length - 1];
    }
Enter fullscreen mode Exit fullscreen mode

Now, we should have a way to add a block to the blockchain.

    addBlock(block) {
        // Since we are adding a new block, prevHash will be the hash of the old latest block
        block.prevHash = this.getLastBlock().hash;
        // Since now prevHash has a value, we must reset the block's hash
        block.hash = block.getHash();

        // Object.freeze ensures immutability in our code
        this.chain.push(Object.freeze(block));
    }
Enter fullscreen mode Exit fullscreen mode

Validation

We need to know whether the chain is still valid or not, so we need a method to check validation. The chain is valid if a block's hash is equal to what its hashing method returns, and a block's prevHash property should be equal to the previous block's hash.

    isValid(blockchain = this) {
        // Iterate over the chain, we need to set i to 1 because there are nothing before the genesis block, so we start at the second block.
        for (let i = 1; i < blockchain.chain.length; i++) {
            const currentBlock = blockchain.chain[i];
            const prevBlock = blockchain.chain[i-1];

            // Check validation
            if (currentBlock.hash !== currentBlock.getHash() || prevBlock.hash !== currentBlock.prevHash) {
                return false;
            }
        }

        return true;
    }
Enter fullscreen mode Exit fullscreen mode

This method will play a really important role when our blockchain is ran on a p2p network.

Proof-of-work

In a peer-to-peer network, where there are no 3rd party system to approve people's action, without any consensus mechanism, nodes (people to be simple) will agree with the majority, but people can start being attackers and take control of the majority, so we need a consensus mechanism. A consensus mechanism exist not entirely to stop attacks, they exist to make people not be attackers. Proof-of-work is one of them.

Before we go more on to that, the system works by making you increase a value called nonce to get the hash which starts with a number of zeros equals/relates to the difficulty.

PoW can help with 2 things: It prevents attackers because it's near impossible to catch up with other nodes alone, and it provides mining rewards so people would try to be neutral rather than being attackers. We will implement mining rewards in the next article when we have a transaction system.

We can implement the PoW system by adding a mine method and a nonce property to our block:

class Block {
    constructor(timestamp = "", data = []) {
        this.timestamp = timestamp;
        this.data = data;
        this.hash = this.getHash();
        this.prevHash = ""; // previous block's hash
        this.nonce = 0;
    }

    // Our hash function.
    getHash() {
        return SHA256(this.prevHash + this.timestamp + JSON.stringify(this.data) + this.nonce);
    }

    mine(difficulty) {
        // Basically, it loops until our hash starts with 
        // the string 0...000 with length of <difficulty>.
        while (!this.hash.startsWith(Array(difficulty + 1).join("0"))) {
            // We increases our nonce so that we can get a whole different hash.
            this.nonce++;
            // Update our new hash with the new nonce value.
            this.hash = this.getHash();
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Because when we change a small detail in our block, the hash will be completely different, so we are just incrementing nonce over and over again until the hash matches the one we need.

(Note that Bitcoin and others normally use a different way to check difficulty, but we are staying simple)

Moving over to the Blockchain class, we should create a difficulty property:

    this.difficulty = 1;
Enter fullscreen mode Exit fullscreen mode

I will set it to 1, the difficulty should update based on how many blocks mined.

We must update the addBlock method from the Blockchain too:

    addBlock(block) {
        block.prevHash = this.getLastBlock().hash;
        block.hash = block.getHash();
        block.mine(this.difficulty);
        this.chain.push(Object.freeze(block));
    }
Enter fullscreen mode Exit fullscreen mode

Now, all blocks need to be mined before being added to the chain.

Quick note

Because we are staying simple, so I used the proof-of-work system for this blockchain. Note that most modern blockchains use a way better system called proof-of-stake (or many of its upgraded variations).

Testing out the chain!

Create a new file, that file will be the entry file.

Let's use our freshly created blockchain! I'll call it JeChain for now.

Export the needed classes first:

module.exports = { Block, Blockchain };
Enter fullscreen mode Exit fullscreen mode
const { Block, Blockchain } = require("./your-blockchain-file.js");

const JeChain = new Blockchain();
// Add a new block
JeChain.addBlock(new Block(Date.now().toString(), { from: "John", to: "Bob", amount: 100 }));
// (This is just a fun example, real cryptocurrencies often have some more steps to implement).

// Prints out the updated chain
console.log(JeChain.chain); 
Enter fullscreen mode Exit fullscreen mode

It should look like this:

Image description

The first block is our genesis block, the second block is the added block.

Updated bonus: Difficulty and block time

Block time

Block time is a constant value that resembles estimated time for a block to be added to the chain. Platforms like Bitcoin has block time of 10 minutes, while Ethereum has block time of 13 seconds.

Bitcoin's difficulty formula

With Bitcoin, its difficulty is updated every 2016 blocks were mined. It uses this formula to calculate its new difficulty:

old difficulty * (2016 blocks * 10 minutes) / mining time for the previous 2016 blocks
Enter fullscreen mode Exit fullscreen mode

Now, let's code!

First, we must have our block time first, I'll just set it to 30 seconds, which is equal to 30000ms. I'm using millisecond because it works better with Date.now().

    this.blockTime = 30000;
Enter fullscreen mode Exit fullscreen mode

(Note that we are coding in the Blockchain class here).

Just as an example, I'll create my own system: the difficulty will be incremented by 1 if block time is less than the actual time the block's mined, it will be decremented otherwise.

    addBlock(block) {
        block.prevHash = this.getLastBlock().hash;
        block.hash = block.getHash();
        block.mine(this.difficulty);
        this.chain.push(Object.freeze(block));

        this.difficulty += Date.now() - parseInt(this.getLastBlock().timestamp) < this.blockTime ? 1 : -1;
    }
Enter fullscreen mode Exit fullscreen mode

Important note!!!

Because of how we checked difficulty earlier, this should work fine. However, it is better to check difficulty using log16(difficulty) rather than the difficulty itself, and by doing that, you can now use the Bitcoin's difficulty formula.

You can come up with your own formula though. You should consider what is the best for security while still having good performance.

Source code

You can get the full source code at this repo:

GitHub logo nguyenphuminh / JeChain

JeChain decentralized application platform and experimental smart contract blockchain network

Honorable mention

I have learnt a lot about blockchains from Simply Explained. This article might never exist without help from their videos. Please check them out on Youtube, they have really good blockchain tutorial series.

I also grabbed some info on this article too. Check them out!

Off-topic

Should I continue the series? And if yes, what should I write about? Proof-of-stake? Full cryptocurrency? Smart contracts? Please let me know in the comment section.

Contacts

Latest comments (58)

Collapse
 
thechallengerr profile image
thechallengerr

bài viết hay quá a ơi

Collapse
 
andrewinsoul profile image
Okoye Andrew

Thanks for this masterpiece 🙏🙏

Collapse
 
aryaanish121 profile image
Arya Anish

Can you please make a full cryptocurrency tutorial?

Collapse
 
labzdjee profile image
Gérard Gauthier

Very interesting. I was with you until your mentioning log16(difficulty): where do you use this log16 function? As a parameter in the mine function? Elsewhere?

Collapse
 
freakcdev297 profile image
FreakCdev

What I meant was log base 16 of the difficulty, it is a better since the "real difficulty" should not drop or increase by a huge margin, and Bitcoin also uses it.

You can create a simple log16 function like this:

function log16(n) {
    return Math.log(n) / Math.log(16);
}
Enter fullscreen mode Exit fullscreen mode

So the new mine method should look like this:

    mine(difficulty) {
        while (!this.hash.startsWith(Array(Math.round(log16(difficulty)) + 1).join("0"))) {
            this.nonce++;
            this.hash = this.getHash();
        }
    }
Enter fullscreen mode Exit fullscreen mode

Also, for a little bonus, Bitcoin also requires 8 zeros by default so if you want to make it Bitcoin-like, it should be "00000000"+Array(Math.round(log16(difficulty)) + 1).join("0").

Collapse
 
labzdjee profile image
Gérard Gauthier

Thank you! That's is very clear. Effectively not as a parameter in the mine function as I mistakenly mentioned it but included in the calculation itself. It looks like the proof of work starts quite harsh with 8 zeroes and evolves quite slowly because of log16. Except maybe if one more "0" adds a lot of more difficulty in the computational demand.

Collapse
 
uche_azubuko profile image
Uchechukwu Azubuko

I really enjoyed this piece @freakcdev297

Collapse
 
careuno profile image
Carlos Merchán

continue please

Collapse
 
coderduck profile image
duccanhole

good post! from vietnam with love

Collapse
 
opauloh profile image
Paulo Henrique

Very nice article!

Collapse
 
emilienbidet profile image
Emilien Bidet

Thank you for your work, I will try it

Collapse
 
freakcdev297 profile image
FreakCdev

Thanks man! New posts will come out soon, hope you'll check them out until then!!!

Collapse
 
ronaldohoch profile image
Ronaldo Hoch

Thank you a lot for the article!
I think you can keep doing this as a serie here and continue to write a full crypto currency 😁

Collapse
 
freakcdev297 profile image
FreakCdev

Definitely!

Collapse
 
robyconte profile image
Roberto Conte Rosito

Great post!
It helps me better understanding this topic. Thank you for your sharing!

Collapse
 
freakcdev297 profile image
FreakCdev

Glad I could help!

Collapse
 
subhadas01 profile image
Subha_das01

Pliz create a topic about node.js

Collapse
 
cnitish profile image
cnitish

Thank you for this article. Appreciate this effort.

Please, if possible, kindly write about Non- Fungible Tokens and full cryptocurrency.

Cheers.

Collapse
 
freakcdev297 profile image
FreakCdev

Have just updated a system to calculate mining difficulty!

Collapse
 
freakcdev297 profile image
FreakCdev

Your welcome, stay tuned because I will release new articles about blockchain soon!