Building a Blockchain With Python

Before starting, let’s define what we’re going to do in this tutorial:

  • Build simple Blockchain system written in Python
  • Use our Blockchain with preestablished transactions represented as strings
  • Test the immutability of our Blockchain

We’re not going to use JSON but Python lists. This will let us simplify the process and focus on applying the key concepts of a Blockchain.

What you’ll need to follow this tutorial:

  • Understanding of classes and methods in Python
  • Basic usage of command line

Creating the Block class

Open your favorite code editor and create a main.py file. This will be the file we’ll work with.

Now, import hashlib, a module that lets us create one-way encrypted messages. Cryptography techniques like hashing make Blockchain create secure transactions.

A hash function is an algorithm that takes some data (usually an encoded string) and returns a unique identifier, often named “digest” or “signature.” This last part is vital; with a hash function, a slight difference in the input produces a radically different identifier as an output. We’ll see this in action later on.

For now, just import the built-in module hashlib:

# main.py file

"""

A simple Blockchain in Python

"""

import hashlib

This module includes most of the hashing algorithms you’ll need. Just keep in mind we’ll be using the hashlib.sha256() function.

Now, let’s get into the GeekCoinBlock, our totally original blockchain name.

class GeekCoinBlock:

    def __init__(self, previous_block_hash, transaction_list):

        self.previous_block_hash = previous_block_hash

        self.transaction_list = transaction_list

        self.block_data = f"{' - '.join(transaction_list)} - {previous_block_hash}"

        self.block_hash = hashlib.sha256(self.block_data.encode()).hexdigest()

I know this may result in a clunky piece of code. Let’s break down each part in the next section.

GeekCoinBlock Explanation

First, we create a class named GeekCoinBlock, a wrapper for objects that will have certain characteristics (attributes) and behaviors (methods).

 

Then we define the __init__ method (also named constructor), which gets invoked each time a GeekCoinBlock object gets created.

This method has three parameters:

  • self (the instance of each object)
  • previous_block_hash (a reference to the previous block)
  • transaction_list (a list of transactions made in the current block).

We store the previous hash and transaction list and create an instance variable block_data as a string. This doesn’t happen with real cryptocurrencies, in which we store that kind of data as another hash, but for simplicity purposes, we’ll store every block of data as a string.

Finally, we create the block_hash, which other blocks will use to continue the chain. Here’s where hashlib comes in handy; instead of creating a custom hash function, we can use the pre-built sha256 to make immutable blocks.

This function receives encoded strings (or bytes) as parameters. That’s why we’re using the block_data.encode() method. After that, we call hexdigest() to return the encoded data into hexadecimal format.

I know all of this can be overwhelming, so let’s play with hashlib on a Python shell.

In [1]: import hashlib

In [2]: message = "Python is great"

In [3]: h1 = hashlib.sha256(message.encode())

In [4]: h1

Out[4]: <sha256 ... object @ 0x7efcd55bfbf0>

In [5]: h1.hexdigest()

Out[5]: 'a40cf9cca ... 42ab97'

In [6]: h2 = hashlib.sha256(b"Python is not great")

In [7]: h2

Out[7]: <sha256 ... object @ 0x7efcd55bfc90>

In [8]: h2.hexdigest()

Out[8]: 'fefe510a6a ... 97e010c0ea34'

As you can see, a slight change in the input like “Python is great” to “Python is not great” can produce a totally different hash. This has all to do with Blockchain integrity. If you introduce some little change into a blockchain, its hash will dramatically change. This is the reason why the saying “You can’t corrupt a Blockchain” is true.

Using our Block Class

We’ll build an entire Blockchain class later, but for now, let’s use our Block class to create a chain of blocks (Blockchain).

In the same file, create a couple of transactions made up of simple strings stored in variables, for example:

class GeekCoinBlock:

    ...

t1 = "Noah sends 5 GC to Mark"

t2 = "Mark sends 2.3 GC to James"

t3 = "James sends 4.2 GC to Alisson"

t4 = "Alisson sends 1.1 GC to Noah"

Now, build the first block of our Blockchain by using the GeekCoinBlock class and print its attributes. Take into account that the previous_hash parameter of the genesis block (first block that precedes other blocks) will always be some arbitrary string or hash, in this case, “firstblock.”

block1 = GeekCoinBlock('firstblock', [t1, t2])

print(f"Block 1 data: {block1.block_data}")

print(f"Block 1 hash: {block1.block_hash}")


Let’s run and analyze the output we get from this piece of code. Once again, type in your terminal:

❯ python main.py

Block 1 data: Noah sends 5 GC to Mark - Mark sends 2.3 GC to James - firstblock

Block 1 hash: 01e4e15242a9601725f4a86ca01fbddaaec7105b442955bb0efcadbfc759806d

Block 2 data: James sends 4.2 GC to Alisson - Alisson sends 1.1 GC to Noah - 01e4e15242a9601725f4a86ca01fbddaaec7105b442955bb0efcadbfc759806d

Block 2 hash: 448c4306caf7f6937b0307f92f27fbea3bb73b3470363dee5026a1209dadcfa8

For now, you only see text and some 64 character hashes, but this resumes pretty much the mechanism of a Blockchain.

You start with a genesis block, the base of all other blocks.

Anyone can validate the chain’s integrity, and that’s why a Blockchain is such a secure system. For example, if we slightly modify the content of a transaction, say:

t2 = "Mark sends 2.3 GC to James" -> t2 = "Mark sends 3.2 GC to James"

We see a dramatic change in the hash of the blocks.

Block 1 data: Noah sends 5 GC to Mark - Mark sends 3.2 GC to James - firstblock

Block 1 hash: 7a990bf1d70230bf2dad6160496c0b3046da7a17b1281fd1d4c63d4eac58e78c

Block 2 data: James sends 4.2 GC to Alisson - Alisson sends 1.1 GC to Noah - 7a990bf1d70230bf2dad6160496c0b3046da7a17b1281fd1d4c63d4eac58e78c

Block 2 hash: 569b977306ce88b53e001dca7ba00c03a51c60d6df4650e7657dcd136f2da0ac
Coding a Blockchain

It’s not that clever to base our system integrity on hand-coded variables, so we need another approach.

We have the blocks. It’s time to build a class that joins them into a Blockchain.

Let’s start by deleting our previous transactions and block objects, then using the code below.

# main.py

class Blockchain:

def __init__(self):

self.chain = []

self.generate_genesis_block()

def generate_genesis_block(self):        self.chain.append(GeekCoinBlock("0", ['Genesis Block']))

def create_block_from_transaction(self, transaction_list):

previous_block_hash = self.last_block.block_hash       self.chain.append(GeekCoinBlock(previous_block_hash, transaction_list))

def display_chain(self):

for i in range(len(self.chain)):

print(f"Data {i + 1}: {self.chain[i].block_data}")

print(f"Hash {i + 1}: {self.chain[i].block_hash}\n")

@property

def last_block(self):

return self.chain[-1]

This is again a huge piece of code. Let’s break down each part:

  • self.chain — The list where all blocks are recorded. We can access each block via list indexes.
  • generate_genesis_block — Append the genesis or first block to the chain. The previous hash of the block is “0”, and the list of transactions is simply “Genesis Block.”
  • create_block_from_transaction — This allows us to append blocks to the chain with just a list of transactions. It would be very annoying to create a block manually every time we want to record a transaction
  • display_chain — Prints the chain of blocks with a for loop
  • last_block — A property that lets us access the last element of the chain. We used it on the create_block_from_transaction method.

Let’s test this Blockchain up.

# main.py

import hashlib

class GeekCoinBlock:

    ...

class Blockchain:

    ...

t1 = "George sends 3.1 GC to Joe"

t2 = "Joe sends 2.5 GC to Adam"

t3 = "Adam sends 1.2 GC to Bob"

t4 = "Bob sends 0.5 GC to Charlie"

t5 = "Charlie sends 0.2 GC to David"

t6 = "David sends 0.1 GC to Eric"

myblockchain = Blockchain()

myblockchain.create_block_from_transaction([t1, t2])

myblockchain.create_block_from_transaction([t3, t4])

myblockchain.create_block_from_transaction([t5, t6])

myblockchain.display_chain()

Now, run the main.py file.

Data 1: Genesis Block - 0

Hash 1: 39331a6a2ea1cf31a5014b2a7c9e8dfad82df0b0666e81ce04cf8173cc5aed3e

Data 2: George sends 3.1 GC to Joe - Joe sends 2.5 GC to Adam - 39331a6a2ea1cf31a5014b2a7c9e8dfad82df0b0666e81ce04cf8173cc5aed3e

Hash 2: 98cf363aecb33989aea0425a3c1287268bd86f63851bc08c0734a31db08506d5

Data 3: Adam sends 1.2 GC to Bob - Bob sends 0.5 GC to Charlie - 98cf363aecb33989aea0425a3c1287268bd86f63851bc08c0734a31db08506d5

Hash 3: 6f1cfcc3082488b97db8fdf8ed33f9ac7519be3e285a37a6fcc2f1904f373589

Data 4: Charlie sends 0.2 GC to David - David sends 0.1 GC to Eric - 6f1cfcc3082488b97db8fdf8ed33f9ac7519be3e285a37a6fcc2f1904f373589

Hash 4: 869df2f03c9860767d35b30a46233fbeea89a3000ae5019d1491e3829d1ab929

Congratulations! 🙌 You just created a simple Python Blockchain from scratch.

You can now strengthen the Blockchain immutability by using getters and setters and implement other features like proof-of-work, mining, or any other concept we explained in the Bitcoin Mining fundamentals article.

Conclusion

Blockchain is the technology behind Bitcoin, Etherium, and every other cryptocurrency out there. In this article, you learned how to create a Blockchain with Python by using hash algorithms like sha256, classes, and objects.

Your challenge is to create a mining system, and why not, implement it with a REST API using frameworks like Django or Flask.

Many people are making fortunes from cryptocurrencies. Just imagine what you could do if you create one by yourself. 🤑

Keep Coding! 👨‍💻

You may also like

Leave a Reply