Did you know that Bitcoin is built on top of Blockchain? Today, we’re going to build a Blockchain with Python from scratch.
What is Blockchain?
In 2008, the Bitcoin paper was published by an unknown individual or group named Satoshi Nakamoto. Bitcoin came out as a peer-to-peer version of electronic cash that allowed transactions without going through centralized institutions (banks). Most people don’t know that in that same paper, Satoshi defined a distributed way of storing information, nowadays known as Blockchain.
To put it simply, Blockchain is a shared, immutable digital ledger that stores transactions over a decentralized network of computers.
We can divide Blockchain into two simple terms:
- Block: A space where we store transactions
- Chain: A set of linked records
This defines Blockchain as a chain of linked blocks, where each block stores a transaction made with specific parameters.
Each block is built on top of another block, creating an irreversible chain of blocks. In other words, every block depends on another. This turns out into a robust and immutable system in which anyone with the correct permissions can review integrity.
Blockchain introduces an interesting set of features:
- History immutability
- Information persistency
- No errors with stored data
A lot of systems currently rely on Blockchain, such as cryptocurrencies, asset transfer (NFTs), and possibly in the near future, voting.
It’s worth mentioning that a Python Blockchain has not to be a complex program with thousands of lines of code. At its core, it would be a list of transactions linked to one another.
Of course, this was a brief explanation, but if you want a full guide, we’ve produced a complete tutorial on Blockchain for beginners. Make sure to check it out.
Without further delay, let’s build a simple Blockchain with Python.
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"
Of course, GC refers to GeekCoin
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}")
Then, we do the same with the second block, but passing the first block hash as the previous_hash argument.
block2 = GeekCoinBlock(block1.block_hash, [t3, t4])
print(f"Block 2 data: {block2.block_data}")
print(f"Block 2 hash: {block2.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
You can see the current project on this GitHub repo.
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, Ethereum, 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 created one by yourself. 🤑
Keep Coding! 👨💻