Title: Build a Simple Blockchain Pet Project with Python
Tags: blockchain, python, beginners
Published: 2023-05-02 21:30:41


Blockchain technology has been around for more than a decade, and its popularity has skyrocketed in recent years. A blockchain is essentially a digital ledger that records transactions in a secure and transparent manner. Each block in the chain contains a unique cryptographic hash of the previous block, creating an immutable and tamper-proof record of all transactions.

In this tutorial, we will build a simple blockchain pet project using Python. We will create a `Blockchain` class that can add new transactions, create blocks, and validate the chain's integrity. The project will allow us to create a simple ledger for pet transactions, including the pet's name, breed, and owner.

### Prerequisites

To follow along with this tutorial, you should have a basic understanding of Python programming and the command line interface. You will also need to have Python installed on your machine.

### Setting up the Project

First, let's create a new directory for our project and navigate to it in the command line:

```
$ mkdir blockchain-pet-project
$ cd blockchain-pet-project
```

Next, let's create a new Python file called `blockchain.py` in our project directory:

```
$ touch blockchain.py
```

We will use this file to define our `Blockchain` class.

### Defining the Blockchain Class

Open up `blockchain.py` in your favorite text editor and define the `Block` and `Blockchain` classes:

```
import datetime
import hashlib
import json

class Block:
    def __init__(self, index, timestamp, transactions, previous_hash):
        self.index = index
        self.timestamp = timestamp
        self.transactions = transactions
        self.previous_hash = previous_hash
        self.hash = self.calculate_hash()

    def calculate_hash(self):
        data = str(self.index) + str(self.timestamp) + json.dumps(self.transactions) + str(self.previous_hash)
        sha = hashlib.sha256()
        sha.update(data.encode('utf-8'))
        return sha.hexdigest()


class Blockchain:
    def __init__(self):
        self.chain = [self.create_genesis_block()]

    def create_genesis_block(self):
        return Block(0, '01/01/2022', [{'name': 'Genesis Block'}], '0')

    def get_latest_block(self):
        return self.chain[-1]

    def add_transaction(self, transaction):
        self.current_transactions.append(transaction)

    def create_new_block(self):
        index = len(self.chain)
        timestamp = str(datetime.datetime.now())
        previous_hash = self.get_latest_block().hash
        new_block = Block(index, timestamp, self.current_transactions, previous_hash)
        self.chain.append(new_block)
        self.current_transactions = []

    def is_chain_valid(self):
        for i in range(1, len(self.chain)):
            current_block = self.chain[i]
            previous_block = self.chain[i-1]
            if current_block.hash != current_block.calculate_hash():
                return False
            if current_block.previous_hash != previous_block.hash:
                return False
        return True
```

The `Block` class represents a single block in the chain. It contains an index, timestamp, list of transactions, previous block hash, and its own hash.

The `Blockchain` class represents the entire chain. It contains a list of blocks, starting with the genesis block. It also contains methods for adding new transactions, creating new blocks, and validating the chain's integrity.

### Adding Transactions

Let's now add a few transactions to our blockchain. We will create a new instance of the `Blockchain` class and add three pet transactions:

### Adding Transactions (Continued)

```
blockchain = Blockchain()

transaction1 = {'name': 'Fluffy', 'breed': 'Golden Retriever', 'owner': 'Alice'}
blockchain.add_transaction(transaction1)

transaction2 = {'name': 'Buddy', 'breed': 'Labrador', 'owner': 'Bob'}
blockchain.add_transaction(transaction2)

transaction3 = {'name': 'Max', 'breed': 'German Shepherd', 'owner': 'Charlie'}
blockchain.add_transaction(transaction3)
```

Each transaction is represented as a Python dictionary with the pet's name, breed, and owner. We add each transaction to the blockchain using the `add_transaction` method.

### Creating Blocks

Once we have added a few transactions, we can create a new block using the `create_new_block` method:

```
blockchain.create_new_block()
```

This method will create a new block with the current timestamp, the list of transactions we added, and the hash of the previous block in the chain.

### Validating the Chain

We can check the validity of the chain at any time using the `is_chain_valid` method:

```
print(blockchain.is_chain_valid())
```

This method iterates over each block in the chain and verifies that its hash matches the result of the `calculate_hash` method. It also verifies that each block's `previous_hash` matches the hash of the previous block in the chain.

## Putting it All Together

Let's now put all the pieces of our blockchain pet project together and see how it works.

First, we create a `Blockchain` object:

```python
class Blockchain:
    def __init__(self):
        self.chain = [self.create_genesis_block()]
        self.current_transactions = []
        self.block_size = 2

    def create_genesis_block(self):
        return Block(0, datetime.now(), [], "0")

    def add_transaction(self, transaction):
        if len(self.current_transactions) < self.block_size:
            self.current_transactions.append(transaction)
        else:
            self.create_new_block()
            self.current_transactions.append(transaction)

    def create_new_block(self):
        previous_hash = self.chain[-1].hash
        block = Block(len(self.chain), datetime.now(), self.current_transactions, previous_hash)
        self.current_transactions = []
        self.chain.append(block)

    def is_chain_valid(self):
        for i in range(1, len(self.chain)):
            current_block = self.chain[i]
            previous_block = self.chain[i - 1]

            if current_block.hash != current_block.calculate_hash():
                return False

            if current_block.previous_hash != previous_block.hash:
                return False

        return True


blockchain = Blockchain()

transaction1 = {'name': 'Fluffy', 'breed': 'Golden Retriever', 'owner': 'Alice'}
blockchain.add_transaction(transaction1)

transaction2 = {'name': 'Buddy', 'breed': 'Labrador', 'owner': 'Bob'}
blockchain.add_transaction(transaction2)

transaction3 = {'name': 'Max', 'breed': 'German Shepherd', 'owner': 'Charlie'}
blockchain.add_transaction(transaction3)

blockchain.create_new_block()

print("Chain is valid: ", blockchain.is_chain_valid())
```

Each transaction is represented as a Python dictionary with the pet's name, breed, and owner. We add each transaction to the blockchain using the `add_transaction` method. 

Our `Blockchain` class has a `block_size` attribute, which determines the maximum number of transactions that can be added to a block. In this example, we set `block_size` to 2, which means that a new block will be created automatically when the third transaction is added.

When we add the first two transactions, they are added to the `current_transactions` list. When we try to add the third transaction, we check if the length of the `current_transactions` list is less than the `block_size`. If it is, we simply append the transaction to the list. If it's not, we create a new block using the `create_new_block` method and add the transaction to the new block.

Finally, we create a new block by calling the `create_new_block` method. This method will create a new block with the current timestamp, the list of transactions we added, and the hash of the previous block in the chain.

We can check the validity of the chain at any time using the `is_chain_valid` method. This method iterates over each block in the chain and verifies that its hash matches the result of the `calculate_hash` method. It also verifies that each block's `previous_hash` matches the hash of the previous block in the chain.

## Further Improvements

Our pet project blockchain is still very simple and lacks some key features that real-world blockchains possess. Here are a few ideas for further improvements:

- **Proof of Work (PoW)**: In a real blockchain, new blocks are only added to the chain if a certain amount of work has been done to create them. This is known as the Proof of Work (PoW) consensus algorithm. Implementing a PoW algorithm would make our blockchain more secure and resistant to attacks.

- **Decentralization**: Currently, our blockchain runs on a single node. To make it more robust and decentralized, we could allow other nodes to join the network and validate transactions. This would require implementing a network protocol to communicate between nodes and reach consensus on the state of the blockchain.
- **Persistence**: In our current implementation, the blockchain is stored in memory and will be lost if the program is stopped or crashes. To make it more persistent, we could save the blockchain to disk or a database.
- **Security**: Our current implementation doesn't include any encryption or authentication mechanisms. Adding these features would make our blockchain more secure and resistant to attacks.

## Conclusion

In this pet project, we created a simple blockchain to store pet ownership information. We started by defining what a blockchain is and how it works. Then, we implemented a basic `Block` class to represent each block in the chain. Next, we created a `Blockchain` class that handles adding transactions to the blockchain and creating new blocks. Finally, we put all the pieces together and tested our blockchain by adding some transactions and verifying the validity of the chain.

While our blockchain is still very simple and lacks many features of real-world blockchains, it provides a good starting point for further exploration and experimentation. With some additional work, we could create a more robust and secure blockchain that could be used for a variety of purposes beyond just tracking pet ownership.