How to write a simple blockchain implementation in 30 minutes with code samples

Blockchain Feb 19, 2020

In 2008, an anonymous person under the alias Satoshi Nakamoto built something extraordinary. He created bitcoin, a controversial currency that changed the way we traditionally viewed currency.

Despite all the controversy that bitcoin has garnered over the years, what doesn't stay controversial is the tech underneath it: blockchain.

What blockchain actually is?

Before, I tell you what blockchain actually is, let me tell you what a blockchain is not.

Blockchain is not a distributed ledger. It has nothing to do with maintaining accounts, and it doesn't have anything to do with decentralized computing. Those are just some of blockchain's use cases.

With that in mind, let's try to understand what is blockchain. Blockchain is an immutable data structure that stores arbitrary data in chunks known as blocks.

Blockchain infographic

How does a blockchain work?

The working principle behind a blockchain is that every block stores some amount of data. Once a block is added to the blockchain, it needs to have a reference to the cryptographic hash of the last block in the blockchain along iwith a nonce value that we'll discuss later on.

This ensures data integrity. If the data inside a block changes at any point of time, we would need to update all the subsequent blocks as the mutated block would yield a different hash since cryptographic hashes are very sensitive to changes and even the change in a single bit (the smallest unit of binary data), leads to a massive change in the hash.

But that doesn't make it very difficult, right? Since calculating a million hashes take only a couple of minutes at best.

Yes. It doesn't. And here we can see the real smarts of a blockchain algorthm. Proof of work/mining.

What is mining?

If you observe the diagram carefully, you can see a field called nonce is there. The nonce contains a random value (mostly numbers) that is used for the mining algorithm.

In order for a block to be added, it needs to have a valid hash. A blockchain imposses certain restrictions on the block to be considered a valid hash. All hashes in every block inside a blockchain must begin with a certain number of zeroes. The more zeroes a blockchain requires, the more difficult it is to find a valid hash.

Please note, the number zero is arbitrary, it doesn't matter if it's zeroes, ones of any character or sequence of characters. As long as a well defined restriction is in place, it works fine.

Mining is the process of finding a nonce that yeilds a valid hash.

We can take multiple approaches for mining, we can generate random numbers, characters or increment a counter. We choose the latter since it is simpler to implement and doesn't make it any more difficult or easier. It's the restriction that matters more than the nonce.

Now we have an understanding of how blockchain works, let's get to the implementation

Before we begin the implementation, we need to make some decisions.

  1. which cryptographic hash functions to use?
    Let's use sha256 for that. hashlib library in python contains that.
  2. how to define a valid hash?
    Valid hashes must contain certain number of zeroes in the beginning.
  3. How to update nonce for mining?
    we define nonce as a number that we'll increment till we find a valid hash

Below is the class that I wrote for Block

class Block:
    def __init__(self, data=""):
        self.previous_hash=""
        self.data=data
        self.hash=""
        self.timestamp=int(time.time()) #only store the number of seconds
        self.nonce=0

    # This will concatenate all the properties and calculate the hash, and return the hash
    def calculate_hash(self):
        thash=sha256(self.previous_hash+self.data+str(self.timestamp)+str(self.nonce))
        return thash.hexdigest()

    # we calculate the hash
    # we check if it passes our condition, if not, we mine with a different nonce
    # if it does, we return the value
    def mine(self, difficulty):
        self.hash=self.calculate_hash()

        if self.hash[0:difficulty] != "0"*difficulty:
            self.nonce+=1
            self.mine(difficulty)
        else:
            return self.hash

    def __str__(self):
        return " :: ".join([self.data, str(self.timestamp), self.hash, self.previous_hash, str(self.nonce)])

We initalize a block with some data. Add the properties previous_hash data hash timestamp and nonce to the class during initialization.

the method calculate_hash serializes the current object into a string and calculates the SHA256 hash of that string.

mine method takes an argument called difficulty and keeps mining till it gets that many number of zeroes in the beginning of the hash.

Let's implement the Blockchain now that we have Blocks.

When we first initialize a blockchain, we must calculate an initial block with some random data. The first block is useless and only used for generating the first hash for the subsequent blocks to use as previous_hash

class Blockchain:
    def __init__(self):
        self.difficulty=2
        self.blockchain=[] #list of blocks
        self.mine_first_block()

    def get_last_block(self):
        return self.blockchain[-1]
    
    def mine_first_block(self):
        b=Block("INITIAL DATA")
        b.mine(self.difficulty)
        self.blockchain.append(b)

    def add_block(self, data):
        b=Block(data)
        b.previous_hash=self.get_last_block().hash
        b.mine(self.difficulty)
        self.blockchain.append(b)

    def verify(self):
        for _block in xrange(len(self.blockchain)-1):
            block=self.blockchain[_block]
            block_n=self.blockchain[_block+1]
            if block.hash!=block_n.previous_hash:
                return False
        
        for block in self.blockchain:
            x = block.calculate_hash()
            if x!=block.hash:
                return False
        return True

    def __str__(self):
        v=map(str, self.blockchain)
        return "\n".join(v)

In the code above, we can see that we have decided on the below properties.

  1. difficulty that is initialized with the constructor. and it is set to 2 for now. (you can change it to make it more difficult)
  2. blockchain is an array that stores all the blocks in sequence.
  3. mine_first_block is called to, um, mine first block.

In addition, we define the below methods

  1. get_last_block is a helper function to retrieve the last block.
  2. mine_first_block creates a new block, mines it and adds it to the blockchain
  3. add_block takes some arbitrary data as a string, sets the reference of previous_hash to the last block's hash.
  4. verify iterates over the entire blockchain, calculates the hash of them, compares them with previous_hash of the next block. If, at any point, a mismatch is found, we invalidate the entire blockchain and say that data has been tampered.

Finished! Let's take it out for a spin.

if __name__=="__main__":
    a=Blockchain()
    print "mining"
    a.add_block("lorem Ipsum dolor")
    a.add_block("sit amet")
    print a;
    print "Verification:", a.verify();
    print 
    print "Altering data"
    a.blockchain[1].data="XKCD"
    print a
    print "Verification", a.verify()
    

At line 2, we initialize a new Blockchain.
At line 4, we add a block containing "lorem Ipsum dolor"
At line 5, we add a block containing "sit amet"
At line 6, we print the blockchain.

Verification False

INITIAL DATA :: 1582152894 :: 0013f0e60f9bf35bfc7543839c971e0f28c12df3da0aad0428a0dde76d7c8193 ::  :: 33
lorem Ipsum dolor :: 1582152894 :: 002be3393372656f01a6a472d129544e58ac7742490407ee5ed9b23deaef76c8 :: 0013f0e60f9bf35bfc7543839c971e0f28c12df3da0aad0428a0dde76d7c8193 :: 158
sit amet :: 1582152894 :: 00ec3c2482309d403b83c27d838f61b0ea7fa98d82fdbe8d480b6edc1858e85f :: 002be3393372656f01a6a472d129544e58ac7742490407ee5ed9b23deaef76c8 :: 297

At line 7, we verify the integrity and we find Verification: True
At line 9, we change the data of the first block to "XKCD"
At line 10, we print the blockchain again.

INITIAL DATA :: 1582152894 :: 0013f0e60f9bf35bfc7543839c971e0f28c12df3da0aad0428a0dde76d7c8193 ::  :: 33
XKCD :: 1582152894 :: 002be3393372656f01a6a472d129544e58ac7742490407ee5ed9b23deaef76c8 :: 0013f0e60f9bf35bfc7543839c971e0f28c12df3da0aad0428a0dde76d7c8193 :: 158
sit amet :: 1582152894 :: 00ec3c2482309d403b83c27d838f61b0ea7fa98d82fdbe8d480b6edc1858e85f :: 002be3393372656f01a6a472d129544e58ac7742490407ee5ed9b23deaef76c8 :: 297

Now, again, at the last line, we perform a validation with result Verification False

Thus, we conclude, this is a crude yet working implementation of a simple blockchain. Up next, I have plans to write an application that uses this blockchain.

Sohan Basak

Hi, I am Sohan. A software engineer by profession, I am really passionate about algorithms, AI/ML, Maths and Physics. Play the guitar as a hobby, the maths behind music is fascinating.