With all the hype about Bitcoin and other cryptocurrencies in recent years, I wanted to understand
their underlying technology, i.e. Blockchain, better. So of course, what better way to learn than
write my own. After reading up a bit on the internals of Bitcoin, the basic structure of blockchains
and related data structures such as Merkle Trees, I decided to write a very simple version in Elixir.

I went with Elixir for a couple of reasons:

To get better at it

See how Erlang’s distributed model could help me with replication

I just love the damn language too much

The original blockchain I wrote is a bit complicated since I end up adding too many features (I wanted
to experiment with node synchronization, RPC calls, cryptographic validations using Ecto, and file
storage as an application). So for the purposes of this article, we are going to write a blockchain
that simply stores some text in each block (but you can check out the actual project here).

The Basics

In the simplest of terms, a blockchain is basically a list of “blocks” where each block object/struct
stores a cryptographic hash of the previous block. A blockchain is valid only if the hash of each block in
the chain matches the stored hash in the next one. Cryptographically, this means that if the tiniest bit
of data changes in any block, the hashes of all consequent blocks would change drastically and as a result
invalidate the blockchain. So, a blockchain must always be append-only, i.e. no previous data can be
changed or removed.

Structure

Each block in the chain must store a couple of items; such as the data being stored and the timestamp it
was created on. We also need to store the has of the previous block, and for good measure let’s store the
hash of the current block as well. Although we should also use Public-Key Cryptography and store the
signature of the author (which can be verified later), we’re going to ignore that part and focus on
understanding the basics (maybe we can do that in another blog post in the future). Our struct should look
something like this:

So, let’s create a Block module, with two methods; new/2 that takes the data that’s going to go in the
block along with the hash of the previous block, and a zero/0 method that builds the first “zero” block
in a blockchain:

123456789101112131415161718192021222324

defmoduleBlockdodefstruct[:data,:timestamp,:prev_hash,:hash]@doc"Build a new block for given data and previous hash"defnew(data,prev_hash)do%Block{data:data,prev_hash:prev_hash,timestamp:NaiveDateTime.utc_now,}end@doc"Build the initial block of the chain"defzerodo%Block{data:"ZERO_DATA",prev_hash:"ZERO_HASH",timestamp:NaiveDateTime.utc_now,}endend

Cryptography

Since blockchains involve a lot of cryptography, it’s better to have a separate module responsible for it
and provide a uniform interface (so we can change the implementation in the future if we want without
breaking the functionality). We also need to encode our data in some format before we hash it. You can go
with anything you want, but we’re going to use JSON. Start by adding the poison dependency in your
mix.exs file:

1

{:poison,"~> 3.1"}

And then create a Crypto module with the helper hashing functions. We’ll use the built in SHA256 hashing
in Erlang’s :crypto module:

123456789101112131415161718192021222324252627

defmoduleCryptodo# Specify which fields to hash in a block@hash_fields[:data,:timestamp,:prev_hash]@doc"Calculate hash of block"defhash(%{}=block)doblock|>Map.take(@hash_fields)|>Poison.encode!|>sha256end@doc"Calculate and put the hash in the block"defput_hash(%{}=block)do%{block|hash:hash(block)}end# Calculate SHA256 for a binary stringdefpsha256(binary)do:crypto.hash(:sha256,binary)|>Base.encode16endend

We were very careful to only encode only the main 3 fields here (without the hash field of the block)
using the Map.take/2 function, and then calculate their SHA256. We also added a helper method put_hash/1
to directly put the hash in it. If we were using public-key cryptography and storing the author’s signature
in the blocks as well, we would have created sign/1 and verify/1 methods for that purpose, using the
RsaEx library or Erlang’s built-in :public_key module.

We’ll also add a valid? method in our Block module to check if the hash of block is valid, and matches
the previous block’s hash. When only the block itself is given, it calculates the hash of the block and
compares it with the stored value. But when the previous block is also given, it compares the value of the
previous block’s hash to the one stored in the prev_hash field:

123456789101112131415

defmoduleBlockdo# Existing stuff...@doc"Check if a block is valid"defvalid?(%Block{}=block)doCrypto.hash(block)==block.hashenddefvalid?(%Block{}=block,%Block{}=prev_block)do(block.prev_hash==prev_block.hash)&&valid?(block)endend

Bringing it Together

Finally, let’s build the Blockchain module that contains all blocks in order and provides a neat interface
to insert new blocks and calculate their hashes. Ideally, the blockchain should be stored on the disk
(using a database, for example) and the module providing a quick interface to it. Even if we decide to not
persist the chain on the disk, we can use GenServers or Mnesia tables to maintain the state. But again,
for the purposes of this post, we won’t manage the state and just interact with it as a list.

1234567891011121314151617181920212223242526272829303132333435363738

defmoduleBlockchaindo@doc"Create a new blockchain with a zero block"defnewdo[Crypto.put_hash(Block.zero)]end@doc"Insert given data as a new block in the blockchain"definsert(blockchain,data)whenis_list(blockchain)do%Block{hash:prev}=hd(blockchain)block=data|>Block.new(prev)|>Crypto.put_hash[block|blockchain]end@doc"Validate the complete blockchain"defvalid?(blockchain)whenis_list(blockchain)dozero=Enum.reduce_while(blockchain,nil,fnprev,current->conddocurrent==nil->{:cont,prev}Block.valid?(current,prev)->{:cont,prev}true->{:halt,false}endend)ifzero,do:Block.valid?(zero),else:falseendend

The new/0 method returns a new blockchain, with a zero block as its only contents. The insert/2 method
creates a new block for the given data, hashes it and inserts it into the blockchain, returning the updated
state. Finally, the most interesting method here, valid?/1, goes through the entire blockchain in reverse
order (most recent block to the oldest one) using Enum.reduce_while/3, validating blocks in pairs. If at
any point the internal Block.valid? returns false, the entire method does too.

Running it

We don’t have fancy blockchain network running right now, so we’ll simply jump in iex and test it out
there:

Implement a custom encoding scheme in a certain order to always guarantee
the same hash for a given map (For example, Maps in Elixir are unordered
and the hash generated would almost never be the same as one generated in another language
for the same values)

With the powerful Erlang Virtual Machine, we can also do some fancy stuff:

Have a distributed network of nodes running the blockchain

Maintaining Blockchain state in Mnesia across many nodes

Broadcast new blocks to the entire network

Perform state consensus and implement conflict resolution

Here are some other blockchain & elixir related resources and projects: