Blockchain is an incredibly hot topic in computer science these days. It become famous in 2008 thanks to the Bitcoin cryptocurrency, which (as you may know) uses a Blockchain in order to record every transaction into a public distributed ledger.
But... how much do we know about Blockchain?
I mean, what if we want to understand how Blockchain works and what makes it so powerful? How should we start?
Let's begin with the basics!

What is a Blockchain?

A Blockchain is literally a chain of blocks, where a block is a piece of information stored inside a public database, the chain.
In JavaScript, we can think of blocks as an object:

{
  timestamp:    1568468720410,
  data:         "I am a block",
  previousHash: "2510c39011c5be704182423e3a695e91",
  hash:         "363b122c528f54df4a0446b6bab05515"
}

now, let's analyze the block above:

  • timestamp: the timestamp of the block creation.
  • data: the data contained inside the block. Can be anything: an object, string, number... we usually store transaction's data inside of this part of our block.
  • hash: the current block hash. Represents the data contained inside the block. If we edit any of the content inside this block, our hash will change.
  • previousHash: a hash representing the previous block.

Wait wait wait! Previous block?
Yes! The key feature of Blockchain in fact, is that every block of the chain must contain a data representing the previous block. That way, if you want to modify one block, you have to recalculate the entire chain, which (we’ll see how later on) can be really difficult (if not impossible).
For that reason, we can say that the Blockchain is an immutable structure.

Building a minimalistic Blockchain

So, how do we start to write our Blockchain?
First of all, let’s define the most important function of our Blockchain: the one that computes the hash for the blocks.

const SHA256 = require("crypto-js/sha256");

function calculateHash({previousHash, timestamp, data, nonce = 1}) {
  return SHA256(previousHash + timestamp + JSON.stringify(data) +  nonce).toString();
}

As you can see, in order to compute our block’s hash, we need four parameters: previousHash, timestamp, data and nonce. We’ve seen what the first three parameters are, but why do we need a nonce?
For security reasons.
We don’t want to let potentially malicious developers to change the content of a block and then recalculate the whole chain in order to make it valid. For that reason, we need to define some constraints about how the hash should be formatted in order to be valid.

For instance, let’s pretend we have the following block:

{
  data: {
    sender:   "x3041d34134g22d",
    receiver: "x89sj8ak2l9al18",
    amount:   0.0012,
    currency: "BTC"
  },
  timestamp: 1568481293771,
  previousHash: "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae",
}

Its hash would be computed in few milliseconds, and it would look like this:

6b15398dcfeac338ac05bc61e37f575819985f897f0a56e329b574b52a3ed4dd

So, what’s wrong with this?
Imagine we have a supercomputer which is able to perform thousands of hashing computations per seconds. How long would it take to recalculate the entire chain?
We can make his life harder by setting some constraints.
For example, we could decide that an hash is valid only when is starting with four zeros and four nines:

00009999cfeac338ac05bc61e37f575819985f897f0a56e329b574b52a3ed4dd

But the hash depends on the block’s content… how can we respect this constraint? Here comes the nonce!
The nonce is a random value inserted during our hashing computation that makes it more probable to get a well formatted hash. Our hash doesn’t respect the imposed rules? Let’s compute it again with a different nonce.

Now let’s test some different constraints and let’s see how long would it take to compute the hash:

  • Hash must start with two zeros: 211ms
  • Hash must start with three zeros: 297ms
  • Hash must start with five zeros: 5966ms
  • Hash must start with f5: 174ms
  • Hash must end with 0990: 196ms
  • Hash must end with f918: 4436ms

Now imagine if we define a very time-expensive rule… if computing a single block takes about four hours, how much would it take to compute (or “to mine”) the whole chain?

The genesis Block

The first block of a Blockchain is called “The Genesis Block”. It cannot have a “previous hash” value, so it will be really simple to write a function that will generate it:

function generateGenesisBlock() {
  const block = {
    timestamp:    + new Date(),
    data:         "Genesis Block",
    previousHash: "0",
  };
  return {
    ...block,
    hash: calculateHash(block)
  }
}

Great! So now we can try to run the generateGenesisBlock function, let’s see what happens:

{ 
  timestamp: 1568533984830,
  data: 'Genesis Block',
  previousHash: '0',
  hash: '7c8b7226901c9ccfb1e1b0301685f6001431e9fd7dbb408fd7735f95dd314627' 
}

Awesome!

Mining new blocks

Now we need a function that computes new blocks for the Blockchain.
But first, we need to define our hash constraints:

function checkDifficulty(difficulty, hash) {
  return hash.substr(0, difficulty) === "0".repeat(difficulty)
}

in the function above ( checkDifficulty) we can pass two arguments: difficulty and hash. We want to keep things super simple, so (for that implementation), we decide that our hash must start with 4 zeros.
This function returns true if the passed hash respects the constraint. Otherwise will return false, so we’ll need to compute it again changing the nonce (as seen before).

As you may have noticed, in order to guarantee a more testable and modular codebase, we’re adopting the Functional paradigm. So, in order to compute the next nonce, we need a function that takes the block and returns a modified version of it, containing a new nonce.
We want to avoid side-effects, so we won’t edit our nonce value directly:

function nextNonce(block) {
  return updateHash({ ...block, nonce: block.nonce + 1 })
}

So as you can see, we’re returning the result of updateHash, which basically takes the block and returns a new version of it with a new hash:

function updateHash(block) {
  return { ...block, hash: calculateHash(block) }
}

Last but not least, we need a recursive function that calculates the hash of our block until it respects the imposed constraints. But here comes a problem: how to make recursion safe in JavaScript?
Thankfully I wrote an article about recursion in JavaScript and how to make it memory safe! Let’s implement a trampoline (learn more here):

function trampoline(func) {
  let result = func.apply(func, ...arguments);
  while(result && typeof(result) === "function") {
    result = result();
  }
  return result;
}

That will be the only impure part of our codebase, but it’s absolutely needed in order to prevent some memory-related errors.

Now let’s put all together:

function mineBlock(difficulty, block) {
  function mine(block) {
    const newBlock = nextNonce(block);
    return checkDifficulty(difficulty, newBlock.hash)
            ? newBlock
            : () => mine(nextNonce(block));
  }
  return trampoline(mine(nextNonce(block)));
}

Don’t get scared! Let’s analyze the code above:

  • We define a new function that takes difficulty and block as arguments. difficulty is just a number representing how many zeros should our hash start with, block is just the block we want to mine.
  • We define a function mine that takes block as argument.
  • Inside that function, we create a new block with a new nonce.
  • Then we need to check if the hash respects our rules. If it does, let’s return our newBlock block as result. Otherwise, we need to change its nonce and mine it again.
  • Now that we have the mine function, we wrap it inside our trampoline. It will run the function recursively until we get a correct hash for our block.

We now need one last function:

function addBlock(chain, data) {
  const { hash: previousHash } = chain[chain.length - 1];
  const block                  = { timestamp: + new Date(), data, previousHash, nonce: 0 }
  const newBlock               = mineBlock(4, block);
  return chain.concat(newBlock);
}

As you can see, the addBlock function takes the entire chain as its first argument and the new block data as its second arguments. Then, it mines the new block and returns a new chain containing the newly created block.

Validating the chain

We’ve done a lot of work so far! We now need to implement a function that validates the whole chain after a new block insertion:

function validateChain(chain) {
  function tce(chain, index) {
    if (index === 0) return true;
    const { hash, ...currentBlockWithoutHash } = chain[index];
    const currentBlock                         = chain[index];
    const previousBlock                        = chain[index - 1];
    const isValidHash         = (hash === calculateHash(currentBlockWithoutHash));
    const isPreviousHashValid = (currentBlock.previousHash === previousBlock.hash);
    const isValidChain        = (isValidHash && isPreviousHashValid);
    
    if (!isValidChain) return false;
    else return tce(chain, index -1);
  }
  return tce(chain, chain.length - 1)
}

This function is pretty self-explanatory:

  • We create a new function which takes the whole chain as its argument.
  • We define a new function called tce (which stands for tail call elimination) that takes the chain and a block index as its arguments.
  • If we’re looking at the first index of our chain (Genesis Block) we’ll return true.
  • Otherwise we need to check some conditions:
    • is the current block’s hash valid?
    • is the previous block’s hash valid?
    • so is the chain valid (until now)?

That is pretty simple, but incredibly powerful!

Putting everything together

Now we’re finally ready to test our Blockchain!
First of all, let’s initialize it:

let chain = [generateGenesisBlock()];

now, let’s create a new block:

const newBlockData = {
  sender:   "ks829fh28192j28d9dk9",
  receiver: "ads8d91w29jsm2822910",
  amount:   0.0023,
  currency: "BTC"
}

We’re now ready to mine this new block!

const newChain = addBlock(chain, newBlockData);

Let’s log the newly created chain:

console.log(newChain);
[ 
  { 
    timestamp: 1568556333240,
    data: 'Genesis Block',
    previousHash: '0',
    hash: 'd7fdf427ec6c60803204004b5f141570996dd8ea33d9f56b32a76d89ada83f5b' 
  },
  { 
    timestamp: 1568556333242,
    data: { 
      sender: 'ks829fh28192j28d9dk9',
      receiver: 'ads8d91w29jsm2822910',
      amount: 0.0023,
      currency: 'BTC'
    },
    previousHash: 'd7fdf427ec6c60803204004b5f141570996dd8ea33d9f56b32a76d89ada83f5b',
    nonce: 25569,
    hash: '00004aedfcae1d45e14bc044e9559a6372bb4a6edb544e806878df63f08127e6' 
  } 
];

We can now add as many blocks as we want to the blockchain!

Some considerations

We’ve just built a functional Blockchain with no side-effects at all. We can write tests and gain a 100% coverage with ease, and that’s an important thing to keep in mind when we want to write an application that can handle tons of data.

Using classes instead of pure functions and for loops instead of recursion can result easier and more performant… but we don’t care too much about performances (I mean, we’re spending days for mining blocks, are these milliseconds of for loops performances really important?) and we don’t want it to be too simple: we want it to be solid. And functional programming can help you to write more solid code, with reusable functions and great tests.

Next steps

We’ve just scratched the surface of how a Blockchain works and how to build one, and there’s still a lot of work to do!

  • Try to improve the hashing constraints. Try to find a rule that makes it hard to mine a new block.
  • Tail call recursion is not implemented on Node.js and browsers (even though its described in the EcmaScript language specification). Try to convert the tce function inside validateChain into a trampoline!
  • We said we don’t want mutable values inside our Blockchain. So how can we handle new block creations updating the existing chain?

How does “miners” get money?

As you can see, mining new blocks requires an incredible amount of time, which can be translated in electric energy cost. For that reason, people who’s mining new block can get a “reward” after mining. That’s where money come from

Did you like this article? Consider becoming a Patron!

This article is CC0 1.0 (Public Domain) licensed.