Skip to main content

Blockchain implementation using JavaScript

7 min read

Older Article

This article was published 8 years ago. Some information may be outdated or no longer applicable.

Blockchain is the buzzword that won’t go away. The best way to study any technology is to get your hands dirty, so in this article we’ll build a blockchain using JavaScript. While wiring up the implementation, we’ll also pick up the basics of how the technology works.

What is blockchain?

The simplest explanation: it’s a distributed and decentralised public ledger. The name “blockchain” comes from the fact that a “block” contains a transaction (a new piece of data, anything from medical records to voting records). Each new transaction creates another block, and they’re all bolted onto a chain. Hence: blockchain, a chain of blocks.

Please note that often blockchain and cryptocurrencies (like Bitcoin) seem to be used interchangeably - this is however not true. The blockchain is the technology that enables cryptocurrencies like Bitcoin to exist in the first place.

Let’s dig into the “distributed and decentralised public ledger” bit. The data held by a blockchain is shared, meaning there’s no centralised version sitting anywhere. It’s distributed amongst hundreds, thousands, or even millions of computers, and the stored information is open to everyone.

Let’s build what we’ve discussed. A blockchain is a chain of blocks, so our implementation needs a method to generate a block and some mechanism to hold all the blocks together.

Get the code

The codebase for this article is available on GitHub.

Creating a block

For our purposes, a block contains: an index (the length of all blocks in the chain plus one, since the chain is a 0-indexed array), a timestamp (set at creation time), a proof (more on that later), and a hash based on the previous block’s hash. (That hash is what ensures items in the blockchain haven’t been tampered with.)

Optionally, a block can also contain data. Here’s a potential implementation:

createBlock(proof, previousHash = undefined) {
  const block = {
    index: this.chain.length + 1,
    timestamp: new Date().getTime(),
    proof,
    previousHash: previousHash ? previousHash : this.hash(JSON.stringify(this.lastBlock()))
  };

  this.chain.push(block);
  return block;
}

Notice the reference to proof in the parameter list and to this.hash() for hashing.

Let’s look at the hash function first. To create a hash of the previous block, we’ll use HMAC SHA256 with a secret. The crypto package handles this, so make sure it’s imported:

const crypto = require('crypto');
// ...
hash(block) {
  return crypto.createHmac('sha256', 'a').update(block).digest('hex');
}

The purpose of the hash is to make sure that the block and the chain of blocks haven’t been fiddled with - meaning that if someone modifies an entry in an earlier hash, it will break the entire chain because the hash is now going to be incorrect.

Please note that the secret a is used here only for demonstration purposes - you should never have such a simple secret in place, and you should never store the secret value in your application code but instead use environment variables.

Mining

To create a new block, we need to mine it. Mining boils down to solving a problem that’s somewhat difficult to solve but easy to verify. These problems get harder after each iteration. Our implementation uses a simple mining problem: find values that, when hashed, start with abcd. The most popular algorithm used by some blockchain implementations is called Proof of Work (PoW). With PoW, we create and solve mathematical puzzles.

To make the mining easier or more difficult the implementation can be changed - looking for hashes that start with abc only will make the work faster, while increasing it to be abcde will slow it down. Please note that these changes come with significant performance increments/decrements.

Here’s the implementation:

proofOfWork(lastProof) {
  let proof = 0;
  while (!this.validProof(lastProof, proof)) {
    proof += 1;
  }
  return proof;
}

validProof(lastProof, proof) {
  let guess = `${lastProof}${proof}`;
  let guessHash = crypto.createHmac('sha256', 'a').update(guess).digest('hex');
  return guessHash.slice(0, 4) === 'abcd';
}

We start proofs from 0. When we find a number that, when hashed, starts with abcd, we return it. That number gets bolted onto the newly forged block.

Proof of Work

The PoW always creates a cryptographic value. How they’re constructed is outside the scope here, but the same input yields the same output. In our case, we iterate through values, appending the last proof with an increasing number, checking whether the first four characters of the hash equal abcd. This produces a different proof number every time.

The PoW implementation could be something different as well - for example, take a hash of a word. Keep appending numbers after the word and if the hash of the word plus the attached numbers’ first four letters equal to 0000 we have a “proof”.

There are some other algorithms to solve problems - another one that pops up often is Proof of Stake (PoS).

Implementing the blockchain

With the blockchain class sorted, we can build an application around it. The simplest approach is a set of API endpoints that call the appropriate class methods:

  • /mine: an endpoint to mine a new block
  • /chain: returns all the blocks in the implementation

The /chain endpoint returns all blocks. But where does our first block come from when the application starts? We create it programmatically. It’s called a genesis block.

Genesis block

The genesis block is the first block created in the blockchain, the root of the chain. All other blocks come after it. In our implementation, we create it with a value of 1 and a proof of 1, by calling createBlock() during class initialisation:

class Blockchain {
  constructor(chain = []) {
    this.chain = chain;
    this.createBlock(1, 1); // genesis block
  }
// ... more code

The endpoints

Here’s the mine endpoint implementation. We’re not using any third-party dependencies (no Express), relying instead on built-in HTTP methods:

const http = require('http');
const url = require('url');

const Blockchain = require('./blockchain.class');
const blockchain = new Blockchain();

const port = 3000;

const server = http.createServer((req, res) => {
  const urlParts = url.parse(req.url);
  switch(urlParts.pathname) {
// ... more code

With this in place, we can wire up the endpoints.

/chain

This endpoint returns the entire chain.

case '/chain':
  const chain = (req, res) => {
    const response = {
      chain: blockchain.chain,
      length: blockchain.chain.length
    };
    return res.end(JSON.stringify(response));
  }
  chain(req, res);
  break;

When the application first starts, it only returns the genesis block:

{
  "chain": [
    {
      "index": 1,
      "timestamp": 1525082818630,
      "proof": 1,
      "previousHash": 1
    }
  ],
  "length": 1
}

Now we can start mining new blocks.

/mine

This endpoint runs through everything we’ve discussed: mining a new block using the PoW algorithm.

case '/mine':
  const mine = (req, res) => {
    const lastBlock = blockchain.lastBlock();
    const lastProof = lastBlock.proof;
    const proof = blockchain.proofOfWork(lastProof);
    const previousHash = blockchain.hash(JSON.stringify(lastBlock));
    const block = blockchain.createBlock(proof, previousHash);

    const response = {
      message: 'New block forged',
      index: block.index,
      proof: block.proof,
      previousHash: block.previousHash
    };

    res.end(JSON.stringify(response));
  };
  mine(req, res);
  break;

Here’s the response:

{
  "message": "New block forged",
  "index": 2,
  "proof": 16562,
  "previousHash": "ca6b685a21712d187fbbb2d0bf5745d617fe275f20524c7bad0c643c25e6f33f"
}

You can mine multiple blocks. Once they’re mined, calling /chain shows the full set:

{
  "chain": [
    {
      "index": 1,
      "timestamp": 1525083443166,
      "proof": 1,
      "previousHash": 1
    },
    {
      "index": 2,
      "timestamp": 1525083449558,
      "proof": 16562,
      "previousHash": "2486175ba172fa43712ad062275c7dc03a179a5582ecbfaf3276bbd14929732b"
    },
    {
      "index": 3,
      "timestamp": 1525083449838,
      "proof": 37046,
      "previousHash": "1ae143cbd8dfe7adfd6bc217bb37f48e99f97c4bc1d2c2d557e5b0c3a9619eb3"
    },
    {
      "index": 4,
      "timestamp": 1525083450248,
      "proof": 21181,
      "previousHash": "869f55314061dae9da72fb85d0020833016198a7ab489bf8bd689e1d723d11da"
    }
  ],
  "length": 4
}

Conclusion

This implementation covers the basics of blockchain. A few things are missing: there’s no data in the chains, and transactions aren’t possible (think buying and selling BitCoins). Those features could be bolted on without too much effort. Have a go at it.