Creating Your First Blockchain with Python

C

In this tutorial we’ll learn how to create a very basic Blockchain with Python. We will create a Blockchain with just 30 lines of code! The aim is to introduce you to Blockchain programming without getting into inessential details. You should already know fundamentals of Blockchain, if not then you may want to read this article first. You should also know basic Python programming and object oriented concepts.

Prerequisites

  1. Python 3 Installed on Windows, Linux or Mac.
  2. Knowledge of running Python programs on terminal or IDLE.

The Fundamentals

A Blockchain is merely a series of blocks. These blocks are logically connected to each other as each one stores previous block’s hash. We will create a class that represents a block and store its predecessor’s address as one of the variables within it. Other variables in the Block class include:

  1. Data: Actual data to be stored in the block
  2. Hash: Hash of this data
  3. Timestamp: Denotes when the block was added to the blockchain
  4. Nonce: A random number that is used to find target hash

Python Libraries

Firstly we import these three Python libraries. You need not to download them as they are part of standard distribution:

  1. hashlib: To generate SHA-256 of block’s data.
  2. datetime: To get current timestamp.
  3. random: To generate nonces.
#for computing sha256
import hashlib

#for generating timestamps
import datetime 

#for generating random numbers
import random 

The Block Class

Block class uses a constructor to initialize variables when it is instantiated. Let’s define proof-of-work as finding a hash value that must start with two zeroes (“00”). We define a function getPoWHash() which returns a hash value which satisfies our proof-of-work condition. Basically it appends different random numbers (nonces) to the data until it finds a target hash. When we find the target hash, we also store nonce used to find this hash in the block so that others can verify it.

class Block:
	def getPoWHash (self, data):
		nonce = str(random.randint(0, 300000))
		noncedData = data + nonce
		hash = hashlib.sha256 (noncedData.encode('utf-8')).hexdigest()
		#hashlib requires data to be encoded before hashed.
		if hash.startswith ("00"):
			self.nonce = nonce
			return hash
		else:
			return self.getPoWHash (data)

	def __init__ (self, data, previousHash):
		self.data = data
		self.nonce = None
		self.previousHash = previousHash
		self.timeStamp = datetime.datetime.now()
		self.hash = self.getPoWHash (data)

Adding Genesis Block and Other Blocks

Next, we add some blocks to our Blockchain. First block is special, so we don’t have previous block’s hash instead we use a 0 here for the sake of simplicity. We simply instantiate the Block class each time we want to add a block.

genesisBlock = Block("I am genesis block!", 0)

secondBlock = Block("I am second block", genesisBlock.hash)

thirdBlock = Block("I am third block", secondBlock.hash)

Viewing the Blockchain

To view our Blockchain we can simply print the hashes of each of the blocks.

print ("Genesis Block Hash: ", genesisBlock.hash)

print ("Second Block Hash: ", secondBlock.hash)

print ("Third Block Hash: ", thirdBlock.hash)

Output:
As you can see all hashes start with two zeroes as that is the condition we’ve set as proof-of-work. In Bitcoin, this requirement is 17 leading zeroes.

Genesis Block Hash:  00ddef133aa388b89d431ffd80874d94c808b363ce1467eb6e38a7c38c7712d1

Second Block Hash:  0029e17e48976fdd651e75ce283770634c33ddaca2ab9d05b2df30a0ab779bfa

Third Block Hash:  0094e2b65446530ff4a046be4a0843799e48e4d8d993fd01669a0328bcf43e79

Congrats! You’ve Made It.

We are all done! Here is the full code for this tutorial:

import hashlib
import datetime
import random

class Block:
	def getPoWHash (self, data):
		nonce = str(random.randint(0, 300000))
		noncedData = data + nonce
		hash = hashlib.sha256 (noncedData.encode('utf-8')).hexdigest()
		#hashlib requires data to be encoded before hashed.
		if hash.startswith ("00"):
			self.nonce = nonce
			return hash
		else:
			return self.getPoWHash (data)

	def __init__ (self, data, previousHash):
		self.data = data
		self.nonce = None
		self.previousHash = previousHash
		self.timeStamp = datetime.datetime.now()
		self.hash = self.getPoWHash (data)

genesisBlock = Block("I am genesis block!", 0)
secondBlock = Block("I am second block", genesisBlock.hash)
thirdBlock = Block("I am third block", secondBlock.hash)

print ("Genesis Block Hash: ", genesisBlock.hash)
print ("Second Block Hash: ", secondBlock.hash)
print ("Third Block Hash: ", thirdBlock.hash)

What’s Ahead?

Our Blockchain is stored on a single machine but a Blockchain serves its purpose only when it is distributed. Nevertheless, it is a great start isn’t it?

9 Comments

This site uses Akismet to reduce spam. Learn how your comment data is processed.

  • getting following error while changing
    genesisBlock = Block(“I am genesis block!”,0) to genesisBlock = Block(“I am genesis block”,0)

    ….
    File “blockDev.py”, line 14, in getPoWHash
    return self.getPoWHash (data)
    File “blockDev.py”, line 14, in getPoWHash
    return self.getPoWHash (data)
    File “blockDev.py”, line 14, in getPoWHash
    return self.getPoWHash (data)
    File “blockDev.py”, line 7, in getPoWHash
    nonce = str(random.randint(0,300000))
    File “/usr/lib/python3.5/random.py”, line 218, in randint
    return self.randrange(a, b+1)
    File “/usr/lib/python3.5/random.py”, line 194, in randrange
    return istart + self._randbelow(width)
    File “/usr/lib/python3.5/random.py”, line 228, in _randbelow
    if type(random) is BuiltinMethod or type(getrandbits) is Method:
    RecursionError: maximum recursion depth exceeded while calling a Python object

    • Hi Smit! Python has a default recursion depth limit of 1000. Recursion depth is number of times a function can recursively call itself.

      As you may know, in this problem when we generate random nonces not always we get target nonce in 1000 tries, when this happens you get this error.

      You can increase recursion limit using sys.setrecursionlimit(x) where x is the new limit you want to set.

      But this is a naive solution, which is good for our tutorial. For production systems you should rewrite getPoWHash() using iterations rather than recursion.

      I hope this helps. If you found this post helpful please share it to others.

    • Hi Nila,

      We are not adding zeroes as such. We are repeatedly running getPoWHash () function to generate a hash until we get a hash with two leading zeroes.

      Computing power invested in this effort is the COST of generating a hash.

      • Hi Devji,
        I also had the same question as Nila, but I will word it differently. Is there a way to make it so we only get hash’s that start with 5 zero’s instead of starting with 2 zero’s?

      • Hi Devji,
        I had the same question as Nila but will phrase it differently. Is there a way to get a hash that leads with 4 zeroes instead of just two?

        • Billy, when designing a proof of work function, the designer will choose how many zeroes are good for it! Zeroes or ones or Zs don’t matter. We need to make sure that whoever is adding a solution to the blockchain is doing so only after a lot of “work”.

          Work, here, means number of computations a miner does before it comes up with a solution. The more the number of 0s the harder it is to come up with the solution. It means miner will have to use more processing power, electricity and other resources to come up with a solution. If you keep low number of 0s, it becomes easy to compute the solution.

          Bill, please feel free to ask more questions if this doesn’t explain. I am here to help!

Subscribe

Follow me on