Build a Tiny Blockchain with Nodejs - Chapter 2

4 minute read

In chapter 1 we built a simple blockchain with Nodejs to demonstrate how a blockchain works.

Anyway the blockchain in chapter 1 was not yet complete as it’s facing many issues as below:

  1. People could create blocks quickly and cause blocks as spam.
  2. It’s very easy to create a valid block.
  3. People could take control of the blockchain. Blockchains are powered by a peer-to-peer network in which the nodes will add blocks to the longest chain available. So people could tamper a block, recalculate all the other blocks and then add as many blocks as they want. They could end up with the longest chain and all the peers will accept it and start adding their own blocks to it.

That’s why our blockchain needs another mechanism (is proof-of-work) to secure itself against attackers.

Proof of Work

A Proof of Work is a piece of data which is difficult (costly, time-consuming) to produce but easy for others to verify and which satisfies certain requirements. proof-of-work will exist before the first blockchain was created. It’s a simple technique that prevents abuse by requiring a certain amount of computing work. That amount of work is a key to prevent spam and tamper.

Bitcoin implements proof-of-work by requiring that: the hash of a block starts with a specific number of zero’s that was called the difficulty.

So, How can the hash of a block change? In this case a block contains details about a financial transaction. Yes, sure we don’t want to mess up with that data just to get a correct hash.

Solutions

To fix this issues, blockchains add a nonce value. This is a number that gets incremented until a good hash is found. And because we can’t predict the output of a hash function, we simply have to try a lot of combinations before you get a hash that satisfies the difficulty. Noted: looking for a valid hash (to create a new block) was called “mining” in the crypto world.

Implementing

Modifying Block class

Let’s start by modifying the Block class and adding the nonce property in it’s constructor.

constructor(index, timestamp, data, previousHash = '') {
  this.index = index;
  this.timestamp = Math.floor(Date.now() / 1000);
  this.data = data;
  this.previousHash = previousHash;
  this.hash = this.calculateHash();
  this.nonce = 0;
}

We are going to create a new method that will increase the nonce value until we get a valid hash and this is dictated by the difficulty:

mineBlock(difficulty) {
  while (this.hash.substring(0, difficulty) !== Array(difficulty + 1).join("0")) {
    this.nonce++;
    this.hash = this.calculateHash();
  }

  console.log("BLOCK MINED: " + this.hash);
}

And then we also going to update the calculateHash() function because currently it doesn’t use the nonce property to calculate the hash:

calculateHash() {
  return SHA256(
    this.index +
    this.previousHash +
    this.timestamp +
    JSON.stringify(this.data) +
    this.nonce
  ).toString();
}

So the full of Block class code should be look so:

class Block {
  constructor(index, timestamp, data, previousHash = '') {
    this.index = index;
    this.timestamp = Math.floor(Date.now() / 1000);
    this.data = data;
    this.previousHash = previousHash;
    this.hash = this.calculateHash();
    this.nonce = 0;
  }

  calculateHash() {
    return SHA256(
      this.index + 
      this.previousHash + 
      this.timestamp + 
      JSON.stringify(this.data) + 
      this.nonce
    ).toString();
  }

  mineBlock(difficulty) {
    while (this.hash.substring(0, difficulty) !== Array(difficulty + 1).join("0")) {
      this.nonce++;
      this.hash = this.calculateHash();
    }

    console.log("BLOCK MINED: " + this.hash);
  }
}

Modifying Blockchain class

Now blocks have a nonce and can be mined, so we are going to implement that behaviour with blockchain as well. Let getting start by adding a new property to the blockchain to keep track of the difficulty of the chain. We will start by set it to 5 (meaning that the hashes of blocks should start with 5 zero’s).

constructor() {
  this.chain = [this.createGenesisBlock()];
  this.difficulty = 2;
}

And then we are going to change addBlock() method so that it actually mines the block before adding it to the chain. We’ll pass the difficulty to the block:

addBlock(newBlock) {
  newBlock.previousHash = this.getLatestBlock().hash;
  newBlock.mineBlock(this.difficulty);
  this.chain.push(newBlock);
}

So the full of Blockchain class code should be look so:

class Blockchain {
  constructor() {
    this.chain = [this.createGenesisBlock()];
    this.difficulty = 5;
  }

  createGenesisBlock() {
     return new Block(0, "Genesis block", "0");
  }

  getLatestBlock() {
    return this.chain[this.chain.length - 1];
  }

  addBlock(newBlock) {
    newBlock.previousHash = this.getLatestBlock().hash;
    newBlock.mineBlock(this.difficulty);
    this.chain.push(newBlock);
  }

  isChainValid() {
    for (let i = 1; i < this.chain.length; i++){
      const currentBlock = this.chain[i];
      const previousBlock = this.chain[i - 1];

      if (currentBlock.hash !== currentBlock.calculateHash()) {
        return false;
      }

      if (currentBlock.previousHash !== previousBlock.hash) {
        return false;
      }
    }

    return true;
  }
}

So far so good, blockchain now has proof-of-work to protect against spam and tamper.

Testing

Okay, now let’s test the blockchain and see what is the effects of proof-of-work on adding new blocks to the chain.

let myCoin = new Blockchain();

console.log('Mining block 1');
myCoin.addBlock(new Block(1, { amount: 4 }));

console.log('Mining block 2');
myCoin.addBlock(new Block(2, { amount: 8 }));

We’ll see that adding new blocks is still very fast because the difficulty was set to 2 (or computers are really fast).

If we set the difficulty to 5, we’ll see that a computer would takes about 10 seconds to mine a block. Now We have a great protection from attackers.

You can download the source code and try it out on Github.

Categories:

Updated: