Codementor Events

Implementing proof-of-work (Blockchain in JavaScript, part 2)

Published Jun 08, 2018Last updated Dec 04, 2018
Implementing proof-of-work (Blockchain in JavaScript, part 2)

Create a Blockchain with JavaScript Pt.2

This is part 2 of a series on how to build a simple blockchain with JavaScript. In the previous part, we created a simple blockchain that allowed us to detect when someone tampered with the contents of the chain.

Problem

There are two problems with our simple blockchain that we should solve:

  • Modern computers are super fast and can add thousands of blocks to our chain. Obviously, we don't want people to spam our blockchain!

  • It's still possible to tamper with our blockchain. You can change a block’s contents and then simply recalculate the hashes (and previous hashes) for all of the blocks after it. You'll end up with a valid chain, even though you tampered with it.

Obviously, that's not what we want! So to solve these issues, blockchains have something that is called “proof of work.” With this mechanism, you have to prove that you've put a lot of computing power into making a block. This process is also called mining.

How mining works

Proof-of-work requires a block’s hash to begin with a certain number of zeros. But how can you make sure that your hash satisfies this rule? The hash of a block is determined by its contents. So if we don't change the contents, we always get the same hash.

The solution is to add a nonce value to each block. This is basically some random data that we can change until the hash of our block starts with enough zeros. And because you can't influence the output of a hash function, you have to try a lot of combinations and hope you get lucky!

The amount of zeros required is also called the “difficulty” and it's set so there's a steady amount of new blocks. In Bitcoin's case, the aim is to create one new block every 10 minutes. As computers get faster over time, they will mine new blocks faster. To compensate for that, the difficulty is automatically increased.

Implement mining into the blockchain

So let's implement this in our simple Blockchain!

Let's start by adding a nonce to our Block class:

class Block{
  constructor(timestamp, data, previousHash = '') {
    this.previousHash = previousHash;
    this.timestamp = timestamp;
    this.data = data;
    this.hash = this.calculateHash();
    this.nonce = 0;
  }

The nonce is the only value inside our block that we can change to influence the hash of the block. We can't change the timestamp or the data!

Next, let's create a mineBlock() method that will actually perform the magic of mining a block. This method will receive the required difficulty as a parameter and will keep running until the hash of our block starts with enough zeros:

mineBlock(difficulty) {
  // Keep changing the nonce until the hash of our block starts with enough zero's.
  while (this.hash.substring(0, difficulty) !== Array(difficulty + 1).join("0")) {
    this.nonce++;
    this.hash = this.calculateHash();
  }
    
  console.log("BLOCK MINED: " + this.hash);
}

I just created a simple while loop that keeps running until our hash starts with enough zeros. We use the difficulty to know how many zeros are required. A difficulty of 5 means that our hash has to start with 5 zeros.

Every time our hash doesn't have enough zeros, we increase the nonce by 1 and calculate the hash again. And if we found a hash that matches the difficulty, we log it to the console. Easy!

There's one more thing we need to do. In our calculateHash function, we're actually not taking the nonce variable into account, so I'll add it:

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

Problem solved!

Blockchain class

Let's use this new system in our blockchain class and see how it works. I'll start by defining the difficulty of our blockchain in the constructor. We define it here because we might need it in multiple places later on:

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

Then, we have to adapt the addBlock method so that it mines the block before pushing it onto our chain:

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

Using it

Alright, all done! Let's now use our new blockchain with the proof-of-work algorithm!

Let’s actually use it. Add a few console.log statements here:

let savjeeCoin = new Blockchain();
console.log('Mining block 1...');
savjeeCoin.addBlock(new Block(1, "20/07/2017", { amount: 4 }));

console.log('Mining block 2...');
savjeeCoin.addBlock(new Block(2, "20/07/2017", { amount: 8 }));

When we run this code we can see that the mining process isn't very fast anymore. The algorithm takes a while to produce blocks who's hash start with 3 zero's (as configured by the difficulty).

Now try increasing the difficulty from 3 to 5 and run it again and you'll see that it takes a lot longer to mine new blocks.

Summary

The proof-of-work algorithm allows us to control how fast new blocks can be added to our blockchain. It's perhaps the most important security mechanism of blockchains, and now you know how it works!

Source code

The source code is on GitHub and there’s a video tutorial for this second part as well.

Discover and read more posts from Xavier Decuyper
get started
post comments5Replies
Mark Cox
4 years ago

Thanks for this. Question are there security measures that are added to prevent an element in a chain array from tampering. I know that no array element that calculates the hash can be altered but how do I prevent adding some other element.

Such as:

coinName.chain[1].funkydoor = 'nasty injection'
Mark Tellez
6 years ago

I was going to say this looks like Savjee’s code but then I saw the url :) Loved this on YouTube months ago! I enjoy your channel immensely.

Martin Goebbels
6 years ago

Nothing better than a simple code to explain a concept, at least its basics. I guess the real big world is a little more complex than that, but the idea is well explained

Show more replies